Files
MosisUnreal/Plugins/MosisSDK/Source/MosisSDK/Private/MosisPhoneComponent.cpp

214 lines
5.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MosisPhoneComponent.h"
#include "MosisSDK.h"
#include "MosisPhoneTexture.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "RenderingThread.h"
#if PLATFORM_ANDROID
#include "MosisClient.h"
#endif
DEFINE_LOG_CATEGORY_STATIC(LogMosisPhone, Log, All);
UMosisPhoneComponent::UMosisPhoneComponent()
{
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.bStartWithTickEnabled = true;
}
void UMosisPhoneComponent::BeginPlay()
{
Super::BeginPlay();
UE_LOG(LogMosisPhone, Log, TEXT("BeginPlay"));
#if PLATFORM_ANDROID
// Get the client and set up callbacks
auto Client = FMosisSDKModule::GetClient();
if (Client)
{
// Use weak pointer to prevent dangling references in callbacks
TWeakObjectPtr<UMosisPhoneComponent> WeakThis(this);
// Set up callbacks (these run on binder thread)
Client->SetBufferCallback([WeakThis](AHardwareBuffer* buffer) {
if (WeakThis.IsValid())
{
WeakThis->bNeedsTextureCreate.Store(true);
}
});
Client->SetFrameCallback([WeakThis]() {
if (WeakThis.IsValid())
{
WeakThis->bPendingTextureUpdate.Store(true);
}
});
UE_LOG(LogMosisPhone, Log, TEXT("BeginPlay: Callbacks registered"));
// Check if buffer is already available (we may have missed the callback)
if (Client->GetHardwareBuffer() != nullptr)
{
UE_LOG(LogMosisPhone, Log, TEXT("BeginPlay: Buffer already available, triggering update"));
bNeedsTextureCreate.Store(true);
}
}
else
{
UE_LOG(LogMosisPhone, Warning, TEXT("BeginPlay: MosisClient not available yet"));
}
#endif
}
void UMosisPhoneComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
UE_LOG(LogMosisPhone, Log, TEXT("EndPlay"));
#if PLATFORM_ANDROID
// Clear callbacks
auto Client = FMosisSDKModule::GetClient();
if (Client)
{
Client->SetBufferCallback(nullptr);
Client->SetFrameCallback(nullptr);
}
#endif
// Release texture
PhoneTexture = nullptr;
Super::EndPlay(EndPlayReason);
}
void UMosisPhoneComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
#if PLATFORM_ANDROID
// Check if we need to create texture from new buffer
if (bNeedsTextureCreate.Exchange(false))
{
OnBufferAvailable();
}
// Check if we need to update texture for new frame
if (bPendingTextureUpdate.Exchange(false) && PhoneTexture)
{
OnFrameAvailable();
}
#endif
}
bool UMosisPhoneComponent::IsConnected() const
{
#if PLATFORM_ANDROID
auto Client = FMosisSDKModule::GetClient();
return Client && Client->IsInitialized() && Client->GetHardwareBuffer() != nullptr;
#else
return false;
#endif
}
void UMosisPhoneComponent::SendTouch(FVector2D NormalizedUV, EMosisTouchType TouchType)
{
#if PLATFORM_ANDROID
auto Client = FMosisSDKModule::GetClient();
if (!Client)
{
return;
}
float X = FMath::Clamp(NormalizedUV.X, 0.0f, 1.0f);
float Y = FMath::Clamp(NormalizedUV.Y, 0.0f, 1.0f);
switch (TouchType)
{
case EMosisTouchType::Down:
Client->SendTouchDown(X, Y);
break;
case EMosisTouchType::Move:
Client->SendTouchMove(X, Y);
break;
case EMosisTouchType::Up:
Client->SendTouchUp(X, Y);
break;
}
#endif
}
void UMosisPhoneComponent::OnBufferAvailable()
{
#if PLATFORM_ANDROID
auto Client = FMosisSDKModule::GetClient();
if (!Client)
{
return;
}
AHardwareBuffer* Buffer = Client->GetHardwareBuffer();
if (!Buffer)
{
UE_LOG(LogMosisPhone, Warning, TEXT("OnBufferAvailable: No buffer"));
return;
}
// Get buffer dimensions
AHardwareBuffer_Desc Desc{};
AHardwareBuffer_describe(Buffer, &Desc);
ScreenWidth = Desc.width;
ScreenHeight = Desc.height;
UE_LOG(LogMosisPhone, Log, TEXT("OnBufferAvailable: %dx%d"), ScreenWidth, ScreenHeight);
// Create phone texture if needed
if (!PhoneTexture)
{
PhoneTexture = NewObject<UMosisPhoneTexture>(this);
PhoneTexture->Initialize(ScreenWidth, ScreenHeight);
UE_LOG(LogMosisPhone, Log, TEXT("OnBufferAvailable: Created phone texture"));
}
// Import the hardware buffer for GPU-accelerated updates
PhoneTexture->ImportHardwareBuffer(Buffer);
// Update material if set
if (PhoneMaterial && PhoneTexture)
{
PhoneMaterial->SetTextureParameterValue(TextureParameterName, PhoneTexture);
}
#endif
}
void UMosisPhoneComponent::OnFrameAvailable()
{
#if PLATFORM_ANDROID
if (!PhoneTexture || !PhoneTexture->HasImportedBuffer())
{
return;
}
// Perform GPU-to-GPU copy from imported hardware buffer
PhoneTexture->CopyFromImportedBuffer();
// Log occasionally to avoid spam
static int32 FrameCount = 0;
if (++FrameCount % 60 == 0)
{
UE_LOG(LogMosisPhone, Log, TEXT("OnFrameAvailable: Frame %d (GPU copy)"), FrameCount);
}
#endif
}
void UMosisPhoneComponent::UpdateTextureOnRenderThread()
{
// No longer needed - handled by UMosisPhoneTexture
}
UTexture* UMosisPhoneComponent::GetPhoneTexture() const
{
return PhoneTexture;
}