zoukankan      html  css  js  c++  java
  • Direct2D Brush操作

    为方便,将D2D的一个基本类DesktopWindow写成如下所示:

    View Code
    #include "Precompiled.h"
    #include <d2d1.h>
    #include <wrl.h>
    
    #pragma comment(lib, "d2d1")
    
    using namespace D2D1;
    using namespace Microsoft::WRL;
    
    template<typename T>
    struct DesktopWindow
        : CWindowImpl<T, CWindow, CWinTraits<WS_OVERLAPPEDWINDOW | WS_VISIBLE>>
    {
        ComPtr<ID2D1Factory> m_factory;
        ComPtr<ID2D1HwndRenderTarget> m_target;
    
        DECLARE_WND_CLASS_EX(L"My D2D1 Window", CS_HREDRAW | CS_VREDRAW, -1);
    
        BEGIN_MSG_MAP(DesktopWindow)
            MESSAGE_HANDLER(WM_PAINT, PaintHandler)
            MESSAGE_HANDLER(WM_DESTROY, DestroyHandler)
            MESSAGE_HANDLER(WM_SIZE, SizeHandler)
            MESSAGE_HANDLER(WM_DISPLAYCHANGE, DisplayChangeHandler)
        END_MSG_MAP()
    
        LRESULT DisplayChangeHandler(UINT, WPARAM, LPARAM, BOOL&)
        {
            Invalidate();
            return 0;
        }
    
        LRESULT SizeHandler(UINT, WPARAM, LPARAM lparam, BOOL&)
        {
            if (m_target)
            {
                if (m_target->Resize(SizeU(LOWORD(lparam), HIWORD(lparam))) != S_OK)
                {
                    m_target.Reset();
                }
            }
            return 0;
        }
    
        LRESULT PaintHandler(UINT, WPARAM, LPARAM, BOOL&)
        {
            PAINTSTRUCT ps;
            VERIFY(BeginPaint(&ps));
            Render();
            EndPaint(&ps);
            return 0;
        }
    
        LRESULT DestroyHandler(UINT, WPARAM, LPARAM, BOOL&)
        {
            PostQuitMessage(0);
            return 0;
        }
    
        void Invalidate()
        {
            VERIFY(InvalidateRect(nullptr, false))
        }
    
        void Render()
        {
            if (!m_target)
            {
                RECT rect;
                VERIFY(GetClientRect(&rect));
    
                auto size = SizeU(rect.right, rect.bottom);
    
                m_factory->CreateHwndRenderTarget(RenderTargetProperties(), 
                                                  HwndRenderTargetProperties(m_hWnd, size), 
                                                  m_target.GetAddressOf());
                static_cast<T *>(this)->CreateDeviceResources();
            }
    
            if (!(m_target->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED))
            {
                m_target->BeginDraw();
    
                static_cast<T *>(this)->Draw();
    
                if (m_target->EndDraw() == D2DERR_RECREATE_TARGET)
                {
                    m_target.Reset();
                }
            }
        }
    
        int Run()
        {
            D2D1_FACTORY_OPTIONS fo = {};
    #ifdef DEBUG
            fo.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
    #endif
    
            D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, 
                              fo, 
                              m_factory.GetAddressOf());
            CreateDeviceIndependentResources();
            VERIFY(__super::Create(nullptr, 0, L"title"));
    
            MSG msg;
            BOOL result;
            while (result = GetMessage(&msg, 0, 0, 0))
            {
                if (result != -1)
                {
                    DispatchMessage(&msg);
                }
            }
    
            return msg.wParam;
        }
    
        virtual void CreateDeviceIndependentResources() {}
    };

    所有的画笔(Brush)都有SetOpacity和SetTransform两个方法,所有的单色画笔(SolidColorBrush)都有SetColor方法,可以设置颜色。
    画笔是可修改的(mutable),因此,可以只声明一个画笔,然后在使用的时候,不断地更换颜色。

    最简单的单色画笔(SolidColorBrush)示例如下所示:

    View Code
    #include "Precompiled.h"
    #include "DesktopWindow.h"
    
    D2D1_COLOR_F const COLOR_BLUE    = { 0.26f, 0.56f, 0.87f, 1.0f };
    D2D1_COLOR_F const COLOR_YELLOW = { 0.99f, 0.85f, 0.0f,  1.0f };
    D2D1_COLOR_F const COLOR_BLACK  = { 0.0f,  0.0f,  0.0f,  1.0f };
    D2D1_COLOR_F const COLOR_WHITE  = { 1.0f,  1.0f,  1.0f,  1.0f };
    
    struct SampleWindow : DesktopWindow
    {
        ComPtr<ID2D1SolidColorBrush> m_brush;
    
        void CreateDeviceResources()
        {
            m_target->CreateSolidColorBrush(COLOR_BLUE, 
                m_brush.ReleaseAndGetAddressOf());
        }
    
        void Draw()
        {
            m_target->Clear(COLOR_BLUE);
    
            auto size = m_target->GetSize();
    
            m_brush->SetOpacity(1.0f);
            
            m_brush->SetColor(COLOR_BLACK);
            auto br = RectF(100.0f, 100.0f, size.width - 100.0f, 200.0f);
            m_target->FillRectangle(br, m_brush.Get());
    
            m_brush->SetColor(COLOR_WHITE);
            auto bw = RectF(100.0f, 300.0f, size.width - 100.0f, 400.0f);
            m_target->FillRectangle(bw, m_brush.Get());
    
            m_brush->SetOpacity(.5f);
    
            m_brush->SetColor(COLOR_YELLOW);
            auto ry = RectF(150.0f, 150.0f, size.width - 150.0f, 350.0f);
            m_target->FillRectangle(ry, m_brush.Get());
        }
    };
    
    int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
    {
        SampleWindow window;
        
        window.Run();
    }

     线性渐变画笔(LinearGradientBrush)稍微麻烦,需要先定义关键点(D2D1_GRADIENT_STOP),然后将关键点加入渐变集合(ID2D1GradientStopCollection),最后将渐变集合定义为渐变画笔,其示例如下所示: 

    View Code
    #include "Precompiled.h"
    #include "DesktopWindow.h"
    
    D2D_COLOR_F const COLOR_BLUE    = { 0.26f, 0.56f, 0.87f, 1.0f };
    D2D_COLOR_F const COLOR_WHITE    = { 1.0f,  1.0f,  1.0f,  1.0f };
    
    struct SampleWindow : DesktopWindow<SampleWindow>
    {
        ComPtr<ID2D1LinearGradientBrush> m_brush;
    
        void CreateDeviceResources()
        {
            D2D1_GRADIENT_STOP stops[] = 
            {
                { 0.0f, COLOR_WHITE }, 
                { 1.0f, COLOR_BLUE }
            };
    
            ComPtr<ID2D1GradientStopCollection> collection;
    
            m_target->CreateGradientStopCollection(stops, _countof(stops), 
                collection.GetAddressOf());
    
            D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES props = {};
    
            m_target->CreateLinearGradientBrush(props, collection.Get(), 
                m_brush.ReleaseAndGetAddressOf());
        }
    
        void Draw()
        {
            auto size = m_target->GetSize();
    
            m_brush->SetEndPoint(Point2F(size.width, size.height));
            
            auto r = RectF(0.0f, 0.0f, size.width, size.height);
    
            m_target->FillRectangle(r, m_brush.Get());
        }
    };
    
    int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
    {
        SampleWindow window;
        
        window.Run();
    }

     可以使用环形渐变画笔(RadialGradientBrush),其定义方法和线性渐变画笔类似,也是定义关键点、渐变集合(COM),然后再定义渐变画笔,其救命如下所示:

    View Code
    #include "Precompiled.h"
    #include "DesktopWindow.h"
    
    D2D1_COLOR_F const COLOR_BLUE    = { 0.26f, 0.56f, 0.87f, 1.0f };
    D2D_COLOR_F const COLOR_WHITE     = { 1.0f,  1.0f,  1.0f,  1.0f };
    
    struct SampleWindow : DesktopWindow<SampleWindow>
    {
        ComPtr<ID2D1RadialGradientBrush> m_brush;
    
        void CreateDeviceResources()
        {
            D2D1_GRADIENT_STOP stops[] = 
            {
                { 0.0f, COLOR_WHITE }, 
                { 1.0f, COLOR_BLUE }
            };
    
            ComPtr<ID2D1GradientStopCollection> collection;
            m_target->CreateGradientStopCollection(stops, _countof(stops),
                collection.GetAddressOf());
            D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES props = {};
    
            m_target->CreateRadialGradientBrush(props, collection.Get(), 
                m_brush.ReleaseAndGetAddressOf());
        }
    
        void Draw()
        {
            auto size = m_target->GetSize();
    
            m_brush->SetCenter(Point2F(size.width / 2.0f, size.height / 2.0f));
            m_brush->SetRadiusX(size.width / 2.0f);
            m_brush->SetRadiusY(size.height / 2.0f);
    
            auto r = RectF(0.0f, 0.0f, size.width, size.height);
            m_target->FillRectangle(r, m_brush.Get());
        }
    };
    
    int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
    {
        SampleWindow window;
        
        window.Run();
    }

     在创建渐变集合时(CreateGradientStopCollection),可以设置D2D1_GAMMA_1_0或者D2D1_GAMMA_2_2,默认是D2D1_GAMMA_2_2,具体区别如下图所示(上图为2.2),直观上的区别就是D2D1_GAMMA_2_2的渐变性更好。

    最后,还可以通过设置边框样式(ID2D1StrokeStyle)来显示各种边框,注意边框样式是独立于设备的资源,因此,只需将边框样式的定义放在CreateDeviceIndependentResources方法中即可:

    View Code
    #include "Precompiled.h"
    #include "DesktopWindow.h"
    
    D2D1_COLOR_F const COLOR_BLUE    = { 0.26f, 0.56f, 0.87f, 1.0f };
    D2D_COLOR_F const COLOR_WHITE     = { 1.0f,  1.0f,  1.0f,  1.0f };
    
    struct SampleWindow : DesktopWindow<SampleWindow>
    {
        ComPtr<ID2D1SolidColorBrush> m_brush;
        ComPtr<ID2D1StrokeStyle> m_style;
    
        void CreateDeviceIndependentResources()
        {
            D2D1_STROKE_STYLE_PROPERTIES props = {};
            props.lineJoin = D2D1_LINE_JOIN_ROUND;
            props.dashStyle = D2D1_DASH_STYLE_DASH_DOT;
            props.dashCap = D2D1_CAP_STYLE_ROUND;
    
            m_factory->CreateStrokeStyle(props, nullptr, 0, m_style.GetAddressOf());
        }
    
        void CreateDeviceResources()
        {
            m_target->CreateSolidColorBrush(COLOR_WHITE, 
                m_brush.ReleaseAndGetAddressOf());
        }
    
        void Draw()
        {
            m_target->Clear(COLOR_BLUE);
            auto size = m_target->GetSize();
            
            auto r = RectF(100.0f, 100.0f, size.width - 100.0f, size.height - 100.0f);
            m_target->DrawRectangle(r, m_brush.Get(), 20.0f, m_style.Get());
        }
    };
    
    int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
    {
        SampleWindow window;
        
        window.Run();
    }


     

  • 相关阅读:
    字典的增删改查
    列表的增删改查 and 元祖
    基础数据类型
    python初始1
    python初始
    android APP 中微信分享功能实现 的总结
    android ADT 版本过低的解决办法
    android 布局: LinearLayout如何使TextView中的内容居中显示
    android获取项目下的一张图片的绝对路径问题以及解决方法
    android 4高级编程(第三版)
  • 原文地址:https://www.cnblogs.com/sdflysha/p/3028225.html
Copyright © 2011-2022 走看看