Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

### ? - ?

##### Breaking Changes :mega:

- `FCesiumPrimitiveMetadata::GetPropertyAttributeIndices` is now deprecated. Use `GetPropertyAttributes` to directly get the `FCesiumPropertyAttribute`s instead.

##### Additions :tada:

- Added `FCesiumPropertyAttributeProperty` to represent glTF property attribute properties and `UCesiumPropertyAttributePropertyBlueprintLibrary` to retrieve their values.
- Added `FCesiumPropertyAttribute` to represent glTF property attributes and `UCesiumPropertyAttributeBlueprintLibrary` to act upon them with Blueprints.
- Added `UCesiumPrimitiveMetadataBlueprintLibrary::GetPropertyAttributes` to retrieve the property attributes from a `FCesiumPrimitiveMetadata`.
- Added `UCesiumPropertyTexturePropertyBlueprintLibrary::GetInteger64`. Although 64-bit integers aren't directly supported by property textures, this enables the lossless retrieval of 32-bit unsigned integers.

##### Fixes :wrench:

- Fixed error messages in the Unreal log about uninitialized fields in `FCesiumGeocoderServiceAttribution` and `FCesiumGeocoderServiceFeature`.
Expand Down
2 changes: 1 addition & 1 deletion Source/CesiumRuntime/Private/CesiumGltfComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1093,7 +1093,7 @@ static void loadPrimitiveFeaturesMetadata(
pFeatures ? FCesiumPrimitiveFeatures(model, primitive, *pFeatures)
: FCesiumPrimitiveFeatures();
primitiveResult.Metadata =
pMetadata ? FCesiumPrimitiveMetadata(primitive, *pMetadata)
pMetadata ? FCesiumPrimitiveMetadata(model, primitive, *pMetadata)
: FCesiumPrimitiveMetadata();

PRAGMA_DISABLE_DEPRECATION_WARNINGS
Expand Down
51 changes: 41 additions & 10 deletions Source/CesiumRuntime/Private/CesiumPrimitiveMetadata.cpp
Original file line number Diff line number Diff line change
@@ -1,26 +1,51 @@
// Copyright 2020-2024 CesiumGS, Inc. and Contributors

#include "CesiumPrimitiveMetadata.h"
#include "CesiumGltf/AccessorView.h"
#include "CesiumGltf/ExtensionMeshPrimitiveExtStructuralMetadata.h"
#include "CesiumGltf/Model.h"
#include "CesiumGltfPrimitiveComponent.h"
#include "CesiumPropertyAttribute.h"

#include <CesiumGltf/ExtensionMeshPrimitiveExtStructuralMetadata.h>
#include <CesiumGltf/ExtensionModelExtStructuralMetadata.h>
#include <CesiumGltf/Model.h>

static FCesiumPrimitiveMetadata EmptyPrimitiveMetadata;

FCesiumPrimitiveMetadata::FCesiumPrimitiveMetadata(
const CesiumGltf::MeshPrimitive& Primitive,
const CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata& Metadata)
: _propertyTextureIndices(), _propertyAttributeIndices() {
this->_propertyTextureIndices.Reserve(Metadata.propertyTextures.size());
for (const int64 propertyTextureIndex : Metadata.propertyTextures) {
const CesiumGltf::Model& model,
const CesiumGltf::MeshPrimitive& primitive,
const CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata& metadata)
: _propertyTextureIndices(),
_propertyAttributes(),
_propertyAttributeIndices() {
this->_propertyTextureIndices.Reserve(metadata.propertyTextures.size());
for (const int64 propertyTextureIndex : metadata.propertyTextures) {
this->_propertyTextureIndices.Emplace(propertyTextureIndex);
}

this->_propertyAttributeIndices.Reserve(Metadata.propertyAttributes.size());
for (const int64 propertyAttributeIndex : Metadata.propertyAttributes) {
// For backwards compatibility with GetPropertyAttributeIndices().
this->_propertyAttributeIndices.Reserve(metadata.propertyAttributes.size());
for (const int64 propertyAttributeIndex : metadata.propertyAttributes) {
this->_propertyAttributeIndices.Emplace(propertyAttributeIndex);
}

const auto* pModelMetadata =
model.getExtension<CesiumGltf::ExtensionModelExtStructuralMetadata>();
if (!pModelMetadata) {
return;
}

for (const int64 propertyAttributeIndex : metadata.propertyAttributes) {
if (propertyAttributeIndex < 0 ||
propertyAttributeIndex >=
int64_t(pModelMetadata->propertyAttributes.size())) {
continue;
}

this->_propertyAttributes.Emplace(FCesiumPropertyAttribute(
model,
primitive,
pModelMetadata->propertyAttributes[propertyAttributeIndex]));
}
}

const FCesiumPrimitiveMetadata&
Expand All @@ -41,6 +66,12 @@ UCesiumPrimitiveMetadataBlueprintLibrary::GetPropertyTextureIndices(
return PrimitiveMetadata._propertyTextureIndices;
}

const TArray<FCesiumPropertyAttribute>&
UCesiumPrimitiveMetadataBlueprintLibrary::GetPropertyAttributes(
UPARAM(ref) const FCesiumPrimitiveMetadata& PrimitiveMetadata) {
return PrimitiveMetadata._propertyAttributes;
}

const TArray<int64>&
UCesiumPrimitiveMetadataBlueprintLibrary::GetPropertyAttributeIndices(
UPARAM(ref) const FCesiumPrimitiveMetadata& PrimitiveMetadata) {
Expand Down
143 changes: 143 additions & 0 deletions Source/CesiumRuntime/Private/CesiumPropertyAttribute.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Copyright 2020-2024 CesiumGS, Inc. and Contributors

#include "CesiumPropertyAttribute.h"
#include <CesiumGltf/PropertyAttributeView.h>

static FCesiumPropertyAttributeProperty EmptyPropertyAttributeProperty;

FCesiumPropertyAttribute::FCesiumPropertyAttribute(
const CesiumGltf::Model& model,
const CesiumGltf::MeshPrimitive& primitive,
const CesiumGltf::PropertyAttribute& propertyAttribute,
const TSharedPtr<FCesiumMetadataEnumCollection>& pEnumCollection)
: _status(
ECesiumPropertyAttributeStatus::ErrorInvalidPropertyAttributeClass),
_name(propertyAttribute.name.value_or("").c_str()),
_className(propertyAttribute.classProperty.c_str()),
_elementCount(0),
_properties() {
CesiumGltf::PropertyAttributeView propertyAttributeView{
model,
propertyAttribute};
switch (propertyAttributeView.status()) {
case CesiumGltf::PropertyAttributeViewStatus::Valid:
_status = ECesiumPropertyAttributeStatus::Valid;
break;
default:
// Status was already set in initializer list.
return;
}

const CesiumGltf::ExtensionModelExtStructuralMetadata* pExtension =
model.getExtension<CesiumGltf::ExtensionModelExtStructuralMetadata>();
// If there was no schema, we would've gotten ErrorMissingSchema for the
// propertyAttributeView status.
check(pExtension != nullptr && pExtension->schema != nullptr);

propertyAttributeView.forEachProperty(
primitive,
[&properties = _properties,
&elementCount = _elementCount,
&Schema = *pExtension->schema,
&propertyAttributeView,
&pEnumCollection](
const std::string& propertyName,
auto propertyValue) mutable {
FString key(UTF8_TO_TCHAR(propertyName.data()));
const CesiumGltf::ClassProperty* pClassProperty =
propertyAttributeView.getClassProperty(propertyName);
check(pClassProperty);

TSharedPtr<FCesiumMetadataEnum> pEnumDefinition(nullptr);
if (pEnumCollection.IsValid() && pClassProperty->enumType.has_value()) {
pEnumDefinition = pEnumCollection->Get(
FString(UTF8_TO_TCHAR(pClassProperty->enumType.value().c_str())));
}

if (elementCount == 0) {
// Use the first non-zero property size to compare against all the
// others.
elementCount = propertyValue.size();
}

if (propertyValue.size() > 0 && elementCount != propertyValue.size()) {
UE_LOG(
LogCesium,
Error,
TEXT(
"The size of one or more property attribute properties does not match the others."));
}

properties.Add(
key,
FCesiumPropertyAttributeProperty(propertyValue, pEnumDefinition));
});
}

/*static*/ ECesiumPropertyAttributeStatus
UCesiumPropertyAttributeBlueprintLibrary::GetPropertyAttributeStatus(
UPARAM(ref) const FCesiumPropertyAttribute& PropertyAttribute) {
return PropertyAttribute._status;
}

/*static*/ const FString&
UCesiumPropertyAttributeBlueprintLibrary::GetPropertyAttributeName(
UPARAM(ref) const FCesiumPropertyAttribute& PropertyAttribute) {
return PropertyAttribute._name;
}

/*static*/ const TMap<FString, FCesiumPropertyAttributeProperty>&
UCesiumPropertyAttributeBlueprintLibrary::GetProperties(
UPARAM(ref) const FCesiumPropertyAttribute& PropertyAttribute) {
return PropertyAttribute._properties;
}

/*static*/ const TArray<FString>
UCesiumPropertyAttributeBlueprintLibrary::GetPropertyNames(
UPARAM(ref) const FCesiumPropertyAttribute& PropertyAttribute) {
TArray<FString> names;
PropertyAttribute._properties.GenerateKeyArray(names);
return names;
}

/*static*/ const FCesiumPropertyAttributeProperty&
UCesiumPropertyAttributeBlueprintLibrary::FindProperty(
UPARAM(ref) const FCesiumPropertyAttribute& PropertyAttribute,
const FString& PropertyName) {
const FCesiumPropertyAttributeProperty* property =
PropertyAttribute._properties.Find(PropertyName);
return property ? *property : EmptyPropertyAttributeProperty;
}

/*static*/ TMap<FString, FCesiumMetadataValue>
UCesiumPropertyAttributeBlueprintLibrary::GetMetadataValuesAtIndex(
UPARAM(ref) const FCesiumPropertyAttribute& PropertyAttribute,
int64 Index) {
TMap<FString, FCesiumMetadataValue> values;
if (Index < 0 || Index >= PropertyAttribute._elementCount) {
return values;
}

for (const auto& pair : PropertyAttribute._properties) {
const FCesiumPropertyAttributeProperty& property = pair.Value;
ECesiumPropertyAttributePropertyStatus status =
UCesiumPropertyAttributePropertyBlueprintLibrary::
GetPropertyAttributePropertyStatus(property);
if (status == ECesiumPropertyAttributePropertyStatus::Valid) {
values.Add(
pair.Key,
UCesiumPropertyAttributePropertyBlueprintLibrary::GetValue(
pair.Value,
Index));
} else if (
status ==
ECesiumPropertyAttributePropertyStatus::EmptyPropertyWithDefault) {
values.Add(
pair.Key,
UCesiumPropertyAttributePropertyBlueprintLibrary::GetDefaultValue(
pair.Value));
}
}

return values;
}
Loading