diff --git a/src/App/PropertyStandard.cpp b/src/App/PropertyStandard.cpp
index 6ebe158bdb..63e4fa57dc 100644
--- a/src/App/PropertyStandard.cpp
+++ b/src/App/PropertyStandard.cpp
@@ -35,6 +35,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -2226,6 +2227,25 @@ unsigned int PropertyBoolList::getMemSize() const
// PropertyColor
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+namespace
+{
+/// The definition of "alpha" was corrected in FreeCAD 1.1 -- returns true if the reader is working
+/// on a file that pre-dates that correction.
+bool readerRequiresAlphaConversion(const Base::XMLReader &reader)
+{
+ return Base::getVersion(reader.ProgramVersion) < Base::Version::v1_1;
+}
+
+/// Given a material, invert the alpha channel of all of its colors.
+void convertAlphaInMaterial(App::Material& material)
+{
+ material.ambientColor.a = 1.0F - material.ambientColor.a;
+ material.diffuseColor.a = 1.0F - material.diffuseColor.a;
+ material.specularColor.a = 1.0F - material.specularColor.a;
+ material.emissiveColor.a = 1.0F - material.emissiveColor.a;
+}
+}
+
TYPESYSTEM_SOURCE(App::PropertyColor, App::Property)
//**************************************************************************
@@ -2367,6 +2387,12 @@ void PropertyColor::Restore(Base::XMLReader& reader)
reader.readElement("PropertyColor");
// get the value of my Attribute
unsigned long rgba = reader.getAttribute("value");
+ if (readerRequiresAlphaConversion(reader)) {
+ // Convert transparency / alpha value
+ constexpr unsigned long alphaMax = 0xff;
+ unsigned long alpha = alphaMax - (rgba & alphaMax);
+ rgba = rgba - (rgba & alphaMax) + alpha;
+ }
setValue(rgba);
}
@@ -2448,6 +2474,8 @@ void PropertyColorList::Restore(Base::XMLReader& reader)
// initiate a file read
reader.addFile(file.c_str(), this);
}
+
+ requiresAlphaConversion = readerRequiresAlphaConversion(reader);
}
}
@@ -2472,6 +2500,11 @@ void PropertyColorList::RestoreDocFile(Base::Reader& reader)
str >> value;
it.setPackedValue(value);
}
+ if (requiresAlphaConversion) {
+ for (auto& it : values) {
+ it.a = 1.0F - it.a;
+ }
+ }
setValues(values);
}
@@ -2702,6 +2735,9 @@ void PropertyMaterial::Restore(Base::XMLReader& reader)
_cMat.emissiveColor.setPackedValue(reader.getAttribute("emissiveColor"));
_cMat.shininess = (float)reader.getAttribute("shininess");
_cMat.transparency = (float)reader.getAttribute("transparency");
+ if (readerRequiresAlphaConversion(reader)) {
+ convertAlphaInMaterial(_cMat);
+ }
if (reader.hasAttribute("image")) {
_cMat.image = reader.getAttribute("image");
}
@@ -3247,6 +3283,8 @@ void PropertyMaterialList::Restore(Base::XMLReader& reader)
// initiate a file read
reader.addFile(file.c_str(), this);
}
+
+ requiresAlphaConversion = readerRequiresAlphaConversion(reader);
}
}
@@ -3330,6 +3368,7 @@ void PropertyMaterialList::RestoreDocFileV0(uint32_t count, Base::Reader& reader
str >> valueF;
it.transparency = valueF;
}
+ convertAlpha(values);
setValues(values);
}
@@ -3360,9 +3399,17 @@ void PropertyMaterialList::RestoreDocFileV3(Base::Reader& reader)
readString(str, it.imagePath);
readString(str, it.uuid);
}
+ convertAlpha(values);
setValues(values);
}
+void PropertyMaterialList::convertAlpha(std::vector& materials) const
+{
+ if (requiresAlphaConversion) {
+ std::ranges::for_each(materials, convertAlphaInMaterial);
+ }
+}
+
void PropertyMaterialList::readString(Base::InputStream& str, std::string& value)
{
uint32_t uCt {};
diff --git a/src/App/PropertyStandard.h b/src/App/PropertyStandard.h
index f864a554a5..9294662440 100644
--- a/src/App/PropertyStandard.h
+++ b/src/App/PropertyStandard.h
@@ -1091,6 +1091,9 @@ public:
protected:
Base::Color getPyValue(PyObject* py) const override;
+
+private:
+ bool requiresAlphaConversion {false}; // In 1.1 the handling of alpha was inverted
};
@@ -1294,8 +1297,10 @@ private:
void verifyIndex(int index) const;
void setMinimumSizeOne();
int resizeByOneIfNeeded(int index);
+ void convertAlpha(std::vector& materials) const;
Format formatVersion {Version_0};
+ bool requiresAlphaConversion {false}; // In 1.1 the handling of alpha was inverted
};
diff --git a/src/Base/ProgramVersion.h b/src/Base/ProgramVersion.h
new file mode 100644
index 0000000000..4f23f52588
--- /dev/null
+++ b/src/Base/ProgramVersion.h
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+/***************************************************************************
+ * Copyright (c) 2024 Werner Mayer *
+ * *
+ * 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 *
+ * . *
+ * *
+ **************************************************************************/
+
+#ifndef BASE_PROGRAM_VERSION_H
+#define BASE_PROGRAM_VERSION_H
+
+#include
+#include
+#include
+#include
+
+namespace Base
+{
+
+enum class Version : std::uint8_t
+{
+ v0_1x,
+ v0_16,
+ v0_17,
+ v0_18,
+ v0_19,
+ v0_20,
+ v0_21,
+ v0_22,
+ v1_0,
+ v1_1,
+ v1_x,
+};
+
+inline Version getVersion(std::string_view str)
+{
+ // clang-format off
+ struct VersionItem
+ {
+ std::string_view name;
+ Version version;
+ };
+ static const std::initializer_list items = {
+ {.name="0.16", .version=Version::v0_16},
+ {.name="0.17", .version=Version::v0_17},
+ {.name="0.18", .version=Version::v0_18},
+ {.name="0.19", .version=Version::v0_19},
+ {.name="0.20", .version=Version::v0_20},
+ {.name="0.21", .version=Version::v0_21},
+ {.name="0.22", .version=Version::v0_22},
+ {.name="1.0" , .version=Version::v1_0 },
+ {.name="1.1" , .version=Version::v1_1 },
+ };
+ // clang-format on
+ auto it = std::ranges::find_if(items, [str](const auto& item) {
+ return str.compare(0, item.name.size(), item.name) == 0;
+ });
+ if (it != items.end()) {
+ return it->version;
+ }
+ if (!str.empty() && str[0] == '0') {
+ return Version::v0_1x;
+ }
+ return Version::v1_x;
+}
+
+} // namespace Base
+
+#endif // BASE_PROGRAM_VERSION_H
diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp
index 42855bdf8f..d8692b824b 100644
--- a/src/Gui/Document.cpp
+++ b/src/Gui/Document.cpp
@@ -1823,6 +1823,7 @@ void Document::RestoreDocFile(Base::Reader& reader)
localreader->readElement("Document");
long scheme = localreader->getAttribute("SchemaVersion");
localreader->DocumentSchema = scheme;
+ localreader->ProgramVersion = d->_pcDocument->getProgramVersion();
bool hasExpansion = localreader->hasAttribute("HasExpansion");
if (hasExpansion) {