This commit is contained in:
2025-07-14 22:24:27 +08:00
parent daacc18ecf
commit 4af19ef574
7722 changed files with 72086 additions and 0 deletions

View File

@ -0,0 +1,518 @@
// ------------------------------------------------
// Copyright Joe Marshall 2024- All Rights Reserved
// ------------------------------------------------
//
// Renders mesh directly to framebuffer from video
// stream (without texture between)
// ------------------------------------------------
#include "DirectVideoMeshRenderer.h"
#include "AndroidVulkanTextureSample.h"
#include "Components/StaticMeshComponent.h"
#include "Engine/StaticMesh.h"
#include "Engine/StaticMeshActor.h"
#include "EngineModule.h"
#include "IMediaPlayer.h"
#include "RHIResources.h"
#include "RawIndexBuffer.h"
#include "RenderGraphBuilder.h"
#include "Rendering/ColorVertexBuffer.h"
#include "Rendering/PositionVertexBuffer.h"
#include "Rendering/StaticMeshVertexBuffer.h"
#include "SceneView.h"
#include "SceneViewExtension.h"
#include "StaticMeshResources.h"
#include "StereoRendering.h"
#include "Math/Matrix.h"
#include "MeshDescription.h"
DEFINE_LOG_CATEGORY(LogDirectVideoMeshRenderer);
class FRendererSceneViewExt : public FSceneViewExtensionBase
{
public:
FRendererSceneViewExt(const FAutoRegister &AutoRegister,
UDirectVideoMeshRendererComponent &InOwner)
: FSceneViewExtensionBase(AutoRegister), Owner(InOwner)
{
}
virtual void PostRenderView_RenderThread(FRDGBuilder &GraphBuilder, FSceneView &InView) override
{
}
virtual void PostRenderBasePassMobile_RenderThread(FRHICommandList &RHICmdList,
FSceneView &InView) override
{
UE_LOGFMT(LogDirectVideoMeshRenderer, VeryVerbose, "PostRenderBasePassMobile");
#if PLATFORM_ANDROID
Owner.DrawToCommandList(RHICmdList, InView);
#endif
}
virtual void SetupViewFamily(FSceneViewFamily &InViewFamily) override
{
}
virtual void SetupView(FSceneViewFamily &InViewFamily, FSceneView &InView) override
{
}
virtual void PreRenderViewFamily_RenderThread(FRDGBuilder &GraphBuilder,
FSceneViewFamily &InViewFamily)
{
#if PLATFORM_ANDROID
// we are outside of a command list, so we can update the mesh if needed
Owner.DoWorkOutsideRenderPass(GraphBuilder.RHICmdList, InViewFamily);
#endif
}
virtual void PreRenderView_RenderThread(FRDGBuilder &GraphBuilder, FSceneView &InView)
{
}
virtual void BeginRenderViewFamily(FSceneViewFamily &InViewFamily) override
{
Owner.UpdateVisibility();
}
UDirectVideoMeshRendererComponent &Owner;
};
UDirectVideoMeshRendererComponent::UDirectVideoMeshRendererComponent()
{
HideMeshWhileWeHaveVideo = true;
PrimaryComponentTick.bCanEverTick = true;
Initialized = false;
}
UDirectVideoMeshRendererComponent::~UDirectVideoMeshRendererComponent()
{
DeInit();
}
void UDirectVideoMeshRendererComponent::DeInit()
{
Initialized = false;
#if PLATFORM_ANDROID
UE_LOGFMT(LogDirectVideoMeshRenderer, VeryVerbose, "Deinit");
// Extensions clean up on destroy
ExtensionHolder.Reset();
if (PreparedSample != NULL)
{
AndroidVulkanTextureSample *VulkanSample =
static_cast<AndroidVulkanTextureSample *>(PreparedSample.Get());
VulkanSample->ImplDeleted();
}
if (CurrentSample != NULL)
{
AndroidVulkanTextureSample *VulkanSample =
static_cast<AndroidVulkanTextureSample *>(CurrentSample.Get());
VulkanSample->ImplDeleted();
}
CurrentSample = NULL;
PreparedSample = NULL;
if (Facade != NULL)
{
auto PFacade = Facade.Pin();
}
#endif
Facade.Reset();
// the media facade sample sink keeps a weak pointer to
// the texture sink and then clears it if destroyed,
// so we don't need to remove the texture sink, we can just
// kill it here.
TextureSink.Reset();
}
void UDirectVideoMeshRendererComponent::BeginDestroy()
{
DeInit();
UActorComponent::BeginDestroy();
}
void UDirectVideoMeshRendererComponent::Initialize()
{
#if PLATFORM_ANDROID
TextureSink = MakeShared<_TextureSink>(this);
if (Facade == NULL)
{
if (LinkedPlayer != NULL)
{
Facade = LinkedPlayer->GetPlayerFacade();
}
}
if (Facade != NULL)
{
if (!HasAnyFlags(RF_ClassDefaultObject))
{
auto PFacade = Facade.Pin();
TSharedRef<FMediaTextureSampleSink> sinkPtr = TextureSink.ToSharedRef();
PFacade.Get()->AddVideoSampleSink(sinkPtr);
UE_LOGFMT(LogDirectVideoMeshRenderer, VeryVerbose, "Registered for frames");
Initialized = true;
}
}
else
{
UE_LOGFMT(LogDirectVideoMeshRenderer, VeryVerbose, "No media player");
}
GetMeshObject();
if (ExtensionHolder == NULL)
{
ExtensionHolder = FSceneViewExtensions::NewExtension<FRendererSceneViewExt>(*this);
}
#endif
}
void UDirectVideoMeshRendererComponent::HandlePlayerMediaEvent(EMediaSampleSinkEvent Event)
{
int IEvent = (int)Event;
UE_LOGFMT(LogDirectVideoMeshRenderer, VeryVerbose, "Handle event {0}", IEvent);
switch (Event)
{
case EMediaSampleSinkEvent::Detached:
case EMediaSampleSinkEvent::MediaClosed:
CurrentSample = NULL;
PreparedSample = NULL;
break;
}
}
void UDirectVideoMeshRendererComponent::TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction *ThisTickFunction)
{
if (!Initialized)
{
Initialize();
}
}
void UDirectVideoMeshRendererComponent::UpdateVisibility()
{
if (HideMeshWhileWeHaveVideo)
{
MeshActor = GetOwner<AStaticMeshActor>();
if (MeshActor == NULL)
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Warning,
"Mesh renderer has to be on StaticMeshActor");
return;
}
// need to unhide or hide the underlying staticmesh here
// depending on whether we have video
UStaticMeshComponent *MeshComponent = MeshActor->GetStaticMeshComponent();
if (MeshComponent == NULL)
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Warning,
"Mesh renderer needs a static mesh component");
return;
}
MeshComponent->bRenderInDepthPass = 0;
MeshComponent->SetRenderInMainPass(CurrentSample == NULL);
}
}
void UDirectVideoMeshRendererComponent::GetMeshObject()
{
MeshActor = GetOwner<AStaticMeshActor>();
if (MeshActor == NULL)
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Warning,
"Mesh renderer has to be on StaticMeshActor");
return;
}
UStaticMeshComponent *MeshComponent = MeshActor->GetStaticMeshComponent();
TObjectPtr<UStaticMesh> Mesh = MeshComponent->GetStaticMesh();
#if WITH_EDITOR
if (Mesh != NULL)
{
FStaticMeshRenderData *RenderData = Mesh->GetRenderData();
if (RenderData != NULL)
{
const FStaticMeshLODResources &LODRenderData = RenderData->LODResources[0];
const auto &VertexBuffers = LODRenderData.VertexBuffers;
const auto &IndexBuffer = LODRenderData.IndexBuffer; // index buffer for rendering this
if (ConstructMeshFromRenderData(VertexBuffers, IndexBuffer))
{
HasMesh = true;
}
else
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Warning, "Mesh making failed");
}
}
else
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Warning, "No render data");
}
}
else
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Warning, "Mesh is null");
}
#endif
}
void DumpMatrix(const char *Name, FMatrix44f Matrix)
{
char MatrixDesc[256];
int ofs = snprintf(MatrixDesc, 250, "%s:\n", Name);
for (int c = 0; c < 4; c++)
{
for (int d = 0; d < 4; d++)
{
int len = snprintf(&MatrixDesc[ofs], 250 - ofs, "%4.4f,", Matrix.M[c][d]);
ofs += len;
}
MatrixDesc[ofs] = '\n';
ofs++;
}
MatrixDesc[ofs] = 0;
UE_LOGFMT(LogDirectVideoMeshRenderer, Verbose, "{0}", MatrixDesc);
}
void UDirectVideoMeshRendererComponent::DrawToCommandList(FRHICommandList &RHICmdList,
FSceneView &InView)
{
bool hasSample = (PreparedSample != NULL);
#if PLATFORM_ANDROID
UE_LOGFMT(LogDirectVideoMeshRenderer, Verbose, "DrawToCOmmandList_Init:{0} HasSample:{1}",
Initialized, hasSample);
if (!Initialized)
{
return;
}
if (PreparedSample != NULL)
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Verbose, "DrawToCOmmandList:{0}",
RHICmdList.IsOutsideRenderPass());
AndroidVulkanTextureSample *VulkanSample =
static_cast<AndroidVulkanTextureSample *>(PreparedSample.Get());
const FTextureRHIRef &ColourTex = InView.Family->RenderTarget->GetRenderTargetTexture();
VulkanSample->RenderToMesh(ColourTex, RHICmdList, (void *)(MeshActor.Get()));
}
#endif
}
void UDirectVideoMeshRendererComponent::GetShaderInfo(const FSceneView *InView, float *m44,
float *vp44, float *pre_view_translation)
{
FTransform Transform = MeshActor->ActorToWorld();
FMatrix44f LocalToRelativeWorld = FMatrix44f(Transform.ToMatrixWithScale());
// DumpMatrix("Model", LocalToRelativeWorld);
auto TranslatedWorldToClip =
FMatrix44f(InView->ViewMatrices.GetTranslatedViewProjectionMatrix());
// DumpMatrix("VP", TranslatedWorldToClip);
auto MVPMatrix = LocalToRelativeWorld * TranslatedWorldToClip;
// DumpMatrix("MVP", MVPMatrix);
auto Translation = InView->ViewMatrices.GetPreViewTranslation();
FVector4f Translation4 = FVector4f(Translation.X, Translation.Y, Translation.Z, 0);
UE_LOGFMT(LogDirectVideoMeshRenderer, VeryVerbose, "Pre view translation 2:{0},{1},{2},{3}",
Translation4.X, Translation4.Y, Translation4.Z, Translation4.W);
memcpy(vp44, TranslatedWorldToClip.M, 16 * sizeof(float));
// auto TransposedVP=TranslatedWorldToClip.GetTransposed();
// memcpy(vp44,TransposedVP.M,16*sizeof(float));
// auto TransposedM = LocalToRelativeWorld.GetTransposed();
// memcpy(m44,TransposedM.M,16*sizeof(float));
memcpy(m44, LocalToRelativeWorld.M, 16 * sizeof(float));
pre_view_translation[0] = Translation4.X;
pre_view_translation[1] = Translation4.Y;
pre_view_translation[2] = Translation4.Z;
pre_view_translation[3] = Translation4.W;
}
void UDirectVideoMeshRendererComponent::DoWorkOutsideRenderPass(FRHICommandList &RHICmdList,
FSceneViewFamily &InViewFamily)
{
// render both views if we are stereo multiview (with single pass rendering)
#if PLATFORM_ANDROID
if (!Initialized)
{
return;
}
if (CurrentSample != NULL)
{
ShaderViewMatrices ViewMatrices;
ShaderModelMatrix ModelMatrix;
PreparedSample = CurrentSample;
AndroidVulkanTextureSample *VulkanSample =
static_cast<AndroidVulkanTextureSample *>(PreparedSample.Get());
UE_LOGFMT(LogDirectVideoMeshRenderer, VeryVerbose, "Work outside render pass:{0}",
RHICmdList.IsOutsideRenderPass());
for (auto &InView : InViewFamily.Views)
{
if (IStereoRendering::IsASecondaryView(*InView))
{
GetShaderInfo(InView, ModelMatrix.m44, ViewMatrices.vp44_2,
ViewMatrices.pre_view_translation_2);
}
else
{
GetShaderInfo(InView, ModelMatrix.m44, ViewMatrices.vp44,
ViewMatrices.pre_view_translation);
}
}
const FTextureRHIRef &ColourTex = InViewFamily.RenderTarget->GetRenderTargetTexture();
VulkanSample->UpdateViewMatrices(ColourTex, RHICmdList, ViewMatrices,
(void *)(MeshActor.Get()));
VulkanSample->UpdateMesh(ColourTex, RHICmdList, Positions, Indices, ModelMatrix,
(void *)(MeshActor.Get()));
VulkanSample->InitFrameForMeshRendering(ColourTex, RHICmdList, (void *)(MeshActor.Get()));
}
else
{
UE_LOGFMT(LogDirectVideoMeshRenderer, VeryVerbose, "Emptying prepared sample");
PreparedSample = NULL;
}
#endif
}
bool UDirectVideoMeshRendererComponent::Enqueue(
const TSharedRef<IMediaTextureSample, ESPMode::ThreadSafe> &Sample)
{
if (!Initialized)
{
return false;
}
static FGuid OurGUID(0x9bf2d7c6, 0xb2b84d26, 0xb6ae5a3a, 0xc9883569);
auto PFacade = Facade.Pin();
if (PFacade->GetPlayer()->GetPlayerPluginGUID() == OurGUID)
{
CurrentSample = Sample;
UE_LOGFMT(LogDirectVideoMeshRenderer, VeryVerbose, "Mesh component has sample");
}
else
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Warning, "Mesh component has wrong player {0}",
PFacade.Get()->GetGuid());
}
return true;
}
void UDirectVideoMeshRendererComponent::Serialize(FArchive &Ar)
{
/* if(!Ar.IsSaving()){
char bob[119];
Ar.Serialize(bob,119);
return;
}*/
#if WITH_EDITOR
if (Ar.IsSaving())
{
if (!HasMesh)
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Warning, "Needs mesh object");
GetMeshObject();
}
if (!HasMesh)
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Warning,
"Couldn't get mesh for DirectVideoMeshRenderComponent");
}
else
{
UE_LOGFMT(LogDirectVideoMeshRenderer, VeryVerbose, "Saving mesh details");
}
}
#endif
UActorComponent::Serialize(Ar);
if (Ar.IsLoading())
{
if (HasMesh)
{
int NumVertices = PositionsAsFloats.Num() / 5;
Positions.Init({}, NumVertices);
for (int c = 0; c < NumVertices; c++)
{
Positions[c].x = PositionsAsFloats[c * 5];
Positions[c].y = PositionsAsFloats[c * 5 + 1];
Positions[c].z = PositionsAsFloats[c * 5 + 2];
Positions[c].u = PositionsAsFloats[c * 5 + 3];
Positions[c].v = PositionsAsFloats[c * 5 + 4];
}
UE_LOGFMT(LogDirectVideoMeshRenderer, VeryVerbose,
"DirectVideoMeshRenderComponent - Vertices {0} Indices {1}", Indices.Num(),
Positions.Num());
}
else
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Warning,
"No saved mesh for DirectVideoMeshRenderComponent");
}
}
}
bool UDirectVideoMeshRendererComponent::ConstructMeshFromRenderData(
const FStaticMeshVertexBuffers &VertexBuffers, const FRawStaticIndexBuffer &IndexBuffer)
{
const FPositionVertexBuffer &Pos =
VertexBuffers.PositionVertexBuffer; // contains vertex positions
const FStaticMeshVertexBuffer &TangentsAndTextureCoords =
VertexBuffers
.StaticMeshVertexBuffer; // contains tangents, texture coords and lightmap coords
const FColorVertexBuffer &Color = VertexBuffers.ColorVertexBuffer; // vertex colours
if (IndexBuffer.GetIndexDataSize() == 0)
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Warning, "No indices for mesh");
return false;
}
// make 1 buffer with:
// position (float * 3, packed as 4 byte)
// texture coordinates (float*2), packed as 4 byte
int NumVertices = Pos.GetNumVertices();
Positions.Init({}, NumVertices);
int NumIndices = IndexBuffer.GetNumIndices();
Indices.Init({}, NumIndices);
for (int c = 0; c < NumVertices; c++)
{
const FVector3f &VPos = Pos.VertexPosition(c);
Positions[c].x = VPos.X;
Positions[c].y = VPos.Y;
Positions[c].z = VPos.Z;
FVector2f TexPos = TangentsAndTextureCoords.GetVertexUV(c, 0);
Positions[c].u = TexPos.X;
Positions[c].v = TexPos.Y;
}
// and 1 index buffer (int32)
IndexBuffer.GetCopy(Indices);
PositionsAsFloats.Init({}, NumVertices * 5);
for (int c = 0; c < NumVertices; c++)
{
PositionsAsFloats[c * 5] = Positions[c].x;
PositionsAsFloats[c * 5 + 1] = Positions[c].y;
PositionsAsFloats[c * 5 + 2] = Positions[c].z;
PositionsAsFloats[c * 5 + 3] = Positions[c].u;
PositionsAsFloats[c * 5 + 4] = Positions[c].v;
}
return true;
}

View File

@ -0,0 +1,26 @@
#include "Modules/ModuleManager.h"
#define LOCTEXT_NAMESPACE "FVulkanVideoMeshComponentModule"
class FVulkanVideoMeshComponentModule : public IModuleInterface
{
void StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is
// specified in the .uplugin file per-module
// Get the base directory of this plugin
// FString BaseDir = IPluginManager::Get().FindPlugin("AndroidVulkanVideo")->GetBaseDir();
//
}
void ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that
// support dynamic reloading, we call this function before unloading the module.
}
};
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FVulkanVideoMeshComponentModule, VulkanVideoMeshComponent)

View File

@ -0,0 +1,188 @@
// ------------------------------------------------
// Copyright Joe Marshall 2024- All Rights Reserved
// ------------------------------------------------
//
// Attaches to a static mesh, and allows the vertex data
// to be passed into the vulkanimpl for rendering
// ------------------------------------------------
#pragma once
#include "Engine/StaticMesh.h"
#include "Engine/StaticMeshActor.h"
#include "IMediaEventSink.h"
#include "MediaObjectPool.h"
#include "MediaPlayer.h"
#include "MediaPlayerFacade.h"
#include "MediaSampleSink.h"
#include "Logging/StructuredLog.h"
#include "IVulkanVertexData.h"
#include "RendererInterface.h"
#include "DirectVideoMeshRenderer.generated.h"
class AndroidVulkanTextureSample;
class FRendererSceneViewExt;
class FRawStaticIndexBuffer;
struct FStaticMeshVertexBuffers;
DECLARE_LOG_CATEGORY_EXTERN(LogDirectVideoMeshRenderer, Log, All);
UCLASS(Blueprintable, ClassGroup = (Rendering, Common),
hidecategories = (Object, Activation, "Components|Activation"), ShowCategories = (Mobility),
editinlinenew, meta = (BlueprintSpawnableComponent))
class VULKANVIDEOMESHCOMPONENT_API UDirectVideoMeshRendererComponent : public UActorComponent
{
friend class FRendererSceneViewExt;
GENERATED_BODY()
public:
UDirectVideoMeshRendererComponent();
~UDirectVideoMeshRendererComponent();
void HandlePlayerMediaEvent(EMediaSampleSinkEvent Event);
void DeInit();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components|DirectVideo")
UMediaPlayer *LinkedPlayer;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components|DirectVideo")
bool HideMeshWhileWeHaveVideo;
// FMediaTextureSampleSink (called indirectly from _TextureSink)
virtual bool Enqueue(const TSharedRef<IMediaTextureSample, ESPMode::ThreadSafe> &Sample);
virtual int32 Num() const
{
if (CurrentSample.IsValid())
return 1;
return 0;
}
virtual void RequestFlush()
{
CurrentSample.Reset();
PreparedSample.Reset();
}
virtual void BeginDestroy() override;
protected:
// draw to a command list (which is already in a render pass with outputs set up)
void DrawToCommandList(FRHICommandList &RHICmdList, FSceneView &InView);
// load mesh, update matrices, create vulkan images (must be outside render pass)
void DoWorkOutsideRenderPass(FRHICommandList &RHICmdList, FSceneViewFamily &InViewFamily);
void UpdateVisibility();
class _TextureSink : public FMediaTextureSampleSink
{
public:
_TextureSink(UDirectVideoMeshRendererComponent *InOwner)
{
Owner = InOwner;
FlushCount = 0;
EventDelegate =
OnMediaSampleSinkEvent().AddRaw(this, &_TextureSink::ReceiveEventHandler);
}
virtual ~_TextureSink()
{
OnMediaSampleSinkEvent().Remove(EventDelegate);
}
virtual bool Enqueue(
const TSharedRef<IMediaTextureSample, ESPMode::ThreadSafe> &Sample) override
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Verbose, "Enqueue");
auto POwner = Owner.Get();
if (POwner != NULL)
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Verbose, "Enqueue2");
return POwner->Enqueue(Sample);
}
return false;
}
virtual int32 Num() const override
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Verbose, "Num");
auto POwner = Owner.Get();
if (POwner != NULL)
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Verbose, "Num2");
return POwner->Num();
}
return 0;
}
virtual void RequestFlush() override
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Verbose, "Flush");
FlushCount += 1;
auto POwner = Owner.Get();
if (POwner != NULL)
{
UE_LOGFMT(LogDirectVideoMeshRenderer, Verbose, "Flush2");
POwner->RequestFlush();
}
}
void ReceiveEventHandler(EMediaSampleSinkEvent Event, const FMediaSampleSinkEventData &Data)
{
int iEvent = (int)Event;
UE_LOGFMT(LogDirectVideoMeshRenderer, Verbose, "On event:{1}", iEvent);
auto POwner = Owner.Get();
if (POwner != NULL)
{
POwner->HandlePlayerMediaEvent(Event);
}
}
TWeakObjectPtr<UDirectVideoMeshRendererComponent> Owner;
int FlushCount;
FDelegateHandle EventDelegate;
};
void Initialize();
void GetMeshObject();
bool ConstructMeshFromRenderData(const FStaticMeshVertexBuffers &VertexBuffers,
const FRawStaticIndexBuffer &IndexBuffer);
void GetShaderInfo(const FSceneView *InView, float *m44, float *vp44,
float *pre_view_translation);
virtual void TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction *ThisTickFunction) override;
virtual void Serialize(FArchive &Ar) override;
UPROPERTY()
bool HasMesh;
// raw mesh data as passed to RenderToMesh
// we save this in UObject::Serialize so that
// we don't need to load it from the mesh at
// runtime
UPROPERTY()
TArray<float> PositionsAsFloats; // x,y,z,u,v (floats)
// vertexData is not a UStruct because we pass it through to
// native android code
TArray<VertexData> Positions; // x,y,z,u,v (floats)
UPROPERTY()
TArray<uint32> Indices; // index buffer for mesh (uint32)
TSharedPtr<_TextureSink> TextureSink;
TSharedPtr<IMediaTextureSample, ESPMode::ThreadSafe> CurrentSample;
TSharedPtr<IMediaTextureSample, ESPMode::ThreadSafe> PreparedSample;
TWeakPtr<FMediaPlayerFacade, ESPMode::ThreadSafe> Facade;
TObjectPtr<AStaticMeshActor> MeshActor;
TSharedPtr<FRendererSceneViewExt, ESPMode::ThreadSafe> ExtensionHolder;
bool Initialized;
};

View File

@ -0,0 +1,73 @@
// ------------------------------------------------
// Copyright Joe Marshall 2024- All Rights Reserved
// ------------------------------------------------
//
// Build AndroidVulkanVideo factory module (to make
// it possible to select this as a video source in
// editor.)
// ------------------------------------------------
using UnrealBuildTool;
using System.IO;
using System;
public class VulkanVideoMeshComponent : ModuleRules
{
public VulkanVideoMeshComponent(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
CppStandard = CppStandardVersion.Cpp17;
PublicIncludePaths.AddRange(
new string[] {
// ... add public include paths required here ...
}
);
PrivateIncludePaths.AddRange(
new string[] {
// ... add other private include paths required here ...
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"Projects",
"CoreUObject", "Engine","RHI","VulkanRHI","MediaUtils"
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"Core","CoreUObject", "Engine","RHI","RenderCore","VulkanRHI","MediaUtils","Media","MediaAssets"
// ... add private dependencies that you statically link with here ...
}
);
PrivateIncludePathModuleNames.AddRange(
new string[] {
"AndroidVulkanVideo",
});
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
}
);
if (Target.Platform == UnrealTargetPlatform.Android)
{
DynamicallyLoadedModuleNames.Add("AndroidVulkanVideo");
}
}
}