diff --git a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp index 368c3a9..5ecbc69 100644 --- a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp +++ b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.cpp @@ -10,12 +10,22 @@ #include "Speckle/Database/BIMElementDatabase.h" #include "Speckle/Record/Element/Element.h" +#ifdef ARCHICAD +#include +#endif + using namespace active::serialise; using namespace connector::record; using namespace speckle::database; using namespace speckle::record::attribute; using namespace speckle::utility; +#ifdef ARCHICAD +namespace connector::record { + class ProjectCollection::FinishCache : public std::unordered_map {}; +} +#endif + namespace { ///Serialisation fields @@ -32,6 +42,23 @@ namespace { } +/*-------------------------------------------------------------------- + Constructor + + project: The source project + --------------------------------------------------------------------*/ +ProjectCollection::ProjectCollection(speckle::environment::Project::Shared project) : base{project->getInfo().name, project} { + m_finishes = std::make_unique(); +} //ProjectCollection::ProjectCollection + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +ProjectCollection::~ProjectCollection() { +} //ProjectCollection::~ProjectCollection + + /*-------------------------------------------------------------------- Add an element to the collection hierarchy @@ -90,6 +117,25 @@ bool ProjectCollection::addMaterialProxy(const speckle::database::BIMIndex& mate } //ProjectCollection::addMaterialProxy +#ifdef ARCHICAD +/*-------------------------------------------------------------------- + Add a ModelerAPI material to the collection (NB: These are not persistent so need to be captured by this method) + + material: A material + objectID: The object the material is applied to + + return: True if the material proxy was added (false typically means the record already exists) + --------------------------------------------------------------------*/ +bool ProjectCollection::addMaterialProxy(const ModelerAPI::Material& material, const speckle::database::BIMRecordID& objectID) { + auto finishID = Guid::fromInt(material.GenerateHashValue()); + if (m_finishes->find(finishID) != m_finishes->end()) + return false; + auto finish = std::make_unique(material); + return m_finishes->insert({finishID, std::move(finish)}).second; +} //ProjectCollection::addMaterialProxy +#endif + + /*-------------------------------------------------------------------- Fill an inventory with the package items @@ -126,11 +172,14 @@ Cargo::Unique ProjectCollection::getCargo(const Inventory::Item& item) const { if (item.available < m_finishProxies.size()) { auto iter = m_finishProxies.begin(); std::advance(iter, item.available); - if (auto attribute = m_project->getAttributeDatabase()->getAttribute(iter->first, iter->first.tableID); attribute) { - if (auto finish = dynamic_cast(attribute.get()); finish != nullptr) { - auto proxy = std::make_unique(*finish, iter->second); - return std::make_unique(std::move(proxy)); - } + const Finish* finish = nullptr; + if (auto fin = m_finishes->find(iter->first); fin != m_finishes->end()) + finish = fin->second.get(); + else if (auto attribute = m_project->getAttributeDatabase()->getAttribute(iter->first, iter->first.tableID); attribute) + finish = dynamic_cast(attribute.get()); + if (finish != nullptr) { + auto proxy = std::make_unique(*finish, iter->second); + return std::make_unique(std::move(proxy)); } } break; diff --git a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h index 33b8931..ddf287a 100644 --- a/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h +++ b/SpeckleConnector/Connector/Record/Collection/ProjectCollection.h @@ -2,6 +2,7 @@ #define CONNECTOR_RECORD_ROOT_COLLECTiON #include "Connector/Record/Collection/RecordCollection.h" +#include "Speckle/Serialise/Collection/FinishCollector.h" #include @@ -20,7 +21,7 @@ namespace connector::record { - Other attributes, e.g. materials Add all this supplementary data to the root container as required */ - class ProjectCollection : public RecordCollection { + class ProjectCollection : public RecordCollection, public speckle::serialise::FinishCollector { public: // MARK: - Types @@ -33,7 +34,12 @@ namespace connector::record { Constructor @param project The source project */ - ProjectCollection(speckle::environment::Project::Shared project) : base{project->getInfo().name, project} {} + ProjectCollection(speckle::environment::Project::Shared project); + ProjectCollection(const ProjectCollection&) = delete; + /*! + Destructor + */ + ~ProjectCollection(); using base::base; @@ -59,7 +65,16 @@ namespace connector::record { @param objectID The object the material is applied to @return True if the material proxy was added (false typically means the record already exists) */ - bool addMaterialProxy(const speckle::database::BIMIndex& materialIndex, const speckle::database::BIMRecordID& objectID); + bool addMaterialProxy(const speckle::database::BIMIndex& materialIndex, const speckle::database::BIMRecordID& objectID) override; +#ifdef ARCHICAD + /*! + Add a ModelerAPI material to the collection (NB: These are not persistent so need to be captured by this method) + @param material A material + @param objectID The object the material is applied to + @return True if the material proxy was added (false typically means the record already exists) + */ + bool addMaterialProxy(const ModelerAPI::Material& material, const speckle::database::BIMRecordID& objectID) override; +#endif // MARK: - Serialisation @@ -81,6 +96,11 @@ namespace connector::record { ///Finish proxies accumulated from meshes generated from the collection elements FinishProxies m_finishProxies; +#ifdef ARCHICAD + class FinishCache; + ///Finishes cached from ModelerAPI materials + std::unique_ptr m_finishes; +#endif }; } diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp index 33aad98..3f346fd 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.cpp +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.cpp @@ -1,8 +1,13 @@ #include "Speckle/Record/Attribute/Finish.h" #include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Utility/BufferOut.h" #include "Speckle/Utility/Guid.h" +#ifdef ARCHICAD +#include +#endif + using namespace active::serialise; using namespace speckle::database; using namespace speckle::record::attribute; @@ -37,6 +42,16 @@ namespace { Identity{"surfaceColour"}, }; +#ifdef ARCHICAD + /*! + Copy a ModelerAPI colour to an AC RGB 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 } /*-------------------------------------------------------------------- @@ -65,6 +80,31 @@ Finish::Finish(const database::BIMRecordID& ID) : base{ID, Finish::table} { Finish::Finish(const API_Attribute& attrData, const BIMRecordID& tableID) : base{attrData.header.guid, Finish::table} { m_data = std::make_unique(attrData); } + + +/*-------------------------------------------------------------------- + Constructor + + material: A ModelerAPI material definition + --------------------------------------------------------------------*/ +Finish::Finish(const ModelerAPI::Material& material) { + API_Attribute attr; + active::utility::Memory::erase(attr); + String{material.GetName()}.writeUTF8(active::utility::BufferOut{attr.header.name}); + attr.header.guid = Guid{Guid::fromInt(material.GenerateHashValue())}; + attr.material.mtype = static_cast(material.GetType()); + attr.material.ambientPc = material.GetAmbientReflection(); + attr.material.diffusePc = material.GetDiffuseReflection(); + attr.material.specularPc = material.GetSpecularReflection(); + attr.material.transpPc = material.GetTransparency(); + attr.material.shine = material.GetShining(); + attr.material.transpAtt = material.GetTransparencyAttenuation(); + attr.material.emissionAtt = material.GetEmissionAttenuation(); + copyModelerColor(material.GetSurfaceColor(), attr.material.surfaceRGB); + copyModelerColor(material.GetSpecularColor(), attr.material.specularRGB); + copyModelerColor(material.GetEmissionColor(), attr.material.emissionRGB); + m_data = std::make_unique(attr); +} //Finish::Finish #endif @@ -95,6 +135,7 @@ const API_Attr_Head& Finish::getHead() const { return m_data->root.head; } //Finish::getHead + /*-------------------------------------------------------------------- Get the (mutable) API attribute header data diff --git a/SpeckleLib/Speckle/Record/Attribute/Finish.h b/SpeckleLib/Speckle/Record/Attribute/Finish.h index 36c274b..1c597f7 100644 --- a/SpeckleLib/Speckle/Record/Attribute/Finish.h +++ b/SpeckleLib/Speckle/Record/Attribute/Finish.h @@ -3,6 +3,12 @@ #include "Speckle/Record/Attribute/Attribute.h" +#ifdef ARCHICAD +namespace ModelerAPI { + class Material; +} +#endif + namespace speckle::record::attribute { /*! @@ -50,6 +56,11 @@ namespace speckle::record::attribute { @param tableID The ID of the parent table */ Finish(const API_Attribute& attrData, const database::BIMRecordID& tableID); + /*! + Constructor + @param material A ModelerAPI material definition + */ + Finish(const ModelerAPI::Material& material); #endif /*! Copy constructor diff --git a/SpeckleLib/Speckle/Serialise/Collection/FinishCollector.h b/SpeckleLib/Speckle/Serialise/Collection/FinishCollector.h new file mode 100644 index 0000000..44d5f87 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Collection/FinishCollector.h @@ -0,0 +1,48 @@ +#ifndef SPECKLE_SERIALISE_FINISH_COLLECTOR +#define SPECKLE_SERIALISE_FINISH_COLLECTOR + +#include "Active/Serialise/Management/Manager.h" + +#ifdef ARCHICAD +namespace ModelerAPI { + class Material; +} +#endif + +namespace speckle::serialise { + + /*! + Collector for object finishes + + Used as a serialisation manager to collect finishes from serialised objects + */ + class FinishCollector : public active::serialise::Manager { + public: + /*! + Destructor + */ + virtual ~FinishCollector() {} + + // MARK: - Functions (mutating) + + /*! + Add a material proxy record to the collection + @param materialIndex The index of the material to add + @param objectID The object the material is applied to + @return True if the material proxy was added (false typically means the record already exists) + */ + virtual bool addMaterialProxy(const speckle::database::BIMIndex& materialIndex, const speckle::database::BIMRecordID& objectID) = 0; +#ifdef ARCHICAD + /*! + Add a ModelerAPI material to the collection (NB: These are not persistent so need to be captured by this method) + @param material A material + @param objectID The object the material is applied to + @return True if the material proxy was added (false typically means the record already exists) + */ + virtual bool addMaterialProxy(const ModelerAPI::Material& material, const speckle::database::BIMRecordID& objectID) = 0; +#endif + }; + +} + +#endif //SPECKLE_SERIALISE_FINISH_COLLECTOR diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp b/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp index 140c476..ac692a0 100644 --- a/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp @@ -64,7 +64,7 @@ Cargo::Unique DetachedReference::getCargo(const Inventory::Item& item) const { //If we don't have an allocated string for receiving a reference (from 'setDefault') then we need to create one if (!m_reference) { //Ask a manager to send the detached data and provide a reference - auto detachmentManager = getManager(); + auto detachmentManager = (management() == nullptr) ? nullptr : management()->get(); if (detachmentManager == nullptr) return nullptr; //TODO: Discuss if this is a serious error - possibly throwing an exception is warranted m_reference = detachmentManager->send(std::forward(base::get()), item.identity()); diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h b/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h index 094eda2..99f4119 100644 --- a/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h @@ -1,7 +1,7 @@ #ifndef SPECKLE_SERIALISE_DETACHMENT_MANAGER #define SPECKLE_SERIALISE_DETACHMENT_MANAGER -#include "Active/Serialise/Manager.h" +#include "Active/Serialise/Management/Manager.h" #include "Active/Serialise/Transport.h" #include "Speckle/Database/Identity/RecordID.h" diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index fad870d..6c8998f 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -48,6 +48,7 @@ 2196F3042CB57E8000450DFC /* Storey.h in Headers */ = {isa = PBXBuildFile; fileRef = 2196F3022CB57E7F00450DFC /* Storey.h */; }; 2196F3052CB57E8000450DFC /* Storey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2196F3032CB57E7F00450DFC /* Storey.cpp */; }; 2199881E2BD833830035E5EA /* libArchicad27.a in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21379E082AE47A6400A1584C /* libArchicad27.a */; }; + 21A0FBA42CB880690023F24E /* FinishCollector.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A0FB9F2CB880690023F24E /* FinishCollector.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 */; }; @@ -186,6 +187,7 @@ 2196F3022CB57E7F00450DFC /* Storey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Storey.h; sourceTree = ""; }; 2196F3032CB57E7F00450DFC /* Storey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Storey.cpp; sourceTree = ""; }; 219712682BE7E2D500D9EF7E /* Serialisation.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Serialisation.md; sourceTree = ""; }; + 21A0FB9F2CB880690023F24E /* FinishCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FinishCollector.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 = ""; }; @@ -290,6 +292,7 @@ isa = PBXGroup; children = ( 2167E27C2C49121F000827D3 /* CMakeLists.txt */, + 21A0FBA02CB880690023F24E /* Collection */, 21AEF9C72CA818EA000B8681 /* Detached */, 21F69F3A2C6B880B008B6A06 /* JSBase */, 2196F2DF2CB0566500450DFC /* Units */, @@ -472,6 +475,14 @@ path = SpeckleLibDoctest; sourceTree = ""; }; + 21A0FBA02CB880690023F24E /* Collection */ = { + isa = PBXGroup; + children = ( + 21A0FB9F2CB880690023F24E /* FinishCollector.h */, + ); + path = Collection; + sourceTree = ""; + }; 21AEF9C72CA818EA000B8681 /* Detached */ = { isa = PBXGroup; children = ( @@ -693,6 +704,7 @@ 21D0BD562C890B1C0077E104 /* ServerMigration.h in Headers */, 210CC88F2C81A98500610F58 /* Guid64.h in Headers */, 21AEF9DD2CAAA4EA000B8681 /* DetachedObjectStore.h in Headers */, + 21A0FBA42CB880690023F24E /* FinishCollector.h in Headers */, 215F088D2CA195EC00CD343B /* ArchicadElementDBaseEngine.h in Headers */, 2196F2F42CB483D600450DFC /* Finish.h in Headers */, 21B67D002C7CE15100FD64FC /* Exception.h in Headers */,