GDI+的替代者—D2D

Winform中的2D绘图,以前用的都是GDI+。在简单应用环境下,如果不在乎速度,GDI+可以表现的很好。机缘巧合,前段时间做了一个简单的3D程序,使用的是C#托管 + DirectX9 SDK,平台是Win7 + VS2012。 项目做完以后,回顾发现,其实也可以使用directX11的Direct2D来进行2D绘图,这样可以尽量使用硬件加速,尽量解放CPU,使程序可以应用于更多场合。

Direct2D的理想环境是MFC/C++;如今的我只有在编写驱动程序时会用C++,对于已经习惯使用C#编写Winform的我来说,使用MFC开发Direct2D不是不可以,但是毕竟抛开MFC已经很久了(那还是VisualC++5.0时的回忆)。。。

在C#中使用Direct2D,目前看来,最合适的工具就是SharpDx,sdx可以说是目前对DirectX的最好封装,而且免费;其最大的缺点是,可以利用的文档实在太少了。闲话少叙,下面就从SharpDx开始:


一、首先从官网下载sdx(我用的时基于Desktop的应用),找到那一堆dll

二、建立一个新工程,本例是创建一个基于SharpDx的Progress的控件。

注:我使用的sdx是3.02版本,新建的c#工程需要定义为.Net FrameWork 4.5

0,准备工作:sdx中,无法使用C#的Color,Rectangle。。。因此需要做一个转换类

    
    public class dxc
    {
        public static SharpDX.Mathematics.Interop.RawColor4 ToColor4(Color cor)
        {
            return new SharpDX.Mathematics.Interop.RawColor4((float)cor.R / 256f, (float)cor.G / 256f, (float)cor.B / 256f, (float)cor.A / 256f);
        }

        public static SharpDX.Mathematics.Interop.RawRectangle ToRect(Rectangle rect)
        {
            return new SharpDX.Mathematics.Interop.RawRectangle(rect.Left, rect.Top, rect.Right, rect.Bottom);
        }

        public static SharpDX.Mathematics.Interop.RawRectangleF ToRectF(RectangleF rect)
        {
            return new SharpDX.Mathematics.Interop.RawRectangleF(rect.Left, rect.Top, rect.Right, rect.Bottom);
        }
   }
sdx中使用的Color,Rectanglef等,大都在SharpDX.Mathematics.Interop空间中,上面dxc中静态函数的作用就是做最基本的转换。
在sdx中,颜色RawColor4的定义是R/G/B/A,各个分量的取值是0~1

在sdx中,RawRectangleF使用的比较多。


1,新建一个基于Control的类

[ToolboxItem(true), ToolboxBitmap(typeof(System.Windows.Forms.ProgressBar))]
public class dxProgressBar : Control
        
2,添加属性

     
        int _pValue = 0;
        public int Value
        {
            get { return _pValue; }
            set
            {
                _pValue = value;
                if (_pValue > 100) _pValue = 100;
                if (_pValue < 0) _pValue = 0;
                this.Refresh();
            }
        }

        Color _pBorderCor = Color.Black;
        public Color BorderColor
        {
            get { return _pBorderCor; }
            set
            {
                _pBorderCor = value;
                Refresh();
            }
        }

        Color _pTextColor = Color.Blue;
        public Color TextColor
        {
            get { return _pTextColor; }
            set
            {
                _pTextColor = value;
                Refresh();
            }
        }

3,构造函数 

   
        public dxProgressBar()
        {
            InitD2D();

            this.SizeChanged+=dxProgressBar_SizeChanged;
        }

initD2D的作用是初始化sdx设备,后面有它的函数原型。


三、下面是绘图相关处理

1,添加引用

using SharpDX.DXGI;
using SharpDX.Direct2D1;
using SharpDX.Mathematics.Interop;
using SharpDX.DirectWrite;
using AlphaMode = SharpDX.Direct2D1.AlphaMode;
using DxFactory = SharpDX.Direct2D1.Factory;
using TxFactory = SharpDX.DirectWrite.Factory;
2,添加变量声明


        DxFactory dxFactory;
        WindowRenderTarget dxTarget;
        PixelFormat pixelFormat = new PixelFormat(Format.Unknown, AlphaMode.Premultiplied);
        SolidColorBrush dxBorderBrush;
        SolidColorBrush dxValueBruseh;
        RawRectangleF dxBorderRectf;
        RawRectangleF dxValueRectf;

        TxFactory txFactory;
        TextFormat txFormat;
        TextLayout txLayout;
        SolidColorBrush txtBrush;

本例中,用于绘图的资源、变量都使用dx开头;而用于绘制文本的都使用 tx开头。


3,变量初始化函数


        private void InitD2D()
        {
            dxFactory = new DxFactory(SharpDX.Direct2D1.FactoryType.SingleThreaded);

            HwndRenderTargetProperties properties = new HwndRenderTargetProperties();
            properties.Hwnd = this.Handle;
            properties.PixelSize = new SharpDX.Size2(this.Width, this.Height);
            properties.PresentOptions = PresentOptions.None;

            dxTarget = new WindowRenderTarget(dxFactory, new RenderTargetProperties(pixelFormat), properties);
            dxTarget.AntialiasMode = AntialiasMode.PerPrimitive;
            dxTarget.TextAntialiasMode = SharpDX.Direct2D1.TextAntialiasMode.Cleartype;

            txFactory = new TxFactory();
            txtBrush = new SolidColorBrush(dxTarget, dxc.ToColor4(_pTextColor));
            txFormat = new TextFormat(txFactory, this.Font.Name, this.Font.Size) { TextAlignment = TextAlignment.Center, ParagraphAlignment = ParagraphAlignment.Center };
        }


Direct2D1.Factory可以声明单线程或者多线程。

WindowRenderTarget 是要绘制图像的目标。

SolidColorBrush 是画笔,Direct2D不使用Pen,它同样使用画笔来绘制轮廓。

TxFactory、TextFormat、TextLayout等,用于绘制文本。


每次控件大小变更,则重新分配资源


        int px, py;
        private void dxProgressBar_SizeChanged(object sender, EventArgs e)
        {
            InitD2D();
            Rectangle _txRect = this.ClientRectangle;
            _txRect.Inflate(-1, -1);
            dxBorderRectf = dxc.ToRectF(_txRect);

            Refresh();
        }

dxBorderRectf是控件的轮廓区域。


4,渲染

      
        private void Render()
        {
            dxTarget.Clear(dxc.ToColor4(this.BackColor));

            dxBorderBrush = new SolidColorBrush(dxTarget, dxc.ToColor4(_pBorderCor));
            dxTarget.DrawRectangle(dxBorderRectf, dxBorderBrush, 2);

            px = Width * _pValue / 100;
            py = this.Height-2;

            dxValueRectf = new RawRectangleF(2, 2, px, py);
            dxValueBruseh = new SolidColorBrush(dxTarget, dxc.ToColor4(ForeColor));
            dxTarget.FillRectangle(dxValueRectf, dxValueBruseh);
            
            txLayout = new TextLayout(txFactory, _pValue.ToString("F2") + "%", txFormat, 60, 25);
            dxTarget.DrawText(_pValue.ToString("F2") + "%", txFormat, dxBorderRectf, txtBrush, DrawTextOptions.Clip);
        }


Render函数,首先清空绘图区域;初始化画笔,绘制外形轮廓;计算进度条举行区域,并绘制当前进度;打印当前进度值。


5,用OnPaint对控件绘图

        protected override void OnPaint(PaintEventArgs e)
        {
            //base.OnPaint(e);
            dxTarget.BeginDraw();
            Render();
            dxTarget.EndDraw();
        }

使用sdx绘图,都要以BeginDraw开始,以EndDraw结束,这个跟D3D很像。

sdx中的资源,在整个程序运行周期中,都应该尽量保留,以节省资源。


下面是运行结果:


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值