Пример #1
0
        public void DrawBeziers(int count, Position <float>[] controls, Color <float>[] colors, float[] width, Matrix4x4[] transforms)
        {
            Utility.Assert(controls.Length >= 3 * count && colors.Length >= count && width.Length >= count);
            Utility.Assert(Mode == RenderMode.Draw);

            if (count == 0)
            {
                return;
            }

            TransformMatrix[] transformMatrices = new TransformMatrix[count];
            Equation[]        equations         = new Equation[count];
            Vector4[]         color             = new Vector4[count];

            Vertex[] vertices = new Vertex[4]
            {
                new Vertex()
                {
                    Position = new Vector3(0, 0, 0)
                },
                new Vertex()
                {
                    Position = new Vector3(0, 1, 0)
                },
                new Vertex()
                {
                    Position = new Vector3(1, 1, 0)
                },
                new Vertex()
                {
                    Position = new Vector3(1, 0, 0)
                }
            };

            var size = new Vector2(mCanvasSize.Width, mCanvasSize.Height) * 0.5f;

            for (int index = 0; index < count; index++)
            {
                Vector2[] points = new Vector2[]
                {
                    new Vector2(controls[index * 3 + 0].X, controls[index * 3 + 0].Y),
                    new Vector2(controls[index * 3 + 1].X, controls[index * 3 + 1].Y),
                    new Vector2(controls[index * 3 + 2].X, controls[index * 3 + 2].Y)
                };

                //get bounding box(before transform) of bezier curve
                var box = QuadraticBezierCurve.BoundingBox(points, width[index]);

                //create transform matrix
                transformMatrices[index] = new TransformMatrix()
                {
                    World =
                        Matrix4x4.CreateScale(box.Max.X - box.Min.X, box.Max.Y - box.Min.Y, 1) *
                        Matrix4x4.CreateTranslation(box.Min.X, box.Min.Y, 0) *
                        Transform,
                    Projection = mProjection
                };

                //we need transform the control points to screen space
                var transformMatrix = (transforms == null ? Matrix4x4.Identity : transforms[index]) * Transform * mProjection;

                //transform points
                for (int i = 0; i < 3; i++)
                {
                    points[i]   = (Vector2.Transform(points[i], transformMatrix) + Vector2.One) * size;
                    points[i].Y = mCanvasSize.Height - points[i].Y;
                }

                //get parameter format of bezier curve
                //Q(t) = At^2 + B^t + C
                var parameters = QuadraticBezierCurve.ParameterFormat(points);
                var A          = parameters[0];
                var B          = parameters[1];
                var C          = parameters[2];

                //For point P, when any root of equation(Q'(s) * (P - Q(s)) = 0) is legal, the P is inside the curve
                //The equation full-format is (-2A^2)t^3 + (-3AB)t^2 + (2AP - 2AC - B^2)t + B(P - C) = 0
                //we can use Cardano formula to solve it in pixel shader.
                //but we can cache some calculation for opt.
                var c0 = -2 * Vector2.Dot(A, A);
                var c1 = -3 * Vector2.Dot(A, B);
                var c2 = -2 * Vector2.Dot(A, C) - Vector2.Dot(B, B);
                var c3 = -Vector2.Dot(B, C);

                equations[index] = new Equation()
                {
                    Coefficient0 = new Vector4(c0, c1, c2, c3),
                    Coefficient1 = new Vector4(A.X, A.Y, B.X, B.Y),
                    Coefficient2 = new Vector4(C.X, C.Y, width[index] * width[index] * 0.25f, width[index] * width[index] * 0.25f)
                };

                color[index] = new Vector4(colors[index].Red, colors[index].Green, colors[index].Blue, colors[index].Alpha);
            }

            if (mColorBufferArray == null || mColorBufferArray.ElementCount != count)
            {
                Utility.Dispose(ref mColorBufferArray);
                Utility.Dispose(ref mEquationBufferArray);
                Utility.Dispose(ref mTransformBufferArray);

                Utility.Dispose(ref mColorBufferArrayUsage);
                Utility.Dispose(ref mEquationBufferArrayUsage);
                Utility.Dispose(ref mTransformBufferArrayUsage);

                mColorBufferArray = new GpuBufferArray(
                    Utility.SizeOf <Vector4>(),
                    count,
                    mDevice,
                    GpuResourceInfo.BufferArray());

                mEquationBufferArray = new GpuBufferArray(
                    Utility.SizeOf <Equation>(),
                    count,
                    mDevice,
                    GpuResourceInfo.BufferArray());

                mTransformBufferArray = new GpuBufferArray(
                    Utility.SizeOf <TransformMatrix>(),
                    count,
                    mDevice,
                    GpuResourceInfo.BufferArray());

                mColorBufferArrayUsage     = new GpuResourceUsage(mDevice, mColorBufferArray);
                mEquationBufferArrayUsage  = new GpuResourceUsage(mDevice, mEquationBufferArray);
                mTransformBufferArrayUsage = new GpuResourceUsage(mDevice, mTransformBufferArray);
            }

            mColorBufferArray.Update(color);
            mEquationBufferArray.Update(equations);
            mTransformBufferArray.Update(transformMatrices);

            mDrawVertexBuffer.Update(vertices);

            //change shader we use
            mDevice.SetVertexShader(mDrawBeziersVertexShader);
            mDevice.SetPixelShader(mDrawBeziersPixelShader);

            //set vertex buffer
            mDevice.SetVertexBuffer(mDrawVertexBuffer);
            mDevice.SetIndexBuffer(mDrawIndexBuffer);

            //set constant buffer and resource
            mDevice.SetResourceUsage(mColorBufferArrayUsage, 0);
            mDevice.SetResourceUsage(mEquationBufferArrayUsage, 1);
            mDevice.SetResourceUsage(mTransformBufferArrayUsage, 2);

            //drwa indexed instanced
            mDevice.DrawIndexedInstanced(6, count);

            //reset the shader
            mDevice.SetVertexShader(mDrawBezierVertexShader);
            mDevice.SetPixelShader(mDrawBezierPixelShader);
        }
Пример #2
0
        public PresentRender(GpuDevice device, IntPtr handle, Size size)
        {
            mHandle    = handle;
            mDevice    = device;
            mSwapChain = new GpuSwapChain(handle, size, GpuPixelFormat.R8G8B8A8Unknown, mDevice);

            mBlendState = new GpuBlendState(mDevice, new RenderTargetBlendDescription()
            {
                AlphaBlendOperation   = GpuBlendOperation.Add,
                BlendOperation        = GpuBlendOperation.Add,
                DestinationAlphaBlend = GpuBlendOption.InverseSourceAlpha,
                DestinationBlend      = GpuBlendOption.InverseSourceAlpha,
                SourceAlphaBlend      = GpuBlendOption.SourceAlpha,
                SourceBlend           = GpuBlendOption.SourceAlpha,
                IsBlendEnable         = true
            });

            //compile shader
            mVertexShader    = new GpuVertexShader(mDevice, GpuVertexShader.Compile(Properties.Resources.PresentVertexShader));
            mDrawPixelShader = new GpuPixelShader(mDevice, GpuPixelShader.Compile(Properties.Resources.PresentDrawPixelShader));
            mMaskPixelShader = new GpuPixelShader(mDevice, GpuPixelShader.Compile(Properties.Resources.PresentMaskPixelShader));

            //create input layout, we only need to render texture
            mInputLayout = new GpuInputLayout(mDevice, new InputElement[]
            {
                new InputElement("POSITION", 0, 12),
                new InputElement("TEXCOORD", 0, 8)
            }, mVertexShader);

            //init vertex and index data
            Vertex[] vertices = new Vertex[]
            {
                new Vertex()
                {
                    Position = new System.Numerics.Vector3(0, 0, 0), TexCoord = new System.Numerics.Vector2(0, 0)
                },
                new Vertex()
                {
                    Position = new System.Numerics.Vector3(0, 1, 0), TexCoord = new System.Numerics.Vector2(0, 1)
                },
                new Vertex()
                {
                    Position = new System.Numerics.Vector3(1, 1, 0), TexCoord = new System.Numerics.Vector2(1, 1)
                },
                new Vertex()
                {
                    Position = new System.Numerics.Vector3(1, 0, 0), TexCoord = new System.Numerics.Vector2(1, 0)
                }
            };

            uint[] indices = new uint[]
            {
                0, 1, 2,
                2, 3, 0
            };

            //create vertex and index buffer
            mVertexBuffer = new GpuBuffer(
                Utility.SizeOf <Vertex>() * vertices.Length,
                Utility.SizeOf <Vertex>(),
                mDevice, GpuResourceInfo.VertexBuffer());

            mIndexBuffer = new GpuBuffer(
                Utility.SizeOf <uint>() * indices.Length,
                Utility.SizeOf <uint>(),
                mDevice, GpuResourceInfo.IndexBuffer());

            mVertexBuffer.Update(vertices);
            mIndexBuffer.Update(indices);

            //create constant buffer
            //transform buffer is used for vertex shader to do transform
            //render config buffer is used for pixel shader to render with opacity
            mTransformBuffer = new GpuBuffer(
                Utility.SizeOf <Transform>(),
                Utility.SizeOf <Transform>(),
                mDevice, GpuResourceInfo.ConstantBuffer());

            mRenderConfigBuffer = new GpuBuffer(
                Utility.SizeOf <RenderConfig>(),
                Utility.SizeOf <RenderConfig>(),
                mDevice, GpuResourceInfo.ConstantBuffer());

            mGpuSamplerState = new GpuSamplerState(mDevice);
        }
Пример #3
0
        public void FillBeziers(int count, Position <float>[] controls, Color <float>[] colors, Matrix4x4[] transforms)
        {
            Utility.Assert(controls.Length >= count * 3 && colors.Length >= count * 3);
            Utility.Assert(Mode == RenderMode.Fill);

            if (count == 0)
            {
                return;
            }

            TrianglePoints[] trianglePointsCanvas = new TrianglePoints[count];
            TrianglePoints[] trianglePoints       = new TrianglePoints[count];
            TriangleColors[] triangleColors       = new TriangleColors[count];

            var size = new Vector4(mCanvasSize.Width * 0.5f, mCanvasSize.Height * 0.5f, 0, 0);

            //create triangle points struct
            for (int index = 0; index < count; index++)
            {
                //get transform matrix
                var transformMatrix = (transforms == null ? Matrix4x4.Identity : transforms[index]) * Transform * mProjection;

                //get control points for bezier_i
                var points = new Position <float>[]
                {
                    controls[index * 3 + 0],
                    controls[index * 3 + 1],
                    controls[index * 3 + 2]
                };

                Vector4 FromColor(Color <float> color) => new Vector4(color.Red, color.Green, color.Blue, color.Alpha);

                //create data for bezier_i in shader
                TrianglePoints subTrianglePoints = new TrianglePoints()
                {
                    Position0 = Vector4.Transform(new Vector3(points[0].X, points[0].Y, 0), transformMatrix),
                    Position1 = Vector4.Transform(new Vector3(points[1].X, points[1].Y, 0), transformMatrix),
                    Position2 = Vector4.Transform(new Vector3(points[2].X, points[2].Y, 0), transformMatrix),
                };

                TriangleColors subTriangleColors = new TriangleColors()
                {
                    Color0 = FromColor(colors[index * 3 + 0]),
                    Color1 = FromColor(colors[index * 3 + 1]),
                    Color2 = FromColor(colors[index * 3 + 2])
                };

                TrianglePoints subTrianglePointsCanvas = new TrianglePoints()
                {
                    Position0 = (subTrianglePoints.Position0 + new Vector4(1)) * size,
                    Position1 = (subTrianglePoints.Position1 + new Vector4(1)) * size,
                    Position2 = (subTrianglePoints.Position2 + new Vector4(1)) * size
                };

                subTrianglePointsCanvas.Position0.Y = mCanvasSize.Height - subTrianglePointsCanvas.Position0.Y;
                subTrianglePointsCanvas.Position1.Y = mCanvasSize.Height - subTrianglePointsCanvas.Position1.Y;
                subTrianglePointsCanvas.Position2.Y = mCanvasSize.Height - subTrianglePointsCanvas.Position2.Y;

                trianglePointsCanvas[index] = subTrianglePointsCanvas;
                trianglePoints[index]       = subTrianglePoints;
                triangleColors[index]       = subTriangleColors;
            }

            if (mTrianglePointsBufferArray == null || mTrianglePointsBufferArray.ElementCount != count)
            {
                Utility.Dispose(ref mTrianglePointsBufferArray);
                Utility.Dispose(ref mTriangleColorsBufferArray);
                Utility.Dispose(ref mTrianglePointsCanvasBufferArray);

                Utility.Dispose(ref mTrianglePointsBufferArrayUsage);
                Utility.Dispose(ref mTriangleColorsBufferArrayUsage);
                Utility.Dispose(ref mTrianglePointsCanvasBufferArrayUsage);

                mTrianglePointsBufferArray = new GpuBufferArray(
                    Utility.SizeOf <TrianglePoints>(),
                    count,
                    mDevice,
                    GpuResourceInfo.BufferArray());

                mTriangleColorsBufferArray = new GpuBufferArray(
                    Utility.SizeOf <TrianglePoints>(),
                    count,
                    mDevice,
                    GpuResourceInfo.BufferArray());

                mTrianglePointsCanvasBufferArray = new GpuBufferArray(
                    Utility.SizeOf <TrianglePoints>(),
                    count,
                    mDevice,
                    GpuResourceInfo.BufferArray());

                mTrianglePointsBufferArrayUsage       = new GpuResourceUsage(mDevice, mTrianglePointsBufferArray);
                mTriangleColorsBufferArrayUsage       = new GpuResourceUsage(mDevice, mTriangleColorsBufferArray);
                mTrianglePointsCanvasBufferArrayUsage = new GpuResourceUsage(mDevice, mTrianglePointsCanvasBufferArray);
            }

            mTrianglePointsBufferArray.Update(trianglePoints);
            mTriangleColorsBufferArray.Update(triangleColors);
            mTrianglePointsCanvasBufferArray.Update(trianglePointsCanvas);

            //change shader we use
            mDevice.SetVertexShader(mFillBeziersVertexShader);
            mDevice.SetPixelShader(mFillBeziersPixelShader);

            //set vertex buffer
            mDevice.SetVertexBuffer(mFillVertexBuffer);
            mDevice.SetIndexBuffer(mFillIndexBuffer);

            //set constant buffer and resource
            mDevice.SetResourceUsage(mTrianglePointsBufferArrayUsage, 0);
            mDevice.SetResourceUsage(mTriangleColorsBufferArrayUsage, 1);
            mDevice.SetResourceUsage(mTrianglePointsCanvasBufferArrayUsage, 2);

            //drwa indexed instanced
            mDevice.DrawIndexedInstanced(3, count);

            //reset the shader
            mDevice.SetVertexShader(mFillBezierVertexShader);
            mDevice.SetPixelShader(mFillBezierPixelShader);
        }