368 lines
14 KiB
C++
368 lines
14 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "DatasmithSketchUpMetadata.h"
|
|
|
|
#include "DatasmithSketchUpString.h"
|
|
#include "DatasmithSketchUpSummary.h"
|
|
|
|
// SketchUp SDK.
|
|
#include "DatasmithSketchUpSDKBegins.h"
|
|
#include "SketchUpAPI/model/attribute_dictionary.h"
|
|
#include "SketchUpAPI/model/classification_attribute.h"
|
|
#include "SketchUpAPI/model/classification_info.h"
|
|
#include "SketchUpAPI/model/component_definition.h"
|
|
#include "SketchUpAPI/model/component_instance.h"
|
|
#include "SketchUpAPI/model/entity.h"
|
|
#include "SketchUpAPI/model/model.h"
|
|
#include "DatasmithSketchUpSDKCeases.h"
|
|
|
|
// Datasmith SDK.
|
|
#include "Containers/Array.h"
|
|
#include "DatasmithSceneFactory.h"
|
|
|
|
using namespace DatasmithSketchUp;
|
|
|
|
|
|
TSet<FString> const FMetadata::InterestingAttributeDictionarySet =
|
|
{
|
|
FString(TEXT("SU_DefinitionSet")),
|
|
FString(TEXT("SU_InstanceSet"))
|
|
};
|
|
|
|
FMetadata::FMetadata(
|
|
SUModelRef InSModelRef
|
|
) :
|
|
SketchupSourceID(MODEL_METADATA_ID)
|
|
{
|
|
// Get the number of attribute dictionaries in the SketchUp model.
|
|
size_t SAttributeDictionaryCount = 0;
|
|
SUModelGetNumAttributeDictionaries(InSModelRef, &SAttributeDictionaryCount); // we can ignore the returned SU_RESULT
|
|
|
|
if (SAttributeDictionaryCount > 0)
|
|
{
|
|
// Retrieve the attribute dictionaries in the SketchUp model.
|
|
TArray<SUAttributeDictionaryRef> SAttributeDictionaries;
|
|
SAttributeDictionaries.Init(SU_INVALID, SAttributeDictionaryCount);
|
|
SUModelGetAttributeDictionaries(InSModelRef, SAttributeDictionaryCount, SAttributeDictionaries.GetData(), &SAttributeDictionaryCount); // we can ignore the returned SU_RESULT
|
|
SAttributeDictionaries.SetNum(SAttributeDictionaryCount);
|
|
|
|
// Retrieve the key-value pairs of the SketchUp attribute dictionaries.
|
|
for (SUAttributeDictionaryRef SAttributeDictionaryRef : SAttributeDictionaries)
|
|
{
|
|
ScanAttributeDictionary(SAttributeDictionaryRef);
|
|
}
|
|
}
|
|
}
|
|
|
|
FMetadata::FMetadata(
|
|
SUEntityRef InSEntityRef
|
|
)
|
|
{
|
|
// Get the SketckUp metadata ID.
|
|
SUEntityGetID(InSEntityRef, &SketchupSourceID); // we can ignore the returned SU_RESULT
|
|
|
|
// Get the number of attribute dictionaries in the SketchUp entity.
|
|
size_t SAttributeDictionaryCount = 0;
|
|
SUEntityGetNumAttributeDictionaries(InSEntityRef, &SAttributeDictionaryCount); // we can ignore the returned SU_RESULT
|
|
|
|
if (SAttributeDictionaryCount > 0)
|
|
{
|
|
// Retrieve the attribute dictionaries in the SketchUp entity.
|
|
TArray<SUAttributeDictionaryRef> SAttributeDictionaries;
|
|
SAttributeDictionaries.Init(SU_INVALID, SAttributeDictionaryCount);
|
|
SUEntityGetAttributeDictionaries(InSEntityRef, SAttributeDictionaryCount, SAttributeDictionaries.GetData(), &SAttributeDictionaryCount); // we can ignore the returned SU_RESULT
|
|
SAttributeDictionaries.SetNum(SAttributeDictionaryCount);
|
|
|
|
// Retrieve the key-value pairs of the SketchUp attribute dictionaries.
|
|
for (SUAttributeDictionaryRef SAttributeDictionaryRef : SAttributeDictionaries)
|
|
{
|
|
ScanAttributeDictionary(SAttributeDictionaryRef);
|
|
}
|
|
}
|
|
|
|
if (SUEntityGetType(InSEntityRef) == SURefType::SURefType_ComponentInstance)
|
|
{
|
|
// Retrieve the classification info from the SketckUp component instance.
|
|
SUClassificationInfoRef SClassificationInfoRef = SU_INVALID;
|
|
SUResult SResult = SUComponentInstanceCreateClassificationInfo(SUComponentInstanceFromEntity(InSEntityRef), &SClassificationInfoRef);
|
|
// Make sure the SketckUp component instance is classified (no SU_ERROR_NO_DATA).
|
|
if (SResult == SU_ERROR_NONE)
|
|
{
|
|
// Get the number of schemas in the SketchUp classification info.
|
|
size_t SSchemaCount = 0;
|
|
SUClassificationInfoGetNumSchemas(SClassificationInfoRef, &SSchemaCount);
|
|
|
|
TArray<FString> ClassificationSchemaTypes;
|
|
ClassificationSchemaTypes.Reserve(SSchemaCount);
|
|
|
|
for (int32 SSchemaNo = 0; SSchemaNo < SSchemaCount; SSchemaNo++)
|
|
{
|
|
SUStringRef ShemaTypeStringRef = SU_INVALID;
|
|
SUStringCreate(&ShemaTypeStringRef);
|
|
SUClassificationInfoGetSchemaType(SClassificationInfoRef, SSchemaNo, &ShemaTypeStringRef);
|
|
FString SchemaType = SuConvertString(ShemaTypeStringRef);
|
|
SUStringRelease(&ShemaTypeStringRef);
|
|
ClassificationSchemaTypes.Add(SchemaType);
|
|
|
|
|
|
// Retrieve the SketchUp classification schema attribute.
|
|
SUClassificationAttributeRef SSchemaAttributeRef = SU_INVALID;
|
|
SUClassificationInfoGetSchemaAttribute(SClassificationInfoRef, SSchemaNo, &SSchemaAttributeRef); // we can ignore the returned SU_RESULT
|
|
|
|
// Retrieve the key-value pairs of the SketchUp classification schema.
|
|
ScanClassificationSchema(SSchemaAttributeRef);
|
|
}
|
|
|
|
if (SSchemaCount > 0)
|
|
{
|
|
MetadataKeyValueMap.Add(TEXT("ClassificationSchemaTypes"), FString::Join(ClassificationSchemaTypes, TEXT(",")));
|
|
}
|
|
|
|
// Release the SketchUp component classification info.
|
|
SUClassificationInfoRelease(&SClassificationInfoRef); // we can ignore the returned SU_RESULT
|
|
}
|
|
}
|
|
}
|
|
|
|
void FMetadata::ScanAttributeDictionary(
|
|
SUAttributeDictionaryRef InSAttributeDictionaryRef
|
|
)
|
|
{
|
|
// Retrieve the SketchUp attribute dictionary name.
|
|
FString SAttributeDictionaryName;
|
|
SAttributeDictionaryName = SuGetString(SUAttributeDictionaryGetName, InSAttributeDictionaryRef);
|
|
|
|
// Skip uninteresting SketchUp attribute dictionaries.
|
|
if (SAttributeDictionaryName.IsEmpty() || !InterestingAttributeDictionarySet.Contains(SAttributeDictionaryName))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Get the number of keys in the SketchUp attribute dictionary.
|
|
size_t SAttributeKeyCount = 0;
|
|
SUAttributeDictionaryGetNumKeys(InSAttributeDictionaryRef, &SAttributeKeyCount); // we can ignore the returned SU_RESULT
|
|
|
|
if (SAttributeKeyCount > 0)
|
|
{
|
|
// Retrieve the keys in the SketchUp attribute dictionary.
|
|
TArray<SUStringRef> SAttributeKeys;
|
|
SAttributeKeys.Init(SU_INVALID, SAttributeKeyCount);
|
|
for (int32 SAttributeKeNo = 0; SAttributeKeNo < SAttributeKeyCount; SAttributeKeNo++)
|
|
{
|
|
SUStringCreate(&SAttributeKeys[SAttributeKeNo]); // we can ignore the returned SU_RESULT
|
|
}
|
|
SUAttributeDictionaryGetKeys(InSAttributeDictionaryRef, SAttributeKeyCount, SAttributeKeys.GetData(), &SAttributeKeyCount); // we can ignore the returned SU_RESULT
|
|
SAttributeKeys.SetNum(SAttributeKeyCount);
|
|
|
|
for (SUStringRef SAttributeKeyRef : SAttributeKeys)
|
|
{
|
|
FString SAttributeKey = SuConvertString(SAttributeKeyRef);
|
|
|
|
// Retrieve the value associated with the key from the SketchUp attribute dictionary.
|
|
SUTypedValueRef STypedValueRef = SU_INVALID;
|
|
SUTypedValueCreate(&STypedValueRef); // we can ignore the returned SU_RESULT
|
|
SUResult SResult = SUAttributeDictionaryGetValue(InSAttributeDictionaryRef, TCHAR_TO_UTF8(*SAttributeKey), &STypedValueRef);
|
|
// Make sure there is a value associated with the given key (no SU_ERROR_NO_DATA).
|
|
if (SResult == SU_ERROR_NONE)
|
|
{
|
|
FString SAttributeValue = GetAttributeValue(STypedValueRef);
|
|
|
|
if (!SAttributeValue.IsEmpty())
|
|
{
|
|
// Add the SketchUp attribute key-value pair to our metadata dictionary.
|
|
MetadataKeyValueMap.Add(FString::Printf(TEXT("%ls:%ls"), *SAttributeDictionaryName, *SAttributeKey), SAttributeValue);
|
|
}
|
|
}
|
|
|
|
// Release the SketchUp attribute key and value.
|
|
SUStringRelease(&SAttributeKeyRef); // we can ignore the returned SU_RESULT
|
|
SUTypedValueRelease(&STypedValueRef); // we can ignore the returned SU_RESULT
|
|
}
|
|
}
|
|
}
|
|
|
|
void FMetadata::ScanClassificationSchema(
|
|
SUClassificationAttributeRef InSSchemaAttributeRef
|
|
)
|
|
{
|
|
// Retrieve the SketchUp schema attribute path (the attribute name as it should be displayed to the user).
|
|
FString SAttributePath = SuGetString(SUClassificationAttributeGetPath, InSSchemaAttributeRef);
|
|
|
|
// Retrieve the SketchUp schema attribute value.
|
|
SUTypedValueRef STypedValueRef = SU_INVALID;
|
|
SUTypedValueCreate(&STypedValueRef); // we can ignore the returned SU_RESULT
|
|
SUClassificationAttributeGetValue(InSSchemaAttributeRef, &STypedValueRef); // we can ignore the returned SU_RESULT
|
|
|
|
FString SAttributeValue = GetAttributeValue(STypedValueRef);
|
|
|
|
if (!SAttributeValue.IsEmpty())
|
|
{
|
|
// Add the SketchUp attribute key-value pair to our metadata dictionary.
|
|
MetadataKeyValueMap.Add(SAttributePath, SAttributeValue);
|
|
}
|
|
|
|
SUTypedValueRelease(&STypedValueRef); // we can ignore the returned SU_RESULT
|
|
|
|
// Get the number of sub-attributes in the SketchUp schema attribute.
|
|
size_t SSubAttributeCount = 0;
|
|
SUClassificationAttributeGetNumChildren(InSSchemaAttributeRef, &SSubAttributeCount); // we can ignore the returned SU_RESULT
|
|
|
|
for (int32 SSubAttributeNo = 0; SSubAttributeNo < SSubAttributeCount; SSubAttributeNo++)
|
|
{
|
|
// Retrieve the sub-attribute in the SketchUp schema attribute.
|
|
SUClassificationAttributeRef SSubAttributeRef = SU_INVALID;
|
|
SUClassificationAttributeGetChild(InSSchemaAttributeRef, SSubAttributeNo, &SSubAttributeRef); // we can ignore the returned SU_RESULT
|
|
|
|
// Retrieve the key-value pairs of the SketchUp schema sub-attribute.
|
|
ScanClassificationSchema(SSubAttributeRef);
|
|
}
|
|
}
|
|
|
|
FString FMetadata::GetAttributeValue(
|
|
SUTypedValueRef InSTypedValueRef
|
|
)
|
|
{
|
|
FString SAttributeValue;
|
|
|
|
// Get the type of the SketchUp attribute value.
|
|
SUTypedValueType SAttributeType;
|
|
SUTypedValueGetType(InSTypedValueRef, &SAttributeType); // we can ignore the returned SU_RESULT
|
|
|
|
// Convert the SketchUp attribute value into a string representation.
|
|
switch (SAttributeType)
|
|
{
|
|
case SUTypedValueType::SUTypedValueType_Empty:
|
|
{
|
|
break;
|
|
}
|
|
case SUTypedValueType::SUTypedValueType_Byte:
|
|
{
|
|
char ByteValue = 0;
|
|
SUTypedValueGetByte(InSTypedValueRef, &ByteValue); // we can ignore the returned SU_RESULT
|
|
SAttributeValue = FString::Printf(TEXT("%hhd"), ByteValue);
|
|
break;
|
|
}
|
|
case SUTypedValueType::SUTypedValueType_Short:
|
|
{
|
|
int16 Int16Value = 0;
|
|
SUTypedValueGetInt16(InSTypedValueRef, &Int16Value); // we can ignore the returned SU_RESULT
|
|
SAttributeValue = FString::Printf(TEXT("%hd"), Int16Value);
|
|
break;
|
|
}
|
|
case SUTypedValueType::SUTypedValueType_Int32:
|
|
{
|
|
int32 Int32Value = 0;
|
|
SUTypedValueGetInt32(InSTypedValueRef, &Int32Value); // we can ignore the returned SU_RESULT
|
|
SAttributeValue = FString::Printf(TEXT("%d"), Int32Value);
|
|
break;
|
|
}
|
|
case SUTypedValueType::SUTypedValueType_Float:
|
|
{
|
|
float FloatValue = 0.0;
|
|
SUTypedValueGetFloat(InSTypedValueRef, &FloatValue); // we can ignore the returned SU_RESULT
|
|
SAttributeValue = FString::Printf(TEXT("%f"), FloatValue);
|
|
break;
|
|
}
|
|
case SUTypedValueType::SUTypedValueType_Double:
|
|
{
|
|
double DoubleValue = 0.0;
|
|
SUTypedValueGetDouble(InSTypedValueRef, &DoubleValue); // we can ignore the returned SU_RESULT
|
|
SAttributeValue = FString::Printf(TEXT("%lf"), DoubleValue);
|
|
break;
|
|
}
|
|
case SUTypedValueType::SUTypedValueType_Bool:
|
|
{
|
|
bool BoolValue = false;
|
|
SUTypedValueGetBool(InSTypedValueRef, &BoolValue); // we can ignore the returned SU_RESULT
|
|
SAttributeValue = BoolValue ? TEXT("true") : TEXT("false");
|
|
break;
|
|
}
|
|
case SUTypedValueType::SUTypedValueType_Color:
|
|
{
|
|
SUColor ColorValue = { 0, 0, 0, 0 };
|
|
SUTypedValueGetColor(InSTypedValueRef, &ColorValue); // we can ignore the returned SU_RESULT
|
|
SAttributeValue = FString::Printf(TEXT("(%hhu, %hhu, %hhu, %hhu)"), ColorValue.red, ColorValue.green, ColorValue.blue, ColorValue.alpha);
|
|
break;
|
|
}
|
|
case SUTypedValueType::SUTypedValueType_Time:
|
|
{
|
|
int64 TimeValue = 0; // seconds since 1970-01-01
|
|
SUTypedValueGetTime(InSTypedValueRef, &TimeValue); // we can ignore the returned SU_RESULT
|
|
SAttributeValue = FString::Printf(TEXT("%lld"), TimeValue);
|
|
break;
|
|
}
|
|
case SUTypedValueType::SUTypedValueType_String:
|
|
{
|
|
SAttributeValue = SuGetString(SUTypedValueGetString, InSTypedValueRef);
|
|
break;
|
|
}
|
|
case SUTypedValueType::SUTypedValueType_Vector3D:
|
|
{
|
|
double Vector3DValue[3] = { 0.0, 0.0, 0.0 };
|
|
SUTypedValueGetVector3d(InSTypedValueRef, Vector3DValue); // we can ignore the returned SU_RESULT
|
|
SAttributeValue = FString::Printf(TEXT("(%lf, %lf, %lf)"), Vector3DValue[0], Vector3DValue[1], Vector3DValue[2]);
|
|
break;
|
|
}
|
|
case SUTypedValueType::SUTypedValueType_Array:
|
|
{
|
|
// Get the number of sub-values in the SketchUp attribute value.
|
|
size_t SSubValueCount = 0;
|
|
SUTypedValueGetNumArrayItems(InSTypedValueRef, &SSubValueCount); // we can ignore the returned SU_RESULT
|
|
|
|
if (SSubValueCount > 0)
|
|
{
|
|
// Retrieve the sub-values in the SketchUp attribute value.
|
|
TArray<SUTypedValueRef> SSubValues;
|
|
SSubValues.Init(SU_INVALID, SSubValueCount);
|
|
SUTypedValueGetArrayItems(InSTypedValueRef, SSubValueCount, SSubValues.GetData(), &SSubValueCount); // we can ignore the returned SU_RESULT
|
|
SSubValues.SetNum(SSubValueCount);
|
|
|
|
// Combine the SketchUp attribute sub-values into one string representation.
|
|
FString SCombinedSubValues;
|
|
for (SUTypedValueRef SSubValueRef : SSubValues)
|
|
{
|
|
FString SSubAttributeValue = GetAttributeValue(SSubValueRef);
|
|
|
|
if (!SSubAttributeValue.IsEmpty())
|
|
{
|
|
SCombinedSubValues.Append(SSubAttributeValue);
|
|
SCombinedSubValues.Append(TEXT(", "));
|
|
}
|
|
}
|
|
|
|
if (!SCombinedSubValues.IsEmpty())
|
|
{
|
|
SAttributeValue.AppendChar(TEXT('('));
|
|
SAttributeValue.Append(SCombinedSubValues.LeftChop(2)); // remove the last ", "
|
|
SAttributeValue.AppendChar(TEXT(')'));
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Removes whitespaces from the start and end of the SketchUp attribute value string representation.
|
|
SAttributeValue.TrimStartAndEndInline();
|
|
|
|
return SAttributeValue;
|
|
}
|
|
|
|
void FMetadata::AddMetadata(
|
|
TSharedPtr<IDatasmithMetaDataElement> IODMetaDataElementPtr
|
|
) const
|
|
{
|
|
// Add the metadata key-value pairs into the Datasmith metadata element.
|
|
for (auto const& MetadataKeyValueEntry : MetadataKeyValueMap)
|
|
{
|
|
// Create a Datasmith key-value property.
|
|
TSharedPtr<IDatasmithKeyValueProperty> DKeyValuePtr = FDatasmithSceneFactory::CreateKeyValueProperty(*MetadataKeyValueEntry.Key);
|
|
DKeyValuePtr->SetValue(*MetadataKeyValueEntry.Value);
|
|
|
|
// Add the key-value property to the Datasmith metadata element.
|
|
IODMetaDataElementPtr->AddProperty(DKeyValuePtr);
|
|
|
|
// ADD_TRACE_LINE(TEXT("Actor %ls metadata: %ls = %ls"), IODMetaDataElementPtr->GetName(), *MetadataKeyValueEntry.Key, *MetadataKeyValueEntry.Value);
|
|
}
|
|
}
|