//>>> _using
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.Windows;
//<<< _using
using Framefield.Core.OperatorPartTraits;
using Framefield.Core.Rendering;
using Buffer = SharpDX.Direct3D11.Buffer;
using SharpDX.Direct3D;

namespace Framefield.Core.IDc0519a20_0ba2_44ee_90b6_5eb532c03fb0
{
    public class Class_TornadoScatterCubeMap : FXSourceCodeFunction, IFXSceneSourceCode, IMeshSupplier
    {
        //>>> _inputids
        private enum InputId
        {
            Code = 0,
            Scene = 1,
            StartPositionX = 2,
            StartPositionY = 3,
            StartPositionZ = 4,
            StartTangentX = 5,
            StartTangentY = 6,
            StartTangentZ = 7,
            EndPositionX = 8,
            EndPositionY = 9,
            EndPositionZ = 10,
            EndTangentX = 11,
            EndTangentY = 12,
            EndTangentZ = 13,
            Radius = 14,
            MoveCenterValue = 15,
            MoveCenterBias = 16,
            MoveEdgeValue = 17,
            MoveEdgeBias = 18,
            ConvergeCenterValue = 19,
            ConvergeCenterBias = 20,
            ConvergeEdgeValue = 21,
            ConvergeEdgeBias = 22,
            TwirlCenterValue = 23,
            TwirlCenterBias = 24,
            TwirlEdgeValue = 25,
            TwirlEdgeBias = 26,
            ShrinkCenterValue = 27,
            ShrinkCenterBias = 28,
            ShrinkEdgeValue = 29,
            ShrinkEdgeBias = 30,
            ScatterCenterValue = 31,
            ScatterCenterBias = 32,
            ScatterEdgeValue = 33,
            ScatterEdgeBias = 34,
            DistortCenterValue = 35,
            DistortCenterBias = 36,
            DistortEdgeValue = 37,
            DistortEdgeBias = 38,
            RotateCenterValue = 39,
            RotateCenterBias = 40,
            RotateEdgeValue = 41,
            RotateEdgeBias = 42,
            CubeMap = 43
        }
        //<<< _inputids

        public Class_TornadoScatterCubeMap()
        {
            _meshCollector = new MeshCollector(this);
        }

        public override void Dispose() 
        {
            Utilities.DisposeObj(ref _mesh);
            base.Dispose();
        }

        public void AddMeshesTo(ICollection<Mesh> meshes)
        {
            UpdateMesh(new OperatorPartContext(), OperatorPart.Connections);
            if (_mesh != null)
                meshes.Add(_mesh);
        }

        public override OperatorPartContext Eval(OperatorPartContext context, List<OperatorPart> inputs, int outputIdx)
        {
            try
            {
                UpdateMesh(context, inputs);

                if (_mesh.Vertices != null)
                {
                    var CubeMap = inputs[(int)InputId.CubeMap].Eval(context).Image;
                    using (var CubeMapView = new ShaderResourceView(context.D3DDevice, CubeMap))
                    {
                        _effect.GetVariableByName("CubeMap").AsShaderResource().SetResource(CubeMapView);

                        // render stream output to screen or whatever target is set
                        context.Renderer.SetupEffect(context);
                        context.Renderer.Render(_mesh, context);
                    }
                }
            }
            catch (Exception exception)
            {
                Logger.Error(this, "Load Effect error: {0}", exception.Message);
            }

            return context;
        }

        bool _firstEval = true;
        private void UpdateMesh(OperatorPartContext context, List<OperatorPart> inputs)
        {
            if (_firstEval)
            {
                for (int i = 0; i < NumCodes(); ++i)
                    Compile(i);
                _firstEval = false;
                Changed = true;
            }

            if (!Changed && _mesh.Vertices != null)
                return;

            //>>> __params
            var Code = inputs[(int)InputId.Code].Eval(context).Text;
            var Scene = inputs[(int)InputId.Scene];
            var StartPositionX = inputs[(int)InputId.StartPositionX].Eval(context).Value;
            var StartPositionY = inputs[(int)InputId.StartPositionY].Eval(context).Value;
            var StartPositionZ = inputs[(int)InputId.StartPositionZ].Eval(context).Value;
            var StartPosition = new Vector3(StartPositionX, StartPositionY, StartPositionZ);
            var StartTangentX = inputs[(int)InputId.StartTangentX].Eval(context).Value;
            var StartTangentY = inputs[(int)InputId.StartTangentY].Eval(context).Value;
            var StartTangentZ = inputs[(int)InputId.StartTangentZ].Eval(context).Value;
            var StartTangent = new Vector3(StartTangentX, StartTangentY, StartTangentZ);
            var EndPositionX = inputs[(int)InputId.EndPositionX].Eval(context).Value;
            var EndPositionY = inputs[(int)InputId.EndPositionY].Eval(context).Value;
            var EndPositionZ = inputs[(int)InputId.EndPositionZ].Eval(context).Value;
            var EndPosition = new Vector3(EndPositionX, EndPositionY, EndPositionZ);
            var EndTangentX = inputs[(int)InputId.EndTangentX].Eval(context).Value;
            var EndTangentY = inputs[(int)InputId.EndTangentY].Eval(context).Value;
            var EndTangentZ = inputs[(int)InputId.EndTangentZ].Eval(context).Value;
            var EndTangent = new Vector3(EndTangentX, EndTangentY, EndTangentZ);
            var Radius = inputs[(int)InputId.Radius].Eval(context).Value;
            var MoveCenterValue = inputs[(int)InputId.MoveCenterValue].Eval(context).Value;
            var MoveCenterBias = inputs[(int)InputId.MoveCenterBias].Eval(context).Value;
            var MoveEdgeValue = inputs[(int)InputId.MoveEdgeValue].Eval(context).Value;
            var MoveEdgeBias = inputs[(int)InputId.MoveEdgeBias].Eval(context).Value;
            var Move = new Vector4(MoveCenterValue, MoveCenterBias, MoveEdgeValue, MoveEdgeBias);
            var ConvergeCenterValue = inputs[(int)InputId.ConvergeCenterValue].Eval(context).Value;
            var ConvergeCenterBias = inputs[(int)InputId.ConvergeCenterBias].Eval(context).Value;
            var ConvergeEdgeValue = inputs[(int)InputId.ConvergeEdgeValue].Eval(context).Value;
            var ConvergeEdgeBias = inputs[(int)InputId.ConvergeEdgeBias].Eval(context).Value;
            var Converge = new Vector4(ConvergeCenterValue, ConvergeCenterBias, ConvergeEdgeValue, ConvergeEdgeBias);
            var TwirlCenterValue = inputs[(int)InputId.TwirlCenterValue].Eval(context).Value;
            var TwirlCenterBias = inputs[(int)InputId.TwirlCenterBias].Eval(context).Value;
            var TwirlEdgeValue = inputs[(int)InputId.TwirlEdgeValue].Eval(context).Value;
            var TwirlEdgeBias = inputs[(int)InputId.TwirlEdgeBias].Eval(context).Value;
            var Twirl = new Vector4(TwirlCenterValue, TwirlCenterBias, TwirlEdgeValue, TwirlEdgeBias);
            var ShrinkCenterValue = inputs[(int)InputId.ShrinkCenterValue].Eval(context).Value;
            var ShrinkCenterBias = inputs[(int)InputId.ShrinkCenterBias].Eval(context).Value;
            var ShrinkEdgeValue = inputs[(int)InputId.ShrinkEdgeValue].Eval(context).Value;
            var ShrinkEdgeBias = inputs[(int)InputId.ShrinkEdgeBias].Eval(context).Value;
            var Shrink = new Vector4(ShrinkCenterValue, ShrinkCenterBias, ShrinkEdgeValue, ShrinkEdgeBias);
            var ScatterCenterValue = inputs[(int)InputId.ScatterCenterValue].Eval(context).Value;
            var ScatterCenterBias = inputs[(int)InputId.ScatterCenterBias].Eval(context).Value;
            var ScatterEdgeValue = inputs[(int)InputId.ScatterEdgeValue].Eval(context).Value;
            var ScatterEdgeBias = inputs[(int)InputId.ScatterEdgeBias].Eval(context).Value;
            var Scatter = new Vector4(ScatterCenterValue, ScatterCenterBias, ScatterEdgeValue, ScatterEdgeBias);
            var DistortCenterValue = inputs[(int)InputId.DistortCenterValue].Eval(context).Value;
            var DistortCenterBias = inputs[(int)InputId.DistortCenterBias].Eval(context).Value;
            var DistortEdgeValue = inputs[(int)InputId.DistortEdgeValue].Eval(context).Value;
            var DistortEdgeBias = inputs[(int)InputId.DistortEdgeBias].Eval(context).Value;
            var Distort = new Vector4(DistortCenterValue, DistortCenterBias, DistortEdgeValue, DistortEdgeBias);
            var RotateCenterValue = inputs[(int)InputId.RotateCenterValue].Eval(context).Value;
            var RotateCenterBias = inputs[(int)InputId.RotateCenterBias].Eval(context).Value;
            var RotateEdgeValue = inputs[(int)InputId.RotateEdgeValue].Eval(context).Value;
            var RotateEdgeBias = inputs[(int)InputId.RotateEdgeBias].Eval(context).Value;
            var Rotate = new Vector4(RotateCenterValue, RotateCenterBias, RotateEdgeValue, RotateEdgeBias);
            //<<< __params

            if (Scene.Func.Changed || _mesh.Vertices == null)
            {
                //Logger.Info(this, "collect meshes");
                _meshCollector.Collect(Scene);
                Scene.Func.Changed = false;
            }

            var inputMesh = _meshCollector.FirstMeshOrDefault;
            if (inputMesh == null)
                return;

            _mesh.AttributesSize = inputMesh.AttributesSize;
            _mesh.NumTriangles = inputMesh.NumTriangles;
            _mesh.InputElements = inputMesh.InputElements;
            if (_mesh.Vertices == null || _mesh.Vertices.Description.SizeInBytes != inputMesh.Vertices.Description.SizeInBytes)
            {
                if (_mesh.Vertices != null)
                    _mesh.Vertices.Dispose();

                _mesh.Vertices = new Buffer(D3DDevice.Device, new BufferDescription()
                                                                    {
                                                                        BindFlags = BindFlags.StreamOutput | BindFlags.VertexBuffer,
                                                                        CpuAccessFlags = CpuAccessFlags.None,
                                                                        OptionFlags = ResourceOptionFlags.None,
                                                                        SizeInBytes = _mesh.NumTriangles*inputMesh.AttributesSize*3,
                                                                        Usage = ResourceUsage.Default
                                                                    });
            }
            

                _effect.GetVariableByName("Radius").AsScalar().Set(Radius);
                _effect.GetVariableByName("StartPosition").AsVector().Set(new Vector3(StartPositionX, StartPositionY, StartPositionZ));
                _effect.GetVariableByName("StartTangent").AsVector().Set(new Vector3(StartTangentX, StartTangentY, StartTangentZ));
                _effect.GetVariableByName("EndPosition").AsVector().Set(new Vector3(EndPositionX, EndPositionY, EndPositionZ));
                _effect.GetVariableByName("EndTangent").AsVector().Set(new Vector3(EndTangentX, EndTangentY, EndTangentZ));
    
                _effect.GetVariableByName("Move").AsVector().Set(new Vector4(MoveCenterValue, MoveCenterBias, MoveEdgeValue, MoveEdgeBias));
                _effect.GetVariableByName("Converge").AsVector().Set(new Vector4(ConvergeCenterValue, ConvergeCenterBias, ConvergeEdgeValue, ConvergeEdgeBias));
                _effect.GetVariableByName("Twirl").AsVector().Set(new Vector4(TwirlCenterValue, TwirlCenterBias, TwirlEdgeValue, TwirlEdgeBias));
                
                
                _effect.GetVariableByName("Shrink").AsVector().Set(new Vector4(ShrinkCenterValue, ShrinkCenterBias, ShrinkEdgeValue, ShrinkEdgeBias));
                _effect.GetVariableByName("Scatter").AsVector().Set(new Vector4(ScatterCenterValue, ScatterCenterBias, ScatterEdgeValue, ScatterEdgeBias));
                _effect.GetVariableByName("Distort").AsVector().Set(new Vector4(DistortCenterValue, DistortCenterBias, DistortEdgeValue, DistortEdgeBias));
                _effect.GetVariableByName("Rotate").AsVector().Set(new Vector4(RotateCenterValue, RotateCenterBias, RotateEdgeValue, RotateEdgeBias));
                
                
                //_effect.GetVariableByName("Translate").AsVector().Set(new Vector3(TranslateX, TranslateY, TranslateZ));
                //_effect.GetVariableByName("Range").AsVector().Set(new Vector2(RangeSize, RangeFallOff));
                //_effect.GetVariableByName("Push").AsScalar().Set(Push);
                //_effect.GetVariableByName("Shrink").AsScalar().Set(Shrink);
                //_effect.GetVariableByName("Scatter").AsScalar().Set(Scatter);
                //_effect.GetVariableByName("Distort").AsScalar().Set(Distort);
                //_effect.GetVariableByName("Rotate").AsScalar().Set(Rotate);
    
                context.D3DDevice.ImmediateContext.StreamOutput.SetTargets(new [] { new StreamOutputBufferBinding(_mesh.Vertices, 0) });
                context.D3DDevice.ImmediateContext.OutputMerger.DepthStencilState = new DepthStencilState(context.D3DDevice,
                                                                                                            new DepthStencilStateDescription()
                                                                                                                {
                                                                                                                    IsDepthEnabled = false,
                                                                                                                    IsStencilEnabled = false
                                                                                                                });
                context.D3DDevice.ImmediateContext.InputAssembler.InputLayout = context.InputLayout;
                context.D3DDevice.ImmediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
                context.D3DDevice.ImmediateContext.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(inputMesh.Vertices, inputMesh.AttributesSize, 0));
                var technique = _effect.GetTechniqueByIndex(0);
                technique.GetPassByIndex(0).Apply(context.D3DDevice.ImmediateContext);
                context.D3DDevice.ImmediateContext.Draw(_mesh.NumTriangles*3, 0);
                context.D3DDevice.ImmediateContext.StreamOutput.SetTargets(new [] { new StreamOutputBufferBinding(null, 0) });
            

            Changed = false;
        }

        private Mesh _mesh = new Mesh();
        private MeshCollector _meshCollector;
    }
}


