October3d55/M/PICOOpen7991a2a23d57V5/Source/PICOOpenXRPassthrough/Private/PICO_PassthroughLayer.cpp

497 lines
14 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "PICO_PassthroughLayer.h"
#include "PICO_PassthroughLayerShape.h"
#include "Curves/CurveLinearColor.h"
#include "PICO_PassthroughModule.h"
#include "Components/StaticMeshComponent.h"
#include "Engine/StaticMesh.h"
#include "StaticMeshResources.h"
void UPassthroughFullScreenLayerPICO::ApplyShape(IStereoLayers::FLayerDesc& LayerDesc)
{
const FVSTEdgeStyleParametersPICO EdgeStyleParameters(bEnableEdgeColor, bEnableColorMap, TextureOpacityFactor, Brightness, Contrast, Posterize, Saturation, EdgeColor, ColorScale, ColorOffset, ColorMapType, GetColorMapGradient(bUseColorMapCurve, ColorMapCurve));
LayerDesc.SetShape<FFullScreenLayerShapePICO>(EdgeStyleParameters, LayerOrder);
}
void UPassthroughCustomShapeLayerPICO::AddGeometry(const FString& MeshName, FPICOPassthroughMeshRef PassthroughMesh, FTransform Transform, bool bUpdateTransform)
{
FCustomShapeGeometryDescPICO CustomShapeGeometryDesc(
MeshName,
PassthroughMesh,
Transform,
bUpdateTransform);
UserGeometryList.Add(CustomShapeGeometryDesc);
}
void UPassthroughCustomShapeLayerPICO::RemoveGeometry(const FString& MeshName)
{
UserGeometryList.RemoveAll([MeshName](const FCustomShapeGeometryDescPICO& Desc) {
return Desc.MeshName == MeshName;
});
}
void UPassthroughCustomShapeLayerPICO::ApplyShape(IStereoLayers::FLayerDesc& LayerDesc)
{
const FVSTEdgeStyleParametersPICO EdgeStyleParameters(bEnableEdgeColor, bEnableColorMap, TextureOpacityFactor, Brightness, Contrast, Posterize, Saturation, EdgeColor, ColorScale, ColorOffset, ColorMapType, GetColorMapGradient(bUseColorMapCurve, ColorMapCurve));
LayerDesc.SetShape<FCustomShapeLayerShapePICO>(UserGeometryList, EdgeStyleParameters, LayerOrder);
}
void UPassthroughLayerBasePICO::SetTextureOpacity(float InOpacity)
{
if (TextureOpacityFactor == InOpacity)
{
return;
}
TextureOpacityFactor = InOpacity;
MarkStereoLayerDirty();
}
void UPassthroughLayerBasePICO::EnableEdgeColor(bool bInEnableEdgeColor)
{
if (bEnableEdgeColor == bInEnableEdgeColor)
{
return;
}
bEnableEdgeColor = bInEnableEdgeColor;
MarkStereoLayerDirty();
}
void UPassthroughLayerBasePICO::EnableColorMap(bool bInEnableColorMap)
{
if (bEnableColorMap == bInEnableColorMap)
{
return;
}
bEnableColorMap = bInEnableColorMap;
MarkStereoLayerDirty();
}
void UPassthroughLayerBasePICO::EnableColorMapCurve(bool bInEnableColorMapCurve)
{
if (bUseColorMapCurve == bInEnableColorMapCurve)
{
return;
}
bUseColorMapCurve = bInEnableColorMapCurve;
ColorMapGradient = GenerateColorMapGradient(bUseColorMapCurve, ColorMapCurve);
MarkStereoLayerDirty();
}
void UPassthroughLayerBasePICO::SetEdgeRenderingColor(FLinearColor InEdgeColor)
{
if (EdgeColor == InEdgeColor)
{
return;
}
EdgeColor = InEdgeColor;
MarkStereoLayerDirty();
}
void UPassthroughLayerBasePICO::SetColorMapControls(float InContrast, float InBrightness, float InPosterize)
{
if (ColorMapType != EColorMapTypePICO::ColorMapType_Grayscale && ColorMapType != EColorMapTypePICO::ColorMapType_GrayscaleToColor) {
UE_LOG(LogPassthroughPICO, Warning, TEXT("SetColorMapControls is ignored for color map types other than Grayscale and Grayscale to color."));
return;
}
Contrast = FMath::Clamp(InContrast, -1.0f, 1.0f);
Brightness = FMath::Clamp(InBrightness, -1.0f, 1.0f);
Posterize = FMath::Clamp(InPosterize, 0.0f, 1.0f);
MarkStereoLayerDirty();
}
void UPassthroughLayerBasePICO::SetBrightnessContrastSaturation(float InContrast, float InBrightness, float InSaturation)
{
if (ColorMapType != EColorMapTypePICO::ColorMapType_ColorAdjustment) {
UE_LOG(LogPassthroughPICO, Warning, TEXT("SetBrightnessContrastSaturation is ignored for color map types other than Color Adjustment."));
return;
}
Contrast = FMath::Clamp(InContrast, -1.0f, 1.0f);
Brightness = FMath::Clamp(InBrightness, -1.0f, 1.0f);
Saturation = FMath::Clamp(InSaturation, -1.0f, 1.0f);
MarkStereoLayerDirty();
}
void UPassthroughLayerBasePICO::SetColorScaleAndOffset(FLinearColor InColorScale, FLinearColor InColorOffset)
{
if (ColorScale == InColorScale && ColorOffset == InColorOffset)
{
return;
}
ColorScale = InColorScale;
ColorOffset = InColorOffset;
MarkStereoLayerDirty();
}
void UPassthroughLayerBasePICO::SetColorMapCurve(UCurveLinearColor* InColorMapCurve)
{
if (ColorMapCurve == InColorMapCurve)
{
return;
}
ColorMapCurve = InColorMapCurve;
ColorMapGradient = GenerateColorMapGradient(bUseColorMapCurve, ColorMapCurve);
MarkStereoLayerDirty();
}
void UPassthroughLayerBasePICO::SetColorMapGradient(const TArray<FLinearColor>& InColorMapGradient)
{
if (InColorMapGradient.Num() == 0)
{
return;
}
if (ColorMapType != EColorMapTypePICO::ColorMapType_GrayscaleToColor) {
UE_LOG(LogPassthroughPICO, Warning, TEXT("SetColorMapGradient is ignored for color map types other than Grayscale to Color."));
return;
}
if (bUseColorMapCurve)
{
UE_LOG(LogPassthroughPICO, Warning, TEXT("UseColorMapCurve is enabled on the layer. Automatic disable and use the Array for color lookup"));
}
bUseColorMapCurve = false;
ColorMapGradient = InColorMapGradient;
MarkStereoLayerDirty();
}
void UPassthroughLayerBasePICO::ClearColorMap()
{
ColorMapGradient.Empty();
}
void UPassthroughLayerBasePICO::SetColorMapType(EColorMapTypePICO InColorMapType)
{
if (ColorMapType == InColorMapType)
{
return;
}
ColorMapType = InColorMapType;
MarkStereoLayerDirty();
}
void UPassthroughLayerBasePICO::SetLayerPlacement(EPassthroughLayerOrderPICO InLayerOrder)
{
if (LayerOrder == InLayerOrder)
{
UE_LOG(LogPassthroughPICO, Warning, TEXT("Same layer order as before, no change needed"));
return;
}
LayerOrder = InLayerOrder;
this->MarkStereoLayerDirty();
}
void UPassthroughLayerBasePICO::MarkStereoLayerDirty()
{
check(GetOuter()->IsA<UPassthroughLayerComponentPICO>());
Cast<UPassthroughLayerComponentPICO>(GetOuter())->MarkStereoLayerDirty();
}
TArray<FLinearColor> UPassthroughLayerBasePICO::GenerateColorGradientFromColorCurve(const UCurveLinearColor* InColorMapCurve) const
{
if (InColorMapCurve == nullptr)
{
return TArray<FLinearColor>();
}
TArray<FLinearColor> Gradient;
constexpr uint32 TotalEntries = 256;
Gradient.Empty();
Gradient.SetNum(TotalEntries);
for (int32 Index = 0; Index < TotalEntries; ++Index)
{
const float Alpha = ((float)Index / TotalEntries);
Gradient[Index] = InColorMapCurve->GetLinearColorValue(Alpha);
}
return Gradient;
}
TArray<FLinearColor> UPassthroughLayerBasePICO::GetOrGenerateNeutralColorMapGradient()
{
if (NeutralMapGradient.Num() == 0) {
const uint32 TotalEntries = 256;
NeutralMapGradient.SetNum(TotalEntries);
for (int32 Index = 0; Index < TotalEntries; ++Index)
{
NeutralMapGradient[Index] = FLinearColor((float)Index / TotalEntries, (float)Index / TotalEntries, (float)Index / TotalEntries);
}
}
return NeutralMapGradient;
}
TArray<FLinearColor> UPassthroughLayerBasePICO::GetColorMapGradient(bool bInUseColorMapCurve, const UCurveLinearColor* InColorMapCurve)
{
if (ColorMapGradient.Num() == 0) {
if (bInUseColorMapCurve) {
return GenerateColorMapGradient(bInUseColorMapCurve, InColorMapCurve);
}
return GetOrGenerateNeutralColorMapGradient();
}
return ColorMapGradient;
}
TArray<FLinearColor> UPassthroughLayerBasePICO::GenerateColorMapGradient(bool bInUseColorMapCurve, const UCurveLinearColor* InColorMapCurve)
{
TArray<FLinearColor> NewColorGradient;
if (bInUseColorMapCurve)
{
NewColorGradient = GenerateColorGradientFromColorCurve(InColorMapCurve);
}
// Check for existing gradient, otherwise generate a neutral one
if (NewColorGradient.Num() == 0)
{
NewColorGradient = GetOrGenerateNeutralColorMapGradient();
}
return NewColorGradient;
}
UPassthroughLayerComponentPICO::UPassthroughLayerComponentPICO(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
void UPassthroughLayerComponentPICO::OnUnregister()
{
Super::OnUnregister();
passthroughLayerId = FPICOOpenXRPassthroughModule::Get().GetPassthroughPlugin().DestroyPassthroughLayer(passthroughLayerId);
passthroughLayerId = 0;
}
void UPassthroughLayerComponentPICO::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
FTransform Transform;
if (StereoLayerType == SLT_WorldLocked)
{
Transform = GetComponentTransform();
}
else
{
Transform = GetRelativeTransform();
}
if (!bIsDirty && (bLastVisible != GetVisibleFlag() || FMemory::Memcmp(&LastTransform, &Transform, sizeof(Transform)) != 0))
{
bIsDirty = true;
}
bool bCurrVisible = GetVisibleFlag();
if (bIsDirty)
{
IStereoLayers::FLayerDesc LayerDesc;
LayerDesc.Priority = Priority;
LayerDesc.QuadSize = QuadSize;
LayerDesc.UVRect = UVRect;
LayerDesc.Transform = Transform;
LayerDesc.Flags |= (bLiveTexture) ? IStereoLayers::LAYER_FLAG_TEX_CONTINUOUS_UPDATE : 0;
LayerDesc.Flags |= (bNoAlphaChannel) ? IStereoLayers::LAYER_FLAG_TEX_NO_ALPHA_CHANNEL : 0;
LayerDesc.Flags |= (bQuadPreserveTextureRatio) ? IStereoLayers::LAYER_FLAG_QUAD_PRESERVE_TEX_RATIO : 0;
LayerDesc.Flags |= (bSupportsDepth) ? IStereoLayers::LAYER_FLAG_SUPPORT_DEPTH : 0;
LayerDesc.Flags |= (!bCurrVisible) ? IStereoLayers::LAYER_FLAG_HIDDEN : 0;
switch (StereoLayerType)
{
case SLT_WorldLocked:
LayerDesc.PositionType = IStereoLayers::WorldLocked;
break;
case SLT_TrackerLocked:
LayerDesc.PositionType = IStereoLayers::TrackerLocked;
break;
case SLT_FaceLocked:
LayerDesc.PositionType = IStereoLayers::FaceLocked;
break;
}
if (Shape == nullptr)
{
return;
}
Shape->ApplyShape(LayerDesc);
if (passthroughLayerId)
{
FPICOOpenXRPassthroughModule::Get().GetPassthroughPlugin().SetLayerDesc(passthroughLayerId, LayerDesc);
}
else
{
passthroughLayerId = FPICOOpenXRPassthroughModule::Get().GetPassthroughPlugin().CreatePassthroughLayer(LayerDesc);
}
LastTransform = Transform;
bLastVisible = bCurrVisible;
bIsDirty = false;
}
UpdatePassthroughObjects();
}
void UPassthroughLayerComponentPICO::UpdatePassthroughObjects()
{
UPassthroughCustomShapeLayerPICO* UserShape = Cast<UPassthroughCustomShapeLayerPICO>(Shape);
if (UserShape)
{
bool bDirty = false;
for (FCustomShapeGeometryDescPICO& Entry : UserShape->GetUserGeometryList())
{
if (Entry.bUpdateTransform)
{
AStaticMeshActor** StaticMeshActor = PassthroughActorMap.Find(Entry.MeshName);
if (StaticMeshActor)
{
UStaticMeshComponent* StaticMeshComponent = (*StaticMeshActor)->GetStaticMeshComponent();
if (StaticMeshComponent)
{
Entry.Transform = StaticMeshComponent->GetComponentTransform();
bDirty = true;
}
}
}
}
if (bDirty) {
MarkStereoLayerDirty();
}
}
}
void UPassthroughLayerComponentPICO::AddSurfaceGeometryPICO(AStaticMeshActor* StaticMeshActor, bool updateTransform)
{
if (StaticMeshActor == nullptr)
{
UE_LOG(LogPassthroughPICO, Error, TEXT("StaticMeshActor is NULL."));
return;
}
UPassthroughCustomShapeLayerPICO* UserShape = Cast<UPassthroughCustomShapeLayerPICO>(Shape);
if (UserShape == nullptr)
{
UE_LOG(LogPassthroughPICO, Warning, TEXT("Surface geometry can be only assign to passthrough layer with `User Defined` shape."));
return;
}
UStaticMeshComponent* StaticMeshComponent = StaticMeshActor->GetStaticMeshComponent();
if (StaticMeshComponent == nullptr || StaticMeshComponent->GetStaticMesh() == nullptr)
{
UE_LOG(LogPassthroughPICO, Warning, TEXT("Static mesh actor does not have mesh component."));
PassthroughActorMap.Add(StaticMeshActor->GetFullName(), StaticMeshActor);
MarkStereoLayerDirty();
return;
}
FPICOPassthroughMeshRef PassthroughMesh = CreatePassthroughMesh(StaticMeshComponent->GetStaticMesh());
if (PassthroughMesh)
{
const FString MeshName = StaticMeshActor->GetFullName();
const FTransform Transform = StaticMeshComponent->GetComponentTransform();
UserShape->AddGeometry(MeshName, PassthroughMesh, Transform, updateTransform);
}
PassthroughActorMap.Add(StaticMeshActor->GetFullName(), StaticMeshActor);
MarkStereoLayerDirty();
}
void UPassthroughLayerComponentPICO::RemoveSurfaceGeometryPICO(AStaticMeshActor* StaticMeshActor)
{
if (StaticMeshActor)
{
UPassthroughCustomShapeLayerPICO* UserShape = Cast<UPassthroughCustomShapeLayerPICO>(Shape);
if (UserShape)
{
UStaticMeshComponent* StaticMeshComponent = StaticMeshActor->GetStaticMeshComponent();
if (StaticMeshComponent)
{
UStaticMesh* StaticMesh = StaticMeshComponent->GetStaticMesh();
if (StaticMesh)
{
const FString MeshName = StaticMeshActor->GetFullName();
UserShape->RemoveGeometry(MeshName);
}
}
PassthroughActorMap.Remove(StaticMeshActor->GetFullName());
}
}
MarkStereoLayerDirty();
}
bool UPassthroughLayerComponentPICO::IsSurfaceGeometryPICO(AStaticMeshActor* StaticMeshActor) const
{
if (StaticMeshActor)
{
UPassthroughCustomShapeLayerPICO* UserShape = Cast<UPassthroughCustomShapeLayerPICO>(Shape);
if (UserShape)
{
return PassthroughActorMap.Contains(StaticMeshActor->GetFullName());
}
}
return false;
}
void UPassthroughLayerComponentPICO::MarkPassthroughStyleForUpdatePICO()
{
bPassthroughStyleNeedsUpdate = true;
}
bool UPassthroughLayerComponentPICO::PausePassthroughPICO()
{
return FPICOOpenXRPassthroughModule::Get().GetPassthroughPlugin().PausePassthroughLayer(passthroughLayerId);;
}
bool UPassthroughLayerComponentPICO::ResumePassthroughPICO()
{
return FPICOOpenXRPassthroughModule::Get().GetPassthroughPlugin().ResumePassthroughLayer(passthroughLayerId);;
}
FPICOPassthroughMeshRef UPassthroughLayerComponentPICO::CreatePassthroughMesh(UStaticMesh* Mesh)
{
if (!Mesh || !Mesh->GetRenderData())
{
UE_LOG(LogPassthroughPICO, Error, TEXT("Passthrough Static Mesh has no Renderdata"));
return nullptr;
}
if (Mesh->GetNumLODs() == 0)
{
UE_LOG(LogPassthroughPICO, Error, TEXT("Passthrough Static Mesh has no LODs"));
return nullptr;
}
if (!Mesh->bAllowCPUAccess)
{
UE_LOG(LogPassthroughPICO, Error, TEXT("Passthrough Static Mesh Requires CPU Access"));
return nullptr;
}
const int32 LODIndex = 0;
FStaticMeshLODResources& LOD = Mesh->GetRenderData()->LODResources[LODIndex];
TArray<int32> Triangles;
const int32 NumIndices = LOD.IndexBuffer.GetNumIndices();
for (int32 i = 0; i < NumIndices; ++i)
{
Triangles.Add(LOD.IndexBuffer.GetIndex(i));
}
TArray<FVector> Vertices;
const int32 NumVertices = LOD.VertexBuffers.PositionVertexBuffer.GetNumVertices();
for (int32 i = 0; i < NumVertices; ++i)
{
Vertices.Add((FVector)LOD.VertexBuffers.PositionVertexBuffer.VertexPosition(i));
}
FPICOPassthroughMeshRef PassthroughMesh = new FPassthroughMeshPICO(Vertices, Triangles);
return PassthroughMesh;
}