Files
UnrealEngine/Engine/Source/Programs/Enterprise/Datasmith/DatasmithARCHICADExporter/Private/SyncData.h
2025-05-18 13:04:45 +08:00

614 lines
16 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Utils/AddonTools.h"
#include "Utils/TimeStat.h"
#include "Light.hpp"
#include "Array.h"
namespace ModelerAPI
{
class Transformation;
}
BEGIN_NAMESPACE_UE_AC
class FElementID;
class FSyncContext;
class FSyncDatabase;
class FSynchronizer;
/* Class that keep synchronization data of Archicad elements.
* Take care of object hierarchy (By synthetizing layer an scene) */
class FSyncData
{
public:
class FScene;
class FActor;
class FLayer;
class FElement;
class FCameraSet;
class FCamera;
class FLight;
class FHotLinksRoot;
class FHotLinkNode;
class FHotLinkInstance;
// Class use for scanning db to find element not yet registered.
class FInterator;
class FProcessMetadata;
class FAttachObservers;
// Constructor
FSyncData(const GS::Guid& InGuid);
// Destructor
virtual ~FSyncData();
// Update data from a 3d element
void Update(const FElementID& IoElementId);
// Return the element index in current 3d context
GS::Int32 GetIndex3D() const { return Index3D; }
// Return true if object have been modified (3d or API)
bool IsModified() const { return bIsModified; }
// Check modification stamp
bool CheckModificationStamp(UInt64 InModificationStamp)
{
if (ModificationStamp != InModificationStamp)
{
ModificationStamp = InModificationStamp;
bIsModified = true;
}
return bIsModified;
}
// Set modification state to true
void MarkAsModified() { bIsModified = true; }
// Before a scan, we presume object as deletable and not modified
void ResetBeforeScan()
{
Index3D = 0;
bIsModified = false;
}
void MarkAsExisting() { Index3D = -1; }
// Recursively clean. Delete element that hasn't 3d geometry related to it
void CleanAfterScan(FSyncDatabase* IOSyncDatabase);
void SetParent(FSyncData* InParent);
void SetIsAComponent(bool bInIsAComponent = true) { bIsAComponent = bInIsAComponent; }
bool HasParent() const { return Parent != nullptr; }
void SetDefaultParent(const FElementID& InElementID);
// Working class that contain data to process elements and it's childs
class FProcessInfo;
// Process (Sync Datasmith element from Archicad element)
virtual void Process(FProcessInfo* IOProcessInfo) = 0;
// Attach observer for Auto Sync
virtual bool AttachObserver(FAttachObservers* /* IOAttachObservers */) { return false; }
// Return true if this element need to update tags and metadata
virtual bool NeedTagsAndMetaDataUpdate() { return false; }
// Process meta data. Return true if meta data was updated
virtual bool ProcessMetaData(FSyncDatabase* /* IOSyncDatabase */) { return false; };
// Delete this sync data
virtual TSharedPtr< IDatasmithElement > GetElement() const = 0;
// Return the Id
const GS::Guid& GetId() const { return ElementId; }
virtual void SetMesh(FSyncDatabase* /* IOSyncDatabase */, const TSharedPtr< IDatasmithMeshElement >& /* InMesh */)
{
}
protected:
// Add a child
virtual void AddChildActor(const TSharedPtr< IDatasmithActorElement >& InActor) = 0;
// Remove a child
virtual void RemoveChildActor(const TSharedPtr< IDatasmithActorElement >& InActor) = 0;
// Set (or replace) datasmith actor element related to this sync data
virtual void SetActorElement(const TSharedPtr< IDatasmithActorElement >& InElement) = 0;
// Return Element as an actor
virtual const TSharedPtr< IDatasmithActorElement >& GetActorElement() const = 0;
// Delete this sync data
virtual void DeleteMe(FSyncDatabase* IOSyncDatabase);
// Add a child to this sync data
void AddChild(FSyncData* InChild);
// Remove a child from this sync data
void RemoveChild(FSyncData* InChild);
// Return true if this element and all it's childs have been cut out
virtual bool CheckAllCutOut();
// Permanent id of the element (Synthethized elements, like layers, have synthetized guid).
GS::Guid ElementId = GS::NULLGuid;
// Temporary 3d index of the element
GS::Int32 Index3D = 0;
// 3d generation id, change when 3d geometry of the object is changed
GS::UInt32 GenId = 0;
// modification stamp
UInt64 ModificationStamp = 0;
// If GenId have changed or object is newly renderered
bool bIsModified = false;
// If this object is a component
bool bIsAComponent = false;
// Parent of this element
FSyncData* Parent = nullptr;
// Childs of this element
typedef TArray< FSyncData* > FChildsArray;
FChildsArray Childs;
};
class FSyncData::FScene : public FSyncData
{
public:
// Guid given to the scene element.
static const GS::Guid SceneGUID;
FScene();
// Delete this sync data
virtual TSharedPtr< IDatasmithElement > GetElement() const override { return SceneElement; };
protected:
// Set the element to the scene element
virtual void Process(FProcessInfo* IOProcessInfo) override;
// Delete this sync data
virtual void DeleteMe(FSyncDatabase* IOSyncDatabase) override;
// Update scene metadata
void UpdateInfo(FProcessInfo* IOProcessInfo);
// Add an child actor to my scene
virtual void AddChildActor(const TSharedPtr< IDatasmithActorElement >& InActor) override;
// Remove an child actor from my scene
virtual void RemoveChildActor(const TSharedPtr< IDatasmithActorElement >& InActor) override;
// Call this a FScene has no meaning... calling it will throw an exception.
virtual void SetActorElement(const TSharedPtr< IDatasmithActorElement >& InActor) override;
// Return an invalid actor shared ptr
virtual const TSharedPtr< IDatasmithActorElement >& GetActorElement() const override;
// The mesh element if this element is a mesh actor
TSharedPtr< IDatasmithScene > SceneElement;
// Empty actor that will contain matedata info on the scene
TSharedPtr< IDatasmithActorElement > SceneInfoActorElement;
// The mesh element if this element is a mesh actor
TSharedPtr< IDatasmithMetaDataElement > SceneInfoMetaData;
};
class FSyncData::FActor : public FSyncData
{
// Delete this sync data
virtual TSharedPtr< IDatasmithElement > GetElement() const override { return ActorElement; };
protected:
FActor(const GS::Guid& InGuid);
// Delete this sync data
virtual void DeleteMe(FSyncDatabase* IOSyncDatabase) override;
// Add an child actor to my element
virtual void AddChildActor(const TSharedPtr< IDatasmithActorElement >& InActor) override;
// Remove an child actor to my element
virtual void RemoveChildActor(const TSharedPtr< IDatasmithActorElement >& InActor) override;
// Set (or replace) datasmith actor element related to this sync data
virtual void SetActorElement(const TSharedPtr< IDatasmithActorElement >& InActor) override;
// Return Element as an actor
virtual const TSharedPtr< IDatasmithActorElement >& GetActorElement() const override { return ActorElement; }
typedef GS::Array< GS::UniString > FTagsArray;
// Update tags data
bool UpdateTags(const FTagsArray& InTags);
void ReplaceMetaData(IDatasmithScene& IOScene, const TSharedPtr< IDatasmithMetaDataElement >& InNewMetaData);
TSharedPtr< IDatasmithActorElement > ActorElement;
// The mesh element if this element is a mesh actor
TSharedPtr< IDatasmithMetaDataElement > MetaData;
};
class FSyncData::FLayer : public FSyncData::FActor
{
public:
// Guid used to synthetize layer guid
static const GS::Guid LayerGUID;
// Return the synthetized layer guid.
static GS::Guid GetLayerGUID(short Layer);
// Return true if this guid is for a layer
static short IsLayerGUID(GS::Guid LayerID);
// Return the layer index
static short GetLayerIndex(const GS::Guid& InLayerID);
FLayer(const GS::Guid& InGuid);
protected:
virtual void Process(FProcessInfo* IOProcessInfo) override;
};
class FSyncData::FElement : public FSyncData::FActor
{
public:
FElement(const GS::Guid& InGuid, const FSyncContext& InSyncContext);
// Mesh has changed, update the actor accordingly
void MeshElementChanged();
// Access to the element mesh handle
TSharedPtr< IDatasmithMeshElement >& GetMeshElementRef() { return MeshElement; }
// Add tags data
bool AddTags(FSyncDatabase* IOSyncDatabase);
protected:
virtual void Process(FProcessInfo* IOProcessInfo) override;
// Delete this sync data
virtual void DeleteMe(FSyncDatabase* IOSyncDatabase) override;
// Attach observer for Auto Sync
virtual bool AttachObserver(FAttachObservers* IOAttachObservers) override;
// Return true if this element need to update tags and metadata
virtual bool NeedTagsAndMetaDataUpdate() override;
// Process meta data. Return true if meta data was updated
virtual bool ProcessMetaData(FSyncDatabase* IOSyncDatabase) override;
virtual void SetMesh(FSyncDatabase* IOSyncDatabase, const TSharedPtr< IDatasmithMeshElement >& InMesh) override;
// Rebuild the meta data of this element
bool UpdateMetaData(IDatasmithScene* InScene);
// Return true if this element and all it's childs have been cut out
bool CheckAllCutOut() override;
// The mesh element if this element is a mesh actor
TSharedPtr< IDatasmithMeshElement > MeshElement;
// True if metadata is updated
bool bMetadataProcessed = false;
// True if we observe this element
bool bIsObserved = false;
// Type of this element
API_ElemTypeID TypeID = API_ZombieElemID;
};
class FSyncData::FCameraSet : public FSyncData::FActor
{
public:
FCameraSet(const GS::Guid& InGuid, const GS::UniString& InName, bool bInOpenedPath)
: FSyncData::FActor(InGuid)
, Name(InName)
, bOpenedPath(bInOpenedPath)
{
}
protected:
virtual void Process(FProcessInfo* IOProcessInfo) override;
const GS::UniString Name;
bool bOpenedPath;
};
class FSyncData::FCamera : public FSyncData::FActor
{
public:
// Guid given to the current view.
static const GS::Guid CurrentViewGUID;
FCamera(const GS::Guid& InGuid, GS::Int32 InIndex)
: FSyncData::FActor(InGuid)
, Index(InIndex)
{
}
protected:
virtual void Process(FProcessInfo* IOProcessInfo) override;
void InitWithCurrentView();
void InitWithCameraElement();
GS::Int32 Index;
};
class FSyncData::FLight : public FSyncData::FActor
{
public:
class FLightGDLParameters
{
public:
FLightGDLParameters();
FLightGDLParameters(const API_Guid& InLightGuid, const class FLibPartInfo* InLibPartInfo);
bool operator!=(const FLightGDLParameters& InOther) const;
enum EC4dDetAreaShape
{
kNoShape = 0,
kDisc,
kRectangle,
kSphere,
kCylinder,
kCube,
kHemisphere,
kLine,
kPerpendicularCylinder
};
ModelerAPI::Color GS_Color;
unsigned char ColorComponentCount = 0;
double Intensity = 1.0;
bool bUsePhotometric = false;
EDatasmithLightUnits Units = EDatasmithLightUnits::Unitless;
double DetRadius = 0.0; // Meter
GS::UniString IESFileName;
bool bIsAreaLight = false;
EC4dDetAreaShape AreaShape = kNoShape;
Geometry::Vector3D AreaSize = {};
double WindowLightAngle = 0.0;
double SunAzimuthAngle = 0.0;
double SunAltitudeAngle = 0.0;
bool bIsParallelLight = false;
bool bGenShadow = false;
};
class FLightData
{
public:
FLightData();
FLightData(const ModelerAPI::Light& InLight);
bool operator!=(const FLightData& InOther) const;
ModelerAPI::Light::Type LightType = ModelerAPI::Light::Type::UndefinedLight;
float InnerConeAngle = 15.0;
float OuterConeAngle = 75.0;
FLinearColor Color = FLinearColor::White;
FVector Position = FVector::ZeroVector;
FQuat Rotation = FQuat::Identity;
};
FLight(const GS::Guid& InGuid, GS::Int32 InIndex)
: FSyncData::FActor(InGuid)
, Index(InIndex)
{
}
void SetLightData(const FLightData& InLightData)
{
if (LightData != InLightData)
{
LightData = InLightData;
bIsModified = true;
}
}
void SetValuesFromParameters(const FLightGDLParameters& InParameters)
{
if (Parameters != InParameters)
{
Parameters = InParameters;
bIsModified = true;
}
}
protected:
virtual void Process(FProcessInfo* IOProcessInfo) override;
GS::Int32 Index;
FLightGDLParameters Parameters;
FLightData LightData;
};
class FSyncData::FHotLinksRoot : public FSyncData::FActor
{
public:
// Guid given to the current view.
static const GS::Guid HotLinksRootGUID;
FHotLinksRoot()
: FSyncData::FActor(HotLinksRootGUID)
{
}
protected:
virtual void Process(FProcessInfo* IOProcessInfo) override;
};
class FSyncData::FHotLinkNode : public FSyncData::FActor
{
public:
FHotLinkNode(const GS::Guid& InGuid)
: FSyncData::FActor(InGuid)
{
}
protected:
virtual void Process(FProcessInfo* IOProcessInfo) override;
};
class FSyncData::FHotLinkInstance : public FSyncData::FActor
{
public:
FHotLinkInstance(const GS::Guid& InGuid, FSyncDatabase* IOSyncDatabase);
const API_Tranmat& GetTransformation() { return Transformation; }
protected:
virtual void Process(FProcessInfo* IOProcessInfo) override;
API_Tranmat Transformation;
};
class FSyncData::FInterator
{
public:
// Destructor
virtual ~FInterator() {}
// Start the process with this root observer
void Start(FSyncData* Root);
// Stop processing
void Stop();
// Return true if we need to process
bool NeedProcess() const { return Stack.Num() != 0; }
// Process attachment until done or until time slice finish
enum EProcessControl
{
kDone, // Task is terminated
kInterrupted, // Task is interrupted -> need restart to resume
kContinue // Time slice end, wait for another idle
};
EProcessControl ProcessUntil(double TimeSliceEnd);
EProcessControl ProcessAll() { return ProcessUntil(std::numeric_limits< double >::max()); }
virtual EProcessControl Process(FSyncData* InCurrent) = 0;
// Return the next FSyncData
FSyncData* Next();
// Return the index of the current.
FChildsArray::SizeType GetCurrentIndex();
// Return the current count of item processed
int32 GetProcessedCount() const { return ProcessedCount; }
// Return the cumulated process time
double GetProcessedTime() const { return ProcessTime; }
private:
// Stack element
class FEntry
{
public:
FSyncData* Parent;
FChildsArray::SizeType ChildIndex;
};
typedef TArray< FEntry > FEntriesArray;
FEntriesArray Stack;
int32 ProcessedCount = 0;
double ProcessTime = 0.0;
};
// Class to process metadata as idle task (Only for Direct Link synchronization)
class FSyncData::FProcessMetadata : public FSyncData::FInterator
{
public:
// Constructor
FProcessMetadata(FSynchronizer* InSynchronizer)
: Synchronizer(InSynchronizer)
{
}
// Start the process with this root observer
void Start(FSyncData* Root);
// Call ProcessMetaData for the sync data
virtual EProcessControl Process(FSyncData* InCurrent) override;
// Return true if at least one sync data updated it's meta data
bool HasMetadataUpdated() const { return bMetadataUpdated; }
// Tell that we already synced previously processed sync data
void CleardMetadataUpdated() { bMetadataUpdated = false; }
// Count of processed
int GetProcessedCount() const { return MetadataProcessedCount; }
private:
// My synchronizer
FSynchronizer* Synchronizer = nullptr;
// Count of processed
int MetadataProcessedCount = 0;
// True if at least one sync data updated it's meta data
bool bMetadataUpdated = false;
};
#define ATTACH_ONSERVER_STAT 1
// Class use for scanning db to find element not yet registered.
class FSyncData::FAttachObservers : public FSyncData::FInterator
{
public:
// Constructor
FAttachObservers();
// Start the process with this root observer
void Start(FSyncData* Root);
// Call AttachObserver for the sync data
virtual EProcessControl Process(FSyncData* InCurrent) override;
// Process attachment until done or until time slice finish
bool ProcessAttachUntil(double TimeSliceEnd);
#if ATTACH_ONSERVER_STAT
void CumulateStats(const FTimeStat& SlotStart, double AfterAttachObserver);
// Log attach observer statistics
void PrintStat();
#endif
private:
#if ATTACH_ONSERVER_STAT
FTimeStat AttachObserverProcessTimeStart;
FTimeStat AttachObserverProcessTimeEnd;
double AttachObserverStartTime = 0.0;
double AttachObserverTime = 0.0;
double GetHeaderTime = 0.0;
int AttachCount = 0;
#endif
};
END_NAMESPACE_UE_AC