//>>> _using
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.Windows;
//<<< _using
using SharpDX.DXGI;
using SharpDX.D3DCompiler;
using SharpDX.Direct3D; 
using Framefield.Core.Rendering;

namespace Framefield.Core.ID5bde13cc_1a1b_4d76_925a_a20b1959bbf9
{
    public class Class_MotionBlur : FXImageFunction
    {
        //>>> _inputids
        private enum InputId
        {
            Code = 0,
            Image = 1,
            Camera = 2,
            Strength = 3,
            Clamp = 4,
            NumberOfSamples = 5
        }
        //<<< _inputids

        protected override bool NeedsDepth { get { return false; } }

        public override OperatorPartContext Eval(OperatorPartContext context, List<OperatorPart> inputs, int outputIdx)
        {
            return PrepareAndEvalOnChange(context, () =>
            {
                //>>> __params
                var imageInput = inputs[(int)InputId.Image].Eval(context);
                var Strength = inputs[(int)InputId.Strength].Eval(context).Value;
                var Clamp = inputs[(int)InputId.Clamp].Eval(context).Value;
                var NumberOfSamples = inputs[(int)InputId.NumberOfSamples].Eval(context).Value;
                var Camera = inputs[(int)InputId.Camera].Eval(context).Dynamic;
                //<<< __params
    
                var image = imageInput.Image;
                var depthImage = imageInput.DepthImage;
                if (image == null || depthImage == null || Camera == null)
                {
                    Logger.Error(this,"{0}: conditions not fulfilled", OperatorPart.Parent);
                    return;
                }
                Framefield.Core.OperatorPartTraits.ICameraProvider camProvider = Camera.This as Framefield.Core.OperatorPartTraits.ICameraProvider;
                if (camProvider == null)
                {
                    Logger.Error(this,"{0}: camera not defined", OperatorPart.Parent);
                    return;
                }

                var viewToWorld = Matrix.Identity;
                var previousWorldToView = Matrix.Identity;

                var worldToCamera = camProvider.CalculateWorldToCamera(context);
                var cameraToView = camProvider.CalculateCameraToView(context);
                viewToWorld = Matrix.Invert(worldToCamera*cameraToView);

                using (new PropertyStasher<OperatorPartContext>(context, "Time")) {
                    context.Time -= 0.01f;
                    OperatorPart.ChangedPropagationEnabled = false;

                    // Invalidate all time accessors
                    var subTree= inputs[(int)InputId.Camera];
                    var invalidator = new OperatorPart.InvalidateTimeAccessors();
                    subTree.TraverseWithFunctionUseSpecificBehavior(null, invalidator);
            
                    var previousWorldToCamera = camProvider.CalculateWorldToCamera(context);
                    var previousCameraToView = camProvider.CalculateCameraToView(context);
                    previousWorldToView = previousWorldToCamera*previousCameraToView;
                    OperatorPart.ChangedPropagationEnabled = true;

                }

                ClearRenderTarget(context, new SharpDX.Color4(0, 0, 0, 1));

                var shaderDesc = new ShaderResourceViewDescription();
                shaderDesc.Format = Format.R32_Float;
                shaderDesc.Dimension = ShaderResourceViewDimension.Texture2D;
                shaderDesc.Texture2D.MipLevels = 1;

                using (var depthTexture = new ShaderResourceView(context.D3DDevice, depthImage, shaderDesc))
                //>>> __setup
                using (var ImageView = new ShaderResourceView(context.D3DDevice, image))
                {
                    _effect.GetVariableByName("RenderTargetSize").AsVector().Set(new Vector2(_usedViewport.Width, _usedViewport.Height));
                    _effect.GetVariableByName("Image").AsShaderResource().SetResource(ImageView);
                    _effect.GetVariableByName("Strength").AsScalar().Set(Strength);
                    _effect.GetVariableByName("Clamp_").AsScalar().Set(Clamp);
                    _effect.GetVariableByName("NumberOfSamples").AsScalar().Set(NumberOfSamples);
                    //<<< __setup
    
                    _effect.GetVariableByName("viewToWorld").AsMatrix().SetMatrix(viewToWorld);
                    _effect.GetVariableByName("previousWorldToView").AsMatrix().SetMatrix(previousWorldToView);
                    _effect.GetVariableByName("txDepth").AsShaderResource().SetResource(depthTexture); 
    
                    Render(context);

                //>>> _cleanup
                }
                //<<< _cleanup
            });
        }
    }
}

