diff --git a/src/App/Material.cpp b/src/App/Material.cpp index 389e2e94c1..af399dcc32 100644 --- a/src/App/Material.cpp +++ b/src/App/Material.cpp @@ -25,10 +25,26 @@ #ifndef _PreComp_ #include +#include #endif +#include "Application.h" #include "Material.h" +// Helper functions to consistently convert between float and long +namespace +{ +float fromPercent(long value) +{ + return std::roundf(value) / 100.0F; +} + +long toPercent(float value) +{ + return std::lround(100.0 * value); +} +} // namespace + using namespace App; @@ -317,4 +333,47 @@ void Material::setType(MaterialType MatType) break; } } + +App::Material Material::getDefaultAppearance() +{ + ParameterGrp::handle hGrp = + App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); + + auto getColor = [hGrp](const char* parameter, App::Color& color) { + uint32_t packed = color.getPackedRGB(); + packed = hGrp->GetUnsigned(parameter, packed); + color.setPackedRGB(packed); + }; + auto intRandom = [](int min, int max) -> int { + static std::mt19937 generator; + std::uniform_int_distribution distribution(min, max); + return distribution(generator); + }; + + App::Material mat(App::Material::DEFAULT); + mat.transparency = fromPercent(hGrp->GetInt("DefaultShapeTransparency", 0)); + long shininess = toPercent(mat.shininess); + mat.shininess = fromPercent(hGrp->GetInt("DefaultShapeShininess", shininess)); + + // This is handled in the material code when using the object appearance + bool randomColor = hGrp->GetBool("RandomColor", false); + + // diffuse color + if (randomColor) { + float red = static_cast(intRandom(0, 255)) / 255.0F; + float green = static_cast(intRandom(0, 255)) / 255.0F; + float blue = static_cast(intRandom(0, 255)) / 255.0F; + mat.diffuseColor = App::Color(red, green, blue); + } + else { + // Color = (204, 204, 230) = 3435980543UL + getColor("DefaultShapeColor", mat.diffuseColor); + } + + getColor("DefaultAmbientColor", mat.ambientColor); + getColor("DefaultEmissiveColor", mat.emissiveColor); + getColor("DefaultSpecularColor", mat.specularColor); + + return mat; +} // NOLINTEND(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) diff --git a/src/App/Material.h b/src/App/Material.h index ba22b510e5..e578d00b62 100644 --- a/src/App/Material.h +++ b/src/App/Material.h @@ -131,6 +131,8 @@ public: Color emissiveColor; /**< Defines the emissive color. */ float shininess; float transparency; + std::string image; + std::string imagePath; std::string uuid; // NOLINTEND //@} @@ -145,6 +147,8 @@ public: && diffuseColor == m.diffuseColor && specularColor == m.specularColor && emissiveColor == m.emissiveColor + && image == m.image + && image == m.imagePath && uuid == m.uuid; // clang-format on } @@ -155,6 +159,8 @@ public: Material& operator=(const Material& other) = default; Material& operator=(Material&& other) = default; + static Material getDefaultAppearance(); + private: MaterialType _matType; }; diff --git a/src/App/PropertyStandard.cpp b/src/App/PropertyStandard.cpp index 4395623fc2..e2ee13c103 100644 --- a/src/App/PropertyStandard.cpp +++ b/src/App/PropertyStandard.cpp @@ -2579,6 +2579,8 @@ void PropertyMaterial::Save(Base::Writer& writer) const << "\" emissiveColor=\"" << _cMat.emissiveColor.getPackedValue() << "\" shininess=\"" << _cMat.shininess << "\" transparency=\"" << _cMat.transparency + << "\" image=\"" << _cMat.image + << "\" imagePath=\"" << _cMat.imagePath << "\" uuid=\"" << _cMat.uuid << "\"/>" << std::endl; // clang-format on @@ -2596,6 +2598,12 @@ void PropertyMaterial::Restore(Base::XMLReader& reader) _cMat.emissiveColor.setPackedValue(reader.getAttributeAsUnsigned("emissiveColor")); _cMat.shininess = (float)reader.getAttributeAsFloat("shininess"); _cMat.transparency = (float)reader.getAttributeAsFloat("transparency"); + if (reader.hasAttribute("image")) { + _cMat.image = reader.getAttribute("image"); + } + if (reader.hasAttribute("imagePath")) { + _cMat.imagePath = reader.getAttribute("imagePath"); + } if (reader.hasAttribute("uuid")) { _cMat.uuid = reader.getAttribute("uuid"); } @@ -2635,7 +2643,7 @@ TYPESYSTEM_SOURCE(App::PropertyMaterialList, App::PropertyLists) PropertyMaterialList::PropertyMaterialList() { - setSizeOne(); + setMinimumSizeOne(); } PropertyMaterialList::~PropertyMaterialList() = default; @@ -2662,7 +2670,7 @@ void PropertyMaterialList::verifyIndex(int index) const } } -void PropertyMaterialList::setSizeOne() +void PropertyMaterialList::setMinimumSizeOne() { int size = getSize(); if (size < 1) { @@ -2690,7 +2698,7 @@ void PropertyMaterialList::setValue() void PropertyMaterialList::setValue(const Material& mat) { aboutToSetValue(); - setSizeOne(); + setSize(1); for (auto& material : _lValueList) { material = mat; } @@ -2710,7 +2718,7 @@ void PropertyMaterialList::setValue(int index, const Material& mat) void PropertyMaterialList::setAmbientColor(const Color& col) { aboutToSetValue(); - setSizeOne(); + setMinimumSizeOne(); for (auto& material : _lValueList) { material.ambientColor = col; } @@ -2720,7 +2728,7 @@ void PropertyMaterialList::setAmbientColor(const Color& col) void PropertyMaterialList::setAmbientColor(float r, float g, float b, float a) { aboutToSetValue(); - setSizeOne(); + setMinimumSizeOne(); for (auto& material : _lValueList) { material.ambientColor.set(r, g, b, a); } @@ -2730,7 +2738,7 @@ void PropertyMaterialList::setAmbientColor(float r, float g, float b, float a) void PropertyMaterialList::setAmbientColor(uint32_t rgba) { aboutToSetValue(); - setSizeOne(); + setMinimumSizeOne(); for (auto& material : _lValueList) { material.ambientColor.setPackedValue(rgba); } @@ -2770,7 +2778,7 @@ void PropertyMaterialList::setAmbientColor(int index, uint32_t rgba) void PropertyMaterialList::setDiffuseColor(const Color& col) { aboutToSetValue(); - setSizeOne(); + setMinimumSizeOne(); for (auto& material : _lValueList) { material.diffuseColor = col; } @@ -2780,7 +2788,7 @@ void PropertyMaterialList::setDiffuseColor(const Color& col) void PropertyMaterialList::setDiffuseColor(float r, float g, float b, float a) { aboutToSetValue(); - setSizeOne(); + setMinimumSizeOne(); for (auto& material : _lValueList) { material.diffuseColor.set(r, g, b, a); } @@ -2790,7 +2798,7 @@ void PropertyMaterialList::setDiffuseColor(float r, float g, float b, float a) void PropertyMaterialList::setDiffuseColor(uint32_t rgba) { aboutToSetValue(); - setSizeOne(); + setMinimumSizeOne(); for (auto& material : _lValueList) { material.diffuseColor.setPackedValue(rgba); } @@ -2827,10 +2835,21 @@ void PropertyMaterialList::setDiffuseColor(int index, uint32_t rgba) hasSetValue(); } +void PropertyMaterialList::setDiffuseColors(const std::vector& colors) +{ + aboutToSetValue(); + setSize(colors.size(), _lValueList[0]); + + for (int i = 0; i < colors.size(); i++) { + _lValueList[i].diffuseColor = colors[i]; + } + hasSetValue(); +} + void PropertyMaterialList::setSpecularColor(const Color& col) { aboutToSetValue(); - setSizeOne(); + setMinimumSizeOne(); for (auto& material : _lValueList) { material.specularColor = col; } @@ -2840,7 +2859,7 @@ void PropertyMaterialList::setSpecularColor(const Color& col) void PropertyMaterialList::setSpecularColor(float r, float g, float b, float a) { aboutToSetValue(); - setSizeOne(); + setMinimumSizeOne(); for (auto& material : _lValueList) { material.specularColor.set(r, g, b, a); } @@ -2850,7 +2869,7 @@ void PropertyMaterialList::setSpecularColor(float r, float g, float b, float a) void PropertyMaterialList::setSpecularColor(uint32_t rgba) { aboutToSetValue(); - setSizeOne(); + setMinimumSizeOne(); for (auto& material : _lValueList) { material.specularColor.setPackedValue(rgba); } @@ -2890,7 +2909,7 @@ void PropertyMaterialList::setSpecularColor(int index, uint32_t rgba) void PropertyMaterialList::setEmissiveColor(const Color& col) { aboutToSetValue(); - setSizeOne(); + setMinimumSizeOne(); for (auto& material : _lValueList) { material.emissiveColor = col; } @@ -2900,7 +2919,7 @@ void PropertyMaterialList::setEmissiveColor(const Color& col) void PropertyMaterialList::setEmissiveColor(float r, float g, float b, float a) { aboutToSetValue(); - setSizeOne(); + setMinimumSizeOne(); for (auto& material : _lValueList) { material.emissiveColor.set(r, g, b, a); } @@ -2910,7 +2929,7 @@ void PropertyMaterialList::setEmissiveColor(float r, float g, float b, float a) void PropertyMaterialList::setEmissiveColor(uint32_t rgba) { aboutToSetValue(); - setSizeOne(); + setMinimumSizeOne(); for (auto& material : _lValueList) { material.emissiveColor.setPackedValue(rgba); } @@ -2950,7 +2969,7 @@ void PropertyMaterialList::setEmissiveColor(int index, uint32_t rgba) void PropertyMaterialList::setShininess(float val) { aboutToSetValue(); - setSizeOne(); + setMinimumSizeOne(); for (auto& material : _lValueList) { material.shininess = val; } @@ -2970,7 +2989,7 @@ void PropertyMaterialList::setShininess(int index, float val) void PropertyMaterialList::setTransparency(float val) { aboutToSetValue(); - setSizeOne(); + setMinimumSizeOne(); for (auto& material : _lValueList) { material.transparency = val; } @@ -3039,12 +3058,12 @@ const Color& PropertyMaterialList::getEmissiveColor(int index) const float PropertyMaterialList::getShininess() const { - return _lValueList[0].transparency; + return _lValueList[0].shininess; } float PropertyMaterialList::getShininess(int index) const { - return _lValueList[index].transparency; + return _lValueList[index].shininess; } float PropertyMaterialList::getTransparency() const @@ -3074,7 +3093,7 @@ void PropertyMaterialList::Save(Base::Writer& writer) const if (!writer.isForceXML()) { writer.Stream() << writer.ind() << "" + << " version=\"3\"/>" << std::endl; } } @@ -3107,8 +3126,21 @@ void PropertyMaterialList::SaveDocFile(Base::Writer& writer) const str << it.emissiveColor.getPackedValue(); str << it.shininess; str << it.transparency; - // str << it.uuid.c_str(); } + + // Apply the latest changes last for backwards compatibility + for (const auto& it : _lValueList) { + writeString(str, it.image); + writeString(str, it.imagePath); + writeString(str, it.uuid); + } +} + +void PropertyMaterialList::writeString(Base::OutputStream& str, const std::string &value) const +{ + uint32_t uCt = (uint32_t)value.size(); + str << uCt; + str.write(value.c_str(), uCt); } void PropertyMaterialList::RestoreDocFile(Base::Reader& reader) @@ -3120,11 +3152,20 @@ void PropertyMaterialList::RestoreDocFile(Base::Reader& reader) str >> count; RestoreDocFileV0(count, reader); } + else if (formatVersion == Version_3) { + // Default to the latest + RestoreDocFileV3(reader); + } else { int32_t version; str >> version; if (version < 0) { - RestoreDocFileV1(reader); + // This was a failed attempt at versioning, but is included + // to support files created during development. In can be removed + // in a future release once dev files are migrated. + uint32_t count = 0; + str >> count; + RestoreDocFileV0(count, reader); } else { uint32_t uCt = static_cast(version); @@ -3156,14 +3197,14 @@ void PropertyMaterialList::RestoreDocFileV0(uint32_t count, Base::Reader& reader setValues(values); } -void PropertyMaterialList::RestoreDocFileV1(Base::Reader& reader) +void PropertyMaterialList::RestoreDocFileV3(Base::Reader& reader) { Base::InputStream str(reader); uint32_t count = 0; str >> count; std::vector values(count); - uint32_t value {}; // must be 32 bit long - float valueF {}; + uint32_t value; // must be 32 bit long + float valueF; for (auto& it : values) { str >> value; it.ambientColor.setPackedValue(value); @@ -3177,12 +3218,29 @@ void PropertyMaterialList::RestoreDocFileV1(Base::Reader& reader) it.shininess = valueF; str >> valueF; it.transparency = valueF; - // str >> valueS; - // it.uuid = valueS; + } + for (auto& it : values) { + readString(str, it.image); + readString(str, it.imagePath); + readString(str, it.uuid); } setValues(values); } +void PropertyMaterialList::readString(Base::InputStream& str, + std::string& value) +{ + uint32_t uCt; + str >> uCt; + + char *temp = new char[uCt]; + + str.read(temp, uCt); + value.assign(temp, static_cast(uCt)); + + delete [] temp; +} + const char* PropertyMaterialList::getEditorName() const { if (testStatus(NoMaterialListEdit)) { diff --git a/src/App/PropertyStandard.h b/src/App/PropertyStandard.h index 60978ecb53..d013400a33 100644 --- a/src/App/PropertyStandard.h +++ b/src/App/PropertyStandard.h @@ -38,6 +38,8 @@ namespace Base { +class InputStream; +class OutputStream; class Writer; } @@ -1132,6 +1134,7 @@ public: void setDiffuseColor(int index, const Color& col); void setDiffuseColor(int index, float r, float g, float b, float a = 0.0F); void setDiffuseColor(int index, uint32_t rgba); + void setDiffuseColors(const std::vector& colors); void setSpecularColor(const Color& col); void setSpecularColor(float r, float g, float b, float a = 0.0F); @@ -1193,14 +1196,18 @@ private: enum Format { Version_0, Version_1, - Version_2 + Version_2, + Version_3 }; void RestoreDocFileV0(uint32_t count, Base::Reader& reader); - void RestoreDocFileV1(Base::Reader& reader); + void RestoreDocFileV3(Base::Reader& reader); + + void writeString(Base::OutputStream& str, const std::string &value) const; + void readString(Base::InputStream& str, std::string& value); void verifyIndex(int index) const; - void setSizeOne(); + void setMinimumSizeOne(); int resizeByOneIfNeeded(int index); Format formatVersion {Version_0}; diff --git a/src/Base/Stream.cpp b/src/Base/Stream.cpp index eb9a8743fb..f95a4fa722 100644 --- a/src/Base/Stream.cpp +++ b/src/Base/Stream.cpp @@ -150,6 +150,12 @@ OutputStream& OutputStream::operator<<(double d) return *this; } +OutputStream& OutputStream::write(const char* s, int n) +{ + _out.write(s, n); + return *this; +} + InputStream::InputStream(std::istream& rin) : _in(rin) {} @@ -246,6 +252,12 @@ InputStream& InputStream::operator>>(double& d) return *this; } +InputStream& InputStream::read(char* s, int n) +{ + _in.read(s, n); + return *this; +} + // ---------------------------------------------------------------------- ByteArrayOStreambuf::ByteArrayOStreambuf(QByteArray& ba) diff --git a/src/Base/Stream.h b/src/Base/Stream.h index 8b816b2754..94055cb118 100644 --- a/src/Base/Stream.h +++ b/src/Base/Stream.h @@ -95,6 +95,8 @@ public: OutputStream& operator<<(float f); OutputStream& operator<<(double d); + OutputStream& write(const char* s, int n); + OutputStream(const OutputStream&) = delete; OutputStream(OutputStream&&) = delete; void operator=(const OutputStream&) = delete; @@ -126,6 +128,8 @@ public: InputStream& operator>>(float& f); InputStream& operator>>(double& d); + InputStream& read(char* s, int n); + explicit operator bool() const { // test if _Ipfx succeeded diff --git a/src/Gui/Application.h b/src/Gui/Application.h index 8f7fb3195e..bbb1aa2258 100644 --- a/src/Gui/Application.h +++ b/src/Gui/Application.h @@ -271,7 +271,7 @@ protected: std::make_pair(QT_TRANSLATE_NOOP("EditMode", "Color"), QT_TRANSLATE_NOOP("EditMode", "The object will have the color of its individual faces " - "editable with the Part FaceColors command"))}, + "editable with the Part FaceAppearances command"))}, }; int userEditMode = userEditModes.begin()->first; diff --git a/src/Gui/DlgMaterialProperties.ui b/src/Gui/DlgMaterialProperties.ui index 7cb7b98860..f0b56befd4 100644 --- a/src/Gui/DlgMaterialProperties.ui +++ b/src/Gui/DlgMaterialProperties.ui @@ -41,62 +41,6 @@ 6 - - - - Ambient color: - - - - - - - - - - - - - - Diffuse color: - - - - - - - - - - - - - - Emissive color: - - - - - - - - - - - - - - Specular color: - - - - - - - - - - @@ -149,6 +93,76 @@ + + + + Diffuse color: + + + + + + + + + + + + + + + + + + + + + Specular color: + + + + + + + + + + + + + + Ambient color: + + + + + + + + + + + + + + Emissive color: + + + + + + + Reset + + + + + + + Default + + + diff --git a/src/Gui/DlgMaterialPropertiesImp.cpp b/src/Gui/DlgMaterialPropertiesImp.cpp index 20e4bcb5a7..305b41c0ae 100644 --- a/src/Gui/DlgMaterialPropertiesImp.cpp +++ b/src/Gui/DlgMaterialPropertiesImp.cpp @@ -22,8 +22,11 @@ #include "PreCompiled.h" +#include +#include #include +#include "Application.h" #include "DlgMaterialPropertiesImp.h" #include "ui_DlgMaterialProperties.h" #include "ViewProvider.h" @@ -46,11 +49,12 @@ DlgMaterialPropertiesImp::DlgMaterialPropertiesImp(const std::string& mat, QWidg : QDialog(parent, fl) , ui(new Ui_DlgMaterialProperties) , material(mat) + , updateColors(true) { ui->setupUi(this); setupConnections(); - if (material != "ShapeMaterial") { + if (material != "ShapeAppearance") { ui->textLabel1->hide(); ui->diffuseColor->hide(); } @@ -68,6 +72,8 @@ DlgMaterialPropertiesImp::~DlgMaterialPropertiesImp() = default; void DlgMaterialPropertiesImp::setupConnections() { + Base::Console().Log("DlgMaterialPropertiesImp::setupConnections()\n"); + connect(ui->ambientColor, &ColorButton::changed, this, &DlgMaterialPropertiesImp::onAmbientColorChanged); connect(ui->diffuseColor, &ColorButton::changed, @@ -78,6 +84,10 @@ void DlgMaterialPropertiesImp::setupConnections() this, &DlgMaterialPropertiesImp::onSpecularColorChanged); connect(ui->shininess, qOverload(&QSpinBox::valueChanged), this, &DlgMaterialPropertiesImp::onShininessValueChanged); + connect(ui->buttonReset, &QPushButton::clicked, + this, &DlgMaterialPropertiesImp::onButtonReset); + connect(ui->buttonDefault, &QPushButton::clicked, + this, &DlgMaterialPropertiesImp::onButtonDefault); } QColor DlgMaterialPropertiesImp::diffuseColor() const @@ -85,24 +95,54 @@ QColor DlgMaterialPropertiesImp::diffuseColor() const return ui->diffuseColor->color(); } +App::Material DlgMaterialPropertiesImp::getMaterial() +{ + for (std::vector::iterator it = Objects.begin(); it != Objects.end(); ++it) { + App::Property* prop = (*it)->getPropertyByName(material.c_str()); + if (prop && prop->isDerivedFrom()) { + auto ShapeAppearance = static_cast(prop); + auto& materials = ShapeAppearance->getValues(); + auto mat = materials[0]; + + mat.setType(App::Material::USER_DEFINED); + + // Reset any texture data + mat.image = ""; + mat.imagePath = ""; + mat.uuid = ""; + + return mat; + } + } + + return App::Material::getDefaultAppearance(); +} + +App::Color DlgMaterialPropertiesImp::getColor(const QColor& color) const +{ + float r = (float)color.red() / 255.0F; + float g = (float)color.green() / 255.0F; + float b = (float)color.blue() / 255.0F; + + return App::Color(r, g, b); +} + /** * Sets the ambient color. */ void DlgMaterialPropertiesImp::onAmbientColorChanged() { - QColor col = ui->ambientColor->color(); - float r = (float)col.red() / 255.0f; - float g = (float)col.green() / 255.0f; - float b = (float)col.blue() / 255.0f; - App::Color ambient(r, g, b); + if (updateColors) { + App::Color ambient = getColor(ui->ambientColor->color()); - for (std::vector::iterator it= Objects.begin(); it != Objects.end(); ++it) { - App::Property* prop = (*it)->getPropertyByName(material.c_str()); - if (prop && prop->isDerivedFrom()) { - auto ShapeMaterial = static_cast(prop); - App::Material mat = ShapeMaterial->getValue(); - mat.ambientColor = ambient; - ShapeMaterial->setValue(mat); + for (std::vector::iterator it= Objects.begin(); it != Objects.end(); ++it) { + App::Property* prop = (*it)->getPropertyByName(material.c_str()); + if (prop && prop->isDerivedFrom()) { + auto ShapeAppearance = static_cast(prop); + auto mat = getMaterial(); + mat.ambientColor = ambient; + ShapeAppearance->setValue(mat); + } } } } @@ -112,19 +152,17 @@ void DlgMaterialPropertiesImp::onAmbientColorChanged() */ void DlgMaterialPropertiesImp::onDiffuseColorChanged() { - QColor col = ui->diffuseColor->color(); - float r = (float)col.red() / 255.0f; - float g = (float)col.green() / 255.0f; - float b = (float)col.blue() / 255.0f; - App::Color diffuse(r, g, b); + if (updateColors) { + App::Color diffuse = getColor(ui->diffuseColor->color()); - for (std::vector::iterator it = Objects.begin(); it != Objects.end(); ++it) { - App::Property* prop = (*it)->getPropertyByName(material.c_str()); - if (prop && prop->isDerivedFrom()) { - auto ShapeMaterial = static_cast(prop); - App::Material mat = ShapeMaterial->getValue(); - mat.diffuseColor = diffuse; - ShapeMaterial->setValue(mat); + for (std::vector::iterator it = Objects.begin(); it != Objects.end(); ++it) { + App::Property* prop = (*it)->getPropertyByName(material.c_str()); + if (prop && prop->isDerivedFrom()) { + auto ShapeAppearance = static_cast(prop); + auto mat = getMaterial(); + mat.diffuseColor = diffuse; + ShapeAppearance->setValue(mat); + } } } } @@ -134,19 +172,17 @@ void DlgMaterialPropertiesImp::onDiffuseColorChanged() */ void DlgMaterialPropertiesImp::onEmissiveColorChanged() { - QColor col = ui->emissiveColor->color(); - float r = (float)col.red() / 255.0f; - float g = (float)col.green() / 255.0f; - float b = (float)col.blue() / 255.0f; - App::Color emissive(r, g, b); + if (updateColors) { + App::Color emissive = getColor(ui->emissiveColor->color()); - for (std::vector::iterator it = Objects.begin(); it != Objects.end(); ++it) { - App::Property* prop = (*it)->getPropertyByName(material.c_str()); - if (prop && prop->isDerivedFrom()) { - auto ShapeMaterial = static_cast(prop); - App::Material mat = ShapeMaterial->getValue(); - mat.emissiveColor = emissive; - ShapeMaterial->setValue(mat); + for (std::vector::iterator it = Objects.begin(); it != Objects.end(); ++it) { + App::Property* prop = (*it)->getPropertyByName(material.c_str()); + if (prop && prop->isDerivedFrom()) { + auto ShapeAppearance = static_cast(prop); + auto mat = getMaterial(); + mat.emissiveColor = emissive; + ShapeAppearance->setValue(mat); + } } } } @@ -156,19 +192,17 @@ void DlgMaterialPropertiesImp::onEmissiveColorChanged() */ void DlgMaterialPropertiesImp::onSpecularColorChanged() { - QColor col = ui->specularColor->color(); - float r = (float)col.red() / 255.0f; - float g = (float)col.green() / 255.0f; - float b = (float)col.blue() / 255.0f; - App::Color specular(r, g, b); + if (updateColors) { + App::Color specular = getColor(ui->specularColor->color()); - for (std::vector::iterator it = Objects.begin(); it != Objects.end(); ++it) { - App::Property* prop = (*it)->getPropertyByName(material.c_str()); - if (prop && prop->isDerivedFrom()) { - auto ShapeMaterial = static_cast(prop); - App::Material mat = ShapeMaterial->getValue(); - mat.specularColor = specular; - ShapeMaterial->setValue(mat); + for (std::vector::iterator it = Objects.begin(); it != Objects.end(); ++it) { + App::Property* prop = (*it)->getPropertyByName(material.c_str()); + if (prop && prop->isDerivedFrom()) { + auto ShapeAppearance = static_cast(prop); + auto mat = getMaterial(); + mat.specularColor = specular; + ShapeAppearance->setValue(mat); + } } } } @@ -178,14 +212,63 @@ void DlgMaterialPropertiesImp::onSpecularColorChanged() */ void DlgMaterialPropertiesImp::onShininessValueChanged(int sh) { - float shininess = (float)sh / 100.0f; + if (updateColors) { + float shininess = (float)sh / 100.0F; + for (std::vector::iterator it = Objects.begin(); it != Objects.end(); ++it) { + App::Property* prop = (*it)->getPropertyByName(material.c_str()); + if (prop && prop->isDerivedFrom()) { + auto ShapeAppearance = static_cast(prop); + auto mat = getMaterial(); + mat.shininess = shininess; + ShapeAppearance->setValue(mat); + } + } + } +} + +/** + * Reset the colors to the Coin3D defaults + */ +void DlgMaterialPropertiesImp::onButtonReset(bool checked) +{ for (std::vector::iterator it = Objects.begin(); it != Objects.end(); ++it) { App::Property* prop = (*it)->getPropertyByName(material.c_str()); - if (prop && prop->isDerivedFrom()) { - auto ShapeMaterial = static_cast(prop); - App::Material mat = ShapeMaterial->getValue(); - mat.shininess = shininess; - ShapeMaterial->setValue(mat); + if (prop && prop->isDerivedFrom()) { + auto ShapeAppearance = static_cast(prop); + auto mat = getMaterial(); + + App::Color defaultAmbient(0.2, 0.2, 0.2); + App::Color defaultDiffuse(0.8, 0.8, 0.8); + App::Color black(0, 0, 0); + + mat.ambientColor = defaultAmbient; + mat.diffuseColor = defaultDiffuse; + mat.emissiveColor = black; + mat.specularColor = black; + mat.shininess = 0.2; + ShapeAppearance->setValue(mat); + + setButtonColors(); + break; + } + } +} + +/** + * Reset the colors to the current default + */ +void DlgMaterialPropertiesImp::onButtonDefault(bool checked) +{ + for (std::vector::iterator it = Objects.begin(); it != Objects.end(); ++it) { + App::Property* prop = (*it)->getPropertyByName(material.c_str()); + if (prop && prop->isDerivedFrom()) { + auto ShapeAppearance = static_cast(prop); + auto mat = App::Material::getDefaultAppearance(); + + ShapeAppearance->setValue(mat); + + setButtonColors(); + break; } } } @@ -197,33 +280,82 @@ void DlgMaterialPropertiesImp::setViewProviders(const std::vector::iterator it = Objects.begin(); it != Objects.end(); ++it) { App::Property* prop = (*it)->getPropertyByName(material.c_str()); - if (prop && prop->isDerivedFrom()) { - auto ShapeMaterial = static_cast(prop); - App::Material mat = ShapeMaterial->getValue(); - int r = int(mat.ambientColor.r * 255.0f); - int g = int(mat.ambientColor.g * 255.0f); - int b = int(mat.ambientColor.b * 255.0f); + if (prop && prop->isDerivedFrom()) { + auto ShapeAppearance = static_cast(prop); + auto& materials = ShapeAppearance->getValues(); + auto& mat = materials[0]; + int r = int(mat.ambientColor.r * 255.0F); + int g = int(mat.ambientColor.g * 255.0F); + int b = int(mat.ambientColor.b * 255.0F); ui->ambientColor->setColor(QColor(r, g, b)); - r = int(mat.diffuseColor.r * 255.0f); - g = int(mat.diffuseColor.g * 255.0f); - b = int(mat.diffuseColor.b * 255.0f); + r = int(mat.diffuseColor.r * 255.0F); + g = int(mat.diffuseColor.g * 255.0F); + b = int(mat.diffuseColor.b * 255.0F); ui->diffuseColor->setColor(QColor(r, g, b)); - r = int(mat.emissiveColor.r * 255.0f); - g = int(mat.emissiveColor.g * 255.0f); - b = int(mat.emissiveColor.b * 255.0f); + r = int(mat.emissiveColor.r * 255.0F); + g = int(mat.emissiveColor.g * 255.0F); + b = int(mat.emissiveColor.b * 255.0F); ui->emissiveColor->setColor(QColor(r, g, b)); - r = int(mat.specularColor.r * 255.0f); - g = int(mat.specularColor.g * 255.0f); - b = int(mat.specularColor.b * 255.0f); + r = int(mat.specularColor.r * 255.0F); + g = int(mat.specularColor.g * 255.0F); + b = int(mat.specularColor.b * 255.0F); ui->specularColor->setColor(QColor(r, g, b)); ui->shininess->blockSignals(true); - ui->shininess->setValue((int)(100.0f * (mat.shininess + 0.001f))); + ui->shininess->setValue((int)(100.0f * (mat.shininess + 0.001F))); ui->shininess->blockSignals(false); break; } } } +/** + * Constructs a Gui::Dialog::DlgFaceMaterialPropertiesImp as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + * + * This differs from Gui::Dialog::DlgMaterialPropertiesImp in that it does not update + * the underlying object. This is undesirable when we're updating only a single face. + */ +DlgFaceMaterialPropertiesImp::DlgFaceMaterialPropertiesImp(const std::string& mat, + QWidget* parent, + Qt::WindowFlags fl) + : DlgMaterialPropertiesImp(mat, parent, fl) +{ + Base::Console().Log("DlgFaceMaterialPropertiesImp::DlgFaceMaterialPropertiesImp()\n"); + + // Override the base class on this. Otherwise the whole object changes + updateColors = false; +} + +/** + * Destroys the object and frees any allocated resources + */ +DlgFaceMaterialPropertiesImp::~DlgFaceMaterialPropertiesImp() = default; + +App::Material DlgFaceMaterialPropertiesImp::getCustomAppearance() const +{ + App::Material material; + material.setType(App::Material::USER_DEFINED); + + material.ambientColor = getColor(ui->ambientColor->color()); + material.diffuseColor = getColor(ui->diffuseColor->color()); + material.emissiveColor = getColor(ui->emissiveColor->color()); + material.specularColor = getColor(ui->specularColor->color()); + material.shininess = (float)ui->shininess->value() / 100.0F; + + return material; +} + #include "moc_DlgMaterialPropertiesImp.cpp" diff --git a/src/Gui/DlgMaterialPropertiesImp.h b/src/Gui/DlgMaterialPropertiesImp.h index 8d1e4b458c..385a4c0259 100644 --- a/src/Gui/DlgMaterialPropertiesImp.h +++ b/src/Gui/DlgMaterialPropertiesImp.h @@ -28,6 +28,12 @@ #include #include +namespace App +{ +class Color; +class Material; +} + namespace Gui { class ViewProvider; @@ -48,18 +54,36 @@ public: void setViewProviders(const std::vector&); QColor diffuseColor() const; -private: +protected: void setupConnections(); + App::Material getMaterial(); + App::Color getColor(const QColor& color) const; void onAmbientColorChanged(); void onDiffuseColorChanged(); void onEmissiveColorChanged(); void onSpecularColorChanged(); void onShininessValueChanged(int); + void onButtonReset(bool checked); + void onButtonDefault(bool checked); + void setButtonColors(); -private: +protected: std::unique_ptr ui; std::string material; std::vector Objects; + bool updateColors; +}; + +class GuiExport DlgFaceMaterialPropertiesImp: public DlgMaterialPropertiesImp +{ + Q_OBJECT + +public: + explicit DlgFaceMaterialPropertiesImp(const std::string& mat, + QWidget* parent = nullptr, + Qt::WindowFlags fl = Qt::WindowFlags()); + ~DlgFaceMaterialPropertiesImp() override; + App::Material getCustomAppearance() const; }; } // namespace Dialog diff --git a/src/Gui/ViewProviderGeometryObject.cpp b/src/Gui/ViewProviderGeometryObject.cpp index 661d6be980..3f8d7dd5c1 100644 --- a/src/Gui/ViewProviderGeometryObject.cpp +++ b/src/Gui/ViewProviderGeometryObject.cpp @@ -23,7 +23,6 @@ #include "PreCompiled.h" #ifndef _PreComp_ -#include #include #include #include @@ -35,12 +34,14 @@ #include #include #include +#include #endif #include #include #include +#include #include "Application.h" #include "Document.h" @@ -56,12 +57,12 @@ using namespace Gui; namespace { float fromPercent(long value) { - return static_cast(value) / 100.0F; + return std::roundf(value) / 100.0F; } long toPercent(float value) { - return static_cast(100.0 * value + 0.5); + return std::lround(100.0 * value); } } @@ -71,7 +72,7 @@ const App::PropertyIntegerConstraint::Constraints intPercent = {0, 100, 5}; ViewProviderGeometryObject::ViewProviderGeometryObject() { - App::Material mat = getUserDefinedMaterial(); + App::Material mat = App::Material::getDefaultAppearance(); long initialTransparency = toPercent(mat.transparency); static const char* dogroup = "Display Options"; @@ -95,10 +96,29 @@ ViewProviderGeometryObject::ViewProviderGeometryObject() Selectable.setValue(isSelectionEnabled()); + pcSwitchAppearance = new SoSwitch; + pcSwitchAppearance->ref(); + pcSwitchTexture = new SoSwitch; + pcSwitchTexture->ref(); + pcShapeMaterial = new SoMaterial; - setSoMaterial(mat); + setCoinAppearance(mat); pcShapeMaterial->ref(); + pcShapeTexture2D = new SoTexture2; + pcShapeTexture2D->ref(); + + pcTextureGroup3D = new SoGroup; + pcTextureGroup3D->ref(); + + // Materials go first, with textured faces drawing over them + pcSwitchAppearance->addChild(pcShapeMaterial); + pcSwitchAppearance->addChild(pcSwitchTexture); + pcSwitchTexture->addChild(pcShapeTexture2D); + pcSwitchTexture->addChild(pcTextureGroup3D); + pcSwitchAppearance->whichChild.setValue(0); + pcSwitchTexture->whichChild.setValue(SO_SWITCH_NONE); + pcBoundingBox = new Gui::SoFCBoundingBox; pcBoundingBox->ref(); @@ -110,54 +130,15 @@ ViewProviderGeometryObject::ViewProviderGeometryObject() ViewProviderGeometryObject::~ViewProviderGeometryObject() { + pcSwitchAppearance->unref(); + pcSwitchTexture->unref(); pcShapeMaterial->unref(); + pcShapeTexture2D->unref(); + pcTextureGroup3D->unref(); pcBoundingBox->unref(); pcBoundColor->unref(); } -App::Material ViewProviderGeometryObject::getUserDefinedMaterial() -{ - ParameterGrp::handle hGrp = - App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); - - auto getColor = [hGrp](const char* parameter, App::Color& color) { - uint32_t packed = color.getPackedRGB(); - packed = hGrp->GetUnsigned(parameter, packed); - color.setPackedRGB(packed); - }; - auto intRandom = [] (int min, int max) -> int { - static std::mt19937 generator; - std::uniform_int_distribution distribution(min, max); - return distribution(generator); - }; - - App::Material mat(App::Material::DEFAULT); - mat.transparency = fromPercent(hGrp->GetInt("DefaultShapeTransparency", 0)); - long shininess = toPercent(mat.shininess); - mat.shininess = fromPercent(hGrp->GetInt("DefaultShapeShininess", shininess)); - - // This is handled in the material code when using the object appearance - bool randomColor = hGrp->GetBool("RandomColor", false); - - // diffuse color - if (randomColor) { - float red = static_cast(intRandom(0, 255)) / 255.0F; - float green = static_cast(intRandom(0, 255)) / 255.0F; - float blue = static_cast(intRandom(0, 255)) / 255.0F; - mat.diffuseColor = App::Color(red, green, blue); - } - else { - // Color = (204, 204, 230) = 3435980543UL - getColor("DefaultShapeColor", mat.diffuseColor); - } - - getColor("DefaultAmbientColor", mat.ambientColor); - getColor("DefaultEmissiveColor", mat.emissiveColor); - getColor("DefaultSpecularColor", mat.specularColor); - - return mat; -} - bool ViewProviderGeometryObject::isSelectionEnabled() const { ParameterGrp::handle hGrp = @@ -187,12 +168,14 @@ void ViewProviderGeometryObject::onChanged(const App::Property* prop) if (getObject() && getObject()->testStatus(App::ObjectStatus::TouchOnColorChange)) { getObject()->touch(true); } - const App::Material& Mat = ShapeAppearance[0]; long value = toPercent(ShapeAppearance.getTransparency()); if (value != Transparency.getValue()) { Transparency.setValue(value); } - setSoMaterial(Mat); + if (ShapeAppearance.getSize() == 1) { + const App::Material& Mat = ShapeAppearance[0]; + setCoinAppearance(Mat); + } } else if (prop == &BoundingBox) { showBoundingBox(BoundingBox.getValue()); @@ -288,14 +271,33 @@ unsigned long ViewProviderGeometryObject::getBoundColor() const return bbcol; } -void ViewProviderGeometryObject::setSoMaterial(const App::Material& source) +void ViewProviderGeometryObject::setCoinAppearance(const App::Material& source) { +#if 0 + if (!source.image.empty()) { + Base::Console().Log("setCoinAppearance(Texture)\n"); + activateTexture2D(); + + QByteArray by = QByteArray::fromBase64(QString::fromStdString(source.image).toUtf8()); + auto image = QImage::fromData(by, "PNG"); //.scaled(64, 64, Qt::KeepAspectRatio); + + SoSFImage texture; + Gui::BitmapFactory().convert(image, texture); + pcShapeTexture2D->image = texture; + } else { + Base::Console().Log("setCoinAppearance(Material)\n"); + activateMaterial(); + } +#endif + activateMaterial(); + + // Always set the material for items such as lines that don't support textures pcShapeMaterial->ambientColor.setValue(source.ambientColor.r, - source.ambientColor.g, - source.ambientColor.b); + source.ambientColor.g, + source.ambientColor.b); pcShapeMaterial->diffuseColor.setValue(source.diffuseColor.r, - source.diffuseColor.g, - source.diffuseColor.b); + source.diffuseColor.g, + source.diffuseColor.b); pcShapeMaterial->specularColor.setValue(source.specularColor.r, source.specularColor.g, source.specularColor.b); @@ -306,6 +308,31 @@ void ViewProviderGeometryObject::setSoMaterial(const App::Material& source) pcShapeMaterial->transparency.setValue(source.transparency); } +void ViewProviderGeometryObject::activateMaterial() +{ + pcSwitchAppearance->whichChild.setValue(0); + pcSwitchTexture->whichChild.setValue(SO_SWITCH_NONE); +} + +void ViewProviderGeometryObject::activateTexture2D() +{ + pcSwitchAppearance->whichChild.setValue(1); + pcSwitchTexture->whichChild.setValue(0); +} + +void ViewProviderGeometryObject::activateTexture3D() +{ + pcSwitchAppearance->whichChild.setValue(1); + pcSwitchTexture->whichChild.setValue(1); +} + +void ViewProviderGeometryObject::activateMixed3D() +{ + pcSwitchAppearance->whichChild.setValue(SO_SWITCH_ALL); + pcSwitchTexture->whichChild.setValue(1); +} + + namespace { float getBoundBoxFontSize() diff --git a/src/Gui/ViewProviderGeometryObject.h b/src/Gui/ViewProviderGeometryObject.h index 44ef6dc80a..5a8b4134e6 100644 --- a/src/Gui/ViewProviderGeometryObject.h +++ b/src/Gui/ViewProviderGeometryObject.h @@ -30,6 +30,7 @@ class SoPickedPointList; class SoSwitch; class SoSensor; +class SoTexture2; class SbVec2s; class SoBaseColor; @@ -58,7 +59,6 @@ public: // Display properties App::PropertyPercent Transparency; - // App::PropertyMaterial ShapeMaterial; // Default appearance and physical properties App::PropertyMaterialList ShapeAppearance; // May be different from material App::PropertyBool BoundingBox; App::PropertyBool Selectable; @@ -108,13 +108,30 @@ protected: void handleChangedPropertyName(Base::XMLReader& reader, const char* TypeName, const char* PropName) override; + void setCoinAppearance(const App::Material& source); + + /** + * Select which appearance type is active + * + */ + /** Material only */ + void activateMaterial(); + /** 2D Texture */ + void activateTexture2D(); + /** 3D texture only */ + void activateTexture3D(); + /** Mix of material and 3D textures */ + void activateMixed3D(); private: - void setSoMaterial(const App::Material& source); bool isSelectionEnabled() const; protected: + SoSwitch* pcSwitchAppearance {nullptr}; + SoSwitch* pcSwitchTexture {nullptr}; SoMaterial* pcShapeMaterial {nullptr}; + SoTexture2* pcShapeTexture2D {nullptr}; + SoGroup* pcTextureGroup3D {nullptr}; SoFCBoundingBox* pcBoundingBox {nullptr}; SoSwitch* pcBoundSwitch {nullptr}; SoBaseColor* pcBoundColor {nullptr}; diff --git a/src/Gui/ViewProviderGeometryObjectPyImp.cpp b/src/Gui/ViewProviderGeometryObjectPyImp.cpp index c7dfba3af8..76d83f1df7 100644 --- a/src/Gui/ViewProviderGeometryObjectPyImp.cpp +++ b/src/Gui/ViewProviderGeometryObjectPyImp.cpp @@ -71,7 +71,7 @@ PyObject* ViewProviderGeometryObjectPy::getCustomAttributes(const char* attr) co PyObject* ViewProviderGeometryObjectPy::getUserDefinedMaterial() { - App::Material mat = ViewProviderGeometryObject::getUserDefinedMaterial(); + App::Material mat = App::Material::getDefaultAppearance(); return new App::MaterialPy(new App::Material(mat)); } diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintOnBoundary.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintOnBoundary.cpp index 51ece8c417..18d168b5a3 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintOnBoundary.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintOnBoundary.cpp @@ -94,7 +94,7 @@ void ViewProviderFemConstraintOnBoundary::highlightReferences(const bool on) else if (subSet.second[0].find("Face") != std::string::npos) { // make sure original colors are remembered if (originalFaceColors[base].empty()) { - originalFaceColors[base] = vp->DiffuseColor.getValues(); + originalFaceColors[base] = vp->ShapeAppearance.getDiffuseColors(); } std::vector colors = originalFaceColors[base]; @@ -104,7 +104,7 @@ void ViewProviderFemConstraintOnBoundary::highlightReferences(const bool on) base->Shape.getValue(), colors.empty() ? ShapeAppearance.getDiffuseColor() : colors[0]); highlighter.getFaceColors(subSet.second, colors); - vp->DiffuseColor.setValues(colors); + vp->ShapeAppearance.setDiffuseColors(colors); } } else { @@ -117,7 +117,7 @@ void ViewProviderFemConstraintOnBoundary::highlightReferences(const bool on) originalLineColors[base].clear(); } else if (!originalFaceColors[base].empty()) { - vp->DiffuseColor.setValues(originalFaceColors[base]); + vp->ShapeAppearance.setDiffuseColors(originalFaceColors[base]); originalFaceColors[base].clear(); } } @@ -164,7 +164,7 @@ void ViewProviderFemConstraintOnBoundary::highlightReferences(const bool on) continue; } - vp->DiffuseColor.setValues(ogPair.second); + vp->ShapeAppearance.setDiffuseColors(ogPair.second); ogPair.second.clear(); } } diff --git a/src/Mod/Import/Gui/ExportOCAFGui.cpp b/src/Mod/Import/Gui/ExportOCAFGui.cpp index b56d1d9688..db20afa4e5 100644 --- a/src/Mod/Import/Gui/ExportOCAFGui.cpp +++ b/src/Mod/Import/Gui/ExportOCAFGui.cpp @@ -39,10 +39,6 @@ void ExportOCAFGui::findColors(Part::Feature* part, std::vector& col { Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(part); if (vp && vp->isDerivedFrom(PartGui::ViewProviderPartExt::getClassTypeId())) { - colors = static_cast(vp)->DiffuseColor.getValues(); - if (colors.empty()) { - colors.push_back( - static_cast(vp)->ShapeAppearance.getDiffuseColor()); - } + colors = static_cast(vp)->ShapeAppearance.getDiffuseColors(); } } diff --git a/src/Mod/Import/Gui/ImportOCAFGui.cpp b/src/Mod/Import/Gui/ImportOCAFGui.cpp index cd594a2123..154e1297fb 100644 --- a/src/Mod/Import/Gui/ImportOCAFGui.cpp +++ b/src/Mod/Import/Gui/ImportOCAFGui.cpp @@ -54,7 +54,7 @@ void ImportOCAFGui::applyFaceColors(Part::Feature* part, const std::vectorTransparency.setValue(100 * colors.front().a); } else { - vp->DiffuseColor.setValues(colors); + vp->ShapeAppearance.setDiffuseColors(colors); } } diff --git a/src/Mod/Material/App/Materials.cpp b/src/Mod/Material/App/Materials.cpp index 5192328211..5727a3a690 100644 --- a/src/Mod/Material/App/Materials.cpp +++ b/src/Mod/Material/App/Materials.cpp @@ -333,6 +333,11 @@ 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)); @@ -1545,13 +1550,21 @@ Material& Material::operator=(const App::Material& other) addAppearance(ModelUUIDs::ModelUUID_Rendering_Basic); } - getAppearanceProperty(QString::fromLatin1("AmbientColor"))->setColor(other.ambientColor); - getAppearanceProperty(QString::fromLatin1("DiffuseColor"))->setColor(other.diffuseColor); - getAppearanceProperty(QString::fromLatin1("SpecularColor"))->setColor(other.specularColor); - getAppearanceProperty(QString::fromLatin1("EmissiveColor"))->setColor(other.emissiveColor); - getAppearanceProperty(QString::fromLatin1("Shininess"))->setFloat(other.shininess); - getAppearanceProperty(QString::fromLatin1("Transparency"))->setFloat(other.transparency); - // std::string uuid; + getAppearanceProperty(QLatin1String("AmbientColor"))->setColor(other.ambientColor); + getAppearanceProperty(QLatin1String("DiffuseColor"))->setColor(other.diffuseColor); + getAppearanceProperty(QLatin1String("SpecularColor"))->setColor(other.specularColor); + getAppearanceProperty(QLatin1String("EmissiveColor"))->setColor(other.emissiveColor); + getAppearanceProperty(QLatin1String("Shininess"))->setFloat(other.shininess); + getAppearanceProperty(QLatin1String("Transparency"))->setFloat(other.transparency); + + if (!other.image.empty() || !other.imagePath.empty()) { + if (!hasAppearanceModel(ModelUUIDs::ModelUUID_Rendering_Texture)) { + addAppearance(ModelUUIDs::ModelUUID_Rendering_Texture); + } + + getAppearanceProperty(QLatin1String("TextureImage"))->setString(other.image); + getAppearanceProperty(QLatin1String("TexturePath"))->setString(other.imagePath); + } return *this; } @@ -1641,33 +1654,46 @@ App::Material Material::getMaterialAppearance() const App::Material material(App::Material::DEFAULT); bool custom = false; - if (hasAppearanceProperty(QString::fromLatin1("AmbientColor"))) { - material.ambientColor = - getAppearanceProperty(QString::fromLatin1("AmbientColor"))->getColor(); + if (hasAppearanceProperty(QLatin1String("AmbientColor"))) { + material.ambientColor = getAppearanceProperty(QLatin1String("AmbientColor"))->getColor(); custom = true; } - if (hasAppearanceProperty(QString::fromLatin1("DiffuseColor"))) { - material.diffuseColor = - getAppearanceProperty(QString::fromLatin1("DiffuseColor"))->getColor(); + if (hasAppearanceProperty(QLatin1String("DiffuseColor"))) { + material.diffuseColor = getAppearanceProperty(QLatin1String("DiffuseColor"))->getColor(); custom = true; } - if (hasAppearanceProperty(QString::fromLatin1("SpecularColor"))) { - material.specularColor = - getAppearanceProperty(QString::fromLatin1("SpecularColor"))->getColor(); + if (hasAppearanceProperty(QLatin1String("SpecularColor"))) { + material.specularColor = getAppearanceProperty(QLatin1String("SpecularColor"))->getColor(); custom = true; } - if (hasAppearanceProperty(QString::fromLatin1("EmissiveColor"))) { - material.emissiveColor = - getAppearanceProperty(QString::fromLatin1("EmissiveColor"))->getColor(); + if (hasAppearanceProperty(QLatin1String("EmissiveColor"))) { + material.emissiveColor = getAppearanceProperty(QLatin1String("EmissiveColor"))->getColor(); custom = true; } - if (hasAppearanceProperty(QString::fromLatin1("Shininess"))) { - material.shininess = getAppearanceProperty(QString::fromLatin1("Shininess"))->getFloat(); + if (hasAppearanceProperty(QLatin1String("Shininess"))) { + material.shininess = getAppearanceProperty(QLatin1String("Shininess"))->getFloat(); custom = true; } - if (hasAppearanceProperty(QString::fromLatin1("Transparency"))) { - material.transparency = - getAppearanceProperty(QString::fromLatin1("Transparency"))->getFloat(); + if (hasAppearanceProperty(QLatin1String("Transparency"))) { + material.transparency = getAppearanceProperty(QLatin1String("Transparency"))->getFloat(); + custom = true; + } + if (hasAppearanceProperty(QLatin1String("TextureImage"))) { + auto property = getAppearanceProperty(QLatin1String("TextureImage")); + if (!property->isNull()) { + Base::Console().Log("Has 'TextureImage'\n"); + material.image = property->getString().toStdString(); + } + + custom = true; + } + else if (hasAppearanceProperty(QLatin1String("TexturePath"))) { + auto property = getAppearanceProperty(QLatin1String("TexturePath")); + if (!property->isNull()) { + Base::Console().Log("Has 'TexturePath'\n"); + material.imagePath = property->getString().toStdString(); + } + custom = true; } diff --git a/src/Mod/Material/App/Materials.h b/src/Mod/Material/App/Materials.h index 1b5630d2b1..7f88aaf963 100644 --- a/src/Mod/Material/App/Materials.h +++ b/src/Mod/Material/App/Materials.h @@ -116,6 +116,7 @@ public: void setValue(const QString& value); void setValue(const std::shared_ptr& value); void setString(const QString& value); + void setString(const std::string& value); void setBoolean(bool value); void setBoolean(int value); void setBoolean(const QString& value); diff --git a/src/Mod/Material/Gui/AppearancePreview.cpp b/src/Mod/Material/Gui/AppearancePreview.cpp index b0351a8773..c72f1c3879 100644 --- a/src/Mod/Material/Gui/AppearancePreview.cpp +++ b/src/Mod/Material/Gui/AppearancePreview.cpp @@ -21,15 +21,23 @@ #include "PreCompiled.h" #ifndef _PreComp_ -#endif +#include +#include +#include #include #include #include #include +#include +#include +#endif + +#include #include #include +#include #include "AppearancePreview.h" @@ -123,11 +131,24 @@ AppearancePreview::AppearancePreview(QWidget* parent) // setBackground(); setEnabledNaviCube(false); - auto root = dynamic_cast(getSceneGraph()); + _group = dynamic_cast(getSceneGraph()); + _group->ref(); + + _switch = new SoSwitch(); + _switch->ref(); _material = new SoMaterial(); _material->ref(); - root->addChild(_material); - root->addChild(new SoSphere()); + _texture = new SoTexture2(); + _texture->ref(); + _environment = new SoTextureCoordinateEnvironment(); + _environment->ref(); + + _switch->addChild(_material); + _switch->addChild(_texture); + _switch->whichChild.setValue(0); + + _group->addChild(_switch); + _group->addChild(new SoSphere()); setCameraType(SoOrthographicCamera::getClassTypeId()); setViewDirection(SbVec3f(1, 1, -5)); @@ -136,8 +157,30 @@ AppearancePreview::AppearancePreview(QWidget* parent) AppearancePreview::~AppearancePreview() { + if (_switch) { + if (_switch->findChild(_material) > -1) { + _switch->removeChild(_material); + } + if (_switch->findChild(_texture) > -1) { + _switch->removeChild(_texture); + } + } + if (_group) { + if (_group->findChild(_switch) > -1) { + _group->removeChild(_switch); + } + } + + _group->unref(); + _group = nullptr; + _switch->unref(); + _switch = nullptr; _material->unref(); _material = nullptr; + _texture->unref(); + _texture = nullptr; + _environment->unref(); + _environment = nullptr; } void AppearancePreview::applySettings() @@ -148,8 +191,19 @@ void AppearancePreview::applySettings() viewSettings->applySettings(); } +void AppearancePreview::setCoinTexture() +{ + _switch->whichChild.setValue(1); +} + +void AppearancePreview::setCoinMaterial() +{ + _switch->whichChild.setValue(0); +} + void AppearancePreview::setAmbientColor(const QColor& color) { + setCoinMaterial(); _material->ambientColor.setValue( SbColor(color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0)); _material->ambientColor.setDefault(false); @@ -157,6 +211,7 @@ void AppearancePreview::setAmbientColor(const QColor& color) void AppearancePreview::setDiffuseColor(const QColor& color) { + setCoinMaterial(); _material->diffuseColor.setValue( SbColor(color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0)); _material->diffuseColor.setDefault(false); @@ -164,6 +219,7 @@ void AppearancePreview::setDiffuseColor(const QColor& color) void AppearancePreview::setSpecularColor(const QColor& color) { + setCoinMaterial(); _material->specularColor.setValue( SbColor(color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0)); _material->specularColor.setDefault(false); @@ -171,6 +227,7 @@ void AppearancePreview::setSpecularColor(const QColor& color) void AppearancePreview::setEmissiveColor(const QColor& color) { + setCoinMaterial(); _material->emissiveColor.setValue( SbColor(color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0)); _material->emissiveColor.setDefault(false); @@ -178,48 +235,74 @@ void AppearancePreview::setEmissiveColor(const QColor& color) void AppearancePreview::setShininess(double value) { + setCoinMaterial(); _material->shininess.setValue(value); _material->shininess.setDefault(false); } void AppearancePreview::setTransparency(double value) { + setCoinMaterial(); _material->transparency.setValue(value); _material->transparency.setDefault(false); } +void AppearancePreview::setTexture(const QImage& image) +{ + setCoinTexture(); + + SoSFImage texture; + Gui::BitmapFactory().convert(image, texture); + _texture->image = texture; +} + +void AppearancePreview::setTextureScaling(double scale) +{} + void AppearancePreview::resetAmbientColor() { + setCoinMaterial(); _material->ambientColor.deleteValues(0); _material->ambientColor.setDefault(true); } void AppearancePreview::resetDiffuseColor() { + setCoinMaterial(); _material->diffuseColor.deleteValues(0); _material->diffuseColor.setDefault(true); } void AppearancePreview::resetSpecularColor() { + setCoinMaterial(); _material->specularColor.deleteValues(0); _material->specularColor.setDefault(true); } void AppearancePreview::resetEmissiveColor() { + setCoinMaterial(); _material->emissiveColor.deleteValues(0); _material->emissiveColor.setDefault(true); } void AppearancePreview::resetShininess() { + setCoinMaterial(); _material->shininess.deleteValues(0); _material->shininess.setDefault(true); } void AppearancePreview::resetTransparency() { + setCoinMaterial(); _material->transparency.deleteValues(0); _material->transparency.setDefault(true); } + +void AppearancePreview::resetTexture() +{} + +void AppearancePreview::resetTextureScaling() +{} diff --git a/src/Mod/Material/Gui/AppearancePreview.h b/src/Mod/Material/Gui/AppearancePreview.h index cbf4a71b2b..115670cf7b 100644 --- a/src/Mod/Material/Gui/AppearancePreview.h +++ b/src/Mod/Material/Gui/AppearancePreview.h @@ -26,7 +26,11 @@ #include #include +class SoGroup; class SoMaterial; +class SoSwitch; +class SoTexture2; +class SoTextureCoordinateEnvironment; namespace MatGui { @@ -57,6 +61,8 @@ public: void setEmissiveColor(const QColor& color); void setShininess(double value); void setTransparency(double value); + void setTexture(const QImage& image); + void setTextureScaling(double scale); void resetAmbientColor(); void resetDiffuseColor(); @@ -64,12 +70,20 @@ public: void resetEmissiveColor(); void resetShininess(); void resetTransparency(); + void resetTexture(); + void resetTextureScaling(); private: + SoSeparator* _group; + SoSwitch* _switch; SoMaterial* _material; + SoTexture2* _texture; + SoTextureCoordinateEnvironment* _environment; std::unique_ptr viewSettings; void applySettings(); + void setCoinTexture(); + void setCoinMaterial(); }; } // namespace MatGui diff --git a/src/Mod/Material/Gui/DlgDisplayProperties.ui b/src/Mod/Material/Gui/DlgDisplayProperties.ui index fd80c1d23d..ae637d1bc9 100644 --- a/src/Mod/Material/Gui/DlgDisplayProperties.ui +++ b/src/Mod/Material/Gui/DlgDisplayProperties.ui @@ -369,7 +369,7 @@ - Shape Appearance: + Custom Appearance @@ -401,7 +401,7 @@ - + ... diff --git a/src/Mod/Material/Gui/DlgDisplayPropertiesImp.cpp b/src/Mod/Material/Gui/DlgDisplayPropertiesImp.cpp index eb68612826..92dcadb41b 100644 --- a/src/Mod/Material/Gui/DlgDisplayPropertiesImp.cpp +++ b/src/Mod/Material/Gui/DlgDisplayPropertiesImp.cpp @@ -167,7 +167,6 @@ DlgDisplayPropertiesImp::DlgDisplayPropertiesImp(bool floating, QWidget* parent, std::vector views = getSelection(); setDisplayModes(views); - setMaterial(views); setColorPlot(views); setShapeAppearance(views); setLineColor(views); @@ -276,10 +275,10 @@ void DlgDisplayPropertiesImp::setupConnections() qOverload(&QSpinBox::valueChanged), this, &DlgDisplayPropertiesImp::onSpinLineTransparencyValueChanged); - connect(d->ui.buttonUserDefinedMaterial, + connect(d->ui.buttonCustomAppearance, &Gui::ColorButton::clicked, this, - &DlgDisplayPropertiesImp::onButtonUserDefinedMaterialClicked); + &DlgDisplayPropertiesImp::onbuttonCustomAppearanceClicked); connect(d->ui.buttonColorPlot, &Gui::ColorButton::clicked, this, @@ -309,7 +308,6 @@ void DlgDisplayPropertiesImp::OnChange(Gui::SelectionSingleton::SubjectType& rCa || Reason.Type == Gui::SelectionChanges::ClrSelection) { std::vector views = getSelection(); setDisplayModes(views); - setMaterial(views); setColorPlot(views); setShapeAppearance(views); setLineColor(views); @@ -357,15 +355,10 @@ void DlgDisplayPropertiesImp::slotChangedObject(const Gui::ViewProvider& obj, } } else if (prop.isDerivedFrom()) { - //auto& value = static_cast(prop).getValue(); if (prop_name == "ShapeAppearance") { - // Base::Console().Log("slotChangeObject(ShapeAppearance)\n"); - // bool blocked = d->ui.buttonColor->blockSignals(true); - // auto color = value.diffuseColor; - // d->ui.buttonColor->setColor(QColor((int)(255.0f * color.r), - // (int)(255.0f * color.g), - // (int)(255.0f * color.b))); - // d->ui.buttonColor->blockSignals(blocked); + auto& values = static_cast(prop).getValues(); + auto& material = values[0]; + d->ui.widgetMaterial->setMaterial(QString::fromStdString(material.uuid)); } } else if (prop.isDerivedFrom()) { @@ -419,10 +412,10 @@ void DlgDisplayPropertiesImp::reject() /** * Opens a dialog that allows to modify the 'ShapeMaterial' property of all selected view providers. */ -void DlgDisplayPropertiesImp::onButtonUserDefinedMaterialClicked() +void DlgDisplayPropertiesImp::onbuttonCustomAppearanceClicked() { std::vector Provider = getSelection(); - Gui::Dialog::DlgMaterialPropertiesImp dlg("ShapeMaterial", this); + Gui::Dialog::DlgMaterialPropertiesImp dlg("ShapeAppearance", this); dlg.setViewProviders(Provider); dlg.exec(); @@ -586,25 +579,6 @@ void DlgDisplayPropertiesImp::setDisplayModes(const std::vector& views) -{ - Q_UNUSED(views); - // bool material = false; - // App::Material mat = App::Material(App::Material::DEFAULT); - // for (auto view : views) { - // if (auto* prop = - // dynamic_cast(view->getPropertyByName("ShapeMaterial"))) { - // mat = prop->getValue(); - // material = mat.uuid.empty(); - // if (!material) { - // d->ui.widgetMaterial->setMaterial(QString::fromStdString(mat.uuid)); - // } - // break; - // } - // } - // d->ui.buttonUserDefinedMaterial->setEnabled(material); -} - void DlgDisplayPropertiesImp::setColorPlot(const std::vector& views) { bool material = false; @@ -627,16 +601,13 @@ void DlgDisplayPropertiesImp::setShapeAppearance(const std::vector(view->getPropertyByName("ShapeAppearance"))) { + material = true; mat = prop->getValues()[0]; - material = mat.uuid.empty(); - if (!material) { - d->ui.widgetMaterial->setMaterial(QString::fromStdString(mat.uuid)); - } + d->ui.widgetMaterial->setMaterial(QString::fromStdString(mat.uuid)); break; } } - // d->ui.buttonUserDefinedMaterial->setEnabled(material); - d->ui.buttonUserDefinedMaterial->setEnabled(true); + d->ui.buttonCustomAppearance->setEnabled(material); } void DlgDisplayPropertiesImp::setLineColor(const std::vector& views) @@ -694,21 +665,7 @@ void DlgDisplayPropertiesImp::onMaterialSelected( for (auto it : Provider) { if (auto* prop = dynamic_cast( it->getPropertyByName("ShapeAppearance"))) { - App::Material mat; - mat.ambientColor = - material->getAppearanceProperty(QString::fromLatin1("AmbientColor"))->getColor(); - mat.diffuseColor = - material->getAppearanceProperty(QString::fromLatin1("DiffuseColor"))->getColor(); - mat.emissiveColor = - material->getAppearanceProperty(QString::fromLatin1("EmissiveColor"))->getColor(); - mat.specularColor = - material->getAppearanceProperty(QString::fromLatin1("SpecularColor"))->getColor(); - mat.shininess = - material->getAppearanceProperty(QString::fromLatin1("Shininess"))->getFloat(); - mat.transparency = - material->getAppearanceProperty(QString::fromLatin1("Transparency"))->getFloat(); - mat.uuid = material->getUUID().toStdString(); - prop->setValue(mat); + prop->setValue(material->getMaterialAppearance()); } } } diff --git a/src/Mod/Material/Gui/DlgDisplayPropertiesImp.h b/src/Mod/Material/Gui/DlgDisplayPropertiesImp.h index d16b2aea88..2d94004b3b 100644 --- a/src/Mod/Material/Gui/DlgDisplayPropertiesImp.h +++ b/src/Mod/Material/Gui/DlgDisplayPropertiesImp.h @@ -75,7 +75,7 @@ private Q_SLOTS: void onButtonPointColorChanged(); void onSpinLineWidthValueChanged(int); void onSpinLineTransparencyValueChanged(int); - void onButtonUserDefinedMaterialClicked(); + void onbuttonCustomAppearanceClicked(); void onButtonColorPlotClicked(); void onMaterialSelected(const std::shared_ptr& material); @@ -87,7 +87,6 @@ private: void setupFilters(); void slotChangedObject(const Gui::ViewProvider&, const App::Property& Prop); void setDisplayModes(const std::vector&); - void setMaterial(const std::vector&); void setColorPlot(const std::vector&); void setShapeAppearance(const std::vector&); void setLineColor(const std::vector&); diff --git a/src/Mod/Material/Gui/DlgMaterialImp.cpp b/src/Mod/Material/Gui/DlgMaterialImp.cpp index e82813ea00..c970752e64 100644 --- a/src/Mod/Material/Gui/DlgMaterialImp.cpp +++ b/src/Mod/Material/Gui/DlgMaterialImp.cpp @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff --git a/src/Mod/Material/Gui/MaterialTreeWidget.cpp b/src/Mod/Material/Gui/MaterialTreeWidget.cpp index 6e3a2eb494..398b46779f 100644 --- a/src/Mod/Material/Gui/MaterialTreeWidget.cpp +++ b/src/Mod/Material/Gui/MaterialTreeWidget.cpp @@ -285,9 +285,19 @@ QModelIndex MaterialTreeWidget::findInTree(const QString& uuid) void MaterialTreeWidget::setMaterial(const QString& uuid) { - if (uuid.isEmpty() || uuid == m_uuid) { + if (uuid == m_uuid) { return; } + + if (uuid.isEmpty()) { + // Nothing is selected + QItemSelectionModel* selectionModel = m_materialTree->selectionModel(); + selectionModel->clear(); + m_material->clear(); + + return; + } + updateMaterial(uuid); // Now select the material in the tree @@ -634,6 +644,11 @@ void MaterialTreeWidget::onSelectMaterial(const QItemSelection& selected, { Q_UNUSED(deselected); + if (selected.isEmpty()) { + m_uuid.clear(); + return; + } + // Get the UUID before changing the underlying data model QString uuid; auto model = dynamic_cast(m_materialTree->model()); diff --git a/src/Mod/Material/Gui/MaterialsEditor.cpp b/src/Mod/Material/Gui/MaterialsEditor.cpp index 582600b6db..c1679de989 100644 --- a/src/Mod/Material/Gui/MaterialsEditor.cpp +++ b/src/Mod/Material/Gui/MaterialsEditor.cpp @@ -89,7 +89,7 @@ void MaterialsEditor::setup() Gui::WaitCursor wc; ui->setupUi(this); - _warningIcon = QIcon(QString::fromStdString(":/icons/Warning.svg")); + _warningIcon = QIcon(QLatin1String(":/icons/Warning.svg")); getFavorites(); getRecents(); @@ -108,7 +108,7 @@ void MaterialsEditor::setup() resize(width, height); - ui->buttonURL->setIcon(QIcon(QString::fromStdString(":/icons/internet-web-browser.svg"))); + ui->buttonURL->setIcon(QIcon(QLatin1String(":/icons/internet-web-browser.svg"))); connect(ui->standardButtons->button(QDialogButtonBox::Ok), &QPushButton::clicked, @@ -491,7 +491,7 @@ void MaterialsEditor::setMaterialDefaults() const char* name = App::licenseItems.at(index).at(App::posnOfFullName); // const char* url = App::licenseItems.at(index).at(App::posnOfUrl); // std::string licenseUrl = (paramGrp->GetASCII("prefLicenseUrl", url)); - _material->setLicense(QString::fromStdString(name)); + _material->setLicense(QLatin1String(name)); // Empty materials will have no parent _materialManager.dereference(_material); @@ -894,54 +894,120 @@ void MaterialsEditor::refreshMaterialTree() fillMaterialTree(); } -void MaterialsEditor::updatePreview() const +bool MaterialsEditor::updateTexturePreview() const { - if (_material->hasAppearanceProperty(QString::fromStdString("AmbientColor"))) { - QString color = _material->getAppearanceValueString(QString::fromStdString("AmbientColor")); + bool hasImage = false; + QImage image; + double scaling = 99.0; + if (_material->hasModel(Materials::ModelUUIDs::ModelUUID_Rendering_Texture)) { + // First try loading an embedded image + try { + auto property = _material->getAppearanceProperty(QLatin1String("TextureImage")); + if (!property->isNull()) { + // Base::Console().Log("Has 'TextureImage'\n"); + auto propertyValue = property->getString(); + if (!propertyValue.isEmpty()) { + QByteArray by = QByteArray::fromBase64(propertyValue.toUtf8()); + image = QImage::fromData(by, "PNG"); //.scaled(64, 64, Qt::KeepAspectRatio); + hasImage = true; + } + } + } + catch (const Materials::PropertyNotFound&) { + } + + // If no embedded image, load from a path + if (!hasImage) { + try { + auto property = _material->getAppearanceProperty(QLatin1String("TexturePath")); + if (!property->isNull()) { + // Base::Console().Log("Has 'TexturePath'\n"); + auto filePath = property->getString(); + if (!image.load(filePath)) { + Base::Console().Log("Unable to load image '%s'\n", + filePath.toStdString().c_str()); + // return; // ??? + } + hasImage = true; + } + } + catch (const Materials::PropertyNotFound&) { + } + } + + // Apply any scaling + try { + auto property = _material->getAppearanceProperty(QLatin1String("TextureScaling")); + if (!property->isNull()) { + scaling = property->getFloat(); + // Base::Console().Log("Has 'TextureScaling' = %g\n", scaling); + } + } + catch (const Materials::PropertyNotFound&) { + } + + if (hasImage) { + _rendered->setTexture(image); + } + } + + return hasImage; +} + +bool MaterialsEditor::updateMaterialPreview() const +{ + if (_material->hasAppearanceProperty(QLatin1String("AmbientColor"))) { + QString color = _material->getAppearanceValueString(QLatin1String("AmbientColor")); _rendered->setAmbientColor(getColorHash(color, 255)); } else { _rendered->resetAmbientColor(); } - if (_material->hasAppearanceProperty(QString::fromStdString("DiffuseColor"))) { - QString color = _material->getAppearanceValueString(QString::fromStdString("DiffuseColor")); + if (_material->hasAppearanceProperty(QLatin1String("DiffuseColor"))) { + QString color = _material->getAppearanceValueString(QLatin1String("DiffuseColor")); _rendered->setDiffuseColor(getColorHash(color, 255)); } else { _rendered->resetDiffuseColor(); } - if (_material->hasAppearanceProperty(QString::fromStdString("SpecularColor"))) { - QString color = - _material->getAppearanceValueString(QString::fromStdString("SpecularColor")); + if (_material->hasAppearanceProperty(QLatin1String("SpecularColor"))) { + QString color = _material->getAppearanceValueString(QLatin1String("SpecularColor")); _rendered->setSpecularColor(getColorHash(color, 255)); } else { _rendered->resetSpecularColor(); } - if (_material->hasAppearanceProperty(QString::fromStdString("EmissiveColor"))) { - QString color = - _material->getAppearanceValueString(QString::fromStdString("EmissiveColor")); + if (_material->hasAppearanceProperty(QLatin1String("EmissiveColor"))) { + QString color = _material->getAppearanceValueString(QLatin1String("EmissiveColor")); _rendered->setEmissiveColor(getColorHash(color, 255)); } else { _rendered->resetEmissiveColor(); } - if (_material->hasAppearanceProperty(QString::fromStdString("Shininess"))) { - double value = - _material->getAppearanceValue(QString::fromStdString("Shininess")).toDouble(); + if (_material->hasAppearanceProperty(QLatin1String("Shininess"))) { + double value = _material->getAppearanceValue(QLatin1String("Shininess")).toDouble(); _rendered->setShininess(value); } else { _rendered->resetShininess(); } - if (_material->hasAppearanceProperty(QString::fromStdString("Transparency"))) { - double value = - _material->getAppearanceValue(QString::fromStdString("Transparency")).toDouble(); + if (_material->hasAppearanceProperty(QLatin1String("Transparency"))) { + double value = _material->getAppearanceValue(QLatin1String("Transparency")).toDouble(); _rendered->setTransparency(value); } else { _rendered->resetTransparency(); } + + return true; +} + +void MaterialsEditor::updatePreview() const +{ + if (updateTexturePreview()) { + return; + } + updateMaterialPreview(); } QString MaterialsEditor::getColorHash(const QString& colorString, int colorRange) @@ -1108,12 +1174,12 @@ QString MaterialsEditor::libraryPath(const std::shared_ptr& QString path; auto library = material->getLibrary(); if (library) { - path = QString::fromStdString("/%1/%2") + path = QString::fromLatin1("/%1/%2") .arg(material->getLibrary()->getName()) .arg(material->getDirectory()); } else { - path = QString::fromStdString("%1").arg(material->getDirectory()); + path = QString::fromLatin1("%1").arg(material->getDirectory()); } return path; diff --git a/src/Mod/Material/Gui/MaterialsEditor.h b/src/Mod/Material/Gui/MaterialsEditor.h index f5311d58e0..9d27f86b9b 100644 --- a/src/Mod/Material/Gui/MaterialsEditor.h +++ b/src/Mod/Material/Gui/MaterialsEditor.h @@ -152,6 +152,8 @@ private: void onInheritNew(bool checked); void setMaterialDefaults(); + bool updateTexturePreview() const; + bool updateMaterialPreview() const; void updatePreview() const; static QString getColorHash(const QString& colorString, int colorRange = 255); diff --git a/src/Mod/Material/Gui/PreCompiled.h b/src/Mod/Material/Gui/PreCompiled.h index 9d0d6c1884..2b1db3466b 100644 --- a/src/Mod/Material/Gui/PreCompiled.h +++ b/src/Mod/Material/Gui/PreCompiled.h @@ -61,10 +61,10 @@ #include #endif -// // Inventor includes OpenGL -// #ifndef __InventorAll__ -// # include -// #endif +// Inventor includes OpenGL +#ifndef __InventorAll__ +# include +#endif #endif //_PreComp_ diff --git a/src/Mod/Material/Resources/Models/Rendering/TextureRendering.yml b/src/Mod/Material/Resources/Models/Rendering/TextureRendering.yml index 49fbec7a9d..0d581ebce0 100644 --- a/src/Mod/Material/Resources/Models/Rendering/TextureRendering.yml +++ b/src/Mod/Material/Resources/Models/Rendering/TextureRendering.yml @@ -35,8 +35,9 @@ AppearanceModel: Type: 'File' Units: '' URL: '' - Description: "Path to file containing a texture image. Only used if TextureImage is unpopulated" + Description: "Path to file containing a texture image. Only used if Texture Image is unpopulated" TextureImage: + DisplayName: "Texture Image" Type: 'Image' Units: '' URL: '' diff --git a/src/Mod/MeshPart/Gui/Tessellation.cpp b/src/Mod/MeshPart/Gui/Tessellation.cpp index 134ad2969e..edb02c878e 100644 --- a/src/Mod/MeshPart/Gui/Tessellation.cpp +++ b/src/Mod/MeshPart/Gui/Tessellation.cpp @@ -378,7 +378,7 @@ void Tessellation::setFaceColors(int method, App::Document* doc, App::DocumentOb auto svp = Base::freecad_dynamic_cast( Gui::Application::Instance->getViewProvider(obj)); if (vpmesh && svp) { - std::vector diff_col = svp->DiffuseColor.getValues(); + std::vector diff_col = svp->ShapeAppearance.getDiffuseColors(); if (ui->groupsFaceColors->isChecked()) { diff_col = getUniqueColors(diff_col); } diff --git a/src/Mod/Part/Gui/AppPartGui.cpp b/src/Mod/Part/Gui/AppPartGui.cpp index a1895fe0e9..519a449fc0 100644 --- a/src/Mod/Part/Gui/AppPartGui.cpp +++ b/src/Mod/Part/Gui/AppPartGui.cpp @@ -1,25 +1,25 @@ /*************************************************************************** -* Copyright (c) 2002 Juergen Riegel * -* * -* This file is part of the FreeCAD CAx development system. * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU Lesser General Public License (LGPL) * -* as published by the Free Software Foundation; either version 2 of * -* the License, or (at your option) any later version. * -* for detail see the LICENCE text file. * -* * -* FreeCAD is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* GNU Lesser General Public License for more details. * -* * -* You should have received a copy of the GNU Library General Public * -* License along with FreeCAD; if not, write to the Free Software * -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -* USA * -* * -***************************************************************************/ + * Copyright (c) 2002 Juergen Riegel * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License (LGPL) * + * as published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * for detail see the LICENCE text file. * + * * + * FreeCAD is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with FreeCAD; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + * * + ***************************************************************************/ #include "PreCompiled.h" @@ -92,13 +92,15 @@ void loadPartResource() Gui::Translator::instance()->refresh(); } -namespace PartGui { -class Module : public Py::ExtensionModule +namespace PartGui +{ +class Module: public Py::ExtensionModule { public: - Module() : Py::ExtensionModule("PartGui") + Module() + : Py::ExtensionModule("PartGui") { - initialize("This module is the PartGui module."); // register with Python + initialize("This module is the PartGui module."); // register with Python } private: @@ -106,10 +108,11 @@ private: PyObject* initModule() { - return Base::Interpreter().addModule(new Module);; + return Base::Interpreter().addModule(new Module); + ; } -} // namespace PartGui +} // namespace PartGui PyMOD_INIT_FUNC(PartGui) { @@ -123,7 +126,7 @@ PyMOD_INIT_FUNC(PartGui) Base::Interpreter().runString("import Part"); Base::Interpreter().runString("import MatGui"); } - catch(const Base::Exception& e) { + catch (const Base::Exception& e) { PyErr_SetString(PyExc_ImportError, e.what()); PyMOD_Return(nullptr); } @@ -137,13 +140,15 @@ PyMOD_INIT_FUNC(PartGui) Gui::BitmapFactory().addPath(QString::fromLatin1(":/icons/parametric")); Gui::BitmapFactory().addPath(QString::fromLatin1(":/icons/tools")); - static struct PyModuleDef pAttachEngineTextsModuleDef = { - PyModuleDef_HEAD_INIT, - "AttachEngineResources", - "AttachEngineResources", -1, - AttacherGui::AttacherGuiPy::Methods, - nullptr, nullptr, nullptr, nullptr - }; + static struct PyModuleDef pAttachEngineTextsModuleDef = {PyModuleDef_HEAD_INIT, + "AttachEngineResources", + "AttachEngineResources", + -1, + AttacherGui::AttacherGuiPy::Methods, + nullptr, + nullptr, + nullptr, + nullptr}; PyObject* pAttachEngineTextsModule = PyModule_Create(&pAttachEngineTextsModuleDef); Py_INCREF(pAttachEngineTextsModule); @@ -220,23 +225,31 @@ PyMOD_INIT_FUNC(PartGui) CreateSimplePartCommands(); CreateParamPartCommands(); CreatePartSelectCommands(); - try{ - Py::Object ae = Base::Interpreter().runStringObject("__import__('AttachmentEditor.Commands').Commands"); - Py::Module(partGuiModule).setAttr(std::string("AttachmentEditor"),ae); - } catch (Base::PyException &err){ + try { + Py::Object ae = + Base::Interpreter().runStringObject("__import__('AttachmentEditor.Commands').Commands"); + Py::Module(partGuiModule).setAttr(std::string("AttachmentEditor"), ae); + } + catch (Base::PyException& err) { err.ReportException(); } // register preferences pages - Gui::Dialog::DlgPreferencesImp::setGroupData("Part/Part Design", "Part design", QObject::tr("Part and Part Design workbench")); - (void)new Gui::PrefPageProducer(QT_TRANSLATE_NOOP("QObject", "Part/Part Design")); - (void)new Gui::PrefPageProducer(QT_TRANSLATE_NOOP("QObject", "Part/Part Design")); - (void)new Gui::PrefPageProducer(QT_TRANSLATE_NOOP("QObject", "Part/Part Design")); - (void)new Gui::PrefPageProducer(QT_TRANSLATE_NOOP("QObject", "Import-Export")); - (void)new Gui::PrefPageProducer(QT_TRANSLATE_NOOP("QObject", "Import-Export")); - Gui::ViewProviderBuilder::add( - Part::PropertyPartShape::getClassTypeId(), - PartGui::ViewProviderPart::getClassTypeId()); + Gui::Dialog::DlgPreferencesImp::setGroupData("Part/Part Design", + "Part design", + QObject::tr("Part and Part Design workbench")); + (void)new Gui::PrefPageProducer( + QT_TRANSLATE_NOOP("QObject", "Part/Part Design")); + (void)new Gui::PrefPageProducer( + QT_TRANSLATE_NOOP("QObject", "Part/Part Design")); + (void)new Gui::PrefPageProducer( + QT_TRANSLATE_NOOP("QObject", "Part/Part Design")); + (void)new Gui::PrefPageProducer( + QT_TRANSLATE_NOOP("QObject", "Import-Export")); + (void)new Gui::PrefPageProducer( + QT_TRANSLATE_NOOP("QObject", "Import-Export")); + Gui::ViewProviderBuilder::add(Part::PropertyPartShape::getClassTypeId(), + PartGui::ViewProviderPart::getClassTypeId()); // add resources and reloads the translators loadPartResource(); diff --git a/src/Mod/Part/Gui/CMakeLists.txt b/src/Mod/Part/Gui/CMakeLists.txt index 9b4e372468..a2899609a6 100644 --- a/src/Mod/Part/Gui/CMakeLists.txt +++ b/src/Mod/Part/Gui/CMakeLists.txt @@ -31,6 +31,8 @@ list(APPEND PartGui_LIBS ${QtConcurrent_LIBRARIES} ) +generate_from_xml(ViewProviderExtPy) + set (Part_TR_QRC ${CMAKE_CURRENT_BINARY_DIR}/Resources/Part_translation.qrc) qt_find_and_add_translation(QM_SRCS "Resources/translations/*_*.ts" ${CMAKE_CURRENT_BINARY_DIR}/Resources/translations) @@ -61,7 +63,7 @@ set(PartGui_UIC_SRCS DlgProjectionOnSurface.ui SectionCutting.ui ShapeFromMesh.ui - TaskFaceColors.ui + TaskFaceAppearances.ui TaskShapeBuilder.ui TaskLoft.ui TaskOffset.ui @@ -69,9 +71,16 @@ set(PartGui_UIC_SRCS TaskAttacher.ui ) +SET(Python_SRCS + ViewProviderExtPy.xml + ViewProviderExtPyImp.cpp +) +SOURCE_GROUP("Python" FILES ${Python_SRCS}) + SET(PartGui_SRCS ${PartGui_QRC_SRCS} ${PartGui_UIC_HDRS} + ${Python_SRCS} AppPartGui.cpp AttacherTexts.h AttacherTexts.cpp @@ -224,9 +233,9 @@ SET(PartGui_SRCS SectionCutting.ui ShapeFromMesh.cpp ShapeFromMesh.h - TaskFaceColors.cpp - TaskFaceColors.h - TaskFaceColors.ui + TaskFaceAppearances.cpp + TaskFaceAppearances.h + TaskFaceAppearances.ui TaskShapeBuilder.cpp TaskShapeBuilder.h TaskShapeBuilder.ui diff --git a/src/Mod/Part/Gui/Command.cpp b/src/Mod/Part/Gui/Command.cpp index 4290cf30c7..d8a44a2885 100644 --- a/src/Mod/Part/Gui/Command.cpp +++ b/src/Mod/Part/Gui/Command.cpp @@ -2112,7 +2112,7 @@ void CmdColorPerFace::activated(int iMsg) return; PartGui::ViewProviderPartExt* vp = dynamic_cast(Gui::Application::Instance->getViewProvider(sel.front())); if (vp) - vp->changeFaceColors(); + vp->changeFaceAppearances(); } bool CmdColorPerFace::isActive() diff --git a/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp b/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp index 9f99c21468..8dd5b95069 100644 --- a/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp +++ b/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp @@ -720,34 +720,38 @@ void PartGui::DlgProjectionOnSurface::higlight_object(Part::Feature* iCurrentObj auto vp = dynamic_cast( Gui::Application::Instance->getViewProvider(iCurrentObject)); if (vp) { - std::vector colors; - App::Color defaultColor; + App::Color aColor; + aColor.setPackedValue(iColor); if (currentShapeType == TopAbs_FACE) { - colors = vp->DiffuseColor.getValues(); - defaultColor = vp->ShapeAppearance.getDiffuseColor(); + std::vector colors = vp->ShapeAppearance.getValues(); + App::Color defaultColor = vp->ShapeAppearance.getDiffuseColor(); + + if (static_cast(colors.size()) != anIndices.Extent()) { + colors.resize(anIndices.Extent(), vp->ShapeAppearance[0]); + } + + if (iHighlight) { + colors.at(index - 1).diffuseColor = aColor; + } + else { + colors.at(index - 1).diffuseColor = defaultColor; + } + vp->ShapeAppearance.setValues(colors); } else if (currentShapeType == TopAbs_EDGE) { - colors = vp->LineColorArray.getValues(); - defaultColor = vp->LineColor.getValue(); - } + std::vector colors = vp->LineColorArray.getValues(); + App::Color defaultColor = vp->LineColor.getValue(); - if (static_cast(colors.size()) != anIndices.Extent()) { - colors.resize(anIndices.Extent(), defaultColor); - } + if (static_cast(colors.size()) != anIndices.Extent()) { + colors.resize(anIndices.Extent(), defaultColor); + } - if (iHighlight) { - App::Color aColor; - aColor.setPackedValue(iColor); - colors.at(index - 1) = aColor; - } - else { - colors.at(index - 1) = defaultColor; - } - if (currentShapeType == TopAbs_FACE) { - vp->DiffuseColor.setValues(colors); - } - else if (currentShapeType == TopAbs_EDGE) { - vp->LineColorArray.setValues(colors); + if (iHighlight) { + colors.at(index - 1) = aColor; + } + else { + colors.at(index - 1) = defaultColor; + } } } } diff --git a/src/Mod/Part/Gui/ReferenceHighlighter.cpp b/src/Mod/Part/Gui/ReferenceHighlighter.cpp index a42d50bc7e..9d2692f9ce 100644 --- a/src/Mod/Part/Gui/ReferenceHighlighter.cpp +++ b/src/Mod/Part/Gui/ReferenceHighlighter.cpp @@ -210,6 +210,17 @@ void ReferenceHighlighter::getFaceColor(const std::string& element, std::vector< colors[pos] = elementColor; } +void ReferenceHighlighter::getFaceColor(const std::string& element, + std::vector& materials) const +{ + int idx = std::stoi(element.substr(4)) - 1; + assert(idx >= 0); + std::size_t pos = std::size_t(idx); + if (pos < materials.size()) { + materials[pos].diffuseColor = elementColor; + } +} + void ReferenceHighlighter::getFaceColors(const std::vector& elements, std::vector& colors) const { @@ -226,3 +237,24 @@ void ReferenceHighlighter::getFaceColors(const std::vector& element std::fill(colors.begin(), colors.end(), objectColor); } } + +void ReferenceHighlighter::getFaceMaterials(const std::vector& elements, + std::vector& materials) const +{ + App::Material defaultMaterial; + materials.resize(fMap.Extent(), defaultMaterial); + + if (!elements.empty()) { + for (const std::string& e : elements) { + if (boost::starts_with(e, "Face")) { + getFaceColor(e, materials); + } + } + } + else { + for (auto& material : materials) { + material.diffuseColor = objectColor; + } + // std::fill(materials.begin(), materials.end(), objectColor); + } +} diff --git a/src/Mod/Part/Gui/ReferenceHighlighter.h b/src/Mod/Part/Gui/ReferenceHighlighter.h index de501c032b..507e383776 100644 --- a/src/Mod/Part/Gui/ReferenceHighlighter.h +++ b/src/Mod/Part/Gui/ReferenceHighlighter.h @@ -79,6 +79,14 @@ public: */ void getFaceColors(const std::vector& elements, std::vector& colors) const; + /*! + * \brief getFaceMaterials + * \param elements The sub-element names. If this list is empty \a materials will be filled with + * the default color. \param materials The size of the \a materials array is equal to the number + * of faces of the shape + */ + void getFaceMaterials(const std::vector& elements, + std::vector& materials) const; private: void getVertexColor(const std::string& element, std::vector& colors) const; @@ -89,6 +97,7 @@ private: void getEdgeColorsOfWire(const std::string& element, std::vector& colors) const; void getEdgeColorsOfFace(const std::string& element, std::vector& colors) const; void getFaceColor(const std::string& element, std::vector& colors) const; + void getFaceColor(const std::string& element, std::vector& materials) const; private: App::Color defaultColor; diff --git a/src/Mod/Part/Gui/TaskFaceColors.cpp b/src/Mod/Part/Gui/TaskFaceAppearances.cpp similarity index 77% rename from src/Mod/Part/Gui/TaskFaceColors.cpp rename to src/Mod/Part/Gui/TaskFaceAppearances.cpp index 4ab51e6923..6361067533 100644 --- a/src/Mod/Part/Gui/TaskFaceColors.cpp +++ b/src/Mod/Part/Gui/TaskFaceAppearances.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -54,8 +55,10 @@ #include #include -#include "TaskFaceColors.h" -#include "ui_TaskFaceColors.h" +#include + +#include "TaskFaceAppearances.h" +#include "ui_TaskFaceAppearances.h" #include "SoBrepFaceSet.h" #include "ViewProviderExt.h" @@ -84,23 +87,23 @@ namespace PartGui { }; } -class FaceColors::Private +class FaceAppearances::Private { public: using Connection = boost::signals2::connection; - Ui_TaskFaceColors* ui; + Ui_TaskFaceAppearances* ui; QPointer view; ViewProviderPartExt* vp; App::DocumentObject* obj; Gui::Document* doc; - std::vector perface; + std::vector perface; QSet index; bool boxSelection; Connection connectDelDoc; Connection connectDelObj; Connection connectUndoDoc; - explicit Private(ViewProviderPartExt* vp) : ui(new Ui_TaskFaceColors()), view(nullptr), vp(vp) + explicit Private(ViewProviderPartExt* vp) : ui(new Ui_TaskFaceAppearances()), view(nullptr), vp(vp) { obj = vp->getObject(); doc = Gui::Application::Instance->getDocument(obj->getDocument()); @@ -113,9 +116,7 @@ public: xp.Next(); } - std::vector current = vp->DiffuseColor.getValues(); - if (current.empty()) - current.push_back(vp->ShapeAppearance.getDiffuseColor()); + std::vector current = vp->ShapeAppearance.getValues(); perface = current; perface.resize(mapOfShape.Extent(), perface.front()); @@ -220,7 +221,7 @@ public: polygon.Add(Base::Vector2d(it[0], it[1])); } - FaceColors* self = static_cast(ud); + FaceAppearances* self = static_cast(ud); self->d->view = nullptr; if (self->d->obj && self->d->obj->isDerivedFrom()) { cb->setHandled(); @@ -235,9 +236,9 @@ public: } }; -/* TRANSLATOR PartGui::TaskFaceColors */ +/* TRANSLATOR PartGui::TaskFaceAppearances */ -FaceColors::FaceColors(ViewProviderPartExt* vp, QWidget* parent) +FaceAppearances::FaceAppearances(ViewProviderPartExt* vp, QWidget* parent) : d(new Private(vp)) { Q_UNUSED(parent); @@ -245,23 +246,22 @@ FaceColors::FaceColors(ViewProviderPartExt* vp, QWidget* parent) setupConnections(); d->ui->groupBox->setTitle(QString::fromUtf8(vp->getObject()->Label.getValue())); - d->ui->colorButton->setDisabled(true); - d->ui->colorButton->setAllowTransparency(true); + d->ui->buttonCustomAppearance->setDisabled(true); FaceSelection* gate = new FaceSelection(d->vp->getObject()); Gui::Selection().addSelectionGate(gate); //NOLINTBEGIN d->connectDelDoc = Gui::Application::Instance->signalDeleteDocument.connect(std::bind - (&FaceColors::slotDeleteDocument, this, sp::_1)); + (&FaceAppearances::slotDeleteDocument, this, sp::_1)); d->connectDelObj = Gui::Application::Instance->signalDeletedObject.connect(std::bind - (&FaceColors::slotDeleteObject, this, sp::_1)); + (&FaceAppearances::slotDeleteObject, this, sp::_1)); d->connectUndoDoc = d->doc->signalUndoDocument.connect(std::bind - (&FaceColors::slotUndoDocument, this, sp::_1)); + (&FaceAppearances::slotUndoDocument, this, sp::_1)); //NOLINTEND } -FaceColors::~FaceColors() +FaceAppearances::~FaceAppearances() { if (d->view) { d->view->stopSelection(); @@ -276,17 +276,23 @@ FaceColors::~FaceColors() delete d; } -void FaceColors::setupConnections() +void FaceAppearances::setupConnections() { - connect(d->ui->colorButton, &Gui::ColorButton::changed, - this, &FaceColors::onColorButtonChanged); connect(d->ui->defaultButton, &QPushButton::clicked, - this, &FaceColors::onDefaultButtonClicked); + this, &FaceAppearances::onDefaultButtonClicked); connect(d->ui->boxSelection, &QPushButton::toggled, - this, &FaceColors::onBoxSelectionToggled); + this, &FaceAppearances::onBoxSelectionToggled); + connect(d->ui->widgetMaterial, + &MatGui::MaterialTreeWidget::materialSelected, + this, + &FaceAppearances::onMaterialSelected); + connect(d->ui->buttonCustomAppearance, + &QPushButton::clicked, + this, + &FaceAppearances::onButtonCustomAppearanceClicked); } -void FaceColors::slotUndoDocument(const Gui::Document& Doc) +void FaceAppearances::slotUndoDocument(const Gui::Document& Doc) { if (d->doc == &Doc) { d->doc->resetEdit(); @@ -294,19 +300,19 @@ void FaceColors::slotUndoDocument(const Gui::Document& Doc) } } -void FaceColors::slotDeleteDocument(const Gui::Document& Doc) +void FaceAppearances::slotDeleteDocument(const Gui::Document& Doc) { if (d->doc == &Doc) Gui::Control().closeDialog(); } -void FaceColors::slotDeleteObject(const Gui::ViewProvider& obj) +void FaceAppearances::slotDeleteObject(const Gui::ViewProvider& obj) { if (d->vp == &obj) Gui::Control().closeDialog(); } -void FaceColors::onBoxSelectionToggled(bool checked) +void FaceAppearances::onBoxSelectionToggled(bool checked) { Gui::View3DInventor* view = qobject_cast(Gui::getMainWindow()->activeWindow()); // toggle the button state and feature @@ -330,28 +336,26 @@ void FaceColors::onBoxSelectionToggled(bool checked) } } -void FaceColors::onDefaultButtonClicked() +void FaceAppearances::onDefaultButtonClicked() { - std::fill(d->perface.begin(), d->perface.end(), d->vp->ShapeAppearance.getDiffuseColor()); - d->vp->DiffuseColor.setValues(d->perface); + std::fill(d->perface.begin(), d->perface.end(), d->vp->ShapeAppearance[0]); + d->vp->ShapeAppearance.setValues(d->perface); } -void FaceColors::onColorButtonChanged() +void FaceAppearances::onMaterialSelected(const std::shared_ptr& material) { if (!d->index.isEmpty()) { - QColor color = d->ui->colorButton->color(); for (int it : d->index) { - // alpha of App::Color is contrary to the one of QColor - d->perface[it].set(color.redF(), color.greenF(), color.blueF(), (1.0 - color.alphaF())); + d->perface[it] = material->getMaterialAppearance(); } - d->vp->DiffuseColor.setValues(d->perface); + d->vp->ShapeAppearance.setValues(d->perface); // new color has been applied, unselect so that users can see this onSelectionChanged(Gui::SelectionChanges::ClrSelection); Gui::Selection().clearSelection(); } } -void FaceColors::onSelectionChanged(const Gui::SelectionChanges& msg) +void FaceAppearances::onSelectionChanged(const Gui::SelectionChanges& msg) { // no object selected in the combobox or no sub-element was selected if (!msg.pSubName) @@ -366,11 +370,10 @@ void FaceColors::onSelectionChanged(const Gui::SelectionChanges& msg) if (docname == msg.pDocName && objname == msg.pObjectName) { int index = std::atoi(msg.pSubName + 4) - 1; d->index.insert(index); - const App::Color& faceColor = d->perface[index]; + const App::Color& faceColor = d->perface[index].diffuseColor; QColor color; // alpha of App::Color is contrary to the one of QColor color.setRgbF(faceColor.r, faceColor.g, faceColor.b, (1.0 - faceColor.a)); - d->ui->colorButton->setColor(color); selection_changed = true; } } @@ -394,7 +397,7 @@ void FaceColors::onSelectionChanged(const Gui::SelectionChanges& msg) } } -void FaceColors::updatePanel() +void FaceAppearances::updatePanel() { QString faces = QString::fromLatin1("["); int size = d->index.size(); @@ -412,16 +415,39 @@ void FaceColors::updatePanel() } d->ui->labelElement->setText(faces); - d->ui->colorButton->setDisabled(d->index.isEmpty()); + d->ui->buttonCustomAppearance->setDisabled(d->index.isEmpty()); } -void FaceColors::open() +/** + * Opens a dialog that allows to modify the 'ShapeMaterial' property of all selected view providers. + */ +void FaceAppearances::onButtonCustomAppearanceClicked() +{ + std::vector Provider; + Provider.push_back(d->vp); + Gui::Dialog::DlgFaceMaterialPropertiesImp dlg("ShapeAppearance", this); + dlg.setViewProviders(Provider); + dlg.exec(); + + // Set the face appearance + if (!d->index.isEmpty()) { + for (int it : d->index) { + d->perface[it] = dlg.getCustomAppearance(); + } + d->vp->ShapeAppearance.setValues(d->perface); + // new color has been applied, unselect so that users can see this + onSelectionChanged(Gui::SelectionChanges::ClrSelection); + Gui::Selection().clearSelection(); + } +} + +void FaceAppearances::open() { Gui::Document* doc = Gui::Application::Instance->getDocument(d->vp->getObject()->getDocument()); doc->openCommand(QT_TRANSLATE_NOOP("Command", "Change face colors")); } -bool FaceColors::accept() +bool FaceAppearances::accept() { Gui::Document* doc = Gui::Application::Instance->getDocument(d->vp->getObject()->getDocument()); doc->commitCommand(); @@ -429,7 +455,7 @@ bool FaceColors::accept() return true; } -bool FaceColors::reject() +bool FaceAppearances::reject() { Gui::Document* doc = Gui::Application::Instance->getDocument(d->vp->getObject()->getDocument()); doc->abortCommand(); @@ -437,7 +463,7 @@ bool FaceColors::reject() return true; } -void FaceColors::changeEvent(QEvent* e) +void FaceAppearances::changeEvent(QEvent* e) { QWidget::changeEvent(e); if (e->type() == QEvent::LanguageChange) { @@ -446,33 +472,33 @@ void FaceColors::changeEvent(QEvent* e) } -/* TRANSLATOR PartGui::TaskFaceColors */ +/* TRANSLATOR PartGui::TaskFaceAppearances */ -TaskFaceColors::TaskFaceColors(ViewProviderPartExt* vp) +TaskFaceAppearances::TaskFaceAppearances(ViewProviderPartExt* vp) { - widget = new FaceColors(vp); + widget = new FaceAppearances(vp); addTaskBox(widget); } -TaskFaceColors::~TaskFaceColors() = default; +TaskFaceAppearances::~TaskFaceAppearances() = default; -void TaskFaceColors::open() +void TaskFaceAppearances::open() { widget->open(); } -void TaskFaceColors::clicked(int) +void TaskFaceAppearances::clicked(int) { } -bool TaskFaceColors::accept() +bool TaskFaceAppearances::accept() { return widget->accept(); } -bool TaskFaceColors::reject() +bool TaskFaceAppearances::reject() { return widget->reject(); } -#include "moc_TaskFaceColors.cpp" +#include "moc_TaskFaceAppearances.cpp" diff --git a/src/Mod/Part/Gui/TaskFaceColors.h b/src/Mod/Part/Gui/TaskFaceAppearances.h similarity index 81% rename from src/Mod/Part/Gui/TaskFaceColors.h rename to src/Mod/Part/Gui/TaskFaceAppearances.h index 929ab1fce3..c83a431c0e 100644 --- a/src/Mod/Part/Gui/TaskFaceColors.h +++ b/src/Mod/Part/Gui/TaskFaceAppearances.h @@ -31,17 +31,21 @@ namespace Gui { class ViewProvider; } +namespace Materials { + class Material; +} + namespace PartGui { class ViewProviderPartExt; -class FaceColors : public QWidget, public Gui::SelectionObserver +class FaceAppearances : public QWidget, public Gui::SelectionObserver { Q_OBJECT public: - explicit FaceColors(ViewProviderPartExt* vp, QWidget* parent = nullptr); - ~FaceColors() override; + explicit FaceAppearances(ViewProviderPartExt* vp, QWidget* parent = nullptr); + ~FaceAppearances() override; void open(); bool accept(); @@ -49,9 +53,10 @@ public: private: void setupConnections(); - void onColorButtonChanged(); + void onMaterialSelected(const std::shared_ptr& material); void onDefaultButtonClicked(); void onBoxSelectionToggled(bool checked); + void onButtonCustomAppearanceClicked(); protected: void onSelectionChanged(const Gui::SelectionChanges& msg) override; @@ -66,13 +71,13 @@ private: Private* d; }; -class TaskFaceColors : public Gui::TaskView::TaskDialog +class TaskFaceAppearances : public Gui::TaskView::TaskDialog { Q_OBJECT public: - explicit TaskFaceColors(ViewProviderPartExt* vp); - ~TaskFaceColors() override; + explicit TaskFaceAppearances(ViewProviderPartExt* vp); + ~TaskFaceAppearances() override; public: void open() override; @@ -84,7 +89,7 @@ public: { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } private: - FaceColors* widget; + FaceAppearances* widget; }; } //namespace PartGui diff --git a/src/Mod/Part/Gui/TaskFaceColors.ui b/src/Mod/Part/Gui/TaskFaceAppearances.ui similarity index 54% rename from src/Mod/Part/Gui/TaskFaceColors.ui rename to src/Mod/Part/Gui/TaskFaceAppearances.ui index dbe93fe3f7..08f64a1527 100644 --- a/src/Mod/Part/Gui/TaskFaceColors.ui +++ b/src/Mod/Part/Gui/TaskFaceAppearances.ui @@ -1,17 +1,17 @@ - PartGui::TaskFaceColors - + PartGui::TaskFaceAppearances + 0 0 247 - 143 + 219 - Set color per face + Set appearance per face @@ -26,57 +26,57 @@ Group box - - - - - - 0 - 0 - - - - Faces: - - + + + + + + + + 0 + 0 + + + + Faces: + + + + + + + [] + + + + - - - - [] - - + + + + + + - - - - - 146 - 0 - - - - - 160 - 16777215 - - - + + + + + + ... + + + + + + + Custom Appearance + + + + - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + @@ -136,9 +136,10 @@ by dragging a selection rectangle in the 3D view - Gui::ColorButton - QPushButton -
Gui/Widgets.h
+ MatGui::MaterialTreeWidget + QWidget +
Mod/Material/Gui/MaterialTreeWidget.h
+ 1
diff --git a/src/Mod/Part/Gui/ViewProvider.cpp b/src/Mod/Part/Gui/ViewProvider.cpp index 00c9082186..7f17c6ee22 100644 --- a/src/Mod/Part/Gui/ViewProvider.cpp +++ b/src/Mod/Part/Gui/ViewProvider.cpp @@ -71,6 +71,20 @@ void ViewProviderPart::applyColor(const Part::ShapeHistory& hist, } } +void ViewProviderPart::applyMaterial(const Part::ShapeHistory& hist, + const App::PropertyMaterialList& colBase, + std::vector& colBool) +{ + std::map>::const_iterator jt; + // apply color from modified faces + for (jt = hist.shapeMap.begin(); jt != hist.shapeMap.end(); ++jt) { + std::vector::const_iterator kt; + for (kt = jt->second.begin(); kt != jt->second.end(); ++kt) { + colBool[*kt] = colBase[jt->first]; + } + } +} + void ViewProviderPart::applyTransparency(const float& transparency, std::vector& colors) { @@ -85,6 +99,20 @@ void ViewProviderPart::applyTransparency(const float& transparency, } } +void ViewProviderPart::applyTransparency(const float& transparency, std::vector& colors) +{ + if (transparency != 0.0) { + // transparency has been set object-wide + std::vector::iterator j; + for (j = colors.begin(); j != colors.end(); ++j) { + // transparency hasn't been set for this face + if (j->transparency == 0.0) { + j->transparency = transparency / 100.0; // transparency comes in percent + } + } + } +} + // ---------------------------------------------------------------------------- void ViewProviderShapeBuilder::buildNodes(const App::Property* , std::vector& ) const diff --git a/src/Mod/Part/Gui/ViewProvider.h b/src/Mod/Part/Gui/ViewProvider.h index 6426c9ae16..dae2d2ef29 100644 --- a/src/Mod/Part/Gui/ViewProvider.h +++ b/src/Mod/Part/Gui/ViewProvider.h @@ -57,8 +57,13 @@ protected: void applyColor(const Part::ShapeHistory& hist, const std::vector& colBase, std::vector& colBool); + void applyMaterial(const Part::ShapeHistory& hist, + const App::PropertyMaterialList& colBase, + std::vector& colBool); void applyTransparency(const float& transparency, std::vector& colors); + void applyTransparency(const float& transparency, + std::vector& colors); }; } // namespace PartGui diff --git a/src/Mod/Part/Gui/ViewProviderBoolean.cpp b/src/Mod/Part/Gui/ViewProviderBoolean.cpp index faeb6b2eb8..df8ebf5383 100644 --- a/src/Mod/Part/Gui/ViewProviderBoolean.cpp +++ b/src/Mod/Part/Gui/ViewProviderBoolean.cpp @@ -100,27 +100,27 @@ void ViewProviderBoolean::updateData(const App::Property* prop) auto vpTool = dynamic_cast( Gui::Application::Instance->getViewProvider(objTool)); if (vpBase && vpTool) { - std::vector colBase = vpBase->DiffuseColor.getValues(); - std::vector colTool = vpTool->DiffuseColor.getValues(); - std::vector colBool; - colBool.resize(boolMap.Extent(), this->ShapeAppearance.getDiffuseColor()); - applyTransparency(vpBase->Transparency.getValue(),colBase); - applyTransparency(vpTool->Transparency.getValue(),colTool); + std::vector colBool; + colBool.resize(boolMap.Extent(), this->ShapeAppearance[0]); + vpBase->ShapeAppearance.setTransparency(vpBase->Transparency.getValue()); + vpTool->ShapeAppearance.setTransparency(vpTool->Transparency.getValue()); - if (static_cast(colBase.size()) == baseMap.Extent()) { - applyColor(hist[0], colBase, colBool); + if (static_cast(vpBase->ShapeAppearance.getSize()) == baseMap.Extent()) { + applyMaterial(hist[0], vpBase->ShapeAppearance, colBool); } - else if (!colBase.empty() && colBase[0] != this->ShapeAppearance.getDiffuseColor()) { - colBase.resize(baseMap.Extent(), colBase[0]); - applyColor(hist[0], colBase, colBool); + else if (vpBase->ShapeAppearance.getSize() > 0 + && vpBase->ShapeAppearance[0] != this->ShapeAppearance[0]) { + vpBase->ShapeAppearance.setSize(baseMap.Extent(), vpBase->ShapeAppearance[0]); + applyMaterial(hist[0], vpBase->ShapeAppearance, colBool); } - if (static_cast(colTool.size()) == toolMap.Extent()) { - applyColor(hist[1], colTool, colBool); + if (static_cast(vpTool->ShapeAppearance.getSize()) == toolMap.Extent()) { + applyMaterial(hist[1], vpTool->ShapeAppearance, colBool); } - else if (!colTool.empty() && colTool[0] != this->ShapeAppearance.getDiffuseColor()) { - colTool.resize(toolMap.Extent(), colTool[0]); - applyColor(hist[1], colTool, colBool); + else if (vpTool->ShapeAppearance.getSize() > 0 + && vpTool->ShapeAppearance[0] != this->ShapeAppearance[0]) { + vpTool->ShapeAppearance.setSize(toolMap.Extent(), vpTool->ShapeAppearance[0]); + applyMaterial(hist[1], vpTool->ShapeAppearance, colBool); } // If the view provider has set a transparency then override the values @@ -129,7 +129,7 @@ void ViewProviderBoolean::updateData(const App::Property* prop) applyTransparency(Transparency.getValue(), colBool); } - this->DiffuseColor.setValues(colBool); + this->ShapeAppearance.setValues(colBool); } } } @@ -186,8 +186,8 @@ void ViewProviderMultiFuse::updateData(const App::Property* prop) TopTools_IndexedMapOfShape boolMap; TopExp::MapShapes(boolShape, TopAbs_FACE, boolMap); - std::vector colBool; - colBool.resize(boolMap.Extent(), this->ShapeAppearance.getDiffuseColor()); + std::vector colBool; + colBool.resize(boolMap.Extent(), this->ShapeAppearance[0]); int index=0; for (std::vector::iterator it = sources.begin(); it != sources.end(); ++it, ++index) { @@ -201,14 +201,14 @@ void ViewProviderMultiFuse::updateData(const App::Property* prop) auto vpBase = dynamic_cast(Gui::Application::Instance->getViewProvider(objBase)); if (vpBase) { - std::vector colBase = vpBase->DiffuseColor.getValues(); - applyTransparency(vpBase->Transparency.getValue(),colBase); - if (static_cast(colBase.size()) == baseMap.Extent()) { - applyColor(hist[index], colBase, colBool); + vpBase->ShapeAppearance.setTransparency(vpBase->Transparency.getValue()); + if (static_cast(vpBase->ShapeAppearance.getSize()) == baseMap.Extent()) { + applyMaterial(hist[index], vpBase->ShapeAppearance, colBool); } - else if (!colBase.empty() && colBase[0] != this->ShapeAppearance.getDiffuseColor()) { - colBase.resize(baseMap.Extent(), colBase[0]); - applyColor(hist[index], colBase, colBool); + else if (vpBase->ShapeAppearance.getSize() > 0 + && vpBase->ShapeAppearance[0] != this->ShapeAppearance[0]) { + vpBase->ShapeAppearance.setSize(baseMap.Extent(), vpBase->ShapeAppearance[0]); + applyMaterial(hist[index], vpBase->ShapeAppearance, colBool); } } } @@ -219,7 +219,7 @@ void ViewProviderMultiFuse::updateData(const App::Property* prop) applyTransparency(Transparency.getValue(), colBool); } - this->DiffuseColor.setValues(colBool); + this->ShapeAppearance.setValues(colBool); } else if (prop->isDerivedFrom()) { std::vector pShapes = static_cast(prop)->getValues(); @@ -321,8 +321,8 @@ void ViewProviderMultiCommon::updateData(const App::Property* prop) TopTools_IndexedMapOfShape boolMap; TopExp::MapShapes(boolShape, TopAbs_FACE, boolMap); - std::vector colBool; - colBool.resize(boolMap.Extent(), this->ShapeAppearance.getDiffuseColor()); + std::vector colBool; + colBool.resize(boolMap.Extent(), this->ShapeAppearance[0]); int index=0; for (std::vector::iterator it = sources.begin(); it != sources.end(); ++it, ++index) { @@ -336,14 +336,14 @@ void ViewProviderMultiCommon::updateData(const App::Property* prop) auto vpBase = dynamic_cast(Gui::Application::Instance->getViewProvider(objBase)); if (vpBase) { - std::vector colBase = vpBase->DiffuseColor.getValues(); - applyTransparency(vpBase->Transparency.getValue(),colBase); - if (static_cast(colBase.size()) == baseMap.Extent()) { - applyColor(hist[index], colBase, colBool); + vpBase->ShapeAppearance.setTransparency(vpBase->Transparency.getValue()); + if (static_cast(vpBase->ShapeAppearance.getSize()) == baseMap.Extent()) { + applyMaterial(hist[index], vpBase->ShapeAppearance, colBool); } - else if (!colBase.empty() && colBase[0] != this->ShapeAppearance.getDiffuseColor()) { - colBase.resize(baseMap.Extent(), colBase[0]); - applyColor(hist[index], colBase, colBool); + else if (vpBase->ShapeAppearance.getSize() > 0 + && vpBase->ShapeAppearance[0] != this->ShapeAppearance[0]) { + vpBase->ShapeAppearance.setSize(baseMap.Extent(), vpBase->ShapeAppearance[0]); + applyMaterial(hist[index], vpBase->ShapeAppearance, colBool); } } } @@ -354,7 +354,7 @@ void ViewProviderMultiCommon::updateData(const App::Property* prop) applyTransparency(Transparency.getValue(), colBool); } - this->DiffuseColor.setValues(colBool); + this->ShapeAppearance.setValues(colBool); } else if (prop->isDerivedFrom()) { std::vector pShapes = static_cast(prop)->getValues(); diff --git a/src/Mod/Part/Gui/ViewProviderCompound.cpp b/src/Mod/Part/Gui/ViewProviderCompound.cpp index d0094e7ac0..9754362524 100644 --- a/src/Mod/Part/Gui/ViewProviderCompound.cpp +++ b/src/Mod/Part/Gui/ViewProviderCompound.cpp @@ -95,8 +95,8 @@ void ViewProviderCompound::updateData(const App::Property* prop) TopTools_IndexedMapOfShape compMap; TopExp::MapShapes(compShape, TopAbs_FACE, compMap); - std::vector compCol; - compCol.resize(compMap.Extent(), this->ShapeAppearance.getDiffuseColor()); + std::vector compCol; + compCol.resize(compMap.Extent(), this->ShapeAppearance[0]); int index=0; for (std::vector::iterator it = sources.begin(); it != sources.end(); ++it, ++index) { @@ -111,14 +111,14 @@ void ViewProviderCompound::updateData(const App::Property* prop) auto vpBase = dynamic_cast(Gui::Application::Instance->getViewProvider(objBase)); if (vpBase) { - std::vector baseCol = vpBase->DiffuseColor.getValues(); - applyTransparency(vpBase->Transparency.getValue(),baseCol); - if (static_cast(baseCol.size()) == baseMap.Extent()) { - applyColor(hist[index], baseCol, compCol); + vpBase->ShapeAppearance.setTransparency(vpBase->Transparency.getValue()); + if (static_cast(vpBase->ShapeAppearance.getSize()) == baseMap.Extent()) { + applyMaterial(hist[index], vpBase->ShapeAppearance, compCol); } - else if (!baseCol.empty() && baseCol[0] != this->ShapeAppearance.getDiffuseColor()) { - baseCol.resize(baseMap.Extent(), baseCol[0]); - applyColor(hist[index], baseCol, compCol); + else if (vpBase->ShapeAppearance.getSize() > 0 + && vpBase->ShapeAppearance[0] != this->ShapeAppearance[0]) { + vpBase->ShapeAppearance.setSize(baseMap.Extent(), vpBase->ShapeAppearance[0]); + applyMaterial(hist[index], vpBase->ShapeAppearance, compCol); } } } @@ -129,7 +129,7 @@ void ViewProviderCompound::updateData(const App::Property* prop) applyTransparency(Transparency.getValue(), compCol); } - this->DiffuseColor.setValues(compCol); + this->ShapeAppearance.setValues(compCol); } else if (prop->isDerivedFrom()) { const std::vector& pBases = static_cast(prop)->getValues(); diff --git a/src/Mod/Part/Gui/ViewProviderExt.cpp b/src/Mod/Part/Gui/ViewProviderExt.cpp index 36eb1d65e2..38140df7de 100644 --- a/src/Mod/Part/Gui/ViewProviderExt.cpp +++ b/src/Mod/Part/Gui/ViewProviderExt.cpp @@ -66,6 +66,7 @@ # include # include # include +# include # include #endif @@ -86,10 +87,11 @@ #include #include "ViewProviderExt.h" +#include "ViewProviderPartExtPy.h" #include "SoBrepEdgeSet.h" #include "SoBrepFaceSet.h" #include "SoBrepPointSet.h" -#include "TaskFaceColors.h" +#include "TaskFaceAppearances.h" FC_LOG_LEVEL_INIT("Part", true, true) @@ -100,12 +102,12 @@ using namespace PartGui; namespace { float fromPercent(long value) { - return static_cast(value) / 100.0F; + return std::roundf(value) / 100.0F; } long toPercent(float value) { - return static_cast(100.0 * value + 0.5); + return std::lround(100.0 * value); } } @@ -175,7 +177,6 @@ ViewProviderPartExt::ViewProviderPartExt() ADD_PROPERTY_TYPE(LineColor, (lmat.diffuseColor), osgroup, App::Prop_None, "Set object line color."); ADD_PROPERTY_TYPE(PointColor, (vmat.diffuseColor), osgroup, App::Prop_None, "Set object point color"); ADD_PROPERTY_TYPE(PointColorArray, (PointColor.getValue()), osgroup, App::Prop_None, "Object point color array."); - ADD_PROPERTY_TYPE(DiffuseColor,(ShapeAppearance.getDiffuseColors()), osgroup, App::Prop_None, "Object diffuse color."); ADD_PROPERTY_TYPE(LineColorArray,(LineColor.getValue()), osgroup, App::Prop_None, "Object line color array."); ADD_PROPERTY_TYPE(LineWidth,(lwidth), osgroup, App::Prop_None, "Set object line width."); LineWidth.setConstraints(&sizeRange); @@ -196,6 +197,16 @@ ViewProviderPartExt::ViewProviderPartExt() ADD_PROPERTY_TYPE(DrawStyle,((long int)0), osgroup, App::Prop_None, "Defines the style of the edges in the 3D view."); DrawStyle.setEnums(DrawStyleEnums); + // This is needed to restore old DiffuseColor values since the restore + // function is asynchronous + App::PropertyColor noColor; + ADD_PROPERTY_TYPE(_diffuseColor, + (noColor.getValue()), + osgroup, + App::Prop_NoPersist, + "Object diffuse color."); + _diffuseColor.setStatus(App::Property::PropHidden, true); + coords = new SoCoordinate3(); coords->ref(); faceset = new SoBrepFaceSet(); @@ -210,6 +221,14 @@ ViewProviderPartExt::ViewProviderPartExt() nodeset = new SoBrepPointSet(); nodeset->ref(); + // Support for textured faces + pcShapeTexture3D = new SoTexture3; + pcShapeTexture3D->ref(); + pcShapeCoordinates = new SoCoordinate3; + pcShapeCoordinates->ref(); + pcShapeFaceset = new SoIndexedFaceSet; + pcShapeFaceset->ref(); + pcFaceBind = new SoMaterialBinding(); pcFaceBind->ref(); @@ -261,6 +280,19 @@ ViewProviderPartExt::~ViewProviderPartExt() normb->unref(); lineset->unref(); nodeset->unref(); + + pcShapeTexture3D->unref(); + pcShapeCoordinates->unref(); + pcShapeFaceset->unref(); +} + +PyObject* ViewProviderPartExt::getPyObject() +{ + if (!pyViewObject) { + pyViewObject = new ViewProviderPartExtPy(this); + } + pyViewObject->IncRef(); + return pyViewObject; } void ViewProviderPartExt::onChanged(const App::Property* prop) @@ -328,29 +360,20 @@ void ViewProviderPartExt::onChanged(const App::Property* prop) else if (prop == &LineColorArray) { setHighlightedEdges(LineColorArray.getValues()); } - else if (prop == &DiffuseColor) { - setHighlightedFaces(DiffuseColor.getValues()); + else if (prop == &_diffuseColor) { + // Used to load the old DiffuseColor values asynchronously + ShapeAppearance.setDiffuseColors(_diffuseColor.getValues()); + ShapeAppearance.setTransparency(Transparency.getValue() / 100.0f); } else if (prop == &ShapeAppearance) { - pcFaceBind->value = SoMaterialBinding::OVERALL; + setHighlightedFaces(ShapeAppearance); ViewProviderGeometryObject::onChanged(prop); - // While restoring a document do not override the - // DiffuseColor that has already been restored - if (!isRestoring()) { - App::Color c = ShapeAppearance.getDiffuseColor(); - c.a = fromPercent(Transparency.getValue()); - DiffuseColor.setValue(c); - } } else if (prop == &Transparency) { const App::Material& Mat = ShapeAppearance[0]; long value = toPercent(Mat.transparency); if (value != Transparency.getValue()) { float trans = fromPercent(Transparency.getValue()); - auto colors = DiffuseColor.getValues(); - for (auto &c : colors) - c.a = trans; - DiffuseColor.setValues(colors); App::PropertyContainer* parent = ShapeAppearance.getContainer(); ShapeAppearance.setContainer(nullptr); @@ -380,12 +403,12 @@ void ViewProviderPartExt::onChanged(const App::Property* prop) updateVisual(); // updateVisual() may not be triggered by any change (e.g. // triggered by an external object through forceUpdate()). And - // since DiffuseColor is not changed here either, do not falsely set + // since ShapeAppearance is not changed here either, do not falsely set // the document modified status Base::ObjectStatusLocker guard( - App::Property::NoModify, &DiffuseColor); + App::Property::NoModify, &ShapeAppearance); // The material has to be checked again (#0001736) - onChanged(&DiffuseColor); + onChanged(&ShapeAppearance); } } @@ -444,7 +467,10 @@ void ViewProviderPartExt::attach(App::DocumentObject *pcFeat) // just faces with no edges or points pcFlatRoot->addChild(pShapeHints); pcFlatRoot->addChild(pcFaceBind); - pcFlatRoot->addChild(pcShapeMaterial); + pcFlatRoot->addChild(pcSwitchAppearance); + pcTextureGroup3D->addChild(pcShapeTexture3D); + pcTextureGroup3D->addChild(pcShapeCoordinates); + pcTextureGroup3D->addChild(pcShapeFaceset); SoDrawStyle* pcFaceStyle = new SoDrawStyle(); pcFaceStyle->style = SoDrawStyle::FILLED; pcFlatRoot->addChild(pcFaceStyle); @@ -599,69 +625,89 @@ std::vector ViewProviderPartExt::getSelectionShape(const char* / return {}; } -void ViewProviderPartExt::setHighlightedFaces(const std::vector& colors) +void ViewProviderPartExt::setHighlightedFaces(const std::vector& materials) { - if (getObject() && getObject()->testStatus(App::ObjectStatus::TouchOnColorChange)) - getObject()->touch(true); - - Gui::SoUpdateVBOAction action; - action.apply(this->faceset); - - int size = static_cast(colors.size()); - if (size > 1 && size == this->faceset->partIndex.getNum()) { - pcFaceBind->value = SoMaterialBinding::PER_PART; - pcShapeMaterial->diffuseColor.setNum(size); - pcShapeMaterial->transparency.setNum(size); - SbColor* ca = pcShapeMaterial->diffuseColor.startEditing(); - float *t = pcShapeMaterial->transparency.startEditing(); - for (int i = 0; i < size; i++) { - ca[i].setValue(colors[i].r, colors[i].g, colors[i].b); - t[i] = colors[i].a; - } - pcShapeMaterial->diffuseColor.finishEditing(); - pcShapeMaterial->transparency.finishEditing(); - } - else if (colors.size() == 1) { - pcFaceBind->value = SoMaterialBinding::OVERALL; - pcShapeMaterial->diffuseColor.setValue(colors[0].r, colors[0].g, colors[0].b); - pcShapeMaterial->transparency = Transparency.getValue()/100.f; - } -} - -void ViewProviderPartExt::setHighlightedFaces(const std::vector& colors) -{ - int size = static_cast(colors.size()); + int size = static_cast(materials.size()); if (size > 1 && size == this->faceset->partIndex.getNum()) { pcFaceBind->value = SoMaterialBinding::PER_PART; + activateMaterial(); pcShapeMaterial->diffuseColor.setNum(size); pcShapeMaterial->ambientColor.setNum(size); pcShapeMaterial->specularColor.setNum(size); pcShapeMaterial->emissiveColor.setNum(size); + pcShapeMaterial->shininess.setNum(size); SbColor* dc = pcShapeMaterial->diffuseColor.startEditing(); SbColor* ac = pcShapeMaterial->ambientColor.startEditing(); SbColor* sc = pcShapeMaterial->specularColor.startEditing(); SbColor* ec = pcShapeMaterial->emissiveColor.startEditing(); + float* sh = pcShapeMaterial->shininess.startEditing(); for (int i = 0; i < size; i++) { - dc[i].setValue(colors[i].diffuseColor.r, colors[i].diffuseColor.g, colors[i].diffuseColor.b); - ac[i].setValue(colors[i].ambientColor.r, colors[i].ambientColor.g, colors[i].ambientColor.b); - sc[i].setValue(colors[i].specularColor.r, colors[i].specularColor.g, colors[i].specularColor.b); - ec[i].setValue(colors[i].emissiveColor.r, colors[i].emissiveColor.g, colors[i].emissiveColor.b); + dc[i].setValue(materials[i].diffuseColor.r, materials[i].diffuseColor.g, materials[i].diffuseColor.b); + ac[i].setValue(materials[i].ambientColor.r, materials[i].ambientColor.g, materials[i].ambientColor.b); + sc[i].setValue(materials[i].specularColor.r, materials[i].specularColor.g, materials[i].specularColor.b); + ec[i].setValue(materials[i].emissiveColor.r, materials[i].emissiveColor.g, materials[i].emissiveColor.b); + sh[i] = materials[i].shininess; } pcShapeMaterial->diffuseColor.finishEditing(); pcShapeMaterial->ambientColor.finishEditing(); pcShapeMaterial->specularColor.finishEditing(); pcShapeMaterial->emissiveColor.finishEditing(); + pcShapeMaterial->shininess.finishEditing(); } - else if (colors.size() == 1) { + else if (size == 1) { pcFaceBind->value = SoMaterialBinding::OVERALL; - pcShapeMaterial->diffuseColor.setValue(colors[0].diffuseColor.r, colors[0].diffuseColor.g, colors[0].diffuseColor.b); - pcShapeMaterial->ambientColor.setValue(colors[0].ambientColor.r, colors[0].ambientColor.g, colors[0].ambientColor.b); - pcShapeMaterial->specularColor.setValue(colors[0].specularColor.r, colors[0].specularColor.g, colors[0].specularColor.b); - pcShapeMaterial->emissiveColor.setValue(colors[0].emissiveColor.r, colors[0].emissiveColor.g, colors[0].emissiveColor.b); + setCoinAppearance(materials[0]); + } +} + +void ViewProviderPartExt::setHighlightedFaces(const App::PropertyMaterialList& appearance) +{ + int size = static_cast(appearance.getSize()); + if (size > 1 && size == this->faceset->partIndex.getNum()) { + pcFaceBind->value = SoMaterialBinding::PER_PART; + activateMaterial(); + + pcShapeMaterial->diffuseColor.setNum(size); + pcShapeMaterial->ambientColor.setNum(size); + pcShapeMaterial->specularColor.setNum(size); + pcShapeMaterial->emissiveColor.setNum(size); + pcShapeMaterial->shininess.setNum(size); + + SbColor* dc = pcShapeMaterial->diffuseColor.startEditing(); + SbColor* ac = pcShapeMaterial->ambientColor.startEditing(); + SbColor* sc = pcShapeMaterial->specularColor.startEditing(); + SbColor* ec = pcShapeMaterial->emissiveColor.startEditing(); + float* sh = pcShapeMaterial->shininess.startEditing(); + + for (int i = 0; i < size; i++) { + dc[i].setValue(appearance.getDiffuseColor(i).r, + appearance.getDiffuseColor(i).g, + appearance.getDiffuseColor(i).b); + ac[i].setValue(appearance.getAmbientColor(i).r, + appearance.getAmbientColor(i).g, + appearance.getAmbientColor(i).b); + sc[i].setValue(appearance.getSpecularColor(i).r, + appearance.getSpecularColor(i).g, + appearance.getSpecularColor(i).b); + ec[i].setValue(appearance.getEmissiveColor(i).r, + appearance.getEmissiveColor(i).g, + appearance.getEmissiveColor(i).b); + sh[i] = appearance.getShininess(i); + } + + pcShapeMaterial->diffuseColor.finishEditing(); + pcShapeMaterial->ambientColor.finishEditing(); + pcShapeMaterial->specularColor.finishEditing(); + pcShapeMaterial->emissiveColor.finishEditing(); + pcShapeMaterial->shininess.finishEditing(); + } + else if (size == 1) { + pcFaceBind->value = SoMaterialBinding::OVERALL; + setCoinAppearance(appearance[0]); } } @@ -678,18 +724,21 @@ std::map ViewProviderPartExt::getElementColors(const cha } if(boost::starts_with(element,"Face")) { - auto size = DiffuseColor.getSize(); + auto size = ShapeAppearance.getSize(); if(element[4]=='*') { auto color = ShapeAppearance.getDiffuseColor(); color.a = Transparency.getValue()/100.0f; bool singleColor = true; for(int i=0;i ViewProviderPartExt::getElementColors(const cha }else{ int idx = atoi(element+4); if(idx>0 && idx<=size) - ret[element] = DiffuseColor[idx-1]; + ret[element] = ShapeAppearance.getDiffuseColor(idx - 1); else ret[element] = ShapeAppearance.getDiffuseColor(); if(size==1) @@ -753,7 +802,8 @@ std::map ViewProviderPartExt::getElementColors(const cha void ViewProviderPartExt::unsetHighlightedFaces() { - DiffuseColor.touch(); + // DiffuseColor.touch(); + ShapeAppearance.touch(); Transparency.touch(); } @@ -875,7 +925,7 @@ void ViewProviderPartExt::finishRestoring() // and currently sets a single color. // In case DiffuseColor has defined multiple colors they will // be passed to the scene graph now. - DiffuseColor.touch(); + ShapeAppearance.touch(); Gui::ViewProviderGeometryObject::finishRestoring(); } @@ -883,11 +933,11 @@ void ViewProviderPartExt::setupContextMenu(QMenu* menu, QObject* receiver, const { QIcon iconObject = mergeGreyableOverlayIcons(Gui::BitmapFactory().pixmap("Part_ColorFace.svg")); Gui::ViewProviderGeometryObject::setupContextMenu(menu, receiver, member); - QAction* act = menu->addAction(iconObject, QObject::tr("Set colors..."), receiver, member); + QAction* act = menu->addAction(iconObject, QObject::tr("Set appearance per face..."), receiver, member); act->setData(QVariant((int)ViewProvider::Color)); } -bool ViewProviderPartExt::changeFaceColors() +bool ViewProviderPartExt::changeFaceAppearances() { Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); if (dlg) { @@ -896,7 +946,7 @@ bool ViewProviderPartExt::changeFaceColors() } Gui::Selection().clearSelection(); - Gui::Control().showDialog(new TaskFaceColors(this)); + Gui::Control().showDialog(new TaskFaceAppearances(this)); return true; } @@ -906,7 +956,7 @@ bool ViewProviderPartExt::setEdit(int ModNum) // When double-clicking on the item for this pad the // object unsets and sets its edit mode without closing // the task panel - return changeFaceColors(); + return changeFaceAppearances(); } else { return Gui::ViewProviderGeometryObject::setEdit(ModNum); @@ -1321,7 +1371,8 @@ void ViewProviderPartExt::updateVisual() VisualTouched = false; // The material has to be checked again - setHighlightedFaces(DiffuseColor.getValues()); + // setHighlightedFaces(DiffuseColor.getValues()); + setHighlightedFaces(ShapeAppearance); setHighlightedEdges(LineColorArray.getValues()); setHighlightedPoints(PointColorArray.getValue()); } @@ -1336,3 +1387,18 @@ void ViewProviderPartExt::forceUpdate(bool enable) { --forceUpdateCount; } + +void ViewProviderPartExt::handleChangedPropertyName(Base::XMLReader& reader, + const char* TypeName, + const char* PropName) +{ + if (strcmp(PropName, "DiffuseColor") == 0 + && strcmp(TypeName, App::PropertyColorList::getClassTypeId().getName()) == 0) { + + // PropertyColorLists are loaded asynchronously as they're stored in separate files + _diffuseColor.Restore(reader); + } + else { + Gui::ViewProviderGeometryObject::handleChangedPropertyName(reader, TypeName, PropName); + } +} diff --git a/src/Mod/Part/Gui/ViewProviderExt.h b/src/Mod/Part/Gui/ViewProviderExt.h index 85ccf105ef..249cae1d2f 100644 --- a/src/Mod/Part/Gui/ViewProviderExt.h +++ b/src/Mod/Part/Gui/ViewProviderExt.h @@ -52,6 +52,7 @@ class SoNormal; class SoNormalBinding; class SoMaterialBinding; class SoIndexedLineSet; +class SoTexture3; namespace PartGui { @@ -85,8 +86,8 @@ public: App::PropertyColor LineColor; App::PropertyMaterial LineMaterial; App::PropertyColorList LineColorArray; - // Faces (Gui::ViewProviderGeometryObject::ShapeColor and Gui::ViewProviderGeometryObject::ShapeMaterial apply) - App::PropertyColorList DiffuseColor; + // Faces (Gui::ViewProviderGeometryObject::ShapeAppearance and Gui::ViewProviderGeometryObject::ShapeMaterial apply) + // App::PropertyColorList DiffuseColor; void attach(App::DocumentObject *) override; void setDisplayMode(const char* ModeName) override; @@ -95,7 +96,7 @@ public: /// Update the view representation void reload(); /// If no other task is pending it opens a dialog to allow to change face colors - bool changeFaceColors(); + bool changeFaceAppearances(); void updateData(const App::Property*) override; @@ -125,8 +126,8 @@ public: * This group of methods do the highlighting of elements. */ //@{ - void setHighlightedFaces(const std::vector& colors); - void setHighlightedFaces(const std::vector& colors); + void setHighlightedFaces(const std::vector& materials); + void setHighlightedFaces(const App::PropertyMaterialList& appearance); void unsetHighlightedFaces(); void setHighlightedEdges(const std::vector& colors); void unsetHighlightedEdges(); @@ -151,6 +152,9 @@ public: //@{ void setupContextMenu(QMenu*, QObject*, const char*) override; + /// Get the python wrapper for that ViewProvider + PyObject* getPyObject() override; + protected: bool setEdit(int ModNum) override; void unsetEdit(int ModNum) override; @@ -161,6 +165,9 @@ protected: void onChanged(const App::Property* prop) override; bool loadParameter(); void updateVisual(); + void handleChangedPropertyName(Base::XMLReader& reader, + const char* TypeName, + const char* PropName) override; // nodes for the data representation SoMaterialBinding * pcFaceBind; @@ -179,6 +186,11 @@ protected: SoBrepEdgeSet * lineset; SoBrepPointSet * nodeset; + // Used to support per face textures + SoTexture3 * pcShapeTexture3D; + SoCoordinate3 * pcShapeCoordinates; + SoIndexedFaceSet * pcShapeFaceset; + bool VisualTouched; bool NormalsFromUV; @@ -190,6 +202,10 @@ private: static App::PropertyQuantityConstraint::Constraints angDeflectionRange; static const char* LightingEnums[]; static const char* DrawStyleEnums[]; + + // This is needed to restore old DiffuseColor values since the restore + // function is asynchronous + App::PropertyColorList _diffuseColor; }; } diff --git a/src/Mod/Part/Gui/ViewProviderExtPy.xml b/src/Mod/Part/Gui/ViewProviderExtPy.xml new file mode 100644 index 0000000000..76b9602ab4 --- /dev/null +++ b/src/Mod/Part/Gui/ViewProviderExtPy.xml @@ -0,0 +1,17 @@ + + + + + + This is the ViewProvider geometry class + + + diff --git a/src/Mod/Part/Gui/ViewProviderExtPyImp.cpp b/src/Mod/Part/Gui/ViewProviderExtPyImp.cpp new file mode 100644 index 0000000000..c25b83a270 --- /dev/null +++ b/src/Mod/Part/Gui/ViewProviderExtPyImp.cpp @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/*************************************************************************** + * Copyright (c) 2024 David Carter * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#include +#endif + +#include +#include + +#include "ViewProviderExt.h" +#include "ViewProviderPartExtPy.h" + +#include "ViewProviderPartExtPy.cpp" + + +using namespace PartGui; + +// returns a string which represents the object e.g. when printed in python +std::string ViewProviderPartExtPy::representation() const +{ + std::stringstream str; + str << ""; + + return str.str(); +} + +PyObject* ViewProviderPartExtPy::getCustomAttributes(const char* attr) const +{ + ViewProviderPartExt* vp = getViewProviderPartExtPtr(); + if (strcmp(attr, "DiffuseColor") == 0) { + // Get the color properties + App::PropertyColorList prop; + prop.setValues(vp->ShapeAppearance.getDiffuseColors()); + return prop.getPyObject(); + } + return nullptr; +} + +int ViewProviderPartExtPy::setCustomAttributes(const char* attr, PyObject* obj) +{ + ViewProviderPartExt* vp = getViewProviderPartExtPtr(); + if (strcmp(attr, "DiffuseColor") == 0) { + // Set the color properties + App::PropertyColorList prop; + prop.setPyObject(obj); + vp->ShapeAppearance.setDiffuseColors(prop.getValues()); + return 1; + } + return 0; +} diff --git a/src/Mod/Part/Gui/ViewProviderMirror.cpp b/src/Mod/Part/Gui/ViewProviderMirror.cpp index eec50b2641..df93218245 100644 --- a/src/Mod/Part/Gui/ViewProviderMirror.cpp +++ b/src/Mod/Part/Gui/ViewProviderMirror.cpp @@ -263,17 +263,18 @@ void ViewProviderFillet::updateData(const App::Property* prop) auto vpBase = dynamic_cast(Gui::Application::Instance->getViewProvider(objBase)); if (vpBase) { - std::vector colBase = vpBase->DiffuseColor.getValues(); - std::vector colFill; - colFill.resize(fillMap.Extent(), vpBase->ShapeAppearance.getDiffuseColor()); - applyTransparency(vpBase->Transparency.getValue(),colBase); + // std::vector colBase = vpBase->DiffuseColor.getValues(); + std::vector colFill; + colFill.resize(fillMap.Extent(), vpBase->ShapeAppearance[0]); + vpBase->ShapeAppearance.setTransparency(vpBase->Transparency.getValue()); - if (static_cast(colBase.size()) == baseMap.Extent()) { - applyColor(hist[0], colBase, colFill); + if (static_cast(vpBase->ShapeAppearance.getSize()) == baseMap.Extent()) { + applyMaterial(hist[0], vpBase->ShapeAppearance, colFill); } - else if (!colBase.empty() && colBase[0] != this->ShapeAppearance.getDiffuseColor()) { - colBase.resize(baseMap.Extent(), colBase[0]); - applyColor(hist[0], colBase, colFill); + else if (vpBase->ShapeAppearance.getSize() > 0 + && vpBase->ShapeAppearance[0] != this->ShapeAppearance[0]) { + vpBase->ShapeAppearance.setSize(baseMap.Extent(), vpBase->ShapeAppearance[0]); + applyMaterial(hist[0], vpBase->ShapeAppearance, colFill); } // If the view provider has set a transparency then override the values @@ -282,7 +283,7 @@ void ViewProviderFillet::updateData(const App::Property* prop) applyTransparency(Transparency.getValue(), colFill); } - this->DiffuseColor.setValues(colFill); + this->ShapeAppearance.setValues(colFill); } } } @@ -373,17 +374,18 @@ void ViewProviderChamfer::updateData(const App::Property* prop) auto vpBase = dynamic_cast(Gui::Application::Instance->getViewProvider(objBase)); if (vpBase) { - std::vector colBase = static_cast(vpBase)->DiffuseColor.getValues(); - std::vector colCham; - colCham.resize(chamMap.Extent(), static_cast(vpBase)->ShapeAppearance.getDiffuseColor()); - applyTransparency(static_cast(vpBase)->Transparency.getValue(),colBase); + // std::vector colBase = static_cast(vpBase)->DiffuseColor.getValues(); + auto& colBase = static_cast(vpBase)->ShapeAppearance; + std::vector colCham; + colCham.resize(chamMap.Extent(), colBase[0]); + colBase.setTransparency(static_cast(vpBase)->Transparency.getValue()); - if (static_cast(colBase.size()) == baseMap.Extent()) { - applyColor(hist[0], colBase, colCham); + if (static_cast(colBase.getSize()) == baseMap.Extent()) { + applyMaterial(hist[0], colBase, colCham); } - else if (!colBase.empty() && colBase[0] != this->ShapeAppearance.getDiffuseColor()) { - colBase.resize(baseMap.Extent(), colBase[0]); - applyColor(hist[0], colBase, colCham); + else if (colBase.getSize() > 0 && colBase[0] != this->ShapeAppearance[0]) { + colBase.setSize(baseMap.Extent(), colBase[0]); + applyMaterial(hist[0], colBase, colCham); } // If the view provider has set a transparency then override the values @@ -392,7 +394,7 @@ void ViewProviderChamfer::updateData(const App::Property* prop) applyTransparency(Transparency.getValue(), colCham); } - this->DiffuseColor.setValues(colCham); + this->ShapeAppearance.setValues(colCham); } } } diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index 68f47a28f5..13c469a898 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -255,11 +255,11 @@ void ViewProviderBody::updateData(const App::Property* prop) } void ViewProviderBody::copyColorsfromTip(App::DocumentObject* tip) { - // update DiffuseColor + // update ShapeAppearance Gui::ViewProvider* vptip = Gui::Application::Instance->getViewProvider(tip); if (vptip && vptip->isDerivedFrom(PartGui::ViewProviderPartExt::getClassTypeId())) { - auto colors = static_cast(vptip)->DiffuseColor.getValues(); - this->DiffuseColor.setValues(colors); + auto materials = static_cast(vptip)->ShapeAppearance.getValues(); + this->ShapeAppearance.setValues(materials); } } @@ -426,7 +426,6 @@ void ViewProviderBody::unifyVisualProperty(const App::Property* prop) { if (prop == &Visibility || prop == &Selectable || prop == &DisplayModeBody || - prop == &DiffuseColor || prop == &PointColorArray || prop == &LineColorArray) { return; diff --git a/src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp b/src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp index 4f1aa54ef4..19b9b757bc 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp @@ -100,13 +100,13 @@ void ViewProviderDressUp::highlightReferences(const bool on) std::vector edges = pcDressUp->Base.getSubValuesStartsWith("Edge"); if (on) { - if (!faces.empty() && originalFaceColors.empty()) { - originalFaceColors = vp->DiffuseColor.getValues(); - std::vector colors = originalFaceColors; + if (!faces.empty() && originalFaceMaterials.empty()) { + originalFaceMaterials = vp->ShapeAppearance.getValues(); + std::vector materials = originalFaceMaterials; PartGui::ReferenceHighlighter highlighter(base->Shape.getValue(), ShapeAppearance.getDiffuseColor()); - highlighter.getFaceColors(faces, colors); - vp->DiffuseColor.setValues(colors); + highlighter.getFaceMaterials(faces, materials); + vp->ShapeAppearance.setValues(materials); } if (!edges.empty() && originalLineColors.empty()) { originalLineColors = vp->LineColorArray.getValues(); @@ -117,9 +117,9 @@ void ViewProviderDressUp::highlightReferences(const bool on) vp->LineColorArray.setValues(colors); } } else { - if (!faces.empty() && !originalFaceColors.empty()) { - vp->DiffuseColor.setValues(originalFaceColors); - originalFaceColors.clear(); + if (!faces.empty() && !originalFaceMaterials.empty()) { + vp->ShapeAppearance.setValues(originalFaceMaterials); + originalFaceMaterials.clear(); } if (!edges.empty() && !originalLineColors.empty()) { vp->LineColorArray.setValues(originalLineColors); diff --git a/src/Mod/PartDesign/Gui/ViewProviderDressUp.h b/src/Mod/PartDesign/Gui/ViewProviderDressUp.h index d04adae269..3c5ff435c9 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDressUp.h +++ b/src/Mod/PartDesign/Gui/ViewProviderDressUp.h @@ -60,7 +60,7 @@ protected: bool setEdit(int ModNum) override; private: - std::vector originalFaceColors; + std::vector originalFaceMaterials; std::vector originalLineColors; }; diff --git a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp index 8c4da52827..5743261360 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp @@ -161,9 +161,9 @@ void ViewProviderShapeBinder::highlightReferences(bool on) lcolors.resize(eMap.Extent(), svp->LineColor.getValue()); TopExp::MapShapes(static_cast(obj)->Shape.getValue(), TopAbs_FACE, eMap); - originalFaceColors = svp->DiffuseColor.getValues(); - std::vector fcolors = originalFaceColors; - fcolors.resize(eMap.Extent(), svp->ShapeAppearance.getDiffuseColor()); + originalFaceAppearance = svp->ShapeAppearance.getValues(); + std::vector fcolors = originalFaceAppearance; + fcolors.resize(eMap.Extent(), svp->ShapeAppearance[0]); for (const std::string& e : subs) { // Note: stoi may throw, but it strictly shouldn't happen @@ -177,11 +177,11 @@ void ViewProviderShapeBinder::highlightReferences(bool on) int idx = std::stoi(e.substr(4)) - 1; assert(idx >= 0); if (idx < static_cast(fcolors.size())) - fcolors[idx] = App::Color(1.0, 0.0, 1.0); // magenta + fcolors[idx].diffuseColor = App::Color(1.0, 0.0, 1.0); // magenta } } svp->LineColorArray.setValues(lcolors); - svp->DiffuseColor.setValues(fcolors); + svp->ShapeAppearance.setValues(fcolors); } } else { @@ -189,8 +189,8 @@ void ViewProviderShapeBinder::highlightReferences(bool on) svp->LineColorArray.setValues(originalLineColors); originalLineColors.clear(); - svp->DiffuseColor.setValues(originalFaceColors); - originalFaceColors.clear(); + svp->ShapeAppearance.setValues(originalFaceAppearance); + originalFaceAppearance.clear(); } } } diff --git a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.h b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.h index 3037b3e862..9a1836afe4 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.h +++ b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.h @@ -48,7 +48,7 @@ protected: private: std::vector originalLineColors; - std::vector originalFaceColors; + std::vector originalFaceAppearance; }; diff --git a/src/Mod/Surface/Gui/TaskFilling.cpp b/src/Mod/Surface/Gui/TaskFilling.cpp index e11b52db56..03ca409b83 100644 --- a/src/Mod/Surface/Gui/TaskFilling.cpp +++ b/src/Mod/Surface/Gui/TaskFilling.cpp @@ -161,22 +161,23 @@ void ViewProviderFilling::highlightReferences(ShapeType type, const References& break; case ViewProviderFilling::Face: if (on) { - std::vector colors; + std::vector materials; TopTools_IndexedMapOfShape fMap; TopExp::MapShapes(base->Shape.getValue(), TopAbs_FACE, fMap); - colors.resize(fMap.Extent(), svp->ShapeAppearance.getDiffuseColor()); + materials.resize(fMap.Extent(), svp->ShapeAppearance[0]); for (const auto& jt : it.second) { std::size_t idx = static_cast(std::stoi(jt.substr(4)) - 1); // check again that the index is in range because it's possible that // the sub-names are invalid - if (idx < colors.size()) { - colors[idx] = App::Color(1.0, 0.0, 1.0); // magenta + if (idx < materials.size()) { + materials[idx].diffuseColor = + App::Color(1.0, 0.0, 1.0); // magenta } } - svp->setHighlightedFaces(colors); + svp->setHighlightedFaces(materials); } else { svp->unsetHighlightedFaces(); diff --git a/src/Mod/Surface/Gui/TaskSections.cpp b/src/Mod/Surface/Gui/TaskSections.cpp index e1e93be19e..d7ee73aa54 100644 --- a/src/Mod/Surface/Gui/TaskSections.cpp +++ b/src/Mod/Surface/Gui/TaskSections.cpp @@ -161,22 +161,23 @@ void ViewProviderSections::highlightReferences(ShapeType type, const References& break; case ViewProviderSections::Face: if (on) { - std::vector colors; + std::vector materials; TopTools_IndexedMapOfShape fMap; TopExp::MapShapes(base->Shape.getValue(), TopAbs_FACE, fMap); - colors.resize(fMap.Extent(), svp->ShapeAppearance.getDiffuseColor()); + materials.resize(fMap.Extent(), svp->ShapeAppearance[0]); for (const auto& jt : it.second) { std::size_t idx = static_cast(std::stoi(jt.substr(4)) - 1); // check again that the index is in range because it's possible that // the sub-names are invalid - if (idx < colors.size()) { - colors[idx] = App::Color(1.0, 0.0, 1.0); // magenta + if (idx < materials.size()) { + materials[idx].diffuseColor = + App::Color(1.0, 0.0, 1.0); // magenta } } - svp->setHighlightedFaces(colors); + svp->setHighlightedFaces(materials); } else { svp->unsetHighlightedFaces();