1 Commits

Author SHA1 Message Date
JR-Morgan 096e840098 Experimental changes for deserilisation 2022-01-31 00:57:12 +00:00
23 changed files with 566 additions and 259 deletions
@@ -1,4 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "API/SpeckleTypeConverter.h"
@@ -1,14 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Components/SpeckleOperationsComponent.h"
// Sets default values for this component's properties
USpeckleOperationsComponent::USpeckleOperationsComponent()
{
PrimaryComponentTick.bCanEverTick = false;
}
@@ -0,0 +1,69 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Conversion/ConversionUtils.h"
FMatrix UConversionUtils::TransformToNative(const TArray<float>& TransformData)
{
if(TransformData.Num() != 16) return FMatrix::Identity;
FMatrix TransformMatrix;
for(int32 Row = 0; Row < 4; Row++)
for(int32 Col = 0; Col < 4; Col++)
{
TransformMatrix.M[Row][Col] = TransformData[Row * 4 + Col];
}
TransformMatrix = TransformMatrix.GetTransposed();
return TransformMatrix;
}
float UConversionUtils::GetUnitsScaleFactorF(const FString& Units, const float WorldToCentimeters)
{
static const auto ParseUnits = [](const FString& LUnits) -> float
{
if (LUnits == "millimeters" || LUnits == "millimeter" || LUnits == "millimetres" || LUnits == "millimetre" || LUnits == "mm")
return 0.1;
if (LUnits == "centimeters" || LUnits == "centimeter" ||LUnits == "centimetres" || LUnits == "centimetre" || LUnits == "cm")
return 1;
if (LUnits == "meters" || LUnits == "meter" || LUnits == "metres" || LUnits == "metre" || LUnits == "m")
return 100;
if (LUnits == "kilometers" || LUnits == "kilometres" || LUnits == "km")
return 100000;
if (LUnits == "inches" || LUnits == "inch" || LUnits == "in")
return 2.54;
if (LUnits == "feet" || LUnits == "foot" || LUnits == "ft")
return 30.48;
if (LUnits == "yards" || LUnits == "yard"|| LUnits == "yd")
return 91.44;
if (LUnits == "miles" || LUnits == "mile" || LUnits == "mi")
return 160934.4;
return 100;
};
return ParseUnits(Units.ToLower()) * WorldToCentimeters;
}
float UConversionUtils::GetUnitsScaleFactor(const FString& Units, const UWorld* World)
{
int32 WorldToCentimeters;
ensureAlways(TryGetWorldUnits(World, WorldToCentimeters));
return GetUnitsScaleFactorF(Units, WorldToCentimeters);
}
bool UConversionUtils::TryGetWorldUnits(const UWorld* World, int32& OutWorldToCentimeters)
{
OutWorldToCentimeters = 1;
if(!IsValid(World)) return false;
const AWorldSettings* Settings = World->GetWorldSettings();
if(!IsValid(Settings)) return false;
OutWorldToCentimeters = Settings->WorldToMeters / 10.0;
return true;
}
@@ -12,6 +12,7 @@ UProceduralMeshConverter::UProceduralMeshConverter()
{
SpeckleTypes.Add(UMesh::StaticClass());
MeshActorType = AActor::StaticClass();
bCreateCollisions = true;
}
AActor* UProceduralMeshConverter::ConvertToNative_Implementation(const UBase* SpeckleBase, ASpeckleUnrealManager* Manager)
@@ -19,13 +20,18 @@ AActor* UProceduralMeshConverter::ConvertToNative_Implementation(const UBase* Sp
const UMesh* P = Cast<UMesh>(SpeckleBase);
if(P == nullptr) return nullptr;
return MeshToNative(P, Manager);
//No existing mesh was found, try and convert SpeckleMesh
UMesh* ScaledMesh = DuplicateObject(P, P->GetOuter(), P->GetFName());
ScaledMesh->ApplyUnits(Manager->GetWorld());
ScaledMesh->AlignVerticesWithTexCoordsByIndex();
return MeshToNative(ScaledMesh, Manager);
}
AActor* UProceduralMeshConverter::MeshToNative(const UMesh* SpeckleMesh, ASpeckleUnrealManager* Manager)
{
AActor* MeshActor = CreateActor(Manager, FTransform(SpeckleMesh->Transform));
AActor* MeshActor = CreateActor(Manager, FTransform(SpeckleMesh->GetTransform()));
UProceduralMeshComponent* MeshComponent = NewObject<UProceduralMeshComponent>(MeshActor, FName("SpeckleMeshComponent"));
MeshComponent->SetupAttachment(MeshActor->GetRootComponent());
MeshComponent->RegisterComponent();
@@ -61,19 +67,23 @@ AActor* UProceduralMeshConverter::MeshToNative(const UMesh* SpeckleMesh, ASpeckl
i += n + 1;
}
TArray<FColor> VertexColors;
VertexColors.Reserve(SpeckleMesh->Colors.Num());
for(const int32& c : SpeckleMesh->Colors) VertexColors.Add(FColor(c));
const TArray<FVector> Normals;
const TArray<FProcMeshTangent> Tangents;
MeshComponent->CreateMeshSection(
0,
SpeckleMesh->Vertices,
SpeckleMesh->GetVerts(),
Faces,
Normals,
SpeckleMesh->TextureCoordinates,
SpeckleMesh->VertexColors,
SpeckleMesh->GetTextureCoordinates(),
VertexColors,
Tangents,
true);
bCreateCollisions);
MeshComponent->SetMaterial(0, GetMaterial(SpeckleMesh->RenderMaterial, Manager));
@@ -107,8 +117,8 @@ UMaterialInterface* UProceduralMeshConverter::GetMaterial(const URenderMaterial*
DynMaterial->SetScalarParameterValue("Opacity", SpeckleMaterial->Opacity);
DynMaterial->SetScalarParameterValue("Metallic", SpeckleMaterial->Metalness);
DynMaterial->SetScalarParameterValue("Roughness", SpeckleMaterial->Roughness);
DynMaterial->SetVectorParameterValue("BaseColor", SpeckleMaterial->Diffuse);
DynMaterial->SetVectorParameterValue("EmissiveColor", SpeckleMaterial->Emissive);
DynMaterial->SetVectorParameterValue("BaseColor", FColor(SpeckleMaterial->Diffuse));
DynMaterial->SetVectorParameterValue("EmissiveColor", FColor(SpeckleMaterial->Emissive));
Manager->ConvertedMaterials.Add(SpeckleMaterial->Id, DynMaterial);
@@ -14,7 +14,6 @@
#include "Objects/RenderMaterial.h"
UStaticMeshConverter::UStaticMeshConverter()
{
Transient = false;
@@ -41,14 +40,20 @@ AActor* UStaticMeshConverter::ConvertToNative_Implementation(const UBase* Speckl
//Find existing mesh
UStaticMesh* Mesh = Cast<UStaticMesh>(Package->FindAssetInPackage());
FMatrix ActorTransform = FMatrix::Identity;
if(!IsValid(Mesh))
{
//No existing mesh was found, try and convert SpeckleMesh
Mesh = MeshToNative(Package, SpeckleMesh, Manager);
UMesh* ScaledMesh = DuplicateObject(SpeckleMesh, SpeckleMesh->GetOuter(), SpeckleMesh->GetFName());
ScaledMesh->ApplyUnits(Manager->GetWorld());
ScaledMesh->AlignVerticesWithTexCoordsByIndex();
Mesh = MeshToNative(Package, ScaledMesh, Manager);
ActorTransform = ScaledMesh->GetTransform();
}
AActor* Actor = CreateActor(Manager, FTransform(ActorTransform));
AActor* Actor = CreateActor(Manager, FTransform(SpeckleMesh->Transform));
TInlineComponentArray<UStaticMeshComponent*> Components;
Actor->GetComponents<UStaticMeshComponent>(Components);
@@ -71,7 +76,6 @@ AActor* UStaticMeshConverter::ConvertToNative_Implementation(const UBase* Speckl
UStaticMesh* UStaticMeshConverter::MeshToNative(UObject* Outer, const UMesh* SpeckleMesh,
ASpeckleUnrealManager* Manager)
{
const EObjectFlags ObjectFags = Transient? RF_Transient | RF_Public : RF_Public;
UStaticMesh* Mesh = NewObject<UStaticMesh>(Outer, FName(SpeckleMesh->Id), ObjectFags);
@@ -108,13 +112,13 @@ UStaticMesh* UStaticMeshConverter::MeshToNative(UObject* Outer, const UMesh* Spe
const FName MaterialSlotName = Mesh->AddMaterial(Material);;
BaseMeshDescription.PolygonGroupAttributes().RegisterAttribute<FName>(MeshAttribute::PolygonGroup::ImportedMaterialSlotName, 1, MaterialSlotName, EMeshAttributeFlags::None);
{
const size_t NumberOfVertices = SpeckleMesh->Vertices.Num();
const size_t NumberOfVertices = SpeckleMesh->GetVertexCount();
StaticMeshDescription->ReserveNewVertices(NumberOfVertices);
TArray<FVertexID> Vertices;
Vertices.Reserve(NumberOfVertices);
for(const FVector VertexPosition : SpeckleMesh->Vertices)
for(const FVector VertexPosition : SpeckleMesh->GetVerts())
{
const FVertexID VertID = StaticMeshDescription->CreateVertex();
StaticMeshDescription->SetVertexPosition(VertID, VertexPosition);
@@ -159,8 +163,8 @@ UStaticMesh* UStaticMeshConverter::MeshToNative(UObject* Outer, const UMesh* Spe
VertexInstances.Add(VertexInstance);
if(SpeckleMesh->TextureCoordinates.Num() > VertIndex)
StaticMeshDescription->SetVertexInstanceUV(VertexInstance, SpeckleMesh->TextureCoordinates[VertIndex]);
if(SpeckleMesh->GetTexCoordCount() > VertIndex)
StaticMeshDescription->SetVertexInstanceUV(VertexInstance, SpeckleMesh->GetTextureCoordinate(VertIndex));
//if(SpeckleMesh->VertexColors.Num() > VertIndex)
// //TODO set vertex colors
@@ -257,8 +261,8 @@ UMaterialInterface* UStaticMeshConverter::GetMaterial(const URenderMaterial* Spe
ConstMaterial->SetScalarParameterValueEditorOnly(FMaterialParameterInfo("Opacity"), SpeckleMaterial->Opacity);
ConstMaterial->SetScalarParameterValueEditorOnly(FMaterialParameterInfo("Metallic"), SpeckleMaterial->Metalness);
ConstMaterial->SetScalarParameterValueEditorOnly(FMaterialParameterInfo("Roughness"), SpeckleMaterial->Roughness);
ConstMaterial->SetVectorParameterValueEditorOnly(FMaterialParameterInfo("BaseColor"), SpeckleMaterial->Diffuse);
ConstMaterial->SetVectorParameterValueEditorOnly(FMaterialParameterInfo("EmissiveColor"), SpeckleMaterial->Emissive);
ConstMaterial->SetVectorParameterValueEditorOnly(FMaterialParameterInfo("BaseColor"), FColor(SpeckleMaterial->Diffuse));
ConstMaterial->SetVectorParameterValueEditorOnly(FMaterialParameterInfo("EmissiveColor"), FColor(SpeckleMaterial->Emissive));
//ConstMaterial->InitStaticPermutation();
@@ -275,8 +279,8 @@ UMaterialInterface* UStaticMeshConverter::GetMaterial(const URenderMaterial* Spe
DynMaterial->SetScalarParameterValue("Opacity", SpeckleMaterial->Opacity);
DynMaterial->SetScalarParameterValue("Metallic", SpeckleMaterial->Metalness);
DynMaterial->SetScalarParameterValue("Roughness", SpeckleMaterial->Roughness);
DynMaterial->SetVectorParameterValue("BaseColor", SpeckleMaterial->Diffuse);
DynMaterial->SetVectorParameterValue("EmissiveColor", SpeckleMaterial->Emissive);
DynMaterial->SetVectorParameterValue("BaseColor", FColor(SpeckleMaterial->Diffuse));
DynMaterial->SetVectorParameterValue("EmissiveColor", FColor(SpeckleMaterial->Emissive));
DynMaterial->SetFlags(RF_Public);
}
@@ -6,21 +6,16 @@
#include "SpeckleUnrealManager.h"
#include "Conversion/Converters/PointCloudConverter.h"
#include "Conversion/Converters/StaticMeshConverter.h"
#include "Objects/Mesh.h"
#include "Objects/PointCloud.h"
// Sets default values for this component's properties
USpeckleConverterComponent::USpeckleConverterComponent()
{
PrimaryComponentTick.bCanEverTick = false;
//TODO consider using an object library for default converters
static ConstructorHelpers::FObjectFinder<UStaticMeshConverter> MeshConverter(TEXT("StaticMeshConverter'/SpeckleUnreal/Converters/DefaultStaticMeshConverter.DefaultStaticMeshConverter'"));
static ConstructorHelpers::FObjectFinder<UPointCloudConverter> PointCloudConverter(TEXT("PointCloudConverter'/SpeckleUnreal/Converters/DefaultPointCloudConverter.DefaultPointCloudConverter'"));
PrimaryComponentTick.bCanEverTick = false;
//Mesh
//Point
@@ -42,9 +37,9 @@ void USpeckleConverterComponent::OnConvertersChangeHandler()
for(int i = 0; i < SpeckleConverters.Num(); i++)
{
const UObject* Converter = SpeckleConverters[i];
if(Converter != nullptr && !Converter->GetClass()->ImplementsInterface(USpeckleConverter::StaticClass()))
if(Converter != nullptr && !Converter->GetClass()->ImplementsInterface(USpeckleTypeConverter::StaticClass()))
{
UE_LOG(LogTemp, Warning, TEXT("Converter {%s} is not a valid converter, Expected to implement interface %s"), *Converter->GetClass()->GetName(), *USpeckleConverter::StaticClass()->GetName())
UE_LOG(LogTemp, Warning, TEXT("Converter {%s} is not a valid converter, Expected to implement interface %s"), *Converter->GetClass()->GetName(), *USpeckleTypeConverter::StaticClass()->GetName())
SpeckleConverters.RemoveAt(i);
i--;
}
@@ -80,15 +75,16 @@ AActor* USpeckleConverterComponent::ConvertToNative(const UBase* Object, ASpeckl
UE_LOG(LogTemp, Warning, TEXT("Skipping Object %s - No conversion functions exist for %s"), *Object->Id, *Type->GetName());
return nullptr;
}
UE_LOG(LogTemp, Log, TEXT("Converting object of type: %s id: %s "), *Object->Id, *Type->GetName());
FEditorScriptExecutionGuard ScriptGuard;
return ISpeckleConverter::Execute_ConvertToNative(Converter, Object, Manager);
AActor* ReturnObject = ISpeckleTypeConverter::Execute_ConvertToNative(Converter, Object, Manager);
UE_LOG(LogTemp, Log, TEXT("Converted object of type: %s id: %s "), *Object->Id, *Type->GetName());
return ReturnObject;
}
TScriptInterface<ISpeckleConverter> USpeckleConverterComponent::GetConverter(const TSubclassOf<UBase> BaseType)
TScriptInterface<ISpeckleTypeConverter> USpeckleConverterComponent::GetConverter(const TSubclassOf<UBase> BaseType)
{
// Check if this SpeckleType has a known converter.
if(SpeckleTypeMap.Contains(BaseType))
@@ -102,13 +98,13 @@ TScriptInterface<ISpeckleConverter> USpeckleConverterComponent::GetConverter(con
{
if(Converter == nullptr) continue;
if(!Converter->GetClass()->ImplementsInterface(USpeckleConverter::StaticClass()))
if(!Converter->GetClass()->ImplementsInterface(USpeckleTypeConverter::StaticClass()))
{
UE_LOG(LogTemp, Warning, TEXT("Converter {%s} is not a valid converter, Expected to implement interface {%s}"), *Converter->GetClass()->GetName(), *USpeckleConverter::StaticClass()->GetName())
UE_LOG(LogTemp, Warning, TEXT("Converter {%s} is not a valid converter, Expected to implement interface {%s}"), *Converter->GetClass()->GetName(), *USpeckleTypeConverter::StaticClass()->GetName())
continue;
}
if(ISpeckleConverter::Execute_CanConvertToNative(Converter, BaseType))
if(ISpeckleTypeConverter::Execute_CanConvertToNative(Converter, BaseType))
{
//Found a Converter! Save this mapping for next time.
SpeckleTypeMap.Add(BaseType, Converter);
+131 -100
View File
@@ -4,104 +4,114 @@
#include "Objects/Mesh.h"
#include "SpeckleUnrealManager.h"
#include "Objects/RenderMaterial.h"
#include "Conversion/ConversionUtils.h"
void UMesh::Parse(const TSharedPtr<FJsonObject> Obj, const ASpeckleUnrealManager* Manager)
FMatrix UMesh::GetTransform() const
{
Super::Parse(Obj, Manager);
const float ScaleFactor = Manager->ParseScaleFactor(Units);
//Parse optional Transform
{
Transform = FMatrix::Identity;
const TArray<TSharedPtr<FJsonValue>>* TransformData = nullptr;
if(Obj->HasField("properties") && Obj->GetObjectField("properties")->TryGetArrayField("transform", TransformData))
{
for(int32 Row = 0; Row < 4; Row++)
for(int32 Col = 0; Col < 4; Col++)
{
Transform.M[Row][Col] = TransformData->operator[](Row * 4 + Col)->AsNumber();
}
Transform = Transform.GetTransposed();
Transform.ScaleTranslation(FVector(ScaleFactor));
}
}
//Parse Vertices
{
TArray<TSharedPtr<FJsonValue>> ObjectVertices = Manager->CombineChunks(Obj->GetArrayField("vertices"));
const int32 NumberOfVertices = ObjectVertices.Num() / 3;
Vertices.Reserve(NumberOfVertices);
for (size_t i = 0, j = 0; i < NumberOfVertices; i++, j += 3)
{
Vertices.Add(Transform.InverseTransformPosition(FVector
(
ObjectVertices[j].Get()->AsNumber(),
ObjectVertices[j + 1].Get()->AsNumber(),
ObjectVertices[j + 2].Get()->AsNumber()
) * ScaleFactor ));
}
}
//Parse Faces
{
const TArray<TSharedPtr<FJsonValue>> FaceVertices = Manager->CombineChunks(Obj->GetArrayField("faces"));
Faces.Reserve(FaceVertices.Num());
for(const auto VertIndex : FaceVertices)
{
Faces.Add(VertIndex->AsNumber());
}
}
//Parse TextureCoords
{
const TArray<TSharedPtr<FJsonValue>>* TextCoordArray;
if(Obj->TryGetArrayField("textureCoordinates", TextCoordArray))
{
TArray<TSharedPtr<FJsonValue>> TexCoords = Manager->CombineChunks(*TextCoordArray);
if(Transform.Num() != 16) return FMatrix::Identity;
TextureCoordinates.Reserve(TexCoords.Num() / 2);
for (int32 i = 0; i + 1 < TexCoords.Num(); i += 2)
{
TextureCoordinates.Add(FVector2D
(
TexCoords[i].Get()->AsNumber(),
TexCoords[i + 1].Get()->AsNumber()
));
}
}
}
//Parse VertexColors
{
const TArray<TSharedPtr<FJsonValue>>* ColorArray;
if(Obj->TryGetArrayField("colors", ColorArray))
FMatrix TransformMatrix;
for(int32 Row = 0; Row < 4; Row++)
for(int32 Col = 0; Col < 4; Col++)
{
TArray<TSharedPtr<FJsonValue>> Colors = Manager->CombineChunks(*ColorArray);
VertexColors.Reserve(Colors.Num());
for (int32 i = 0; i + 1 < Colors.Num(); i ++)
{
VertexColors.Add(FColor(Colors[i].Get()->AsNumber()));
}
TransformMatrix.M[Row][Col] = Transform[Row * 4 + Col];
}
}
//Parse Optional RenderMaterial
if (Obj->HasField("renderMaterial"))
{
RenderMaterial = NewObject<URenderMaterial>();
RenderMaterial->Parse(Obj->GetObjectField("renderMaterial"), Manager);
}
AlignVerticesWithTexCoordsByIndex();
TransformMatrix = TransformMatrix.GetTransposed();
return TransformMatrix;
}
void UMesh::SetTransform(const FMatrix& T)
{
const FMatrix TransformMatrix = T.GetTransposed();
for(int32 Row = 0; Row < 4; Row++)
for(int32 Col = 0; Col < 4; Col++)
{
Transform[Row * 4 + Col] = TransformMatrix.M[Row][Col];
}
}
FVector UMesh::GetVert(int32 Index) const
{
Index *= 3;
return FVector(
Vertices[Index],
Vertices[Index + 1],
Vertices[Index + 2]
);
}
TArray<FVector> UMesh::GetVerts() const
{
check(Vertices.Num() % 3 == 0);
//TODO - Maybe could just use a blit copy assuming 3 floats -> FVector
TArray<FVector> VertexVectors;
const int32 NumberOfVertices = Vertices.Num() / 3;
VertexVectors.Reserve(NumberOfVertices);
for (size_t i = 0, j = 0; i < NumberOfVertices; i++, j += 3)
{
VertexVectors.Add(FVector
(
Vertices[j],
Vertices[j + 1],
Vertices[j + 2]
));
}
return VertexVectors;
}
FVector2D UMesh::GetTextureCoordinate(int32 Index) const
{
Index *= 2;
return FVector2D(TextureCoordinates[Index], TextureCoordinates[Index + 1]);
}
TArray<FVector2D> UMesh::GetTextureCoordinates() const
{
//TODO - Maybe could just use a blit copy assuming 2 floats -> FVector2D
TArray<FVector2D> TexCoords;
TexCoords.Reserve(TextureCoordinates.Num() / 2);
for (int32 i = 0; i + 1 < TexCoords.Num(); i += 2)
{
TexCoords.Add(FVector2D
(
TextureCoordinates[i],
TextureCoordinates[i + 1]
));
}
return TexCoords;
}
FColor UMesh::GetVertexColor(int32 Index) const
{
return FColor(Colors[Index]);
}
TArray<FColor> UMesh::GetVertexColors() const
{
TArray<FColor> VertexColors;
VertexColors.Reserve(Colors.Num());
for (int32 i = 0; i + 1 < Colors.Num(); i ++)
{
VertexColors.Add(FColor(Colors[i]));
}
return VertexColors;
}
@@ -115,12 +125,12 @@ void UMesh::AlignVerticesWithTexCoordsByIndex()
if(TextureCoordinates.Num() == 0) return;
if(TextureCoordinates.Num() == Vertices.Num()) return; //Tex-coords already aligned as expected
TArray<int> FacesUnique;
TArray<int32> FacesUnique;
FacesUnique.Reserve(Faces.Num());
TArray<FVector> VerticesUnique;
VerticesUnique.Reserve(TextureCoordinates.Num());
const bool HasColor = VertexColors.Num() > 0;
TArray<FColor> ColorsUnique;
TArray<float> VerticesUnique;
VerticesUnique.Reserve(TextureCoordinates.Num() * 3);
const bool HasColor = Colors.Num() > 0;
TArray<int32> ColorsUnique;
if(HasColor) ColorsUnique.Reserve(TextureCoordinates.Num());
int32 NIndex = 0;
@@ -140,14 +150,35 @@ void UMesh::AlignVerticesWithTexCoordsByIndex()
VerticesUnique.Add(Vertices[VertIndex]);
if(HasColor) ColorsUnique.Add(VertexColors[NewVertIndex]);
if(HasColor) ColorsUnique.Add(Colors[NewVertIndex]);
FacesUnique.Add(NewVertIndex);
}
NIndex += n + 1;
}
Vertices = VerticesUnique;
VertexColors = ColorsUnique;
Colors = ColorsUnique;
Faces = FacesUnique;
}
}
void UMesh::ApplyScaleFactor(const float ScaleFactor)
{
for (size_t i = 0; i < Vertices.Num(); i++)
{
Vertices[i] *= ScaleFactor;
}
FMatrix Transform = GetTransform();
Transform.ScaleTranslation(FVector(ScaleFactor));
}
void UMesh::ApplyUnits(const UWorld* World)
{
const UWorld* CheckedWorld = IsValid(World)? World : GetWorld();
const float ScaleFactor = UConversionUtils::GetUnitsScaleFactor(Units, CheckedWorld);
ApplyScaleFactor(ScaleFactor);
Units = "cm";
}
@@ -1,3 +1,4 @@
#include "JsonObjectConverter.h"
#include "SpeckleUnrealActor.h"
#include "SpeckleUnrealManager.h"
#include "Objects/Mesh.h"
@@ -98,7 +99,7 @@ bool ASpeckleUnrealManager::TryGetMaterial(const URenderMaterial* SpeckleMateria
}
UBase* ASpeckleUnrealManager::DeserializeBase(const TSharedPtr<FJsonObject> Obj) const
{
{
{ // Handle Detached Objects
TSharedPtr<FJsonObject> DetachedObject;
if(ResolveReference(Obj, DetachedObject))
@@ -111,22 +112,192 @@ UBase* ASpeckleUnrealManager::DeserializeBase(const TSharedPtr<FJsonObject> Obj)
if (!Obj->TryGetStringField("speckle_type", SpeckleType)) return nullptr;
FString ObjectId = "";
Obj->TryGetStringField("id", ObjectId);
const TSubclassOf<UBase> BaseType = UBase::FindClosestType(SpeckleType);
// Get the registered type from Base register
const TSubclassOf<UBase> ObjectType = UBase::FindClosestType(SpeckleType);
if(BaseType == nullptr)
if(ObjectType == nullptr)
{
UE_LOG(LogTemp, Verbose, TEXT("SpeckleType: %s is unknown,%t object: %s will be ignored"), *SpeckleType, *ObjectId );
return nullptr; //BaseType = UBase::StaticClass();
}
UBase* Base = NewObject<UBase>(GetTransientPackage(), BaseType);
Base->Parse(Obj, this);
//TODO before we create and deserialised a new object, first check if we have already deserialised this object
//Create instance of the ObjectType
UBase* Base = NewObject<UBase>(GetTransientPackage(), ObjectType);
//Map of all properties with no explicit UProperty to set.
//For now we add all values to this map, then remove the ones we find explicit UProperties for.
auto DynamicProperties = TMap<FString, TSharedPtr<FJsonValue>>(Obj->Values);
//Loop through each UProperty in the UBase and try and set its value from the JSON obj
for (TFieldIterator<UProperty> It(ObjectType); It; ++It)
{
FProperty* Property = *It;
void* PropertyValueAddress = Property->ContainerPtrToValuePtr<uint8>(Base);
// Find a json value matching this property name
const FString Key = Property->GetName();
const TSharedPtr<FJsonValue>* JsonValuePtr = Obj->Values.Find(Key);
//Ensure value is valid
if (!JsonValuePtr) continue;
TSharedPtr<FJsonValue> JsonValue = *JsonValuePtr;
if ( (!JsonValue.IsValid()) || JsonValue->IsNull() ) continue;
//Handle chunked values!!!!!
if (const FArrayProperty* ArrayProperty = CastField<FArrayProperty>(Property))
{
const TSharedPtr<FJsonObject>* ChunkedObject;
FString ChunkedType;
if(JsonValue->TryGetObject(ChunkedObject)
&& ChunkedObject->operator->()->TryGetStringField("", ChunkedType)
&& ChunkedType == "Speckle.Core.Models.DataChunk")
{
const TArray<TSharedPtr<FJsonValue>>* ChunkedArray;
if(JsonValue->TryGetArray(ChunkedArray))
{
auto Arr = CombineChunks(*ChunkedArray);
if()
{
}
}
}
}
//Check if property is a Speckle Object
if (const FObjectProperty* ObjectProperty = CastField<FObjectProperty>(Property))
{
UBase* SpeckleObject;
if(TryParseSpeckleObjectFromJsonProperty(JsonValue, SpeckleObject))
{
ObjectProperty->SetObjectPropertyValue(PropertyValueAddress, SpeckleObject);
DynamicProperties.Remove(Key);
continue;
}
}
//Handle primitive types
if(FJsonObjectConverter::JsonValueToUProperty(JsonValue, Property, PropertyValueAddress, 0, 0))
{
DynamicProperties.Remove(Key);
continue;
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Failed to deserialise a value, object id: %s, property key: %s"), *ObjectId, *Key)
}
}
//Find any remaining Speckle objects and add them as children
TMap<FString, UBase*> ChildBases;
{
const auto DynamicPropertiesCopy = TMap<FString, TSharedPtr<FJsonValue>>(DynamicProperties);
for(const auto& Kvp : DynamicPropertiesCopy)
{
UBase* ChildObject;
if(TryParseSpeckleObjectFromJsonProperty(Kvp.Value, ChildObject))
{
DynamicProperties.Remove(Kvp.Key);
ChildBases.Add(ChildObject->Id, ChildObject);
}
}
}
Base->DynamicProperties = DynamicProperties;
Base->Children = ChildBases;
return Base;
}
bool ASpeckleUnrealManager::TryParseSpeckleObjectFromJsonProperty(const TSharedPtr<FJsonValue> JsonValue, UBase*& OutBase) const
{
const TSharedPtr<FJsonObject>* JsonObjectPtr;
if(JsonValue->TryGetObject(JsonObjectPtr))
{
TSharedPtr<FJsonObject> JsonObject;
if(!ResolveReference(*JsonObjectPtr, JsonObject))
JsonObject = *JsonObjectPtr;
if(JsonObject.IsValid())
{
//Handle Speckle object types
OutBase = DeserializeBase(JsonObject);
return IsValid(OutBase);
}
}
return false;
}
void Test(const TSharedPtr<FJsonValue> JsonValue, const FProperty* Property, UObject* Base)
{
if (const FNumericProperty* NumericProperty = CastField<FNumericProperty>(Property))
{
if (NumericProperty->IsFloatingPoint())
{
NumericProperty->SetFloatingPointPropertyValue(Base, JsonValue->AsNumber());
}
else if (NumericProperty->IsInteger())
{
NumericProperty->SetIntPropertyValue(Base, (int64)JsonValue->AsNumber());
}
}
else if (const FBoolProperty* BoolProperty = CastField<FBoolProperty>(Property))
{
// Export bools as bools
BoolProperty->SetPropertyValue(Base, JsonValue->AsBool());
}
else if (const FStrProperty* StringProperty = CastField<FStrProperty>(Property))
{
StringProperty->SetPropertyValue(Base, JsonValue->AsString());
}
else if (const FMapProperty* MapProperty = CastField<FMapProperty>(Property))
{
}
else if (const FSetProperty* SetProperty = CastField<FSetProperty>(Property))
{
}
else if (const FArrayProperty* ArrayProperty = CastField<FArrayProperty>(Property))
{
if (JsonValue->Type != EJson::Array) return;
const TArray< TSharedPtr<FJsonValue> > ArrayValue = JsonValue->AsArray();
int32 ArrLen = ArrayValue.Num();
// make the output array size match
}
else if (const FStructProperty *StructProperty = CastField<FStructProperty>(Property))
{
}
else if (const FObjectProperty *ObjectProperty = CastField<FObjectProperty>(Property))
{
}
else
{
}
}
bool ASpeckleUnrealManager::HasObject(const FString& Id) const
{
return SpeckleObjects.Contains(Id);
@@ -139,7 +310,7 @@ TSharedPtr<FJsonObject, ESPMode::Fast> ASpeckleUnrealManager::GetSpeckleObject(c
bool ASpeckleUnrealManager::ResolveReference(const TSharedPtr<FJsonObject> Object, TSharedPtr<FJsonObject>& OutObject) const
{
FString SpeckleType;
FString SpeckleType;
FString ReferenceID;
if (Object->TryGetStringField("speckle_type", SpeckleType)
-29
View File
@@ -1,29 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
//#pragma once
//#include "CoreMinimal.h"
//#include "Client.generated.h"
//
// /**
// *
// */
// UCLASS()
// class SPECKLEUNREAL_API UClient : public UClass
// {
// GENERATED_BODY()
//
// public:
//
// static int DefaultBranchLimit = 10;
//
// //UFUNCTION(BlueprintPure, Category="Speckle")
// //void GetAccounts();
//
// //UFUNCTION(BlueprintPure, Category="Speckle")
// //Branch StreamGetBranches(FString StreamID, int BranchesLimit = DefaultBranchLimit, int CommitLimit = DefaultBranchLimit);
//
//
// };
@@ -1,13 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
/**
*
*/
class FSpeckleTypeConverter
{
};
@@ -1,21 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "SpeckleOperationsComponent.generated.h"
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class SPECKLEUNREAL_API USpeckleOperationsComponent : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
USpeckleOperationsComponent();
};
@@ -0,0 +1,31 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "ConversionUtils.generated.h"
/**
*
*/
UCLASS()
class SPECKLEUNREAL_API UConversionUtils : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Speckle|Conversion Utilities")
static FMatrix TransformToNative(const TArray<float>& TransformData);
//Parses units string into
UFUNCTION(BlueprintCallable, BlueprintPure)
static float GetUnitsScaleFactorF(const FString& Units, const float WorldToCentimeters = 1);
UFUNCTION(BlueprintCallable, BlueprintPure)
static float GetUnitsScaleFactor(const FString& Units, const UWorld* World = nullptr);
//Safely try and get the WorldToCentimeters unit scale factor from the given world.
UFUNCTION(BlueprintCallable, BlueprintPure)
static bool TryGetWorldUnits(const UWorld* World, int32& OutWorldToCentimeters);
};
@@ -3,7 +3,7 @@
#pragma once
#include "CoreMinimal.h"
#include "Conversion/SpeckleConverter.h"
#include "Conversion/SpeckleTypeConverter.h"
#include "PointCloudConverter.generated.h"
@@ -13,7 +13,7 @@ class ULidarPointCloud;
class UPointCloud;
UCLASS()
class SPECKLEUNREAL_API UPointCloudConverter : public UObject, public ISpeckleConverter
class SPECKLEUNREAL_API UPointCloudConverter : public UObject, public ISpeckleTypeConverter
{
GENERATED_BODY()
@@ -3,7 +3,7 @@
#pragma once
#include "CoreMinimal.h"
#include "Conversion/SpeckleConverter.h"
#include "Conversion/SpeckleTypeConverter.h"
#include "ProceduralMeshConverter.generated.h"
@@ -12,7 +12,7 @@ class UMesh;
class URenderMaterial;
UCLASS()
class SPECKLEUNREAL_API UProceduralMeshConverter : public UObject, public ISpeckleConverter
class SPECKLEUNREAL_API UProceduralMeshConverter : public UObject, public ISpeckleTypeConverter
{
GENERATED_BODY()
@@ -27,6 +27,9 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TSubclassOf<AActor> MeshActorType;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool bCreateCollisions;
// Sets default values for this actor's properties
UProceduralMeshConverter();
@@ -3,7 +3,7 @@
#pragma once
#include "CoreMinimal.h"
#include "Conversion/SpeckleConverter.h"
#include "Conversion/SpeckleTypeConverter.h"
#include "StaticMeshConverter.generated.h"
@@ -12,7 +12,7 @@ class UMesh;
class URenderMaterial;
UCLASS()
class SPECKLEUNREAL_API UStaticMeshConverter : public UObject, public ISpeckleConverter
class SPECKLEUNREAL_API UStaticMeshConverter : public UObject, public ISpeckleTypeConverter
{
GENERATED_BODY()
@@ -6,11 +6,14 @@
#include "Components/ActorComponent.h"
#include "SpeckleConverterComponent.generated.h"
class USpeckleConverter;
class USpeckleTypeConverter;
class ASpeckleUnrealManager;
class UBase;
class ISpeckleConverter;
class ISpeckleTypeConverter;
/**
* This component contains modular conversion functions for converting Speckle Objects <--> Native Unreal Objects.
*/
UCLASS(ClassGroup=(Speckle), meta=(BlueprintSpawnableComponent))
class SPECKLEUNREAL_API USpeckleConverterComponent : public UActorComponent
{
@@ -19,7 +22,7 @@ class SPECKLEUNREAL_API USpeckleConverterComponent : public UActorComponent
protected:
// A lazily initialised mapping of SpeckleType -> converters.
TMap<TSubclassOf<UBase>, TScriptInterface<ISpeckleConverter>> SpeckleTypeMap;
TMap<TSubclassOf<UBase>, TScriptInterface<ISpeckleTypeConverter>> SpeckleTypeMap;
public:
@@ -45,7 +48,7 @@ public:
AActor* ConvertToNative(const UBase* Object, ASpeckleUnrealManager* Manager);
UFUNCTION(BlueprintCallable, Category="Speckle|Conversion")
TScriptInterface<ISpeckleConverter> GetConverter(const TSubclassOf<UBase> BaseType);
TScriptInterface<ISpeckleTypeConverter> GetConverter(const TSubclassOf<UBase> BaseType);
};
@@ -6,22 +6,29 @@
#include "Objects/Base.h"
#include "UObject/Interface.h"
#include "SpeckleConverter.generated.h"
#include "SpeckleTypeConverter.generated.h"
class UBase;
class ASpeckleUnrealManager;
// This class does not need to be modified.
UINTERFACE()
class USpeckleConverter : public UInterface
class USpeckleTypeConverter : public UInterface
{
GENERATED_BODY()
};
/**
* Interfaces for conversion functions (ToSpeckle and ToNative) of a specific native type.
* Interfaces for object conversion functions (ToSpeckle and ToNative) of a specific (most likely single) native type.
*
* Classes implementing this function are responsible for converting one or more UBase types
* to a native AActor. (ToNative)
* And/Or
* Converting one or more AActor types to a UBase type.
*
* Note: This interface is not equivalent to ISpeckleConverter in the .NET SDK.
*/
class SPECKLEUNREAL_API ISpeckleConverter
class SPECKLEUNREAL_API ISpeckleTypeConverter
{
GENERATED_BODY()
+10 -5
View File
@@ -43,11 +43,16 @@ public:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Speckle|Objects")
FString SpeckleType;
//TODO this won't be serialised
TMap<FString, TSharedPtr<FJsonValue>> DynamicProperties;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Speckle|Objects")
TMap<FString, UBase*> Children;
virtual void Parse(const TSharedPtr<FJsonObject> Obj, const ASpeckleUnrealManager* Manager)
{
Obj->TryGetStringField("id", Id);
Obj->TryGetStringField("units", Units);
}
/// Callback called right before serialization of this object
virtual void OnBeforeSerialize();
/// Callback called right after deserialization of this object
virtual void OnAfterDeserialize();
};
+39 -8
View File
@@ -22,25 +22,56 @@ public:
UMesh() : UBase(TEXT("Objects.Geometry.Mesh")) {}
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
TArray<FVector> Vertices;
TArray<float> Vertices;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
TArray<int32> Faces;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
TArray<FVector2D> TextureCoordinates;
TArray<float> TextureCoordinates;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
TArray<FColor> VertexColors;
TArray<int32> Colors;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
FMatrix Transform;
TArray<float> Transform;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
URenderMaterial* RenderMaterial;
virtual void Parse(const TSharedPtr<FJsonObject> Obj, const ASpeckleUnrealManager* Manager) override;
protected:
public:
UFUNCTION(BlueprintPure)
FVector GetVert(int32 Index) const;
UFUNCTION(BlueprintPure)
TArray<FVector> GetVerts() const;
UFUNCTION(BlueprintPure)
int32 GetVertexCount() const { return Vertices.Num() / 3; }
UFUNCTION(BlueprintPure)
FVector2D GetTextureCoordinate(int32 Index) const;
UFUNCTION(BlueprintPure)
TArray<FVector2D> GetTextureCoordinates() const;
UFUNCTION(BlueprintPure)
int32 GetTexCoordCount() const { return TextureCoordinates.Num() / 2; }
UFUNCTION(BlueprintPure)
FORCEINLINE FColor GetVertexColor(int32 Index) const;
UFUNCTION(BlueprintPure)
TArray<FColor> GetVertexColors() const;
UFUNCTION(BlueprintPure)
FMatrix GetTransform() const;
UFUNCTION(BlueprintCallable)
void SetTransform(const FMatrix& T);
UFUNCTION()
virtual void AlignVerticesWithTexCoordsByIndex();
UFUNCTION()
virtual void ApplyScaleFactor(const float ScaleFactor);
UFUNCTION()
virtual void ApplyUnits(const UWorld* World);
};
@@ -19,10 +19,10 @@ public:
UPointCloud() : UBase(TEXT("Objects.Other.Pointcloud")) {}
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
TArray<FVector> Points;
TArray<float> Points;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
TArray<FColor> Colors;
TArray<int32> Colors;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Speckle|Objects")
TArray<float> Sizes;
@@ -32,10 +32,12 @@ public:
double Roughness = 1;
UPROPERTY()
FLinearColor Diffuse = FColor{221,221,221};
int32 Diffuse = FColor{221,221,221};
UPROPERTY()
FLinearColor Emissive = FLinearColor::Black;
int32 Emissive = FLinearColor::Black;
virtual void Parse(const TSharedPtr<FJsonObject> Obj, const ASpeckleUnrealManager* Manager) override
{
@@ -0,0 +1,23 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "BaseObjectSerializer.generated.h"
class UBase;
/**
*
*/
UCLASS()
class SPECKLEUNREAL_API UBaseObjectSerializer : public UObject
{
GENERATED_BODY()
public:
//UFUNCTION()
//UBase* DeserialiseBase();
};
@@ -119,6 +119,8 @@ protected:
float WorldToCentimeters;
bool TryParseSpeckleObjectFromJsonProperty(const TSharedPtr<FJsonValue> JsonValue, UBase*& OutBase) const;
TMap<FString, TSharedPtr<FJsonObject>> SpeckleObjects;
UPROPERTY()