diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp index 7f2221b..0946417 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp @@ -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(attr.material.transpPc) / 100.0); + roughness = 1.0 - (static_cast(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(std::round(alpha * 255.0)); - uint8_t r = static_cast(std::round(red * 255.0)); - uint8_t g = static_cast(std::round(green * 255.0)); - uint8_t b = static_cast(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(std::round(alpha * 255.0)); - uint8_t r = static_cast(std::round(color.f_red * 255.0)); - uint8_t g = static_cast(std::round(color.f_green * 255.0)); - uint8_t b = static_cast(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>(ARGBToInt(opacity, m_data->root.surfaceRGB)); - } + case diffuseID: +#ifdef ARCHICAD + return std::make_unique>(m_data->root.surfaceRGB); +#endif case opacityID: - return std::make_unique>(1.0); + return std::make_unique(m_data->opacity); case emissiveID: - return std::make_unique>(ARGBToInt(0.0, 0.0, 0.0, 0.0)); +#ifdef ARCHICAD + return std::make_unique>(m_data->root.emissionRGB); +#endif case metalnessID: - return std::make_unique>(1.0); + return std::make_unique(m_data->metalness); case roughnessID: - return std::make_unique>(1.0); + return std::make_unique(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(100 * (1.0 - m_data->opacity)); + m_data->root.shine = static_cast(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 --------------------------------------------------------------------*/ diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.h b/SpeckleLib/Speckle/Record/Attribute/Finish.h index 1c597f7..72fb19d 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.h +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.h @@ -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: /*! diff --git a/SpeckleLib/Speckle/Record/Element/Element.cpp b/SpeckleLib/Speckle/Record/Element/Element.cpp index d5605fd..02fda04 100644 --- a/SpeckleLib/Speckle/Record/Element/Element.cpp +++ b/SpeckleLib/Speckle/Record/Element/Element.cpp @@ -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(std::round(alpha * 255.0)); - uint8_t r = static_cast(std::round(red * 255.0)); - uint8_t g = static_cast(std::round(green * 255.0)); - uint8_t b = static_cast(std::round(blue * 255.0)); - - // Pack ARGB into a single 32-bit integer - return (a << 24) | (r << 16) | (g << 8) | b; - } } /*-------------------------------------------------------------------- diff --git a/SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h b/SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h new file mode 100644 index 0000000..ad076d0 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Types/ArchicadRGB.h @@ -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 + +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 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(*intValue & 0xFF) / 255.0; + *intValue >>= 8; + result.f_green = static_cast(*intValue & 0xFF) / 255.0; + *intValue >>= 8; + result.f_blue = static_cast(*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::read(const utility::String& source) { + if (auto colour = convertToAPI_RGBColor(source); colour) { + get() = *colour; + return true; + } + return false; + } //ValueWrap::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>::read(const utility::String& source) { + if (auto colour = convertToAPI_RGBColor(source); colour) + get() = colour; + return true; + } //ValueWrap::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::write(utility::String& dest) const { + dest = speckle::utility::String{(static_cast(get().f_red * 255.0) << 24) | + ((static_cast(get().f_green * 255.0)) << 16) | + ((static_cast(get().f_blue * 255.0)) << 8)}; + return true; + } //ValueWrap::write + +} + +#endif //ARCHICAD +#endif //SPECKLE_SERIALISE_ARCHICAD_RGB diff --git a/SpeckleLib/Speckle/Serialise/Types/Str256.h b/SpeckleLib/Speckle/Serialise/Types/Str256.h index 13f16b7..76a85c1 100644 --- a/SpeckleLib/Speckle/Serialise/Types/Str256.h +++ b/SpeckleLib/Speckle/Serialise/Types/Str256.h @@ -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; - // 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::read(const utility::String& source) { source.writeUTF8(active::utility::BufferOut{get()}); return true; - } //ValueWrap::read + } //ValueWrap::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::read + } //ValueWrap::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::write(utility::String& dest) const { dest.assign(reinterpret_cast(&get()), str256Size); return true; - } //ValueWrap::write + } //ValueWrap::write } -#endif //SPECKLE_SERIALISE_LENGTH_UNIT +#endif //SPECKLE_SERIALISE_STR256 diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index 18f49e9..0781bc6 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -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 = ""; }; 21A0FBA92CB9324A0023F24E /* FinishProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FinishProxy.h; sourceTree = ""; }; 21A0FBB42CBA5E380023F24E /* Str256.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Str256.h; sourceTree = ""; }; + 21A0FBB92CBBC04C0023F24E /* ArchicadRGB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchicadRGB.h; sourceTree = ""; }; 21AEF9B32CA5F7CF000B8681 /* DetachedWrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedWrap.h; sourceTree = ""; }; 21AEF9B52CA5FA02000B8681 /* DetachedReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedReference.h; sourceTree = ""; }; 21AEF9B72CA5FCB6000B8681 /* DetachmentManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachmentManager.h; sourceTree = ""; }; @@ -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 */,