void UndistortCameraImages(Canvas canvas)
        {
            GraphicsDevice device = canvas.GetDevice();

            undistortShader.SetupShader(canvas);
            device.Textures[0] = cameraA.GetCameraImage();
            device.SetPixelShaderConstant(0, new Vector4((float)DistortParamsA[0],
                (float)DistortParamsA[1], (float)DistortParamsA[2], (float)DistortParamsA[3]));
            device.SetPixelShaderConstant(1, new Vector4((float)CameraParamsA[0],
                (float)CameraParamsA[1], (float)CameraParamsA[2], (float)CameraParamsA[3])
                / new Vector4(cameraA.Width, cameraA.Height, cameraA.Width, cameraA.Height));

            DepthStencilBuffer dsOld = device.DepthStencilBuffer;
            device.DepthStencilBuffer = canvas.GetDepthStencil();
            device.SetRenderTarget(0, renderTarget);
            CanvasPrimitives.Quad.Render(canvas);
            device.SetRenderTarget(0, null);
            device.DepthStencilBuffer = dsOld;

            cameraAImage = renderTarget.GetTexture();
        }
        void RenderMatrixStyle(Canvas canvas)
        {
            GraphicsDevice device = canvas.GetDevice();

            matrixShader.SetupShader(canvas);
            device.Textures[0] = cameraA.GetCameraImage();
            device.Textures[1] = unicodeTable;
            //device.Textures[2] = noiseTexture;
            device.SetVertexShaderConstant(CanvasShaderConstants.VC_INVTEXRES, Vector2.Zero);
            device.SetPixelShaderConstant(0, new Vector4(1.0f / (float)unicodeTable.Width, 1.0f / (float)unicodeTable.Height,
                (float)unicodeTableRows / (float)unicodeTable.Width, (float)unicodeTableColumns / (float)unicodeTable.Height));
            device.SetPixelShaderConstant(1, new Vector4(0, 1.0f, 0, 1.0f));

            DepthStencilBuffer dsOld = device.DepthStencilBuffer;
            device.DepthStencilBuffer = canvas.GetDepthStencil();
            device.SetRenderTarget(0, renderTarget);
            CanvasPrimitives.Quad.Render(canvas);
            device.SetRenderTarget(0, null);
            device.DepthStencilBuffer = dsOld;

            cameraAImage = renderTarget.GetTexture();
        }
        BoundingRect[] DetectFingersFromImage(Canvas canvas, Texture2D image)
        {
            GraphicsDevice device = canvas.GetDevice();
            DepthStencilBuffer dsOld = device.DepthStencilBuffer;
            device.DepthStencilBuffer = canvas.GetDepthStencil();
            device.SetRenderTarget(0, dsChain[0]);
            canvas.DrawImage(image, Vector2.One * -1, Vector2.One, (int)ImageParameters.FlipY);
            device.SetRenderTarget(0, null);

            downsampleMaxLumShader.SetupShader(canvas);
            for(int i = 1; i < dsChain.Length; i++)
            {
                device.Textures[0] = dsChain[i-1].GetTexture();
                Vector2 invRes = Vector2.One / new Vector2(dsChain[i-1].Width, dsChain[i-1].Height);
                device.SetVertexShaderConstant(CanvasShaderConstants.VC_INVTEXRES, invRes);
                device.SetPixelShaderConstant(0, invRes);
                device.SetRenderTarget(0, dsChain[i]);
                CanvasPrimitives.Quad.Render(canvas);
                device.SetRenderTarget(0, null);
            }

            biasLumShader.SetupShader(canvas);
            int idx = dsChain.Length - 1;
            device.Textures[0] = dsChain[idx].GetTexture();
            Vector2 iRes = Vector2.One / new Vector2(dsChain[idx].Width, dsChain[idx].Height);
            device.SetVertexShaderConstant(CanvasShaderConstants.VC_INVTEXRES, iRes);
            device.SetRenderTarget(0, dsChain[idx]);
            CanvasPrimitives.Quad.Render(canvas);
            device.SetRenderTarget(0, null);

            device.DepthStencilBuffer = dsOld;

            return FloodFillBounds(dsChain[idx].GetTexture());
        }
        void RenderEdgesStyle(Canvas canvas)
        {
            GraphicsDevice device = canvas.GetDevice();
            edgeShader.SetupShader(canvas);
            device.Textures[0] = renderTarget.GetTexture();
            //device.Textures[2] = noiseTexture;
            device.SetVertexShaderConstant(CanvasShaderConstants.VC_INVTEXRES, Vector2.Zero);
            device.SetPixelShaderConstant(0, Vector2.One / new Vector2(renderTarget.Width, renderTarget.Height));

            DepthStencilBuffer dsOld = device.DepthStencilBuffer;
            device.DepthStencilBuffer = canvas.GetDepthStencil();
            device.SetRenderTarget(0, renderTarget);
            CanvasPrimitives.Quad.SetPositions(Vector2.One * -1, Vector2.One);
            CanvasPrimitives.Quad.Render(canvas);
            device.SetRenderTarget(0, null);
            device.DepthStencilBuffer = dsOld;
        }
        public void CompositeFinalImage(Canvas canvas)
        {
            BoundingRect[] drawRects = GetCameraDrawBoxes();

            GraphicsDevice device = canvas.GetDevice();
            DepthStencilBuffer dsOld = device.DepthStencilBuffer;
            device.DepthStencilBuffer = canvas.GetDepthStencil();
            device.SetRenderTarget(0, renderTarget);

            canvas.DrawImage(cameraAImage, drawRects[0].Min, drawRects[0].Max, (int)(ImageParameters.FlipY));
            canvas.DrawImage(cameraBImage, drawRects[1].Min, drawRects[1].Max, (int)(ImageParameters.FlipY));

            device.RenderState.AlphaBlendEnable = true;
            device.RenderState.SourceBlend = Blend.SourceAlpha;
            device.RenderState.DestinationBlend = Blend.InverseSourceAlpha;

            canvas.DrawImage(renderLayerA.GetImage(), drawRects[0].Min, drawRects[0].Max);
            canvas.DrawImage(renderLayerB.GetImage(), drawRects[1].Min, drawRects[1].Max);

            device.SetRenderTarget(0, null);
            device.DepthStencilBuffer = dsOld;

            //RenderMatrixStyle(canvas);
            //RenderEdgesStyle(canvas);
            //CanvasPrimitives.Quad.SetPositions(Vector2.One * -2, Vector2.One);

            device.RenderState.DepthBufferEnable = false;
            device.RenderState.DepthBufferWriteEnable = false;
            canvas.DrawImage(renderTarget.GetTexture());
            /*
            CanvasPrimitives.Quad.SetPositions(Vector2.One * -1, Vector2.One);
            device.RenderState.DepthBufferEnable = true;
            device.RenderState.DepthBufferWriteEnable = true;
            render3D.SetupShader(canvas);
            Matrix scaleMat = Matrix.CreateScale(0.05f);
            device.SetVertexShaderConstant(CanvasShaderConstants.VC_MODELVIEW, virtualCameraA.ViewProjection);
            for (int i = 0; i < detectionPoints.Length; i++)
            {
                device.SetPixelShaderConstant(0, fingerColors[i % fingerColors.Length].ToVector4());
                scaleMat.Translation = detectionPoints[i].Center;
                device.SetVertexShaderConstant(CanvasShaderConstants.VC_WORLD, scaleMat);
                CanvasPrimitives.Quad.Render(canvas);
            }
            */
        }