using UnityEngine; using UnityEngine.Rendering; using System; using System.Runtime.InteropServices; public class KotlinBridge : MonoBehaviour { static KotlinBridge Instance; [StructLayout(LayoutKind.Sequential)] struct NativeCallbacks { public IntPtr OnMessage; public IntPtr OnServiceInitialized; public IntPtr OnFrameAvailable; public IntPtr OnBufferReady; public IntPtr OnTextureReady; } delegate void OnMessageDelegate(string message); delegate void OnServiceInitializedDelegate(bool success); delegate void OnFrameAvailableDelegate(); delegate void OnBufferReadyDelegate(); delegate void OnTextureReadyDelegate(IntPtr nativeTexturePtr, int width, int height, bool isVulkan); [DllImport("my_native_lib")] static extern void SetNativeCallbacks(ref NativeCallbacks callbacks); [DllImport("my_native_lib")] public static extern void SendTouchDown(float u, float v); [DllImport("my_native_lib")] public static extern void SendTouchMove(float u, float v); [DllImport("my_native_lib")] public static extern void SendTouchUp(float u, float v); [DllImport("my_native_lib")] static extern IntPtr InitBackend(); [DllImport("my_native_lib")] static extern IntPtr UpdateTexture(); // Legacy compatibility [DllImport("my_native_lib")] static extern IntPtr InitGLAD(); [AOT.MonoPInvokeCallback(typeof(OnMessageDelegate))] static void OnMessage(string message) { // High-speed callback, disabled for performance // Debug.Log("Native callback: " + message); } [AOT.MonoPInvokeCallback(typeof(OnServiceInitializedDelegate))] static void OnServiceInitialized(bool success) { Debug.Log("Service Initialized: " + success); } [AOT.MonoPInvokeCallback(typeof(OnFrameAvailableDelegate))] static void OnFrameAvailable() { UnityMainThreadDispatcher.Enqueue(() => { GL.IssuePluginEvent(UpdateTexture(), 1); }); } [AOT.MonoPInvokeCallback(typeof(OnBufferReadyDelegate))] static void OnBufferReady() { Debug.Log("Buffer Ready"); UnityMainThreadDispatcher.Enqueue(() => { GL.IssuePluginEvent(InitBackend(), 1); }); } [AOT.MonoPInvokeCallback(typeof(OnTextureReadyDelegate))] static void OnTextureReady(IntPtr nativeTexturePtr, int width, int height, bool isVulkan) { Debug.Log($"Texture Ready: ptr={nativeTexturePtr}, size={width}x{height}, vulkan={isVulkan}"); UnityMainThreadDispatcher.Enqueue(() => { var renderer = Instance.GetComponent(); if (renderer == null) { Debug.LogError("KotlinBridge: No Renderer component found"); return; } // Create external texture with actual dimensions from the service // Unity handles both OpenGL and Vulkan native textures via CreateExternalTexture Texture2D texture = Texture2D.CreateExternalTexture( width, height, TextureFormat.RGBA32, false, // mipChain false, // linear nativeTexturePtr ); if (texture == null) { Debug.LogError("KotlinBridge: Failed to create external texture"); return; } // Set texture on material (index 2 is the phone screen material) if (renderer.materials.Length > 2) { renderer.materials[2].mainTexture = texture; Debug.Log($"KotlinBridge: Texture set on material[2], {width}x{height}"); } else { Debug.LogWarning($"KotlinBridge: Not enough materials (have {renderer.materials.Length}, need 3)"); // Fall back to first material if not enough renderer.material.mainTexture = texture; } }); } void Start() { Instance = this; NativeCallbacks callbacks = new NativeCallbacks(); callbacks.OnMessage = Marshal.GetFunctionPointerForDelegate(new OnMessageDelegate(OnMessage)); callbacks.OnServiceInitialized = Marshal.GetFunctionPointerForDelegate(new OnServiceInitializedDelegate(OnServiceInitialized)); callbacks.OnFrameAvailable = Marshal.GetFunctionPointerForDelegate(new OnFrameAvailableDelegate(OnFrameAvailable)); callbacks.OnBufferReady = Marshal.GetFunctionPointerForDelegate(new OnBufferReadyDelegate(OnBufferReady)); callbacks.OnTextureReady = Marshal.GetFunctionPointerForDelegate(new OnTextureReadyDelegate(OnTextureReady)); SetNativeCallbacks(ref callbacks); if (Application.platform == RuntimePlatform.Android) { using (var ktClass = new AndroidJavaClass("com.omixlab.mosis.unity.MyKotlinPlugin")) { ktClass.CallStatic("StartMosisService"); } } } }