Finishes incorporates all Archicad material properties

Serialisation wrapper for Archicad colour rgb colour
This commit is contained in:
Ralph Wessel
2024-10-13 17:49:17 +01:00
parent 05c2cdc47a
commit 7f4b7112ae
6 changed files with 145 additions and 54 deletions
+47 -34
View File
@@ -5,6 +5,7 @@
#include "Active/Serialise/CargoHold.h"
#include "Active/Utility/BufferOut.h"
#include "Speckle/Serialise/Collection/FinishCollector.h"
#include "Speckle/Serialise/Types/ArchicadRGB.h"
#include "Speckle/Utility/Guid.h"
#ifdef ARCHICAD
@@ -22,14 +23,28 @@ using namespace speckle::utility;
namespace speckle::record::attribute {
///Internal representation of a rendered finish on a 3D body, i.e. the surface colour/texture etc.
class Finish::Data {
public:
#ifdef ARCHICAD
Data(const API_Attribute& attr) : root{attr.material} {}
Data(const Data& source) : root{source.root} {}
/*!
Constructor from Archicad surface material
@param attr An Archicad attribute
*/
Data(const API_Attribute& attr) : root{attr.material} {
opacity = 1.0 - (static_cast<double>(attr.material.transpPc) / 100.0);
roughness = 1.0 - (static_cast<double>(attr.material.shine) / 10000.0);
}
///Archicad representation of a surface material
API_MaterialType root;
#endif
//Opacity (0.0 -> 1.0)
double opacity = 1.0;
//Roughness (0.0 -> 1.0)
double roughness = 0.0;
//Metalness (0.0 -> 1.0)
double metalness = 0.0;
};
}
@@ -57,35 +72,15 @@ namespace {
#ifdef ARCHICAD
/*!
Copy a ModelerAPI colour to an AC RGB colour
@param modelColour The modeler API colour
@param colour The attribute API colour
*/
void copyModelerColor(const ModelerAPI::Color& modelColour, API_RGBColor& colour) {
colour.f_red = modelColour.red;
colour.f_green = modelColour.green;
colour.f_blue = modelColour.blue;
} //copyModelerColor
}
#endif
int32_t ARGBToInt(double alpha, double red, double green, double blue) {
// Convert double (0.0 - 1.0) to uint8_t (0 - 255)
uint8_t a = static_cast<uint8_t>(std::round(alpha * 255.0));
uint8_t r = static_cast<uint8_t>(std::round(red * 255.0));
uint8_t g = static_cast<uint8_t>(std::round(green * 255.0));
uint8_t b = static_cast<uint8_t>(std::round(blue * 255.0));
// Pack ARGB into a single 32-bit integer
return (a << 24) | (r << 16) | (g << 8) | b;
}
int32_t ARGBToInt(double alpha, const API_RGBColor& color) {
// Convert double (0.0 - 1.0) to uint8_t (0 - 255)
uint8_t a = static_cast<uint8_t>(std::round(alpha * 255.0));
uint8_t r = static_cast<uint8_t>(std::round(color.f_red * 255.0));
uint8_t g = static_cast<uint8_t>(std::round(color.f_green * 255.0));
uint8_t b = static_cast<uint8_t>(std::round(color.f_blue * 255.0));
// Pack ARGB into a single 32-bit integer
return (a << 24) | (r << 16) | (g << 8) | b;
}
}
/*--------------------------------------------------------------------
@@ -217,18 +212,20 @@ Cargo::Unique Finish::getCargo(const Inventory::Item& item) const {
confirmData();
using namespace active::serialise;
switch (item.index) {
case diffuseID: {
auto opacity = 1.0 - m_data->root.transpPc;
return std::make_unique<CargoHold<Int32Wrap, int32_t>>(ARGBToInt(opacity, m_data->root.surfaceRGB));
}
case diffuseID:
#ifdef ARCHICAD
return std::make_unique<ValueWrap<API_RGBColor>>(m_data->root.surfaceRGB);
#endif
case opacityID:
return std::make_unique<CargoHold<DoubleWrap,double>>(1.0);
return std::make_unique<DoubleWrap>(m_data->opacity);
case emissiveID:
return std::make_unique<CargoHold<Int32Wrap, int32_t>>(ARGBToInt(0.0, 0.0, 0.0, 0.0));
#ifdef ARCHICAD
return std::make_unique<ValueWrap<API_RGBColor>>(m_data->root.emissionRGB);
#endif
case metalnessID:
return std::make_unique<CargoHold<DoubleWrap, double>>(1.0);
return std::make_unique<DoubleWrap>(m_data->metalness);
case roughnessID:
return std::make_unique<CargoHold<DoubleWrap, double>>(1.0);
return std::make_unique<DoubleWrap>(m_data->roughness);
default:
return nullptr; //Requested an unknown index
}
@@ -239,10 +236,26 @@ Cargo::Unique Finish::getCargo(const Inventory::Item& item) const {
Set to the default package content
--------------------------------------------------------------------*/
void Finish::setDefault() {
m_data->root = {};
m_data->opacity = 0.0;
m_data->roughness = 1.0;
m_data->metalness = 0.0;
} //Finish::setDefault
/*--------------------------------------------------------------------
Validate the cargo data
return: True if the data has been validated
--------------------------------------------------------------------*/
bool Finish::validate() {
m_data->root.transpPc = static_cast<short>(100 * (1.0 - m_data->opacity));
m_data->root.shine = static_cast<short>(10000 * (1.0 - m_data->roughness));
//NB: Archicad has no metalness value - currently discarded
return true;
} //Finish::validate
/*--------------------------------------------------------------------
Confirm the internal data, either loading from the BIM application or setting a default
--------------------------------------------------------------------*/
@@ -122,6 +122,11 @@ namespace speckle::record::attribute {
Set to the default package content
*/
void setDefault() override;
/*!
Validate the cargo data
@return True if the data has been validated
*/
bool validate() override;
private:
/*!
@@ -57,16 +57,6 @@ namespace {
Identity{"displayValue"},
};
int32_t ARGBToInt(double alpha, double red, double green, double blue) {
// Convert double (0.0 - 1.0) to uint8_t (0 - 255)
uint8_t a = static_cast<uint8_t>(std::round(alpha * 255.0));
uint8_t r = static_cast<uint8_t>(std::round(red * 255.0));
uint8_t g = static_cast<uint8_t>(std::round(green * 255.0));
uint8_t b = static_cast<uint8_t>(std::round(blue * 255.0));
// Pack ARGB into a single 32-bit integer
return (a << 24) | (r << 16) | (g << 8) | b;
}
}
/*--------------------------------------------------------------------
@@ -0,0 +1,79 @@
#ifndef SPECKLE_SERIALISE_ARCHICAD_RGB
#define SPECKLE_SERIALISE_ARCHICAD_RGB
#ifdef ARCHICAD
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h"
#include "Active/Utility/BufferOut.h"
#include <APIdefs_base.h>
namespace active::serialise {
// MARK: - Specialisations for API_RGBColor
/*!
Convert a string (encoding a 32-bit unsigned integer) to an Archicad RGB colour structure
@param source The source string to convert
@return The equivalent colour (nullopt on failure)
*/
std::optional<API_RGBColor> convertToAPI_RGBColor(const utility::String& source) {
auto intValue = source.toUInt32();
if (!intValue)
return std::nullopt;
API_RGBColor result{};
*intValue >>= 8;
result.f_red = static_cast<double>(*intValue & 0xFF) / 255.0;
*intValue >>= 8;
result.f_green = static_cast<double>(*intValue & 0xFF) / 255.0;
*intValue >>= 8;
result.f_blue = static_cast<double>(*intValue & 0xFF) / 255.0;
return result;
}
/*!
Import the object from the specified string (specialisation for API_RGBColor)
@param source The string to read
@return True if the data was successfully read
*/
template<> inline
bool ValueWrap<API_RGBColor>::read(const utility::String& source) {
if (auto colour = convertToAPI_RGBColor(source); colour) {
get() = *colour;
return true;
}
return false;
} //ValueWrap<API_RGBColor>::read
/*!
Import the object from the specified string (specialisation for API_RGBColor)
@param source The string to read
@return True if the data was successfully read
*/
template<> inline
bool ValueWrap<std::optional<API_RGBColor>>::read(const utility::String& source) {
if (auto colour = convertToAPI_RGBColor(source); colour)
get() = colour;
return true;
} //ValueWrap<API_RGBColor>::read
/*!
Export the object to the specified string (specialisation for API_RGBColor)
@param dest The string to write the data to
@return True if the data was successfully written
*/
template<> inline
bool ValueWrap<API_RGBColor>::write(utility::String& dest) const {
dest = speckle::utility::String{(static_cast<uint32_t>(get().f_red * 255.0) << 24) |
((static_cast<uint32_t>(get().f_green * 255.0)) << 16) |
((static_cast<uint32_t>(get().f_blue * 255.0)) << 8)};
return true;
} //ValueWrap<API_RGBColor>::write
}
#endif //ARCHICAD
#endif //SPECKLE_SERIALISE_ARCHICAD_RGB
+10 -10
View File
@@ -1,5 +1,5 @@
#ifndef SPECKLE_SERIALISE_LENGTH_UNIT
#define SPECKLE_SERIALISE_LENGTH_UNIT
#ifndef SPECKLE_SERIALISE_STR256
#define SPECKLE_SERIALISE_STR256
#include "Active/Serialise/Item/Wrapper/ValueWrap.h"
#include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h"
@@ -12,10 +12,10 @@ namespace active::serialise {
///NB: This is primarily for Archicad that still uses fixed 256-bytes char array strings in some contexts
using Str256 = std::array<char, str256Size>;
// MARK: - Specialisations for bool
// MARK: - Specialisations for Str256
/*!
Import the object from the specified string (specialisation for bool)
Import the object from the specified string (specialisation for Str256)
@param source The string to read
@return True if the data was successfully read
*/
@@ -23,11 +23,11 @@ namespace active::serialise {
bool ValueWrap<Str256>::read(const utility::String& source) {
source.writeUTF8(active::utility::BufferOut{get()});
return true;
} //ValueWrap<bool>::read
} //ValueWrap<Str256>::read
/*!
Import the object from the specified string (specialisation for bool)
Import the object from the specified string (specialisation for Str256)
@param source The string to read
@return True if the data was successfully read
*/
@@ -36,11 +36,11 @@ namespace active::serialise {
base::get() = Str256{};
source.writeUTF8(active::utility::BufferOut{*base::get()});
return true;
} //ValueWrap<bool>::read
} //ValueWrap<Str256>::read
/*!
Export the object to the specified string (specialisation for bool)
Export the object to the specified string (specialisation for Str256)
@param dest The string to write the data to
@return True if the data was successfully written
*/
@@ -48,8 +48,8 @@ namespace active::serialise {
bool ValueWrap<Str256>::write(utility::String& dest) const {
dest.assign(reinterpret_cast<const char*>(&get()), str256Size);
return true;
} //ValueWrap<bool>::write
} //ValueWrap<Str256>::write
}
#endif //SPECKLE_SERIALISE_LENGTH_UNIT
#endif //SPECKLE_SERIALISE_STR256
@@ -50,6 +50,7 @@
2199881E2BD833830035E5EA /* libArchicad27.a in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21379E082AE47A6400A1584C /* libArchicad27.a */; };
21A0FBA42CB880690023F24E /* FinishCollector.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FB9F2CB880690023F24E /* FinishCollector.h */; };
21A0FBB52CBA5E380023F24E /* Str256.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FBB42CBA5E380023F24E /* Str256.h */; };
21A0FBBC2CBBC04C0023F24E /* ArchicadRGB.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FBB92CBBC04C0023F24E /* ArchicadRGB.h */; };
21AEF9BA2CA606B5000B8681 /* DetachedReference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9B92CA606B4000B8681 /* DetachedReference.cpp */; };
21AEF9BC2CA6DF84000B8681 /* DetachmentManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BB2CA6DF84000B8681 /* DetachmentManager.cpp */; };
21AEF9BE2CA6FDA4000B8681 /* DetachedWrap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BD2CA6FDA4000B8681 /* DetachedWrap.cpp */; };
@@ -191,6 +192,7 @@
21A0FB9F2CB880690023F24E /* FinishCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FinishCollector.h; sourceTree = "<group>"; };
21A0FBA92CB9324A0023F24E /* FinishProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FinishProxy.h; sourceTree = "<group>"; };
21A0FBB42CBA5E380023F24E /* Str256.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Str256.h; sourceTree = "<group>"; };
21A0FBB92CBBC04C0023F24E /* ArchicadRGB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchicadRGB.h; sourceTree = "<group>"; };
21AEF9B32CA5F7CF000B8681 /* DetachedWrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedWrap.h; sourceTree = "<group>"; };
21AEF9B52CA5FA02000B8681 /* DetachedReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedReference.h; sourceTree = "<group>"; };
21AEF9B72CA5FCB6000B8681 /* DetachmentManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachmentManager.h; sourceTree = "<group>"; };
@@ -490,6 +492,7 @@
21A0FBB12CBA5E0E0023F24E /* Types */ = {
isa = PBXGroup;
children = (
21A0FBB92CBBC04C0023F24E /* ArchicadRGB.h */,
21A0FBB42CBA5E380023F24E /* Str256.h */,
2196F2DF2CB0566500450DFC /* Units */,
);
@@ -731,6 +734,7 @@
210CC8802C80CD2A00610F58 /* BridgeChild.h in Headers */,
21D0BD4D2C8901A00077E104 /* ServerInfo.h in Headers */,
2196F3042CB57E8000450DFC /* Storey.h in Headers */,
21A0FBBC2CBBC04C0023F24E /* ArchicadRGB.h in Headers */,
21D0BDB52C8F8AB60077E104 /* DocumentStoreEngine.h in Headers */,
21D0BDC52C9241940077E104 /* ProjectSubscriber.h in Headers */,
2196F2EC2CB4816B00450DFC /* ArchicadAttributeDBaseEngine.h in Headers */,