Compare commits
3 Commits
dc1bd14ff0
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 9cd16d98e4 | |||
| fb58c2d959 | |||
| 9cf3ffdbaf |
@@ -19,7 +19,7 @@ public static final XAPKFile[] xAPKS = {
|
||||
new XAPKFile(
|
||||
true, // true signifies a main file
|
||||
"1", // the version of the APK that the file was uploaded against
|
||||
97538444L // the length of the file in bytes
|
||||
98985607L // the length of the file in bytes
|
||||
)
|
||||
};
|
||||
};
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -85,7 +85,7 @@ bAllowClientSideNavigation=True
|
||||
+ActiveGameNameRedirects=(OldGameName="/Script/TP_VirtualRealityBP",NewGameName="/Script/MosisUnreal")
|
||||
|
||||
[/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings]
|
||||
bEnablePlugin=True
|
||||
bEnablePlugin=False
|
||||
bAllowNetworkConnection=True
|
||||
SecurityToken=40AD4D57409C43F8A8ADC6BE2AFF4735
|
||||
bIncludeInShipping=False
|
||||
|
||||
BIN
Content/Fab/Generic_Phone_-_Low_poly/Bezels.uasset
LFS
Normal file
BIN
Content/Fab/Generic_Phone_-_Low_poly/Bezels.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/Fab/Generic_Phone_-_Low_poly/Camera.uasset
LFS
Normal file
BIN
Content/Fab/Generic_Phone_-_Low_poly/Camera.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/Fab/Generic_Phone_-_Low_poly/CameraGlass.uasset
LFS
Normal file
BIN
Content/Fab/Generic_Phone_-_Low_poly/CameraGlass.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/Fab/Generic_Phone_-_Low_poly/Color-sides.uasset
LFS
Normal file
BIN
Content/Fab/Generic_Phone_-_Low_poly/Color-sides.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/Fab/Generic_Phone_-_Low_poly/Color.uasset
LFS
Normal file
BIN
Content/Fab/Generic_Phone_-_Low_poly/Color.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/Fab/Generic_Phone_-_Low_poly/Dark.uasset
LFS
Normal file
BIN
Content/Fab/Generic_Phone_-_Low_poly/Dark.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/Fab/Generic_Phone_-_Low_poly/Flash.uasset
LFS
Normal file
BIN
Content/Fab/Generic_Phone_-_Low_poly/Flash.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/Fab/Generic_Phone_-_Low_poly/Plastic.uasset
LFS
Normal file
BIN
Content/Fab/Generic_Phone_-_Low_poly/Plastic.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/Fab/Generic_Phone_-_Low_poly/Screen.uasset
LFS
Normal file
BIN
Content/Fab/Generic_Phone_-_Low_poly/Screen.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/Fab/Generic_Phone_-_Low_poly/phone.uasset
LFS
Normal file
BIN
Content/Fab/Generic_Phone_-_Low_poly/phone.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/Mosis/Input/Actions/IA_MosisClick.uasset
LFS
Normal file
BIN
Content/Mosis/Input/Actions/IA_MosisClick.uasset
LFS
Normal file
Binary file not shown.
Binary file not shown.
BIN
Content/Mosis/Phone/BP_MosisPhone.uasset
LFS
Normal file
BIN
Content/Mosis/Phone/BP_MosisPhone.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/Mosis/Textures/uvgrid.uasset
LFS
Normal file
BIN
Content/Mosis/Textures/uvgrid.uasset
LFS
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,7 +3,7 @@
|
||||
"Version": 1,
|
||||
"VersionName": "1.0",
|
||||
"FriendlyName": "MosisSDK",
|
||||
"Description": "",
|
||||
"Description": "Mosis Virtual Phone SDK for VR",
|
||||
"Category": "Other",
|
||||
"CreatedBy": "OmixLab LTD",
|
||||
"CreatedByURL": "",
|
||||
@@ -20,5 +20,11 @@
|
||||
"Type": "Runtime",
|
||||
"LoadingPhase": "Default"
|
||||
}
|
||||
],
|
||||
"Plugins": [
|
||||
{
|
||||
"Name": "EnhancedInput",
|
||||
"Enabled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -26,7 +26,9 @@ public class MosisSDK : ModuleRules
|
||||
"Slate",
|
||||
"SlateCore",
|
||||
"RenderCore",
|
||||
"RHI"
|
||||
"RHI",
|
||||
"EnhancedInput",
|
||||
"InputCore"
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -17,6 +17,12 @@ AMosisPhoneActor::AMosisPhoneActor()
|
||||
PhoneMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("PhoneMesh"));
|
||||
RootComponent = PhoneMesh;
|
||||
|
||||
// Configure collision for raycast detection
|
||||
PhoneMesh->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
|
||||
PhoneMesh->SetCollisionResponseToAllChannels(ECR_Ignore);
|
||||
PhoneMesh->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
|
||||
PhoneMesh->SetGenerateOverlapEvents(false);
|
||||
|
||||
// Load the default plane mesh
|
||||
static ConstructorHelpers::FObjectFinder<UStaticMesh> PlaneMeshFinder(
|
||||
TEXT("/Engine/BasicShapes/Plane.Plane"));
|
||||
@@ -50,6 +56,11 @@ void AMosisPhoneActor::BeginPlay()
|
||||
{
|
||||
// Default plane is 100x100 units, so bounds are -50 to 50 in X and Y
|
||||
ScreenBoundsLocal = FVector4(-50.0f, -50.0f, 50.0f, 50.0f);
|
||||
|
||||
// Flip the mesh on Y axis to correct texture orientation
|
||||
// (OpenGL renders with origin at bottom-left, Vulkan/UE5 expects top-left)
|
||||
FVector CurrentScale = PhoneMesh->GetRelativeScale3D();
|
||||
PhoneMesh->SetRelativeScale3D(FVector(CurrentScale.X, -CurrentScale.Y, CurrentScale.Z));
|
||||
}
|
||||
|
||||
// Create dynamic material for the screen
|
||||
@@ -137,5 +148,8 @@ bool AMosisPhoneActor::WorldToPhoneUV(FVector WorldLocation, FVector2D& OutUV) c
|
||||
OutUV.X = (LocalLocation.X - MinX) / (MaxX - MinX);
|
||||
OutUV.Y = (LocalLocation.Y - MinY) / (MaxY - MinY);
|
||||
|
||||
// Flip Y to match the flipped mesh scale (corrects for OpenGL vs Vulkan coordinate systems)
|
||||
OutUV.Y = 1.0f - OutUV.Y;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -171,8 +171,8 @@ void UMosisPhoneComponent::OnBufferAvailable()
|
||||
UE_LOG(LogMosisPhone, Log, TEXT("OnBufferAvailable: Created phone texture"));
|
||||
}
|
||||
|
||||
// Import the hardware buffer
|
||||
PhoneTexture->UpdateFromHardwareBuffer(Buffer);
|
||||
// Import the hardware buffer for GPU-accelerated updates
|
||||
PhoneTexture->ImportHardwareBuffer(Buffer);
|
||||
|
||||
// Update material if set
|
||||
if (PhoneMaterial && PhoneTexture)
|
||||
@@ -185,20 +185,19 @@ void UMosisPhoneComponent::OnBufferAvailable()
|
||||
void UMosisPhoneComponent::OnFrameAvailable()
|
||||
{
|
||||
#if PLATFORM_ANDROID
|
||||
if (!PhoneTexture)
|
||||
if (!PhoneTexture || !PhoneTexture->HasImportedBuffer())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Notify texture that a new frame is available
|
||||
// This schedules the render thread copy
|
||||
PhoneTexture->NotifyFrameAvailable();
|
||||
// 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"), FrameCount);
|
||||
UE_LOG(LogMosisPhone, Log, TEXT("OnFrameAvailable: Frame %d (GPU copy)"), FrameCount);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2,21 +2,40 @@
|
||||
|
||||
#include "MosisPhoneTexture.h"
|
||||
#include "RenderingThread.h"
|
||||
#include "RHICommandList.h"
|
||||
|
||||
#if PLATFORM_ANDROID
|
||||
#include "IVulkanDynamicRHI.h"
|
||||
#endif
|
||||
|
||||
DEFINE_LOG_CATEGORY_STATIC(LogMosisPhoneTexture, Log, All);
|
||||
|
||||
UMosisPhoneTexture::UMosisPhoneTexture()
|
||||
{
|
||||
// UTexture2DDynamic defaults are fine
|
||||
SRGB = true;
|
||||
Filter = TF_Bilinear;
|
||||
}
|
||||
|
||||
UMosisPhoneTexture::~UMosisPhoneTexture()
|
||||
{
|
||||
#if PLATFORM_ANDROID
|
||||
// Release imported texture RHI resource
|
||||
if (ImportedTextureRHI.IsValid())
|
||||
{
|
||||
ImportedTextureRHI.SafeRelease();
|
||||
}
|
||||
CurrentBuffer = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void UMosisPhoneTexture::Initialize(uint32 InWidth, uint32 InHeight)
|
||||
{
|
||||
UE_LOG(LogMosisPhoneTexture, Log, TEXT("Initialize: %dx%d"), InWidth, InHeight);
|
||||
|
||||
// Use UTexture2DDynamic's Init method
|
||||
TextureWidth = InWidth;
|
||||
TextureHeight = InHeight;
|
||||
|
||||
// Initialize the UTexture2DDynamic base - this creates our destination texture
|
||||
Init(InWidth, InHeight, PF_R8G8B8A8, false);
|
||||
|
||||
bIsReady = true;
|
||||
@@ -24,127 +43,118 @@ void UMosisPhoneTexture::Initialize(uint32 InWidth, uint32 InHeight)
|
||||
|
||||
#if PLATFORM_ANDROID
|
||||
|
||||
void UMosisPhoneTexture::UpdateFromHardwareBuffer(AHardwareBuffer* Buffer)
|
||||
void UMosisPhoneTexture::ImportHardwareBuffer(AHardwareBuffer* Buffer)
|
||||
{
|
||||
if (!Buffer)
|
||||
{
|
||||
UE_LOG(LogMosisPhoneTexture, Warning, TEXT("UpdateFromHardwareBuffer: null buffer"));
|
||||
UE_LOG(LogMosisPhoneTexture, Warning, TEXT("ImportHardwareBuffer: null buffer"));
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentBuffer = Buffer;
|
||||
|
||||
// Get buffer dimensions
|
||||
AHardwareBuffer_Desc Desc{};
|
||||
AHardwareBuffer_describe(Buffer, &Desc);
|
||||
|
||||
UE_LOG(LogMosisPhoneTexture, Log, TEXT("UpdateFromHardwareBuffer: %dx%d"), Desc.width, Desc.height);
|
||||
UE_LOG(LogMosisPhoneTexture, Log, TEXT("ImportHardwareBuffer: %dx%d, format=%d, usage=0x%x"),
|
||||
Desc.width, Desc.height, Desc.format, Desc.usage);
|
||||
|
||||
// Lock buffer and read data
|
||||
void* LockedData = nullptr;
|
||||
int32 Result = AHardwareBuffer_lock(Buffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, -1, nullptr, &LockedData);
|
||||
|
||||
if (Result != 0 || !LockedData)
|
||||
// Verify buffer has GPU sampled image usage (required for Vulkan import)
|
||||
if ((Desc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) == 0)
|
||||
{
|
||||
UE_LOG(LogMosisPhoneTexture, Error, TEXT("UpdateFromHardwareBuffer: Failed to lock buffer, result=%d"), Result);
|
||||
UE_LOG(LogMosisPhoneTexture, Error,
|
||||
TEXT("ImportHardwareBuffer: Buffer missing AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE flag"));
|
||||
return;
|
||||
}
|
||||
|
||||
uint8* PixelData = static_cast<uint8*>(LockedData);
|
||||
|
||||
// Copy data to a buffer for update (accounting for stride)
|
||||
uint32 StridePixels = Desc.stride > 0 ? Desc.stride : Desc.width;
|
||||
TArray<uint8> TextureData;
|
||||
TextureData.SetNumUninitialized(Desc.width * Desc.height * 4);
|
||||
|
||||
for (uint32 y = 0; y < Desc.height; y++)
|
||||
// Check if RHI is Vulkan
|
||||
if (GDynamicRHI->GetInterfaceType() != ERHIInterfaceType::Vulkan)
|
||||
{
|
||||
FMemory::Memcpy(
|
||||
TextureData.GetData() + y * Desc.width * 4,
|
||||
PixelData + y * StridePixels * 4,
|
||||
Desc.width * 4
|
||||
);
|
||||
UE_LOG(LogMosisPhoneTexture, Error,
|
||||
TEXT("ImportHardwareBuffer: Vulkan RHI required for hardware buffer import"));
|
||||
return;
|
||||
}
|
||||
|
||||
AHardwareBuffer_unlock(Buffer, nullptr);
|
||||
|
||||
// Update the texture using UTexture2DDynamic's update regions
|
||||
FTexture2DDynamicResource* TextureResource = static_cast<FTexture2DDynamicResource*>(GetResource());
|
||||
if (TextureResource)
|
||||
// Release old imported texture if any
|
||||
if (ImportedTextureRHI.IsValid())
|
||||
{
|
||||
ENQUEUE_RENDER_COMMAND(UpdateMosisTexture)(
|
||||
[TextureResource, Data = MoveTemp(TextureData), Width = Desc.width, Height = Desc.height](FRHICommandListImmediate& RHICmdList)
|
||||
{
|
||||
FUpdateTextureRegion2D Region(0, 0, 0, 0, Width, Height);
|
||||
RHIUpdateTexture2D(
|
||||
TextureResource->GetTexture2DRHI(),
|
||||
0,
|
||||
Region,
|
||||
Width * 4,
|
||||
Data.GetData()
|
||||
);
|
||||
}
|
||||
);
|
||||
ImportedTextureRHI.SafeRelease();
|
||||
}
|
||||
|
||||
CurrentBuffer = Buffer;
|
||||
|
||||
// Import the hardware buffer using UE5's Vulkan RHI API
|
||||
// This creates a VkImage backed by the AHardwareBuffer's shared memory (zero-copy)
|
||||
IVulkanDynamicRHI* VulkanRHI = GetIVulkanDynamicRHI();
|
||||
ImportedTextureRHI = VulkanRHI->RHICreateTexture2DFromAndroidHardwareBuffer(Buffer);
|
||||
|
||||
if (ImportedTextureRHI.IsValid())
|
||||
{
|
||||
UE_LOG(LogMosisPhoneTexture, Log,
|
||||
TEXT("ImportHardwareBuffer: Successfully imported as Vulkan texture"));
|
||||
|
||||
// Initialize our destination texture if not done yet
|
||||
if (!bIsReady)
|
||||
{
|
||||
Initialize(Desc.width, Desc.height);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogMosisPhoneTexture, Error,
|
||||
TEXT("ImportHardwareBuffer: Failed to create Vulkan texture from hardware buffer"));
|
||||
}
|
||||
}
|
||||
|
||||
void UMosisPhoneTexture::NotifyFrameAvailable()
|
||||
void UMosisPhoneTexture::CopyFromImportedBuffer()
|
||||
{
|
||||
if (!CurrentBuffer || !bIsReady)
|
||||
if (!ImportedTextureRHI.IsValid() || !bIsReady)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get buffer dimensions
|
||||
AHardwareBuffer_Desc Desc{};
|
||||
AHardwareBuffer_describe(CurrentBuffer, &Desc);
|
||||
|
||||
// Lock buffer and read data
|
||||
void* LockedData = nullptr;
|
||||
int32 Result = AHardwareBuffer_lock(CurrentBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, -1, nullptr, &LockedData);
|
||||
|
||||
if (Result != 0 || !LockedData)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint8* PixelData = static_cast<uint8*>(LockedData);
|
||||
|
||||
// Copy data to a buffer for update (accounting for stride)
|
||||
uint32 StridePixels = Desc.stride > 0 ? Desc.stride : Desc.width;
|
||||
TArray<uint8> TextureData;
|
||||
TextureData.SetNumUninitialized(Desc.width * Desc.height * 4);
|
||||
|
||||
for (uint32 y = 0; y < Desc.height; y++)
|
||||
{
|
||||
FMemory::Memcpy(
|
||||
TextureData.GetData() + y * Desc.width * 4,
|
||||
PixelData + y * StridePixels * 4,
|
||||
Desc.width * 4
|
||||
);
|
||||
}
|
||||
|
||||
AHardwareBuffer_unlock(CurrentBuffer, nullptr);
|
||||
|
||||
// Update the texture
|
||||
// Get our destination texture resource
|
||||
FTexture2DDynamicResource* TextureResource = static_cast<FTexture2DDynamicResource*>(GetResource());
|
||||
if (TextureResource)
|
||||
if (!TextureResource)
|
||||
{
|
||||
ENQUEUE_RENDER_COMMAND(UpdateMosisTextureFrame)(
|
||||
[TextureResource, Data = MoveTemp(TextureData), Width = Desc.width, Height = Desc.height](FRHICommandListImmediate& RHICmdList)
|
||||
{
|
||||
FUpdateTextureRegion2D Region(0, 0, 0, 0, Width, Height);
|
||||
RHIUpdateTexture2D(
|
||||
TextureResource->GetTexture2DRHI(),
|
||||
0,
|
||||
Region,
|
||||
Width * 4,
|
||||
Data.GetData()
|
||||
);
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
FTextureRHIRef DestTextureRHI = TextureResource->GetTexture2DRHI();
|
||||
if (!DestTextureRHI.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Capture references for the render thread lambda
|
||||
FTextureRHIRef SrcTexture = ImportedTextureRHI;
|
||||
FTextureRHIRef DstTexture = DestTextureRHI;
|
||||
uint32 Width = TextureWidth;
|
||||
uint32 Height = TextureHeight;
|
||||
|
||||
// Enqueue GPU-to-GPU copy on render thread
|
||||
ENQUEUE_RENDER_COMMAND(CopyMosisTexture)(
|
||||
[SrcTexture, DstTexture, Width, Height](FRHICommandListImmediate& RHICmdList)
|
||||
{
|
||||
// Transition source to copy source state
|
||||
RHICmdList.Transition(FRHITransitionInfo(SrcTexture, ERHIAccess::Unknown, ERHIAccess::CopySrc));
|
||||
|
||||
// Transition destination to copy dest state
|
||||
RHICmdList.Transition(FRHITransitionInfo(DstTexture, ERHIAccess::Unknown, ERHIAccess::CopyDest));
|
||||
|
||||
// Perform GPU copy
|
||||
FRHICopyTextureInfo CopyInfo;
|
||||
CopyInfo.Size.X = Width;
|
||||
CopyInfo.Size.Y = Height;
|
||||
CopyInfo.Size.Z = 1;
|
||||
CopyInfo.NumMips = 1;
|
||||
CopyInfo.NumSlices = 1;
|
||||
|
||||
RHICmdList.CopyTexture(SrcTexture, DstTexture, CopyInfo);
|
||||
|
||||
// Transition destination back to shader resource for rendering
|
||||
RHICmdList.Transition(FRHITransitionInfo(DstTexture, ERHIAccess::CopyDest, ERHIAccess::SRVMask));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#endif // PLATFORM_ANDROID
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* UMosisPhoneTexture - Dynamic texture that displays the Mosis phone screen.
|
||||
*
|
||||
* This texture is updated from an AHardwareBuffer received from MosisService.
|
||||
* Uses GPU-to-GPU copy via Vulkan external memory import for optimal performance.
|
||||
* Inherits from UTexture2DDynamic for proper material integration.
|
||||
*/
|
||||
UCLASS()
|
||||
@@ -23,26 +24,27 @@ class UMosisPhoneTexture : public UTexture2DDynamic
|
||||
|
||||
public:
|
||||
UMosisPhoneTexture();
|
||||
virtual ~UMosisPhoneTexture();
|
||||
|
||||
/** Initialize the texture with dimensions */
|
||||
void Initialize(uint32 InWidth, uint32 InHeight);
|
||||
|
||||
#if PLATFORM_ANDROID
|
||||
/**
|
||||
* Update the texture from a hardware buffer.
|
||||
* Import a hardware buffer for GPU-accelerated texture updates.
|
||||
* Creates a Vulkan image from the AHardwareBuffer for zero-copy import.
|
||||
* @param Buffer The AHardwareBuffer from MosisService
|
||||
*/
|
||||
void UpdateFromHardwareBuffer(AHardwareBuffer* Buffer);
|
||||
void ImportHardwareBuffer(AHardwareBuffer* Buffer);
|
||||
|
||||
/**
|
||||
* Notify that a new frame is available.
|
||||
* Copies buffer data to the texture.
|
||||
* Perform GPU-to-GPU copy from imported buffer to this texture.
|
||||
* Called each frame when new content is available.
|
||||
*/
|
||||
void NotifyFrameAvailable();
|
||||
void CopyFromImportedBuffer();
|
||||
|
||||
/** Store the current hardware buffer reference */
|
||||
void SetHardwareBuffer(AHardwareBuffer* Buffer) { CurrentBuffer = Buffer; }
|
||||
AHardwareBuffer* GetHardwareBuffer() const { return CurrentBuffer; }
|
||||
/** Check if the imported buffer is valid */
|
||||
bool HasImportedBuffer() const { return ImportedTextureRHI.IsValid(); }
|
||||
#endif
|
||||
|
||||
/** Check if the texture is ready for rendering */
|
||||
@@ -50,10 +52,17 @@ public:
|
||||
|
||||
private:
|
||||
#if PLATFORM_ANDROID
|
||||
/** Current hardware buffer */
|
||||
/** RHI texture imported from AHardwareBuffer (zero-copy Vulkan import) */
|
||||
FTextureRHIRef ImportedTextureRHI;
|
||||
|
||||
/** Current hardware buffer reference */
|
||||
AHardwareBuffer* CurrentBuffer = nullptr;
|
||||
#endif
|
||||
|
||||
/** True when texture has been initialized */
|
||||
bool bIsReady = false;
|
||||
|
||||
/** Texture dimensions */
|
||||
uint32 TextureWidth = 0;
|
||||
uint32 TextureHeight = 0;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "MosisPointerComponent.h"
|
||||
#include "MosisPhoneActor.h"
|
||||
#include "EnhancedInputComponent.h"
|
||||
#include "EnhancedInputSubsystems.h"
|
||||
#include "InputAction.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "DrawDebugHelpers.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY_STATIC(LogMosisPointer, Log, All);
|
||||
|
||||
UMosisPointerComponent::UMosisPointerComponent()
|
||||
{
|
||||
PrimaryComponentTick.bCanEverTick = true;
|
||||
PrimaryComponentTick.bStartWithTickEnabled = true;
|
||||
}
|
||||
|
||||
void UMosisPointerComponent::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
// Try to setup input bindings after a short delay to ensure player controller is ready
|
||||
if (TriggerAction)
|
||||
{
|
||||
SetupInputBindings();
|
||||
}
|
||||
|
||||
UE_LOG(LogMosisPointer, Log, TEXT("MosisPointerComponent initialized. RayLength: %.1f"), RayLength);
|
||||
}
|
||||
|
||||
void UMosisPointerComponent::SetupInputBindings()
|
||||
{
|
||||
if (bInputBound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AActor* Owner = GetOwner();
|
||||
if (!Owner)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the owning pawn and its controller
|
||||
APawn* OwningPawn = Cast<APawn>(Owner);
|
||||
if (!OwningPawn)
|
||||
{
|
||||
OwningPawn = Owner->GetInstigator<APawn>();
|
||||
}
|
||||
|
||||
if (!OwningPawn)
|
||||
{
|
||||
UE_LOG(LogMosisPointer, Warning, TEXT("Could not find owning pawn for input binding"));
|
||||
return;
|
||||
}
|
||||
|
||||
APlayerController* PC = Cast<APlayerController>(OwningPawn->GetController());
|
||||
if (!PC)
|
||||
{
|
||||
UE_LOG(LogMosisPointer, Warning, TEXT("Could not find player controller for input binding"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the Enhanced Input component from the pawn
|
||||
UEnhancedInputComponent* EnhancedInput = Cast<UEnhancedInputComponent>(OwningPawn->InputComponent);
|
||||
if (!EnhancedInput)
|
||||
{
|
||||
UE_LOG(LogMosisPointer, Warning, TEXT("Could not find Enhanced Input component on pawn"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Bind the trigger action
|
||||
EnhancedInput->BindAction(TriggerAction, ETriggerEvent::Triggered, this, &UMosisPointerComponent::OnTriggerAction);
|
||||
EnhancedInput->BindAction(TriggerAction, ETriggerEvent::Completed, this, &UMosisPointerComponent::OnTriggerAction);
|
||||
|
||||
bInputBound = true;
|
||||
UE_LOG(LogMosisPointer, Log, TEXT("Successfully bound trigger input action"));
|
||||
}
|
||||
|
||||
void UMosisPointerComponent::OnTriggerAction(const FInputActionInstance& Instance)
|
||||
{
|
||||
// Triggered = pressed, Completed = released
|
||||
bIsTriggerPressed = (Instance.GetTriggerEvent() == ETriggerEvent::Triggered);
|
||||
}
|
||||
|
||||
void UMosisPointerComponent::SetTriggerPressed(bool bPressed)
|
||||
{
|
||||
bIsTriggerPressed = bPressed;
|
||||
}
|
||||
|
||||
void UMosisPointerComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
||||
{
|
||||
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||||
|
||||
// Try to bind input if not yet bound and we have an action
|
||||
if (TriggerAction && !bInputBound)
|
||||
{
|
||||
SetupInputBindings();
|
||||
}
|
||||
|
||||
// Perform raycast to find phone
|
||||
PerformRaycast();
|
||||
|
||||
// Update touch state and send events
|
||||
UpdateTouchState();
|
||||
|
||||
// Draw debug visualization
|
||||
if (bShowDebugRay)
|
||||
{
|
||||
DrawDebugRay();
|
||||
}
|
||||
}
|
||||
|
||||
void UMosisPointerComponent::PerformRaycast()
|
||||
{
|
||||
FVector Start = GetComponentLocation();
|
||||
FVector Direction = GetForwardVector();
|
||||
FVector End = Start + Direction * RayLength;
|
||||
|
||||
FHitResult Hit;
|
||||
FCollisionQueryParams Params;
|
||||
Params.AddIgnoredActor(GetOwner());
|
||||
|
||||
// Also ignore any parent actors
|
||||
AActor* Parent = GetOwner() ? GetOwner()->GetAttachParentActor() : nullptr;
|
||||
while (Parent)
|
||||
{
|
||||
Params.AddIgnoredActor(Parent);
|
||||
Parent = Parent->GetAttachParentActor();
|
||||
}
|
||||
|
||||
bool bHit = GetWorld()->LineTraceSingleByChannel(
|
||||
Hit, Start, End, TraceChannel, Params);
|
||||
|
||||
if (bHit)
|
||||
{
|
||||
AMosisPhoneActor* HitPhone = Cast<AMosisPhoneActor>(Hit.GetActor());
|
||||
if (HitPhone)
|
||||
{
|
||||
CurrentPhone = HitPhone;
|
||||
CurrentHitLocation = Hit.ImpactPoint;
|
||||
bIsOverPhone = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentPhone = nullptr;
|
||||
bIsOverPhone = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentPhone = nullptr;
|
||||
bIsOverPhone = false;
|
||||
}
|
||||
}
|
||||
|
||||
void UMosisPointerComponent::UpdateTouchState()
|
||||
{
|
||||
// Detect state transitions
|
||||
bool bJustPressed = bIsTriggerPressed && !bWasTriggerPressed;
|
||||
bool bJustReleased = !bIsTriggerPressed && bWasTriggerPressed;
|
||||
|
||||
if (bIsOverPhone && CurrentPhone.IsValid())
|
||||
{
|
||||
if (bJustPressed)
|
||||
{
|
||||
// Touch down
|
||||
CurrentPhone->SendTouchAtWorldLocation(CurrentHitLocation, EMosisTouchType::Down);
|
||||
LastTouchedPhone = CurrentPhone;
|
||||
LastHitLocation = CurrentHitLocation;
|
||||
UE_LOG(LogMosisPointer, Verbose, TEXT("Touch Down at (%.1f, %.1f, %.1f)"),
|
||||
CurrentHitLocation.X, CurrentHitLocation.Y, CurrentHitLocation.Z);
|
||||
}
|
||||
else if (bIsTriggerPressed)
|
||||
{
|
||||
// Touch move (only if position changed significantly)
|
||||
if (FVector::DistSquared(CurrentHitLocation, LastHitLocation) > 0.01f)
|
||||
{
|
||||
CurrentPhone->SendTouchAtWorldLocation(CurrentHitLocation, EMosisTouchType::Move);
|
||||
LastHitLocation = CurrentHitLocation;
|
||||
}
|
||||
}
|
||||
else if (bJustReleased)
|
||||
{
|
||||
// Touch up
|
||||
CurrentPhone->SendTouchAtWorldLocation(CurrentHitLocation, EMosisTouchType::Up);
|
||||
LastTouchedPhone = nullptr;
|
||||
UE_LOG(LogMosisPointer, Verbose, TEXT("Touch Up at (%.1f, %.1f, %.1f)"),
|
||||
CurrentHitLocation.X, CurrentHitLocation.Y, CurrentHitLocation.Z);
|
||||
}
|
||||
}
|
||||
else if (bJustReleased && LastTouchedPhone.IsValid())
|
||||
{
|
||||
// Ray moved off phone while pressed, but trigger was just released
|
||||
// Send up event to the last touched phone
|
||||
LastTouchedPhone->SendTouchAtWorldLocation(LastHitLocation, EMosisTouchType::Up);
|
||||
LastTouchedPhone = nullptr;
|
||||
UE_LOG(LogMosisPointer, Verbose, TEXT("Touch Up (off-phone) at (%.1f, %.1f, %.1f)"),
|
||||
LastHitLocation.X, LastHitLocation.Y, LastHitLocation.Z);
|
||||
}
|
||||
|
||||
bWasTriggerPressed = bIsTriggerPressed;
|
||||
}
|
||||
|
||||
void UMosisPointerComponent::DrawDebugRay() const
|
||||
{
|
||||
FVector Start = GetComponentLocation();
|
||||
FVector Direction = GetForwardVector();
|
||||
FVector End = bIsOverPhone ? CurrentHitLocation : (Start + Direction * RayLength);
|
||||
|
||||
FColor Color = bIsOverPhone ? DebugRayHitColor.ToFColor(true) : DebugRayColor.ToFColor(true);
|
||||
|
||||
DrawDebugLine(GetWorld(), Start, End, Color, false, -1.0f, 0, 1.0f);
|
||||
|
||||
if (bIsOverPhone)
|
||||
{
|
||||
// Draw hit point
|
||||
DrawDebugSphere(GetWorld(), CurrentHitLocation, 2.0f, 8, Color, false, -1.0f, 0, 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
AMosisPhoneActor* UMosisPointerComponent::GetTargetPhone() const
|
||||
{
|
||||
return CurrentPhone.Get();
|
||||
}
|
||||
|
||||
FVector UMosisPointerComponent::GetRayOrigin() const
|
||||
{
|
||||
return GetComponentLocation();
|
||||
}
|
||||
|
||||
FVector UMosisPointerComponent::GetRayDirection() const
|
||||
{
|
||||
return GetForwardVector();
|
||||
}
|
||||
133
Plugins/MosisSDK/Source/MosisSDK/Public/MosisPointerComponent.h
Normal file
133
Plugins/MosisSDK/Source/MosisSDK/Public/MosisPointerComponent.h
Normal file
@@ -0,0 +1,133 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/SceneComponent.h"
|
||||
#include "MosisPhoneComponent.h"
|
||||
#include "MosisPointerComponent.generated.h"
|
||||
|
||||
class AMosisPhoneActor;
|
||||
class UInputAction;
|
||||
struct FInputActionInstance;
|
||||
|
||||
/**
|
||||
* UMosisPointerComponent - VR ray interaction component for Mosis phone.
|
||||
*
|
||||
* Attach this component as a child of a motion controller to enable
|
||||
* VR pointer-based touch interaction with MosisPhoneActor.
|
||||
*
|
||||
* Usage:
|
||||
* 1. Add as child of MotionControllerComponent
|
||||
* 2. Set TriggerAction to your trigger input action (optional)
|
||||
* 3. Touch events are sent automatically when pointing at a phone and triggering
|
||||
*
|
||||
* Manual control (without Enhanced Input):
|
||||
* - Call SetTriggerPressed(true/false) from your input handling code
|
||||
*/
|
||||
UCLASS(ClassGroup=(Mosis), meta=(BlueprintSpawnableComponent))
|
||||
class MOSISSDK_API UMosisPointerComponent : public USceneComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UMosisPointerComponent();
|
||||
|
||||
// Configuration
|
||||
|
||||
/** Maximum ray length for detecting phone actors (in cm) */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mosis|Pointer")
|
||||
float RayLength = 500.0f;
|
||||
|
||||
/** Draw debug ray visualization */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mosis|Pointer")
|
||||
bool bShowDebugRay = false;
|
||||
|
||||
/** Color of the debug ray when not hitting anything */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mosis|Pointer", meta=(EditCondition="bShowDebugRay"))
|
||||
FLinearColor DebugRayColor = FLinearColor::Red;
|
||||
|
||||
/** Color of the debug ray when hitting a phone */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mosis|Pointer", meta=(EditCondition="bShowDebugRay"))
|
||||
FLinearColor DebugRayHitColor = FLinearColor::Green;
|
||||
|
||||
/** Collision channel used for raycast */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mosis|Pointer")
|
||||
TEnumAsByte<ECollisionChannel> TraceChannel = ECC_Visibility;
|
||||
|
||||
// Input
|
||||
|
||||
/**
|
||||
* Enhanced Input Action for trigger press.
|
||||
* If set, the component will automatically bind to this action.
|
||||
* Leave null to use manual SetTriggerPressed() calls.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mosis|Input")
|
||||
TObjectPtr<UInputAction> TriggerAction;
|
||||
|
||||
// State queries
|
||||
|
||||
/** Check if the pointer is currently pointing at a phone */
|
||||
UFUNCTION(BlueprintCallable, Category = "Mosis|Pointer")
|
||||
bool IsPointingAtPhone() const { return bIsOverPhone; }
|
||||
|
||||
/** Get the phone actor currently being pointed at (nullptr if none) */
|
||||
UFUNCTION(BlueprintCallable, Category = "Mosis|Pointer")
|
||||
AMosisPhoneActor* GetTargetPhone() const;
|
||||
|
||||
/** Get the world location where the ray hits the phone */
|
||||
UFUNCTION(BlueprintCallable, Category = "Mosis|Pointer")
|
||||
FVector GetHitLocation() const { return CurrentHitLocation; }
|
||||
|
||||
/** Get the current ray origin in world space */
|
||||
UFUNCTION(BlueprintCallable, Category = "Mosis|Pointer")
|
||||
FVector GetRayOrigin() const;
|
||||
|
||||
/** Get the current ray direction in world space */
|
||||
UFUNCTION(BlueprintCallable, Category = "Mosis|Pointer")
|
||||
FVector GetRayDirection() const;
|
||||
|
||||
/** Check if the trigger is currently pressed */
|
||||
UFUNCTION(BlueprintCallable, Category = "Mosis|Pointer")
|
||||
bool IsTriggerPressed() const { return bIsTriggerPressed; }
|
||||
|
||||
// Manual control
|
||||
|
||||
/**
|
||||
* Manually set the trigger pressed state.
|
||||
* Use this when not using Enhanced Input, or for custom input handling.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Mosis|Pointer")
|
||||
void SetTriggerPressed(bool bPressed);
|
||||
|
||||
protected:
|
||||
// UActorComponent interface
|
||||
virtual void BeginPlay() override;
|
||||
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||
|
||||
private:
|
||||
/** Perform raycast and update CurrentPhone/CurrentHitLocation */
|
||||
void PerformRaycast();
|
||||
|
||||
/** Update touch state machine and send touch events */
|
||||
void UpdateTouchState();
|
||||
|
||||
/** Draw debug visualization */
|
||||
void DrawDebugRay() const;
|
||||
|
||||
/** Callback for Enhanced Input trigger action */
|
||||
void OnTriggerAction(const FInputActionInstance& Instance);
|
||||
|
||||
/** Setup Enhanced Input bindings */
|
||||
void SetupInputBindings();
|
||||
|
||||
// State
|
||||
TWeakObjectPtr<AMosisPhoneActor> CurrentPhone;
|
||||
TWeakObjectPtr<AMosisPhoneActor> LastTouchedPhone;
|
||||
FVector CurrentHitLocation = FVector::ZeroVector;
|
||||
FVector LastHitLocation = FVector::ZeroVector;
|
||||
bool bIsTriggerPressed = false;
|
||||
bool bWasTriggerPressed = false;
|
||||
bool bIsOverPhone = false;
|
||||
bool bInputBound = false;
|
||||
};
|
||||
207
build-unreal.bat
Normal file
207
build-unreal.bat
Normal file
@@ -0,0 +1,207 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
:: MosisUnreal Build and Deploy Script
|
||||
:: Usage: build-unreal.bat [build|install|deploy|launch|clean]
|
||||
:: build - Build Android APK only
|
||||
:: install - Install APK to device only
|
||||
:: deploy - Build and install (default)
|
||||
:: launch - Launch app (starts MosisService first)
|
||||
:: clean - Clean build artifacts
|
||||
|
||||
set ENGINE_PATH=D:\Epic\UE_5.5
|
||||
set PROJECT_PATH=%~dp0MosisUnreal.uproject
|
||||
set UAT_PATH=%ENGINE_PATH%\Engine\Build\BatchFiles\RunUAT.bat
|
||||
set CONFIG=Development
|
||||
|
||||
:: Parse command line argument
|
||||
set ACTION=%1
|
||||
if "%ACTION%"=="" set ACTION=deploy
|
||||
|
||||
:: Validate engine path
|
||||
if not exist "%UAT_PATH%" (
|
||||
echo ERROR: Unreal Engine not found at %ENGINE_PATH%
|
||||
echo Please update ENGINE_PATH in this script.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: Execute action
|
||||
if "%ACTION%"=="build" goto :build
|
||||
if "%ACTION%"=="install" goto :install
|
||||
if "%ACTION%"=="deploy" goto :deploy
|
||||
if "%ACTION%"=="launch" goto :launch
|
||||
if "%ACTION%"=="clean" goto :clean
|
||||
|
||||
echo Unknown action: %ACTION%
|
||||
echo Usage: build-unreal.bat [build^|install^|deploy^|launch^|clean]
|
||||
exit /b 1
|
||||
|
||||
:build
|
||||
echo.
|
||||
echo ============================================
|
||||
echo Building MosisUnreal for Android...
|
||||
echo ============================================
|
||||
echo.
|
||||
|
||||
call "%UAT_PATH%" BuildCookRun ^
|
||||
-project="%PROJECT_PATH%" ^
|
||||
-platform=Android ^
|
||||
-clientconfig=%CONFIG% ^
|
||||
-build -cook -stage -pak -package ^
|
||||
-noP4 ^
|
||||
-utf8output
|
||||
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo ERROR: Build failed!
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo Build completed successfully!
|
||||
echo APK: %~dp0Binaries\Android\MosisUnreal-arm64.apk
|
||||
goto :eof
|
||||
|
||||
:install
|
||||
echo.
|
||||
echo ============================================
|
||||
echo Installing MosisUnreal to device...
|
||||
echo ============================================
|
||||
echo.
|
||||
|
||||
:: Check for connected device
|
||||
adb devices | findstr /r /c:"device$" >nul
|
||||
if errorlevel 1 (
|
||||
echo ERROR: No Android device connected!
|
||||
echo Connect a device and enable USB debugging.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: Get device ID
|
||||
for /f "tokens=1" %%d in ('adb devices ^| findstr /r /c:"device$"') do (
|
||||
set DEVICE=%%d
|
||||
goto :found_device
|
||||
)
|
||||
:found_device
|
||||
echo Device: %DEVICE%
|
||||
|
||||
set APK_PATH=%~dp0Binaries\Android\MosisUnreal-arm64.apk
|
||||
set OBB_PATH=%~dp0Binaries\Android\main.1.com.omixlab.MosisUnreal.obb
|
||||
|
||||
:: Check APK exists
|
||||
if not exist "%APK_PATH%" (
|
||||
echo ERROR: APK not found at %APK_PATH%
|
||||
echo Run 'build-unreal.bat build' first.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: Install APK
|
||||
echo Installing APK...
|
||||
adb -s %DEVICE% install -r "%APK_PATH%"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: APK installation failed!
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: Install OBB if exists
|
||||
if exist "%OBB_PATH%" (
|
||||
echo.
|
||||
echo Installing OBB...
|
||||
|
||||
:: Create temp directory
|
||||
adb -s %DEVICE% shell "mkdir -p /data/local/tmp/obb/com.omixlab.MosisUnreal"
|
||||
|
||||
:: Push OBB (use forward slashes for adb)
|
||||
set OBB_UNIX=%OBB_PATH:\=/%
|
||||
adb -s %DEVICE% push "!OBB_UNIX!" /data/local/tmp/obb/com.omixlab.MosisUnreal/
|
||||
|
||||
:: Move to final location
|
||||
adb -s %DEVICE% shell "rm -rf /sdcard/Android/obb/com.omixlab.MosisUnreal"
|
||||
adb -s %DEVICE% shell "mv /data/local/tmp/obb/com.omixlab.MosisUnreal /sdcard/Android/obb/"
|
||||
|
||||
echo OBB installed.
|
||||
) else (
|
||||
echo No OBB file found, skipping.
|
||||
)
|
||||
|
||||
echo.
|
||||
echo Installation completed!
|
||||
echo.
|
||||
echo To launch: adb -s %DEVICE% shell am start -n com.omixlab.MosisUnreal/com.epicgames.unreal.GameActivity
|
||||
goto :eof
|
||||
|
||||
:deploy
|
||||
call :build
|
||||
if errorlevel 1 exit /b 1
|
||||
call :install
|
||||
if errorlevel 1 exit /b 1
|
||||
call :launch
|
||||
goto :eof
|
||||
|
||||
:launch
|
||||
echo.
|
||||
echo ============================================
|
||||
echo Launching MosisUnreal...
|
||||
echo ============================================
|
||||
echo.
|
||||
|
||||
:: Check for connected device
|
||||
adb devices | findstr /r /c:"device$" >nul
|
||||
if errorlevel 1 (
|
||||
echo ERROR: No Android device connected!
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: Get device ID
|
||||
for /f "tokens=1" %%d in ('adb devices ^| findstr /r /c:"device$"') do (
|
||||
set DEVICE=%%d
|
||||
goto :found_device_launch
|
||||
)
|
||||
:found_device_launch
|
||||
echo Device: %DEVICE%
|
||||
|
||||
:: Stop any running instances
|
||||
echo Stopping existing instances...
|
||||
adb -s %DEVICE% shell am force-stop com.omixlab.MosisUnreal >nul 2>&1
|
||||
adb -s %DEVICE% shell am force-stop com.omixlab.mosis >nul 2>&1
|
||||
timeout /t 1 /nobreak >nul
|
||||
|
||||
:: Start MosisService first
|
||||
echo Starting MosisService...
|
||||
adb -s %DEVICE% shell am start -n com.omixlab.mosis/.MainActivity
|
||||
timeout /t 2 /nobreak >nul
|
||||
|
||||
:: Start MosisUnreal
|
||||
echo Starting MosisUnreal...
|
||||
adb -s %DEVICE% shell am start -n com.omixlab.MosisUnreal/com.epicgames.unreal.GameActivity
|
||||
|
||||
echo.
|
||||
echo Launched! Monitoring logs (Ctrl+C to stop)...
|
||||
echo.
|
||||
adb -s %DEVICE% logcat -s MosisSDK MosisOS MosisTest UE
|
||||
goto :eof
|
||||
|
||||
:clean
|
||||
echo.
|
||||
echo ============================================
|
||||
echo Cleaning build artifacts...
|
||||
echo ============================================
|
||||
echo.
|
||||
|
||||
if exist "%~dp0Binaries" (
|
||||
echo Removing Binaries...
|
||||
rmdir /s /q "%~dp0Binaries"
|
||||
)
|
||||
|
||||
if exist "%~dp0Intermediate\Build" (
|
||||
echo Removing Intermediate\Build...
|
||||
rmdir /s /q "%~dp0Intermediate\Build"
|
||||
)
|
||||
|
||||
if exist "%~dp0Saved\StagedBuilds" (
|
||||
echo Removing Saved\StagedBuilds...
|
||||
rmdir /s /q "%~dp0Saved\StagedBuilds"
|
||||
)
|
||||
|
||||
echo Clean completed!
|
||||
goto :eof
|
||||
Reference in New Issue
Block a user