using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Device = SharpDX.Direct3D11.Device;
using Buffer = SharpDX.Direct3D11.Buffer;
using MapFlags = SharpDX.Direct3D11.MapFlags;
using SharpDX.Direct3D11;
using System.IO;
using CodeWalker.GameFiles;
using CodeWalker.World;
using SharpDX;
using SharpDX.DXGI;
using SharpDX.Mathematics.Interop;

namespace CodeWalker.Rendering
{

    public struct PostProcessorReduceCSVars
    {
        public uint dimx;
        public uint dimy;
        public uint Width;
        public uint Height;
    }
    public struct PostProcessorLumBlendCSVars
    {
        public Vector4 blend;
    }
    public struct PostProcessorFilterSampleWeights
    {
        public Vector4 avSampleWeights00; //[15];
        public Vector4 avSampleWeights01;
        public Vector4 avSampleWeights02;
        public Vector4 avSampleWeights03;
        public Vector4 avSampleWeights04;
        public Vector4 avSampleWeights05;
        public Vector4 avSampleWeights06;
        public Vector4 avSampleWeights07;
        public Vector4 avSampleWeights08;
        public Vector4 avSampleWeights09;
        public Vector4 avSampleWeights10;
        public Vector4 avSampleWeights11;
        public Vector4 avSampleWeights12;
        public Vector4 avSampleWeights13;
        public Vector4 avSampleWeights14;

        public Vector4 Get(int i)
        {
            switch (i)
            {
                default:
                case 0: return avSampleWeights00;
                case 1: return avSampleWeights01;
                case 2: return avSampleWeights02;
                case 3: return avSampleWeights03;
                case 4: return avSampleWeights04;
                case 5: return avSampleWeights05;
                case 6: return avSampleWeights06;
                case 7: return avSampleWeights07;
                case 8: return avSampleWeights08;
                case 9: return avSampleWeights09;
                case 10: return avSampleWeights10;
                case 11: return avSampleWeights11;
                case 12: return avSampleWeights12;
                case 13: return avSampleWeights13;
                case 14: return avSampleWeights14;
            }
        }
        public void Set(int i, Vector4 v)
        {
            switch (i)
            {
                case 0: avSampleWeights00 = v; break;
                case 1: avSampleWeights01 = v; break;
                case 2: avSampleWeights02 = v; break;
                case 3: avSampleWeights03 = v; break;
                case 4: avSampleWeights04 = v; break;
                case 5: avSampleWeights05 = v; break;
                case 6: avSampleWeights06 = v; break;
                case 7: avSampleWeights07 = v; break;
                case 8: avSampleWeights08 = v; break;
                case 9: avSampleWeights09 = v; break;
                case 10: avSampleWeights10 = v; break;
                case 11: avSampleWeights11 = v; break;
                case 12: avSampleWeights12 = v; break;
                case 13: avSampleWeights13 = v; break;
                case 14: avSampleWeights14 = v; break;
            }
        }
    }
    public struct PostProcessorFilterBPHCSVars
    {
        public PostProcessorFilterSampleWeights avSampleWeights;
        public uint outputwidth;
        public float finverse;
        public int inputsize0;
        public int inputsize1;
    }
    public struct PostProcessorFilterVCSVars
    {
        public PostProcessorFilterSampleWeights avSampleWeights;
        public int outputsize0;
        public int outputsize1;
        public int inputsize0;
        public int inputsize1;
    }
    public struct PostProcessorFinalPSVars
    {
        public Vector4 invPixelCount;
    }


    public class PostProcessor
    {
        ComputeShader ReduceTo1DCS;
        ComputeShader ReduceTo0DCS;
        ComputeShader LumBlendCS;
        ComputeShader BloomFilterBPHCS;
        ComputeShader BloomFilterVCS;
        PixelShader CopyPixelsPS;
        VertexShader FinalPassVS;
        PixelShader FinalPassPS;
        UnitQuad FinalPassQuad;
        InputLayout FinalPassLayout;
        GpuVarsBuffer<PostProcessorReduceCSVars> ReduceCSVars;
        GpuVarsBuffer<PostProcessorLumBlendCSVars> LumBlendCSVars;
        GpuVarsBuffer<PostProcessorFilterBPHCSVars> FilterBPHCSVars;
        GpuVarsBuffer<PostProcessorFilterVCSVars> FilterVCSVars;
        GpuVarsBuffer<PostProcessorFinalPSVars> FinalPSVars;

        GpuTexture Primary;

        GpuBuffer<float> Reduction0;
        GpuBuffer<float> Reduction1;

        GpuBuffer<float> LumBlendResult;

        GpuBuffer<Vector4> Bloom0;
        GpuBuffer<Vector4> Bloom1;
        GpuTexture Bloom;

        SamplerState SampleStatePoint;
        SamplerState SampleStateLinear;
        BlendState BlendState;
        long WindowSizeVramUsage = 0;
        int Width = 0;
        int Height = 0;
        ViewportF Viewport;
        bool Multisampled = false;
        bool EnableBloom = true;
        float ElapsedTime = 0.0f;
        public float LumBlendSpeed = 1.0f;

        bool CS_FULL_PIXEL_REDUCTION = false;

        public long VramUsage
        {
            get
            {
                return WindowSizeVramUsage;
            }
        }

        RawViewportF[] vpOld = new RawViewportF[15];

        DeferredScene DefScene;
        bool UsePrimary = true;

        ShaderResourceView SceneColourSRV
        {
            get
            {
                var srv = DefScene?.SceneColour?.SRV;
                if (UsePrimary || (srv == null))
                {
                    srv = Primary.SRV;
                }
                return srv;
            }
        }


        public PostProcessor(DXManager dxman)
        {
            var device = dxman.device;

            byte[] bReduceTo1DCS = File.ReadAllBytes("Shaders\\PPReduceTo1DCS.cso");
            byte[] bReduceTo0DCS = File.ReadAllBytes("Shaders\\PPReduceTo0DCS.cso");
            byte[] bLumBlendCS = File.ReadAllBytes("Shaders\\PPLumBlendCS.cso");
            byte[] bBloomFilterBPHCS = File.ReadAllBytes("Shaders\\PPBloomFilterBPHCS.cso");
            byte[] bBloomFilterVCS = File.ReadAllBytes("Shaders\\PPBloomFilterVCS.cso");
            byte[] bCopyPixelsPS = File.ReadAllBytes("Shaders\\PPCopyPixelsPS.cso");
            byte[] bFinalPassVS = File.ReadAllBytes("Shaders\\PPFinalPassVS.cso");
            byte[] bFinalPassPS = File.ReadAllBytes("Shaders\\PPFinalPassPS.cso");

            ReduceTo1DCS = new ComputeShader(device, bReduceTo1DCS);
            ReduceTo0DCS = new ComputeShader(device, bReduceTo0DCS);
            LumBlendCS = new ComputeShader(device, bLumBlendCS);
            BloomFilterBPHCS = new ComputeShader(device, bBloomFilterBPHCS);
            BloomFilterVCS = new ComputeShader(device, bBloomFilterVCS);
            CopyPixelsPS = new PixelShader(device, bCopyPixelsPS);
            FinalPassVS = new VertexShader(device, bFinalPassVS);
            FinalPassPS = new PixelShader(device, bFinalPassPS);
            FinalPassQuad = new UnitQuad(device, true);
            FinalPassLayout = new InputLayout(device, bFinalPassVS, new[]
            {
                new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
                new InputElement("TEXCOORD", 0, Format.R32G32_Float, 16, 0),
            });


            ReduceCSVars = new GpuVarsBuffer<PostProcessorReduceCSVars>(device);
            LumBlendCSVars = new GpuVarsBuffer<PostProcessorLumBlendCSVars>(device);
            FilterBPHCSVars = new GpuVarsBuffer<PostProcessorFilterBPHCSVars>(device);
            FilterVCSVars = new GpuVarsBuffer<PostProcessorFilterVCSVars>(device);
            FinalPSVars = new GpuVarsBuffer<PostProcessorFinalPSVars>(device);

            TextureAddressMode a = TextureAddressMode.Clamp;
            Color4 b = new Color4(0.0f, 0.0f, 0.0f, 0.0f);
            Comparison c = Comparison.Always;
            SampleStatePoint = DXUtility.CreateSamplerState(device, a, b, c, Filter.MinMagMipPoint, 0, 1.0f, 1.0f, 0.0f);
            SampleStateLinear = DXUtility.CreateSamplerState(device, a, b, c, Filter.MinMagMipLinear, 0, 1.0f, 1.0f, 0.0f);

            BlendState = DXUtility.CreateBlendState(device, false, BlendOperation.Add, BlendOption.One, BlendOption.Zero, BlendOperation.Add, BlendOption.One, BlendOption.Zero, ColorWriteMaskFlags.All);

            GetSampleWeights(ref FilterVCSVars.Vars.avSampleWeights, 3.0f, 1.25f); //init sample weights
            FilterBPHCSVars.Vars.avSampleWeights = FilterVCSVars.Vars.avSampleWeights;
        }
        public void Dispose()
        {
            DisposeBuffers();

            if (BlendState != null)
            {
                BlendState.Dispose();
                BlendState = null;
            }
            if (SampleStateLinear != null)
            {
                SampleStateLinear.Dispose();
                SampleStateLinear = null;
            }
            if (SampleStatePoint != null)
            {
                SampleStatePoint.Dispose();
                SampleStatePoint = null;
            }
            if (FinalPSVars != null)
            {
                FinalPSVars.Dispose();
                FinalPSVars = null;
            }
            if (FilterVCSVars != null)
            {
                FilterVCSVars.Dispose();
                FilterVCSVars = null;
            }
            if (FilterBPHCSVars != null)
            {
                FilterBPHCSVars.Dispose();
                FilterBPHCSVars = null;
            }
            if (LumBlendCSVars != null)
            {
                LumBlendCSVars.Dispose();
                LumBlendCSVars = null;
            }
            if (ReduceCSVars != null)
            {
                ReduceCSVars.Dispose();
                ReduceCSVars = null;
            }
            if (FinalPassLayout != null)
            {
                FinalPassLayout.Dispose();
                FinalPassLayout = null;
            }
            if (FinalPassQuad != null)
            {
                FinalPassQuad.Dispose();
                FinalPassQuad = null;
            }
            if (FinalPassPS != null)
            {
                FinalPassPS.Dispose();
                FinalPassPS = null;
            }
            if (FinalPassVS != null)
            {
                FinalPassVS.Dispose();
                FinalPassVS = null;
            }
            if (CopyPixelsPS != null)
            {
                CopyPixelsPS.Dispose();
                CopyPixelsPS = null;
            }
            if (BloomFilterVCS != null)
            {
                BloomFilterVCS.Dispose();
                BloomFilterVCS = null;
            }
            if (BloomFilterBPHCS != null)
            {
                BloomFilterBPHCS.Dispose();
                BloomFilterBPHCS = null;
            }
            if (LumBlendCS != null)
            {
                LumBlendCS.Dispose();
                LumBlendCS = null;
            }
            if (ReduceTo0DCS != null)
            {
                ReduceTo0DCS.Dispose();
                ReduceTo0DCS = null;
            }
            if (ReduceTo1DCS != null)
            {
                ReduceTo1DCS.Dispose();
                ReduceTo1DCS = null;
            }
        }

        public void OnWindowResize(DXManager dxman)
        {
            DisposeBuffers();

            var device = dxman.device;


            int sc = dxman.multisamplecount;
            int sq = dxman.multisamplequality;
            Multisampled = (sc > 1);

            int uw = Width = dxman.backbuffer.Description.Width;
            int uh = Height = dxman.backbuffer.Description.Height;
            Viewport = new ViewportF();
            Viewport.Width = (float)uw;
            Viewport.Height = (float)uh;
            Viewport.MinDepth = 0.0f;
            Viewport.MaxDepth = 1.0f;
            Viewport.X = 0.0f;
            Viewport.Y = 0.0f;


            Format f = Format.R32G32B32A32_Float;
            Format df = Format.D32_Float;


            Primary = new GpuTexture(device, uw, uh, f, sc, sq, true, df);
            WindowSizeVramUsage += Primary.VramUsage;


            int rc = (int)(Math.Ceiling(uw / 8.0f) * Math.Ceiling(uh / 8.0f));

            Reduction0 = new GpuBuffer<float>(device, 1, rc);
            Reduction1 = new GpuBuffer<float>(device, 1, rc);
            WindowSizeVramUsage += sizeof(float) * rc * 2;

            LumBlendResult = new GpuBuffer<float>(device, 1, 1);
            WindowSizeVramUsage += sizeof(float); //because 4 bytes matter

            int tw = uw / 8;
            int th = uh / 8;
            rc = tw * th;
            f = Format.R8G8B8A8_UNorm;

            Bloom0 = new GpuBuffer<Vector4>(device, 1, rc);
            Bloom1 = new GpuBuffer<Vector4>(device, 1, rc);
            WindowSizeVramUsage += /*sizeof(V4F)*/ 16 * rc * 2;

            Bloom = new GpuTexture(device, tw, th, f, 1, 0, false, df);
            WindowSizeVramUsage += Bloom.VramUsage;


        }
        public void DisposeBuffers()
        {
            if (Bloom != null)
            {
                Bloom.Dispose();
                Bloom = null;
            }
            if (Bloom0 != null)
            {
                Bloom0.Dispose();
                Bloom0 = null;
            }
            if (Bloom1 != null)
            {
                Bloom1.Dispose();
                Bloom1 = null;
            }
            if (LumBlendResult != null)
            {
                LumBlendResult.Dispose();
                LumBlendResult = null;
            }
            if (Reduction0 != null)
            {
                Reduction0.Dispose();
                Reduction0 = null;
            }
            if (Reduction1 != null)
            {
                Reduction1.Dispose();
                Reduction1 = null;
            }
            if (Primary != null)
            {
                Primary.Dispose();
                Primary = null;
            }
            WindowSizeVramUsage = 0;
        }

        public void Clear(DeviceContext context)
        {
            Color4 clearColour = new Color4(0.2f, 0.4f, 0.6f, 0.0f);
            //Color4 clearColour = new Color4(0.0f, 0.0f, 0.0f, 0.0f);

            Primary.Clear(context, clearColour);
        }
        public void ClearDepth(DeviceContext context)
        {
            Primary.ClearDepth(context);
        }
        public void SetPrimary(DeviceContext context)
        {
            Primary.SetRenderTarget(context);
            context.Rasterizer.SetViewport(Viewport);
        }

        public void Render(DXManager dxman, float elapsed, DeferredScene defScene)
        {
            ElapsedTime = elapsed;
            DefScene = defScene;
            UsePrimary = ((defScene?.SSAASampleCount ?? 2) > 1) || (defScene?.SceneColour == null);

            var context = dxman.context;

            if (Multisampled && UsePrimary)
            {
                int sr = 0;// D3D11CalcSubresource(0, 0, 1);
                context.ResolveSubresource(Primary.TextureMS, sr, Primary.Texture, sr, Format.R32G32B32A32_Float);
            }

            context.OutputMerger.SetRenderTargets((RenderTargetView)null);

            ProcessLuminance(context);
            ProcessBloom(context);

            dxman.SetDefaultRenderTarget(context);
            context.OutputMerger.SetBlendState(BlendState, null, 0xFFFFFFFF);
            FinalPass(context);
        }


        private void ProcessLuminance(DeviceContext context)
        {
            var srv = SceneColourSRV;

            uint dimx, dimy;
            if (CS_FULL_PIXEL_REDUCTION)
            {
                dimx = (uint)(Math.Ceiling(Width / 8.0f));
                dimx = (uint)(Math.Ceiling(dimx / 2.0f));
                dimy = (uint)(Math.Ceiling(Height / 8.0f));
                dimy = (uint)(Math.Ceiling(dimy / 2.0f));
            }
            else
            {
                dimx = (uint)(Math.Ceiling(81.0f / 8.0f)); //ToneMappingTexSize = (int)pow(3.0f, NUM_TONEMAP_TEXTURES-1);
                dimy = dimx;
            }

            ReduceCSVars.Vars.dimx = dimx;
            ReduceCSVars.Vars.dimy = dimy;
            ReduceCSVars.Vars.Width = (uint)Width;
            ReduceCSVars.Vars.Height = (uint)Height;
            ReduceCSVars.Update(context);


            Compute(context, ReduceTo1DCS, ReduceCSVars.Buffer, Reduction0.UAV, (int)dimx, (int)dimy, 1, srv);

            uint dim = dimx * dimy;
            uint nNumToReduce = dim;
            dim = (uint)(Math.Ceiling(dim / 128.0f));
            if (nNumToReduce > 1)
            {
                for (;;)
                {
                    ReduceCSVars.Vars.dimx = nNumToReduce;
                    ReduceCSVars.Vars.dimy = dim;
                    ReduceCSVars.Vars.Width = 0;
                    ReduceCSVars.Vars.Height = 0;
                    ReduceCSVars.Update(context);

                    Compute(context, ReduceTo0DCS, ReduceCSVars.Buffer, Reduction1.UAV, (int)dim, 1, 1, Reduction0.SRV);

                    nNumToReduce = dim;
                    dim = (uint)(Math.Ceiling(dim / 128.0f));

                    if (nNumToReduce == 1) break;

                    var r0 = Reduction0;
                    Reduction0 = Reduction1;
                    Reduction1 = r0;
                }
            }
            else
            {
                var r0 = Reduction0;
                Reduction0 = Reduction1;
                Reduction1 = r0;
            }

            LumBlendCSVars.Vars.blend = new Vector4(Math.Min(ElapsedTime * LumBlendSpeed, 1.0f));
            LumBlendCSVars.Update(context);

            Compute(context, LumBlendCS, LumBlendCSVars.Buffer, LumBlendResult.UAV, 1, 1, 1, Reduction1.SRV);

        }
        private void ProcessBloom(DeviceContext context)
        {
            if (EnableBloom)
            {
                var srv = SceneColourSRV;

                // Bright pass and horizontal blur

                //GetSampleWeights(cbFilter.avSampleWeights, 3.0f, 1.25f);
                FilterBPHCSVars.Vars.outputwidth = (uint)(Width / 8);
                if (CS_FULL_PIXEL_REDUCTION)
                {
                    FilterBPHCSVars.Vars.finverse = 1.0f / (Width * Height);
                }
                else
                {
                    FilterBPHCSVars.Vars.finverse = 1.0f / (81 * 81); //(ToneMappingTexSize*ToneMappingTexSize);
                }
                FilterBPHCSVars.Vars.inputsize0 = (int)Width;
                FilterBPHCSVars.Vars.inputsize1 = (int)Height;
                FilterBPHCSVars.Update(context);

                int x = (int)(Math.Ceiling((float)FilterBPHCSVars.Vars.outputwidth / (128 - 7 * 2)));
                int y = (Height / 8);
                Compute(context, BloomFilterBPHCS, FilterBPHCSVars.Buffer, Bloom1.UAV, x, y, 1, srv, LumBlendResult.SRV);

                // Vertical blur
                FilterVCSVars.Vars.outputsize0 = (int)(Width / 8);
                FilterVCSVars.Vars.outputsize1 = (int)(Height / 8);
                FilterVCSVars.Vars.inputsize0 = (int)(Width / 8);
                FilterVCSVars.Vars.inputsize1 = (int)(Height / 8);
                FilterVCSVars.Update(context);
                x = Width / 8;
                y = (int)(Math.Ceiling((float)FilterVCSVars.Vars.outputsize1 / (128 - 7 * 2)));

                Compute(context, BloomFilterVCS, FilterVCSVars.Buffer, Bloom0.UAV, x, y, 1, Bloom1.SRV, LumBlendResult.SRV);
            }

            CopyPixels(context, Width / 8, Height / 8, Bloom0.SRV, Bloom.RTV);

        }
        private void FinalPass(DeviceContext context)
        {
            context.Rasterizer.SetViewport(Viewport);
            context.VertexShader.Set(FinalPassVS);
            context.PixelShader.Set(FinalPassPS);

            var srv = SceneColourSRV;

            context.PixelShader.SetShaderResources(0, srv, LumBlendResult.SRV, EnableBloom ? Bloom.SRV : null);

            if (CS_FULL_PIXEL_REDUCTION)
            {
                FinalPSVars.Vars.invPixelCount = new Vector4(1.0f / (Width * Height));
            }
            else
            {
                FinalPSVars.Vars.invPixelCount = new Vector4(1.0f / (81 * 81));
            }
            FinalPSVars.Update(context);
            FinalPSVars.SetPSCBuffer(context, 0);

            context.PixelShader.SetSamplers(0, SampleStatePoint, SampleStateLinear);

            context.InputAssembler.InputLayout = FinalPassLayout;
            FinalPassQuad.Draw(context);

            context.VertexShader.Set(null);
            context.PixelShader.Set(null);
            context.PixelShader.SetShaderResources(0, null, null, null);
            context.PixelShader.SetSamplers(0, null, null);
        }




        private float GaussianDistribution(float x, float y, float rho)
        {
            float g = 1.0f / (float)Math.Sqrt(2.0f * 3.14159265f * rho * rho);
            g *= (float)Math.Exp(-(x * x + y * y) / (2 * rho * rho));
            return g;
        }
        private void GetSampleWeights(ref PostProcessorFilterSampleWeights w, float fDeviation, float fMultiplier)
        {
            // Fill the center texel
            float weight = 1.0f * GaussianDistribution(0, 0, fDeviation);
            w.Set(7, new Vector4(weight, weight, weight, 1.0f));

            // Fill the right side
            for (int i = 1; i < 8; i++)
            {
                weight = fMultiplier * GaussianDistribution((float)i, 0, fDeviation);
                w.Set(7 - i, new Vector4(weight, weight, weight, 1.0f));
            }

            // Copy to the left side
            for (int i = 8; i < 15; i++)
            {
                w.Set(i, w.Get(14 - i));
            }

            // Debug convolution kernel which doesn't transform input data
            /*ZeroMemory( avColorWeight, sizeof(D3DXVECTOR4)*15 );
            w.Set(7, new Vector4( 1, 1, 1, 1 ));*/
        }


        private void Compute(DeviceContext context, ComputeShader cs, Buffer constantBuffer, UnorderedAccessView unorderedAccessView, int X, int Y, int Z, params ShaderResourceView[] resourceViews)
        {
            context.ComputeShader.Set(cs);
            context.ComputeShader.SetShaderResources(0, resourceViews);
            context.ComputeShader.SetUnorderedAccessView(0, unorderedAccessView);

            if (constantBuffer != null)
            {
                //make sure buffer is updated first...
                //D3D11_MAPPED_SUBRESOURCE mappedResource;
                //dc->Map(constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
                //memcpy(mappedResource.pData, constantData, constantDataSize);
                //dc->Unmap(constantBuffer, 0);
                context.ComputeShader.SetConstantBuffer(0, constantBuffer); //dc->CSSetConstantBuffers(0, 1, &constantBuffer);
            }

            context.Dispatch(X, Y, Z);

            ShaderResourceView[] ppSRVNULL = { null, null, null };
            context.ComputeShader.SetUnorderedAccessView(0, null);
            context.ComputeShader.SetShaderResources(0, 3, ppSRVNULL);
            context.ComputeShader.SetConstantBuffer(0, null);
        }

        private void CopyPixels(DeviceContext context, int w, int h, ShaderResourceView fromSRV, RenderTargetView toRTV)
        {
            context.VertexShader.Set(FinalPassVS);
            context.PixelShader.Set(CopyPixelsPS);

            ShaderResourceView[] aRViews = { fromSRV };
            context.PixelShader.SetShaderResource(0, fromSRV);

            RenderTargetView[] aRTViews = { toRTV };
            context.OutputMerger.SetRenderTargets(toRTV);

            //D3D11_MAPPED_SUBRESOURCE mappedResource;
            //dc->Map(ReduceCSVars.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
            //UINT* p = (UINT*)mappedResource.pData;
            //p[0] = w;
            //p[1] = h;
            //dc->Unmap(ReduceCSVars.Get(), 0);
            //ID3D11Buffer* ppCB[1] = { ReduceCSVars.Get() };
            //dc->PSSetConstantBuffers(0, 1, ppCB);
            ReduceCSVars.Vars.dimx = (uint)w;
            ReduceCSVars.Vars.dimy = (uint)h;
            ReduceCSVars.Update(context);
            ReduceCSVars.SetPSCBuffer(context, 0);

            //DrawFullScreenQuad11( pd3dImmediateContext, g_pDumpBufferPS, dwWidth, dwHeight );
            //ViewportF[] vpOld = new ViewportF[15];// [D3D11_VIEWPORT_AND_SCISSORRECT_MAX_INDEX];
            //UINT nViewPorts = 1;
            //dc->RSGetViewports(&nViewPorts, vpOld);
            context.Rasterizer.GetViewports(vpOld);

            // Setup the viewport to match the backbuffer
            ViewportF vp;
            vp.Width = (float)Width;
            vp.Height = (float)Height;
            vp.MinDepth = 0.0f;
            vp.MaxDepth = 1.0f;
            vp.X = 0;
            vp.Y = 0;
            context.Rasterizer.SetViewport(vp);

            context.InputAssembler.InputLayout = FinalPassLayout;
            FinalPassQuad.Draw(context);


            context.Rasterizer.SetViewports(vpOld); //reverting viewports maybe not necessary...
        }


    }
}
