/**********************************************************************************
* Blueprint Reality Inc. CONFIDENTIAL
* 2021 Blueprint Reality Inc.
* All Rights Reserved.
*
* NOTICE:  All information contained herein is, and remains, the property of
* Blueprint Reality Inc. and its suppliers, if any.  The intellectual and
* technical concepts contained herein are proprietary to Blueprint Reality Inc.
* and its suppliers and may be covered by Patents, pending patents, and are
* protected by trade secret or copyright law.
*
* Dissemination of this information or reproduction of this material is strictly
* forbidden unless prior written permission is obtained from Blueprint Reality Inc.
***********************************************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Rendering;

namespace BlueprintReality.Interprocess.Textures
{
    public class OwnedUnitySharedTexture : IDisposable
    {
        private IntPtr updateFunc;

        private bool ntHandleMode;
        private GraphicsDeviceType gfxType;

        private int texIndex;

        private Texture sourceTex;
        public Texture SourceTex
        {
            get
            {
                return sourceTex;
            }
            set
            {
                if (sourceTex != value)
                {
                    Texture oldTex = SourceTex;
                    sourceTex = value;

                    if (oldTex.width == sourceTex.width && oldTex.height == sourceTex.height)
                    {
                        switch (gfxType)
                        {
                            case GraphicsDeviceType.Direct3D11:
                                UpdateOwnedSharedTextureSource_D3D11(texIndex, sourceTex.GetNativeTexturePtr());
                                break;
                            case GraphicsDeviceType.Direct3D12:
                                UpdateOwnedSharedTextureSource_D3D11(texIndex, sourceTex.GetNativeTexturePtr());
                                break;
                        }
                    }
                    else
                    {
                        DisposeOwnedSharedTexture(texIndex);
                        switch (gfxType)
                        {
                            case GraphicsDeviceType.Direct3D11:
                                texIndex = CreateOwnedSharedTexture_D3D11(sourceTex.GetNativeTexturePtr(), ntHandleMode, out handle, out format);
                                break;
                            case GraphicsDeviceType.Direct3D12:
                                texIndex = CreateOwnedSharedTexture_D3D12(sourceTex.GetNativeTexturePtr(), out handle, out format);
                                break;
                        }
                    }
                }
            }
        }

        private IntPtr handle;
        public IntPtr Handle { get { return handle; } }

        private uint format;
        public uint Format { get { return format; } }

        public OwnedUnitySharedTexture(Texture srcTex, bool ntHandles)
        {
            sourceTex = srcTex;

            ntHandleMode = ntHandles;
            gfxType = SystemInfo.graphicsDeviceType;

            updateFunc = GetUpdateOwnedSharedTextureFunc();

            switch (gfxType)
            {
                case GraphicsDeviceType.Direct3D11:
                    texIndex = CreateOwnedSharedTexture_D3D11(sourceTex.GetNativeTexturePtr(), ntHandles, out handle, out format);
                    break;
                case GraphicsDeviceType.Direct3D12:
                    texIndex = CreateOwnedSharedTexture_D3D12(sourceTex.GetNativeTexturePtr(), out handle, out format);
                    break;
            }
        }
        public void Dispose()
        {
            DisposeOwnedSharedTexture(texIndex);
        }

        public void IssueUpdate()
        {
            GL.IssuePluginEvent(updateFunc, texIndex);
        }
        public void IssueUpdate(Texture newSrcTex)
        {
            SourceTex = newSrcTex;
            IssueUpdate();
        }

        [DllImport(MixCastInteropPlugin.DllName)]
        private static extern int CreateOwnedSharedTexture_D3D11(IntPtr srcTex, [MarshalAs(UnmanagedType.U1)] bool ntHandles, out IntPtr texHandle, out uint texFormat);
        [DllImport(MixCastInteropPlugin.DllName)]
        private static extern int CreateOwnedSharedTexture_D3D12(IntPtr srcTex, out IntPtr texHandle, out uint texFormat);
        [DllImport(MixCastInteropPlugin.DllName)]
        private static extern int DisposeOwnedSharedTexture(int index);

        [DllImport(MixCastInteropPlugin.DllName)]
        private static extern IntPtr UpdateOwnedSharedTextureSource_D3D11(int textureIndex, IntPtr srcTex);
        [DllImport(MixCastInteropPlugin.DllName)]
        private static extern IntPtr UpdateOwnedSharedTextureSource_D3D12(int textureIndex, IntPtr srcTex);

        [DllImport(MixCastInteropPlugin.DllName)]
        private static extern IntPtr GetUpdateOwnedSharedTextureFunc();
    }
}
