// Copyright Epic Games, Inc. All Rights Reserved. #include "DataVisualizations/PCGSplineDataVisualization.h" #include "PCGContext.h" #include "Data/PCGPointData.h" #include "Data/PCGSplineData.h" #include "Data/PCGSplineStruct.h" #include "DataVisualizations/PCGDataVisualizationHelpers.h" #include "AdvancedPreviewScene.h" #include "EditorViewportClient.h" #include "Components/SplineComponent.h" #define LOCTEXT_NAMESPACE "PCGSplineDataVisualization" namespace PCGSplineDataVisualizationConstants { const FVector HalfExtents = FVector(50.0); // Set the points to fill up 1 meter of space by default. } FPCGTableVisualizerInfo IPCGSplineDataVisualization::GetTableVisualizerInfoWithDomain(const UPCGData* Data, const FPCGMetadataDomainID& DomainID) const { using namespace PCGDataVisualizationHelpers; const UPCGSplineData* SplineData = CastChecked(Data); FPCGTableVisualizerInfo Info; Info.Data = SplineData; if (DomainID == PCGMetadataDomainID::Data) { // Column Sorting FPCGAttributePropertySelector IndexSelector = FPCGAttributePropertySelector::CreateExtraPropertySelector(EPCGExtraProperties::Index); IndexSelector.SetDomainName(PCGDataConstants::DataDomainName); AddColumnInfo(Info, SplineData, IndexSelector); Info.SortingColumn = Info.ColumnInfos.Last().Id; // Columns AddPropertyEnumColumnInfo(Info, SplineData, EPCGSplineDataProperties::SplineTransform); AddPropertyEnumColumnInfo(Info, SplineData, EPCGSplineDataProperties::IsClosed); // Add Metadata Columns CreateMetadataColumnInfos(SplineData, Info, PCGMetadataDomainID::Data); return Info; } // Column Sorting AddColumnInfo(Info, SplineData, FPCGAttributePropertySelector::CreateExtraPropertySelector(EPCGExtraProperties::Index)); Info.SortingColumn = Info.ColumnInfos.Last().Id; // Columns AddPropertyEnumColumnInfo(Info, SplineData, EPCGSplineStructProperties::Position); AddPropertyEnumColumnInfo(Info, SplineData, EPCGSplineStructProperties::Rotation); AddPropertyEnumColumnInfo(Info, SplineData, EPCGSplineStructProperties::Scale); AddPropertyEnumColumnInfo(Info, SplineData, EPCGSplineStructProperties::LocalPosition); AddPropertyEnumColumnInfo(Info, SplineData, EPCGSplineStructProperties::LocalRotation); AddPropertyEnumColumnInfo(Info, SplineData, EPCGSplineStructProperties::LocalScale); AddPropertyEnumColumnInfo(Info, SplineData, EPCGSplineStructProperties::ArriveTangent); AddPropertyEnumColumnInfo(Info, SplineData, EPCGSplineStructProperties::LeaveTangent); AddPropertyEnumColumnInfo(Info, SplineData, EPCGSplineStructProperties::InterpType); // Add Metadata Columns CreateMetadataColumnInfos(SplineData, Info, PCGMetadataDomainID::Elements); // Focus on data behavior if (DomainID == PCGMetadataDomainID::Elements) { Info.FocusOnDataCallback = [](const UPCGData* Data, TArrayView Indices) { if (const UPCGSplineData* SplineData = Cast(Data)) { FBox BoundingBox(EForceInit::ForceInit); if (Indices.IsEmpty()) { BoundingBox = SplineData->GetBounds(); } else { const TArray& Positions = SplineData->SplineStruct.GetSplinePointsPosition().Points; const TArray& Scales = SplineData->SplineStruct.GetSplinePointsScale().Points; for (const int& Index : Indices) { check(Positions.IsValidIndex(Index) && Scales.IsValidIndex(Index)); const FVector& Position = SplineData->GetTransform().TransformPosition(Positions[Index].OutVal); const FVector HalfExtent = Scales[Index].OutVal * PCGSplineDataVisualizationConstants::HalfExtents; FBox PointBoundingBox(Position + HalfExtent, Position - HalfExtent); BoundingBox += PointBoundingBox; } } if (GEditor && BoundingBox.IsValid) { GEditor->MoveViewportCamerasToBox(BoundingBox, /*bActiveViewportOnly=*/true, /*DrawDebugBoxTimeInSeconds=*/2.5f); } } }; } return Info; } const UPCGBasePointData* IPCGSplineDataVisualization::CollapseToDebugBasePointData(FPCGContext* Context, const UPCGData* Data) const { if (const UPCGSplineData* SplineData = Cast(Data)) { UPCGBasePointData* PointData = FPCGContext::NewPointData_AnyThread(Context); FPCGInitializeFromDataParams InitializeFromDataParams(SplineData); PointData->InitializeFromDataWithParams(InitializeFromDataParams); const int32 NumControlPoints = SplineData->SplineStruct.GetSplinePointsPosition().Points.Num(); TConstArrayView EntryKeys = SplineData->SplineStruct.GetConstControlPointsEntryKeys(); PointData->SetNumPoints(NumControlPoints); PointData->SetExtents(PCGSplineDataVisualizationConstants::HalfExtents); PointData->AllocateProperties(EPCGPointNativeProperties::Transform | EPCGPointNativeProperties::MetadataEntry); TPCGValueRange TransformRange = PointData->GetTransformValueRange(/*bAllocate=*/false); TPCGValueRange MetadataEntryRange = PointData->GetMetadataEntryValueRange(/*bAllocate=*/false); for (int ControlPointIndex = 0; ControlPointIndex < NumControlPoints; ++ControlPointIndex) { TransformRange[ControlPointIndex] = SplineData->SplineStruct.GetTransformAtSplineInputKey(ControlPointIndex, ESplineCoordinateSpace::World); MetadataEntryRange[ControlPointIndex] = EntryKeys.IsValidIndex(ControlPointIndex) ? EntryKeys[ControlPointIndex] : PCGInvalidEntryKey; } if (SplineData->HasCachedLastSelector()) { PointData->SetLastSelector(SplineData->GetCachedLastSelector()); } return PointData; } return nullptr; } FPCGSetupSceneFunc IPCGSplineDataVisualization::GetViewportSetupFunc(const UPCGData* Data) const { return[this, Data](FPCGSceneSetupParams& InOutParams) { check(InOutParams.Scene); check(InOutParams.EditorViewportClient); const UPCGSplineData* SplineData = Cast(Data); if (!SplineData) { return; } TObjectPtr SplineComponent = NewObject(GetTransientPackage(), NAME_None, RF_Transient); SplineData->ApplyTo(SplineComponent); if (GEditor->PreviewPlatform.GetEffectivePreviewFeatureLevel() <= ERHIFeatureLevel::ES3_1) { SplineComponent->SetMobility(EComponentMobility::Static); } InOutParams.ManagedResources.Add(SplineComponent); InOutParams.Scene->AddComponent(SplineComponent, SplineComponent->GetComponentToWorld()); FBoxSphereBounds Bounds = SplineComponent->CalcBounds(SplineComponent->GetComponentToWorld()); InOutParams.Scene->SetFloorOffset(-Bounds.Origin.Z + Bounds.BoxExtent.Z); InOutParams.EditorViewportClient->SetViewLocation(Bounds.Origin); if (Bounds.SphereRadius > 0.0f) { InOutParams.EditorViewportClient->SetViewLocationForOrbiting(Bounds.Origin, Bounds.SphereRadius * 2.0f); } }; } #undef LOCTEXT_NAMESPACE