using System;
using System.Runtime.InteropServices;
namespace UnityEngine.XR.MagicLeap
{
    public partial class YcbcrRenderer
    {
        private sealed class NativeBindings
        {
            private const string MLYcbcrRendererDll = "ml_ycbcr_renderer";
            [DllImport(MLYcbcrRendererDll, CallingConvention = CallingConvention.Cdecl)]
            public static extern MLResult.Code MLYcbcrRendererCreate([In] ref CreateInfo createInfo, out ulong handle);
            [DllImport(MLYcbcrRendererDll, CallingConvention = CallingConvention.Cdecl)]
            public static extern int MLYcbcrRendererGetEventIdForPluginEvent(PluginEvent pluginEvent);
            [DllImport(MLYcbcrRendererDll, CallingConvention = CallingConvention.Cdecl)]
            public static extern IntPtr MLYcbcrRendererGetCallbackForPluginEvent(PluginEvent pluginEvent);
            public delegate void AcquireNextAvailableBufferDelegate([MarshalAs(UnmanagedType.I1)][In][Out] ref bool success, [In][Out] ref ulong nativeBufferHandle, IntPtr context);
            public delegate void AcquireNextAvailableHwBufferDelegate([MarshalAs(UnmanagedType.I1)][In][Out] ref bool success, [In][Out] ref IntPtr hwBuffer, IntPtr context);
            public delegate void ReleaseBufferDelegate(ulong nativeBufferHandle, IntPtr context);
            public delegate void ReleaseHwBufferDelegate(IntPtr hwBuffer, IntPtr context);
            public delegate void GetFrameTransformMatrixDelegate([MarshalAs(UnmanagedType.I1)][In][Out] ref bool success, [In][Out] ref Native.MagicLeapNativeBindings.MLMat4f frameMat, IntPtr context);
            public delegate void IsNewFrameAvailableDelegate([MarshalAs(UnmanagedType.I1)][In][Out] ref bool success, IntPtr context);
            public delegate void OnCleanupCompleteDelegate(IntPtr context);
            public delegate void OnFirstFrameRenderedDelegate(IntPtr context);
            public delegate void OverrideYcbcrConversionSamplerDelegate([In] ref VkAndroidHardwareBufferFormatPropertiesANDROID hwBufferFormatProperties, [MarshalAs(UnmanagedType.I1)][In][Out] ref bool samplerChanged, [In][Out] ref VkSamplerYcbcrConversionCreateInfo sampler, IntPtr context);
            [AOT.MonoPInvokeCallback(typeof(AcquireNextAvailableBufferDelegate))]
            private static void AcquireNextAvailableBuffer([MarshalAs(UnmanagedType.I1)][In][Out] ref bool success, [In][Out] ref ulong nativeBufferHandle, IntPtr context)
            {
                GCHandle gCHandle = GCHandle.FromIntPtr(context);
                INativeBufferProvider provider = gCHandle.Target as INativeBufferProvider;
                if (provider == null)
                {
                    return;
                }
                success = provider.AcquireNextAvailableBuffer(out nativeBufferHandle);
            }
            [AOT.MonoPInvokeCallback(typeof(AcquireNextAvailableHwBufferDelegate))]
            private static void AcquireNextAvailableHwBuffer([MarshalAs(UnmanagedType.I1)][In][Out] ref bool success, [In][Out] ref IntPtr hwBuffer, IntPtr context)
            {
                GCHandle gCHandle = GCHandle.FromIntPtr(context);
                IHardwareBufferProvider provider = gCHandle.Target as IHardwareBufferProvider;
                if (provider == null)
                {
                    return;
                }
                success = provider.AcquireNextAvailableHwBuffer(out hwBuffer);
            }
            [AOT.MonoPInvokeCallback(typeof(ReleaseBufferDelegate))]
            private static void ReleaseBuffer(ulong nativeBufferHandle, IntPtr context)
            {
                GCHandle gCHandle = GCHandle.FromIntPtr(context);
                INativeBufferProvider provider = gCHandle.Target as INativeBufferProvider;
                if (provider == null)
                {
                    return;
                }
                provider.ReleaseBuffer(nativeBufferHandle);
            }
            [AOT.MonoPInvokeCallback(typeof(ReleaseHwBufferDelegate))]
            private static void ReleaseHwBuffer(IntPtr hwBuffer, IntPtr context)
            {
                GCHandle gCHandle = GCHandle.FromIntPtr(context);
                IHardwareBufferProvider provider = gCHandle.Target as IHardwareBufferProvider;
                if (provider == null)
                {
                    return;
                }
                provider.ReleaseHwBuffer(hwBuffer);
            }
            [AOT.MonoPInvokeCallback(typeof(GetFrameTransformMatrixDelegate))]
            private static void GetFrameTransformMatrix([MarshalAs(UnmanagedType.I1)][In][Out] ref bool success, [In][Out] ref Native.MagicLeapNativeBindings.MLMat4f frameMat, IntPtr context)
            {
                GCHandle gCHandle = GCHandle.FromIntPtr(context);
                IFrameTransformMatrixProvider provider = gCHandle.Target as IFrameTransformMatrixProvider;
                if (provider == null)
                {
                    return;
                }
                success = provider.GetFrameTransformMatrix(frameMat.MatrixColmajor);
            }
            [AOT.MonoPInvokeCallback(typeof(IsNewFrameAvailableDelegate))]
            private static void IsNewFrameAvailable([MarshalAs(UnmanagedType.I1)][In][Out] ref bool success, IntPtr context)
            {
                GCHandle gCHandle = GCHandle.FromIntPtr(context);
                IFrameAvailabilityProvider provider = gCHandle.Target as IFrameAvailabilityProvider;
                if (provider == null)
                {
                    return;
                }
                success = provider.IsNewFrameAvailable();
            }
            [AOT.MonoPInvokeCallback(typeof(OnCleanupCompleteDelegate))]
            private static void OnCleanupComplete(IntPtr context)
            {
                GCHandle gcHandle = GCHandle.FromIntPtr(context);
                YcbcrRenderer ycbcrRenderer = (gcHandle.Target as YcbcrRenderer);
                if (ycbcrRenderer == null)
                {
                    return;
                }
                ycbcrRenderer.InvokeOnCleanupComplete_CallbackThread();
            }
            [AOT.MonoPInvokeCallback(typeof(OnFirstFrameRenderedDelegate))]
            private static void OnFirstFrameRendered(IntPtr context)
            {
                GCHandle gcHandle = GCHandle.FromIntPtr(context);
                YcbcrRenderer ycbcrRenderer = (gcHandle.Target as YcbcrRenderer);
                if (ycbcrRenderer == null)
                {
                    return;
                }
                ycbcrRenderer.InvokeOnFirstFrameRendered();
            }
            [AOT.MonoPInvokeCallback(typeof(OverrideYcbcrConversionSamplerDelegate))]
            private static void OverrideYcbcrConversionSampler([In] ref VkAndroidHardwareBufferFormatPropertiesANDROID hwBufferFormatProperties, [MarshalAs(UnmanagedType.I1)][In][Out] ref bool samplerChanged, [In][Out] ref VkSamplerYcbcrConversionCreateInfo sampler, IntPtr context)
            {
                GCHandle gcHandle = GCHandle.FromIntPtr(context);
                IYcbcrConversionSamplerProvider ycbcrRenderer = (gcHandle.Target as IYcbcrConversionSamplerProvider);
                if (ycbcrRenderer == null)
                {
                    return;
                }
                samplerChanged = ycbcrRenderer.OverrideYcbcrConversionSampler(ref hwBufferFormatProperties, ref sampler);
            }
            public enum ColorSpace : uint
            {
                Linear,
                Gamma
            }
            public enum PluginEvent : uint
            {
                SetTexture,
                Draw,
                Cleanup,
                AccessTexture
            }
            [StructLayout(LayoutKind.Sequential)]
            public struct PluginEventData
            {
                public ulong RendererHandle;
                public IntPtr TextureHandle;
                public int Width;
                public int Height;
                public ColorSpace ColorSpace;
                public PluginEventData(ulong rendererHandle, RenderTexture renderBuffer)
                {
                    this.RendererHandle = rendererHandle;
                    this.TextureHandle = renderBuffer.colorBuffer.GetNativeRenderBufferPtr();
                    this.Width = renderBuffer.width;
                    this.Height = renderBuffer.height;
                    
                    
                    
                    
                    
                    
                    this.ColorSpace = renderBuffer.sRGB ? ColorSpace.Linear : ColorSpace.Gamma;
                }
            }
            [StructLayout(LayoutKind.Sequential)]
            public struct CreateInfo
            {
                public IntPtr Context;
                public AcquireNextAvailableBufferDelegate AcquireNextAvailableBufferCallback;
                public AcquireNextAvailableHwBufferDelegate AcquireNextAvailableHwBufferCallback;
                public ReleaseBufferDelegate ReleaseBufferCallback;
                public ReleaseHwBufferDelegate ReleaseHwBufferCallback;
                public GetFrameTransformMatrixDelegate GetFrameTransformMatrixCallback;
                public IsNewFrameAvailableDelegate IsNewFrameAvailableCallback;
                public OnCleanupCompleteDelegate OnCleanupCompleteCallback;
                public OnFirstFrameRenderedDelegate OnFirstFrameRenderedCallback;
                public OverrideYcbcrConversionSamplerDelegate OverrideYcbcrConversionSamplerCallback;
                [MarshalAs(UnmanagedType.I1)]
                public bool ShouldWaitForQueueIdleOnSubmit;
                public CreateInfo(GCHandle context, YcbcrRenderer renderer, bool waitForQueueIdleOnSubmit)
                {
                    this.Context = GCHandle.ToIntPtr(context);
                    this.AcquireNextAvailableBufferCallback = null;
                    this.ReleaseBufferCallback = null;
                    if (renderer is INativeBufferProvider)
                    {
                        this.AcquireNextAvailableBufferCallback = AcquireNextAvailableBuffer;
                        this.ReleaseBufferCallback = ReleaseBuffer;
                    }
                    this.AcquireNextAvailableHwBufferCallback = null;
                    this.ReleaseHwBufferCallback = null;
                    if (renderer is IHardwareBufferProvider)
                    {
                        this.AcquireNextAvailableHwBufferCallback = AcquireNextAvailableHwBuffer;
                        this.ReleaseHwBufferCallback = ReleaseHwBuffer;
                    }
                    this.GetFrameTransformMatrixCallback = null;
                    if (renderer is IFrameTransformMatrixProvider)
                    {
                        this.GetFrameTransformMatrixCallback = GetFrameTransformMatrix;
                    }
                    this.IsNewFrameAvailableCallback = null;
                    if (renderer is IFrameAvailabilityProvider)
                    {
                        this.IsNewFrameAvailableCallback = IsNewFrameAvailable;
                    }
                    this.OnCleanupCompleteCallback = OnCleanupComplete;
                    this.OnFirstFrameRenderedCallback = OnFirstFrameRendered;
                    this.OverrideYcbcrConversionSamplerCallback = null;
                    if (renderer is IYcbcrConversionSamplerProvider)
                    {
                        this.OverrideYcbcrConversionSamplerCallback = OverrideYcbcrConversionSampler;
                    }
                    this.ShouldWaitForQueueIdleOnSubmit = waitForQueueIdleOnSubmit;
                }
            }
        }
    }
}