Core: Convert transparency to alpha (#24891)
* Core: Convert transparency to alpha Create new `Base::getVersion()` function for extracting a program version enumeration given a version string. Convert transparency to alpha value for old project files. * Base/App: Address review comments --------- Co-authored-by: wmayer <wmayer@freecad.org>
This commit is contained in:
@@ -35,6 +35,7 @@
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <Base/ProgramVersion.h>
|
||||
#include <Base/Reader.h>
|
||||
#include <Base/Writer.h>
|
||||
#include <Base/Quantity.h>
|
||||
@@ -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<unsigned long>("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<unsigned long>("emissiveColor"));
|
||||
_cMat.shininess = (float)reader.getAttribute<double>("shininess");
|
||||
_cMat.transparency = (float)reader.getAttribute<double>("transparency");
|
||||
if (readerRequiresAlphaConversion(reader)) {
|
||||
convertAlphaInMaterial(_cMat);
|
||||
}
|
||||
if (reader.hasAttribute("image")) {
|
||||
_cMat.image = reader.getAttribute<const char*>("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<App::Material>& materials) const
|
||||
{
|
||||
if (requiresAlphaConversion) {
|
||||
std::ranges::for_each(materials, convertAlphaInMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyMaterialList::readString(Base::InputStream& str, std::string& value)
|
||||
{
|
||||
uint32_t uCt {};
|
||||
|
||||
@@ -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<App::Material>& materials) const;
|
||||
|
||||
Format formatVersion {Version_0};
|
||||
bool requiresAlphaConversion {false}; // In 1.1 the handling of alpha was inverted
|
||||
};
|
||||
|
||||
|
||||
|
||||
84
src/Base/ProgramVersion.h
Normal file
84
src/Base/ProgramVersion.h
Normal file
@@ -0,0 +1,84 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef BASE_PROGRAM_VERSION_H
|
||||
#define BASE_PROGRAM_VERSION_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <FCGlobal.h>
|
||||
|
||||
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<VersionItem> 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
|
||||
@@ -1823,6 +1823,7 @@ void Document::RestoreDocFile(Base::Reader& reader)
|
||||
localreader->readElement("Document");
|
||||
long scheme = localreader->getAttribute<long>("SchemaVersion");
|
||||
localreader->DocumentSchema = scheme;
|
||||
localreader->ProgramVersion = d->_pcDocument->getProgramVersion();
|
||||
|
||||
bool hasExpansion = localreader->hasAttribute("HasExpansion");
|
||||
if (hasExpansion) {
|
||||
|
||||
Reference in New Issue
Block a user