312 lines
10 KiB
C++
312 lines
10 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "ElementID.h"
|
|
|
|
#include "GSProcessControl.hpp"
|
|
#include "Transformation.hpp"
|
|
|
|
#include <stdexcept>
|
|
|
|
BEGIN_NAMESPACE_UE_AC
|
|
|
|
template <>
|
|
FAssValueName::SAssValueName TAssEnumName< ModelerAPI::Element::Type >::AssEnumName[] = {
|
|
EnumName(ModelerAPI::Element, UndefinedElement),
|
|
EnumName(ModelerAPI::Element, WallElement),
|
|
EnumName(ModelerAPI::Element, SlabElement),
|
|
EnumName(ModelerAPI::Element, RoofElement),
|
|
EnumName(ModelerAPI::Element, CurtainWallElement),
|
|
EnumName(ModelerAPI::Element, CWFrameElement),
|
|
EnumName(ModelerAPI::Element, CWPanelElement),
|
|
EnumName(ModelerAPI::Element, CWJunctionElement),
|
|
EnumName(ModelerAPI::Element, CWAccessoryElement),
|
|
EnumName(ModelerAPI::Element, CWSegmentElement),
|
|
EnumName(ModelerAPI::Element, ShellElement),
|
|
EnumName(ModelerAPI::Element, SkylightElement),
|
|
EnumName(ModelerAPI::Element, FreeshapeElement),
|
|
EnumName(ModelerAPI::Element, DoorElement),
|
|
EnumName(ModelerAPI::Element, WindowElement),
|
|
EnumName(ModelerAPI::Element, ObjectElement),
|
|
EnumName(ModelerAPI::Element, LightElement),
|
|
EnumName(ModelerAPI::Element, ColumnElement),
|
|
EnumName(ModelerAPI::Element, MeshElement),
|
|
EnumName(ModelerAPI::Element, BeamElement),
|
|
EnumName(ModelerAPI::Element, RoomElement),
|
|
#if AC_VERSION >= 21
|
|
EnumName(ModelerAPI::Element, StairElement),
|
|
EnumName(ModelerAPI::Element, RiserElement),
|
|
EnumName(ModelerAPI::Element, TreadElement),
|
|
EnumName(ModelerAPI::Element, StairStructureElement),
|
|
EnumName(ModelerAPI::Element, RailingElement),
|
|
EnumName(ModelerAPI::Element, ToprailElement),
|
|
EnumName(ModelerAPI::Element, HandrailElement),
|
|
EnumName(ModelerAPI::Element, RailElement),
|
|
EnumName(ModelerAPI::Element, RailingPostElement),
|
|
EnumName(ModelerAPI::Element, InnerPostElement),
|
|
EnumName(ModelerAPI::Element, BalusterElement),
|
|
EnumName(ModelerAPI::Element, RailingPanelElement),
|
|
EnumName(ModelerAPI::Element, RailingSegmentElement),
|
|
EnumName(ModelerAPI::Element, RailingNodeElement),
|
|
EnumName(ModelerAPI::Element, RailPatternElement),
|
|
EnumName(ModelerAPI::Element, InnerTopRailEndElement),
|
|
EnumName(ModelerAPI::Element, InnerHandRailEndElement),
|
|
EnumName(ModelerAPI::Element, RailFinishingObjectElement),
|
|
EnumName(ModelerAPI::Element, TopRailConnectionElement),
|
|
EnumName(ModelerAPI::Element, HandRailConnectionElement),
|
|
EnumName(ModelerAPI::Element, RailConnectionElement),
|
|
EnumName(ModelerAPI::Element, RailEndElement),
|
|
EnumName(ModelerAPI::Element, BalusterSetElement),
|
|
#endif
|
|
#if AC_VERSION >= 23
|
|
|
|
#if AC_VERSION < 28
|
|
EnumName(ModelerAPI::Element, AnalyticalSupportElement),
|
|
EnumName(ModelerAPI::Element, AnalyticalLinkElement),
|
|
#endif
|
|
|
|
EnumName(ModelerAPI::Element, Opening),
|
|
EnumName(ModelerAPI::Element, Openingframeinfill),
|
|
EnumName(ModelerAPI::Element, Openingpatchinfill),
|
|
EnumName(ModelerAPI::Element, ColumnSegmentElement),
|
|
EnumName(ModelerAPI::Element, BeamSegmentElement),
|
|
#endif
|
|
EnumName(ModelerAPI::Element, OtherElement),
|
|
EnumEnd(-1)};
|
|
|
|
// Contructor
|
|
FElementID::FElementID(const FSyncContext& InSyncContext)
|
|
: SyncContext(InSyncContext)
|
|
, Index3D(0)
|
|
, SyncData(nullptr)
|
|
, MeshClass(nullptr)
|
|
, LibPartInfo(nullptr)
|
|
, bLibPartInfoFetched(false)
|
|
{
|
|
}
|
|
|
|
// Initialize with 3D element
|
|
void FElementID::InitElement(GS::Int32 InIndex3d)
|
|
{
|
|
Index3D = InIndex3d;
|
|
SyncContext.GetModel().GetElement(Index3D, &Element3D);
|
|
APIElementHeader.guid = APINULLGuid;
|
|
MeshClass = nullptr;
|
|
LibPartInfo = nullptr;
|
|
bLibPartInfoFetched = false;
|
|
ElementName.clear();
|
|
}
|
|
|
|
// Initialize with sync data
|
|
void FElementID::InitElement(FSyncData* IOSyncdata)
|
|
{
|
|
UE_AC_TestPtr(IOSyncdata);
|
|
SyncData = IOSyncdata;
|
|
Index3D = IOSyncdata->GetIndex3D();
|
|
if (Index3D > 0)
|
|
{
|
|
GS::Int32 ElementCount = SyncContext.GetModel().GetElementCount();
|
|
if (ensureMsgf(ElementCount >= Index3D, TEXT("Element index became outside of elements range of the model")))
|
|
{
|
|
SyncContext.GetModel().GetElement(Index3D, &Element3D);
|
|
}
|
|
}
|
|
MeshClass = nullptr;
|
|
LibPartInfo = nullptr;
|
|
bLibPartInfoFetched = false;
|
|
}
|
|
|
|
// Initialize element header from 3D element
|
|
bool FElementID::InitHeader()
|
|
{
|
|
if (IsInvalid())
|
|
{
|
|
throw std::runtime_error(
|
|
Utf8StringFormat("FElementID::InitHeader - Invalid element for index=%d\n", Index3D).c_str());
|
|
}
|
|
Zap(&APIElementHeader);
|
|
APIElementHeader.guid = GSGuid2APIGuid(Element3D.GetElemGuid());
|
|
GSErrCode GSErr = ACAPI_Element_GetHeader(&APIElementHeader, 0);
|
|
if (GSErr != NoError)
|
|
{
|
|
utf8_string ErrorName(GetErrorName(GSErr));
|
|
utf8_string TypeName(GetTypeName());
|
|
UE_AC_DebugF("Error \"%s\" with element %d {%s} Type=%s\n", ErrorName.c_str(), Index3D,
|
|
Element3D.GetElemGuid().ToUniString().ToUtf8(), TypeName.c_str());
|
|
if (GSErr != APIERR_BADID)
|
|
{
|
|
UE_AC::ThrowGSError(GSErr, __FILE__, __LINE__);
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
FMeshClass* FElementID::GetMeshClass()
|
|
{
|
|
if (MeshClass == nullptr && Index3D != 0)
|
|
{
|
|
ModelerAPI::BaseElemId BaseElemId;
|
|
GS::NonInterruptibleProcessControl processControl;
|
|
Element3D.GetBaseElemId(&BaseElemId, processControl, ModelerAPI::Element::EdgeColorInBaseElemId::NotIncluded,
|
|
ModelerAPI::Element::PolygonAndFaceTextureMappingInBaseElemId::NotIncluded,
|
|
ModelerAPI::Element::BodyTextureMappingInBaseElemId::NotIncluded,
|
|
ModelerAPI::Element::EliminationInfoInBaseElemId::NotIncluded);
|
|
#if AC_VERSION < 24
|
|
GS::HashValue OldHashValue = BaseElemId;
|
|
GS::ULong HashValue = OldHashValue.hashValue;
|
|
#else
|
|
GS::ULong HashValue = BaseElemId.GenerateHashValue();
|
|
#endif
|
|
MeshClass = SyncContext.GetSyncDatabase().GetMeshClass(HashValue);
|
|
bool bTransformed = (Element3D.GetElemLocalToWorldTransformation().status & TR_IDENT) != 0;
|
|
if (MeshClass == nullptr)
|
|
{
|
|
TUniquePtr< FMeshClass > NewInstance = MakeUnique< FMeshClass >();
|
|
MeshClass = NewInstance.Get();
|
|
MeshClass->Hash = HashValue;
|
|
MeshClass->ElementType = Element3D.GetType();
|
|
MeshClass->TransformCount = bTransformed ? 0 : 1;
|
|
SyncContext.GetSyncDatabase().AddInstance(HashValue, std::move(NewInstance));
|
|
|
|
UE_AC_VerboseF("FElementID::GetMeshClass - First instance %u {%s}\n", MeshClass->Hash,
|
|
APIGuidToString(APIElementHeader.guid).ToUtf8());
|
|
}
|
|
else
|
|
{
|
|
if (MeshClass->ElementType != Element3D.GetType())
|
|
{
|
|
if (MeshClass->ElementType == ModelerAPI::Element::Type::UndefinedElement)
|
|
{
|
|
MeshClass->ElementType = Element3D.GetType();
|
|
}
|
|
else
|
|
{
|
|
UE_AC_DebugF("FElementID::GetMeshClass - MeshClass Hash %u collision Type %s != %s\n",
|
|
MeshClass->Hash, GetTypeName(MeshClass->ElementType), GetTypeName());
|
|
MeshClass->ElementType = Element3D.GetType();
|
|
MeshClass->MeshElement.Reset();
|
|
MeshClass->bMeshElementInitialized = false;
|
|
}
|
|
}
|
|
++MeshClass->InstancesCount;
|
|
MeshClass->TransformCount += bTransformed ? 0 : 1;
|
|
UE_AC_VerboseF("FElementID::GetMeshClass - Reuse MeshClass %u {%s}\n", MeshClass->Hash,
|
|
APIGuidToString(APIElementHeader.guid).ToUtf8());
|
|
}
|
|
}
|
|
return MeshClass;
|
|
}
|
|
|
|
// If this element is related to a lib part ?
|
|
const FLibPartInfo* FElementID::GetLibPartInfo()
|
|
{
|
|
if (bLibPartInfoFetched == false)
|
|
{
|
|
// Get the lib part from it's UnId
|
|
FGSUnID::Buffer lpfUnID = {0};
|
|
GSErrCode GSErr = ACAPI_Goodies(APIAny_GetElemLibPartUnIdID, &APIElementHeader, lpfUnID);
|
|
if (GSErr == NoError)
|
|
{
|
|
LibPartInfo = SyncContext.GetSyncDatabase().GetLibPartInfo(lpfUnID);
|
|
}
|
|
else if (GSErr != APIERR_BADID)
|
|
{
|
|
UE_AC_DebugF("FElementID::InitLibPartInfo - APIAny_GetElemLibPartUnIdID return error %s\n",
|
|
GetErrorName(GSErr));
|
|
}
|
|
bLibPartInfoFetched = true;
|
|
}
|
|
|
|
return LibPartInfo;
|
|
}
|
|
|
|
// Get the name of the element (For debugging trace)
|
|
const utf8_t* FElementID::GetElementName()
|
|
{
|
|
if (ElementName.size() == 0)
|
|
{
|
|
GS::UniString InfoStringID;
|
|
GSErrCode GSErr = ACAPI_Database(APIDb_GetElementInfoStringID, (void*)&APIElementHeader.guid, &InfoStringID);
|
|
if (GSErr == NoError)
|
|
{
|
|
ElementName =
|
|
Utf8StringFormat("{%s}:\"%s\"", APIGuidToString(APIElementHeader.guid).ToUtf8(), InfoStringID.ToUtf8());
|
|
}
|
|
else
|
|
{
|
|
ElementName =
|
|
Utf8StringFormat("{%s}:Error=%s", APIGuidToString(APIElementHeader.guid).ToUtf8(), GetErrorName(GSErr));
|
|
}
|
|
}
|
|
return ElementName.c_str();
|
|
}
|
|
|
|
// Connect childs of this parent
|
|
void FElementID::CollectDependantElementsType(API_ElemTypeID TypeID) const
|
|
{
|
|
GS::Array< API_Guid > ConnectedElements;
|
|
UE_AC_TestGSError(ACAPI_Element_GetConnectedElements(APIElementHeader.guid, TypeID, &ConnectedElements));
|
|
for (USize i = 0; i < ConnectedElements.GetSize(); ++i)
|
|
{
|
|
FSyncData*& ChildSyncData = SyncContext.GetSyncDatabase().GetSyncData(APIGuid2GSGuid(ConnectedElements[i]));
|
|
if (ChildSyncData == nullptr)
|
|
{
|
|
ChildSyncData = new FSyncData::FElement(APIGuid2GSGuid(ConnectedElements[i]), SyncContext);
|
|
}
|
|
ChildSyncData->SetParent(SyncData);
|
|
UE_AC_VerboseF("FElementID::ConnectedElements %u %s -> %s\n", i, APIGuidToString(ConnectedElements[i]).ToUtf8(),
|
|
SyncData->GetId().ToUniString().ToUtf8());
|
|
}
|
|
}
|
|
|
|
// Connect to parent or childs
|
|
void FElementID::HandleDepedencies() const
|
|
{
|
|
if (GET_HEADER_TYPEID(APIElementHeader) == API_WallID)
|
|
{
|
|
CollectDependantElementsType(API_WindowID);
|
|
CollectDependantElementsType(API_DoorID);
|
|
}
|
|
else if (GET_HEADER_TYPEID(APIElementHeader) == API_RoofID || GET_HEADER_TYPEID(APIElementHeader) == API_ShellID)
|
|
{
|
|
CollectDependantElementsType(API_SkylightID);
|
|
}
|
|
else if (GET_HEADER_TYPEID(APIElementHeader) == API_WindowID || GET_HEADER_TYPEID(APIElementHeader) == API_DoorID ||
|
|
GET_HEADER_TYPEID(APIElementHeader) == API_SkylightID)
|
|
{
|
|
// Do nothing
|
|
}
|
|
else
|
|
{
|
|
GS::Guid OwnerElemGuid = APIGuid2GSGuid(APIElementHeader.guid);
|
|
API_Guid OwnerElemApiGuid = APIElementHeader.guid;
|
|
API_HierarchicalElemType HierarchicalElemType = API_SingleElem;
|
|
API_HierarchicalOwnerType HierarchicalOwnerType = API_RootHierarchicalOwner;
|
|
GSErrCode GSErr = ACAPI_Goodies(APIAny_GetHierarchicalElementOwnerID, &OwnerElemGuid, &HierarchicalOwnerType,
|
|
&HierarchicalElemType, &OwnerElemApiGuid);
|
|
if (GSErr != NoError || OwnerElemApiGuid == APINULLGuid)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (HierarchicalElemType == API_ChildElemInMultipleElem)
|
|
{
|
|
FSyncData*& Parent = SyncContext.GetSyncDatabase().GetSyncData(APIGuid2GSGuid(OwnerElemApiGuid));
|
|
if (Parent == nullptr)
|
|
{
|
|
Parent = new FSyncData::FElement(APIGuid2GSGuid(OwnerElemApiGuid), SyncContext);
|
|
}
|
|
SyncData->SetParent(Parent);
|
|
SyncData->SetIsAComponent();
|
|
Parent->SetDefaultParent(*this);
|
|
UE_AC_VerboseF("FElementID::MakeConnections Child %s -> Parent %s\n",
|
|
SyncData->GetId().ToUniString().ToUtf8(), APIGuidToString(OwnerElemApiGuid).ToUtf8());
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
END_NAMESPACE_UE_AC
|