Direct2D 几何图形

通过ID2D1HwndRenderTarget,可以轻松地画作各种样式的长方形和椭圆形:

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_WHITE     = { 1.0f,  1.0f,  1.0f,  1.0f };
D2D1_COLOR_F const COLOR_BLACK     = { 0.0f,  0.0f,  0.0f,  1.0f };
D2D1_COLOR_F const COLOR_YELLOW = { 0.99f, 0.85f, 0.0f,  1.0f };

struct SampleWindow : DesktopWindow<SampleWindow>
{
    ComPtr<ID2D1SolidColorBrush> m_brush;
    ComPtr<ID2D1StrokeStyle> m_style;

    void CreateDeviceIndependentResources()
    {
    }

    void CreateDeviceResources()
    {
        m_target->CreateSolidColorBrush(COLOR_WHITE, 
            m_brush.ReleaseAndGetAddressOf());
    }

    void Draw()
    {
        m_target->Clear(COLOR_BLUE);
        auto size = m_target->GetSize();
        auto offset = 50.0f;
        auto rect = RectF( offset, offset, size.width - offset, size.height - offset );
        D2D1_ROUNDED_RECT rounded = { rect, 200.0f, 200.0f };
        D2D1_POINT_2F center = { size.width / 2.0f, size.height / 2.0 };
        D2D1_ELLIPSE ellipse = { center, center.x - offset, center.y - offset };
        
        m_brush->SetColor(COLOR_WHITE);
        m_brush->SetOpacity(1.0f);
        m_target->FillRectangle(rect, m_brush.Get());

        m_brush->SetColor(COLOR_BLACK);
        m_brush->SetOpacity(0.5f);
        m_target->DrawRectangle(rect, m_brush.Get(), 20.0f);
        
        m_target->DrawRoundedRectangle(rounded, m_brush.Get(), 40.0f);

        m_brush->SetColor(COLOR_YELLOW);
        m_target->DrawEllipse(ellipse, m_brush.Get(), 20.0f);
    }
};

int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
    SampleWindow window;
    
    window.Run();
}

通过运行在高中学过的一些数学知识,可以轻易绘制出一些其它有意思的图形:

View Code
#include "Precompiled.h"
#include "DesktopWindow.h"
#include <cmath>

D2D1_COLOR_F const COLOR_BLUE   = { 0.26f, 0.56f, 0.87f, 1.0f };
D2D1_COLOR_F const COLOR_WHITE    = { 1.0f,  1.0f,  1.0f,  1.0f };
D2D1_COLOR_F const COLOR_BLACK    = { 0.0f,  0.0f,  0.0f,  1.0f };
D2D1_COLOR_F const COLOR_YELLOW = { 0.99f, 0.85f, 0.0f,  1.0f };
D2D1_COLOR_F const COLOR_RED    = { 1.0f,  0.0f,  0.0f,  1.0f };

struct SampleWindow : DesktopWindow<SampleWindow>
{
    ComPtr<ID2D1SolidColorBrush> m_brush;
    ComPtr<ID2D1StrokeStyle> m_style;

    void CreateDeviceIndependentResources()
    {
    }

    void CreateDeviceResources()
    {
        m_target->CreateSolidColorBrush(COLOR_WHITE, 
            m_brush.ReleaseAndGetAddressOf());
    }

    D2D1_POINT_2F EllipsePoint(D2D1_ELLIPSE const & ellipse, float angle)
    {
        const float pi = 3.1415926f;

        D2D1_POINT_2F point = 
        {
            ellipse.point.x + ellipse.radiusX * cos(angle * pi / 180.0f), 
            ellipse.point.y + ellipse.radiusY * sin(angle * pi / 180.0f), 
        };
        return point;
    }

    void Draw()
    {
        m_target->Clear(COLOR_BLACK);
        auto size = m_target->GetSize();
        auto offset = 50.0f;
        auto rect = RectF( offset, offset, size.width - offset, size.height - offset );
        D2D1_ROUNDED_RECT rounded = { rect, 200.0f, 200.0f };
        D2D1_POINT_2F center = { size.width / 2.0f, size.height / 2.0f };
        D2D1_ELLIPSE ellipse = { center, center.x - offset, center.y - offset };
        
        m_brush->SetColor(COLOR_WHITE);
        m_target->FillEllipse(ellipse, m_brush.Get());
        m_brush->SetColor(COLOR_RED);
        m_target->DrawEllipse(ellipse, m_brush.Get(), 40.0f);
        m_target->DrawLine(
            EllipsePoint(ellipse, 135), 
            EllipsePoint(ellipse, 315), 
            m_brush.Get(), 40.0f);
    }
};

int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
    SampleWindow window;
    
    window.Run();
}

可以定义一些D2D1中的几何图形组件(ID2D1***Geometry),来简化绘制流程。注意,几何图形组件是独立于设备的资源(DeviceIndependentResources),因此只需要在CreateDeviceIndependentResources方法中定义即可。另外,几何图形组件是不可更改的(immutable),因此,一旦定义,将无法更改。以下是几何图形组件的一些基本应用:

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_WHITE    = { 1.0f,  1.0f,  1.0f,  1.0f };
D2D1_COLOR_F const COLOR_BLACK    = { 0.0f,  0.0f,  0.0f,  1.0f };
D2D1_COLOR_F const COLOR_YELLOW = { 0.99f, 0.85f, 0.0f,  1.0f };
D2D1_COLOR_F const COLOR_RED    = { 1.0f,  0.0f,  0.0f,  1.0f };

struct SampleWindow : DesktopWindow<SampleWindow>
{
    ComPtr<ID2D1SolidColorBrush> m_brush;
    ComPtr<ID2D1RectangleGeometry> m_rect;
    ComPtr<ID2D1RoundedRectangleGeometry> m_rounded;
    ComPtr<ID2D1EllipseGeometry> m_ellipse;

    void CreateDeviceIndependentResources()
    {
        D2D1_RECT_F rect = { 100.0f, 100.0f, 600.0f, 400.0f };
        D2D1_ROUNDED_RECT rounded = { rect, 40.0f, 40.0f };
        D2D1_ELLIPSE ellipse = 
        {
            { 350.0f, 250.0f }, 
            250.0f, 150.f,
        };

        m_factory->CreateRectangleGeometry(rect, m_rect.GetAddressOf());
        m_factory->CreateRoundedRectangleGeometry(rounded, m_rounded.GetAddressOf());
        m_factory->CreateEllipseGeometry(ellipse, m_ellipse.GetAddressOf());
    }

    void CreateDeviceResources()
    {
        m_target->CreateSolidColorBrush(COLOR_WHITE, 
            m_brush.ReleaseAndGetAddressOf());
    }

    void Draw()
    {
        m_target->Clear(COLOR_BLUE);
        auto size = m_target->GetSize();

        m_brush->SetOpacity(0.5f);

        m_brush->SetColor(COLOR_WHITE);
        m_target->DrawGeometry(m_rect.Get(), m_brush.Get(), 40.0f);

        m_brush->SetColor(COLOR_RED);
        m_target->DrawGeometry(m_rounded.Get(), m_brush.Get(), 20.0f);

        m_brush->SetColor(COLOR_YELLOW);
        m_target->DrawGeometry(m_ellipse.Get(), m_brush.Get());
        m_target->FillGeometry(m_ellipse.Get(), m_brush.Get());
    }
};

int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
    SampleWindow window;
    
    window.Run();
}

可以使用路径几何图形(ID2D1PathGeometry),来定义更加复杂的图形,ID2D1PathGeometry是独立于设备的资源,因此只需在CreateDeviceIndependentResources方法中定义:

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_WHITE    = { 1.0f,  1.0f,  1.0f,  1.0f };
D2D1_COLOR_F const COLOR_BLACK    = { 0.0f,  0.0f,  0.0f,  1.0f };
D2D1_COLOR_F const COLOR_YELLOW = { 0.99f, 0.85f, 0.0f,  1.0f };
D2D1_COLOR_F const COLOR_RED    = { 1.0f,  0.0f,  0.0f,  1.0f };

struct SampleWindow : DesktopWindow<SampleWindow>
{
    ComPtr<ID2D1SolidColorBrush> m_brush;
    ComPtr<ID2D1PathGeometry> m_path;

    void CreateDeviceIndependentResources()
    {
        m_factory->CreatePathGeometry(m_path.GetAddressOf());

        ComPtr<ID2D1GeometrySink> sink;
        m_path->Open(sink.GetAddressOf());

        // 使用BEGIN_HOLLOW将不会填充多边形
        sink->BeginFigure(Point2F(50.0f, 50.0f), D2D1_FIGURE_BEGIN_HOLLOW);
        sink->AddLine(Point2F(250.0f, 50.0f));
        D2D1_POINT_2F points[] = 
        {
            { 250.0f, 250.0f }, 
            { 50.0f, 250.0f }
        };
        sink->AddLines(points, _countof(points));
        // 如果使用END_OPEN,则不会绘制最后一条边
        sink->EndFigure(D2D1_FIGURE_END_OPEN);

        // 可以绘制多个图形
        sink->BeginFigure(Point2F(300.0f, 50.0f), D2D1_FIGURE_BEGIN_FILLED);
        D2D1_POINT_2F points2[] = 
        {
            { 500.0f, 50.0f }, 
            { 550.0f, 250.0f }, 
            { 350.0f, 250.0f }, 
        };
        sink->AddLines(points2, _countof(points2));
        sink->EndFigure(D2D1_FIGURE_END_CLOSED);

        sink->Close();
    }

    void CreateDeviceResources()
    {
        m_target->CreateSolidColorBrush(COLOR_WHITE, 
            m_brush.ReleaseAndGetAddressOf());
    }

    void Draw()
    {
        m_target->Clear(COLOR_BLUE);
        
        m_brush->SetColor(COLOR_YELLOW);
        m_target->FillGeometry(m_path.Get(), m_brush.Get());

        m_brush->SetColor(COLOR_RED);
        m_target->DrawGeometry(m_path.Get(), m_brush.Get(), 10.0f);
    }
};

int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
    SampleWindow window;
    
    window.Run();
}

注意定义的不同可以让图形也不同。

除了路径组成的多边形外,Geometry还可以使用圆弧:

View Code
#include "stdafx.h"
#include "DesktopWindow.h"

D2D1_COLOR_F const COLOR_BLUE   = { 0.26f, 0.56f, 0.87f, 1.0f };
D2D1_COLOR_F const COLOR_WHITE    = { 1.0f,  1.0f,  1.0f,  1.0f };
D2D1_COLOR_F const COLOR_BLACK    = { 0.0f,  0.0f,  0.0f,  1.0f };
D2D1_COLOR_F const COLOR_YELLOW = { 0.99f, 0.85f, 0.0f,  1.0f };
D2D1_COLOR_F const COLOR_RED    = { 1.0f,  0.0f,  0.0f,  1.0f };

struct SampleWindow : DesktopWindow<SampleWindow>
{
    ComPtr<ID2D1SolidColorBrush> m_brush;
    ComPtr<ID2D1PathGeometry> m_arc1;
    ComPtr<ID2D1PathGeometry> m_arc2;
    ComPtr<ID2D1PathGeometry> m_arc3;
    ComPtr<ID2D1PathGeometry> m_arc4;
    D2D1_POINT_2F m_begin;  
    D2D1_POINT_2F m_end; 
     
    void BuildPath(ComPtr<ID2D1PathGeometry>& path, 
        D2D1_SWEEP_DIRECTION direction, D2D1_ARC_SIZE size)
    { 
        D2D1_ARC_SEGMENT arc = 
        {
            m_end, 
            { 100.0f, 100.0f }, 
            0.0f, 
            direction, 
            size
        };
        m_factory->CreatePathGeometry(path.ReleaseAndGetAddressOf());

        ComPtr<ID2D1GeometrySink> sink;
        path->Open(sink.GetAddressOf());
        sink->BeginFigure(m_begin, D2D1_FIGURE_BEGIN_FILLED);
        sink->AddArc(arc);
        sink->EndFigure(D2D1_FIGURE_END_OPEN);
        sink->Close();
    }

    void BuildPaths()
    {
        BuildPath(m_arc1, D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE, D2D1_ARC_SIZE_LARGE);
        BuildPath(m_arc2, D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE, D2D1_ARC_SIZE_SMALL);
        BuildPath(m_arc3, D2D1_SWEEP_DIRECTION_CLOCKWISE, D2D1_ARC_SIZE_LARGE);
        BuildPath(m_arc4, D2D1_SWEEP_DIRECTION_CLOCKWISE, D2D1_ARC_SIZE_SMALL);
    }

    void CreateDeviceIndependentResources()
    {
        m_begin = Point2F(100.0f, 60.0f);
        m_end = Point2F(200.0f, 210.0f);

        BuildPaths();
    }

    void CreateDeviceResources()
    {
        m_target->CreateSolidColorBrush(COLOR_WHITE, 
            m_brush.ReleaseAndGetAddressOf());
    }

    void Draw()
    {
        m_target->Clear(COLOR_BLUE);

        m_brush->SetOpacity(1.0f);
        m_brush->SetColor(COLOR_RED);
        m_target->DrawGeometry(m_arc1.Get(), m_brush.Get(), 5.0f);
        m_target->DrawGeometry(m_arc2.Get(), m_brush.Get(), 5.0f);
        m_brush->SetColor(COLOR_WHITE);
        m_target->DrawGeometry(m_arc3.Get(), m_brush.Get(), 5.0f);
        m_target->DrawGeometry(m_arc4.Get(), m_brush.Get(), 5.0f);

        m_brush->SetColor(COLOR_BLACK);
        m_target->DrawLine(m_begin, m_end, m_brush.Get(), 3.0f);

        m_brush->SetOpacity(0.5f);
        m_brush->SetColor(COLOR_YELLOW);
        m_target->FillEllipse(Ellipse(m_begin, 8.0f, 8.0f), m_brush.Get());
        m_brush->SetColor(COLOR_YELLOW);
        m_target->FillEllipse(Ellipse(m_end, 8.0f, 8.0f), m_brush.Get());
    }
};

int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
    SampleWindow window;
    
    window.Run();
}

可以使用贝兹尔曲线(Bezier),来绘制出一些更加有意思的图形:

View Code
#include "stdafx.h"
#include "DesktopWindow.h"

D2D1_COLOR_F const COLOR_BLUE   = { 0.26f, 0.56f, 0.87f, 1.0f };
D2D1_COLOR_F const COLOR_WHITE    = { 1.0f,  1.0f,  1.0f,  1.0f };
D2D1_COLOR_F const COLOR_BLACK    = { 0.0f,  0.0f,  0.0f,  1.0f };
D2D1_COLOR_F const COLOR_YELLOW = { 0.99f, 0.85f, 0.0f,  1.0f };
D2D1_COLOR_F const COLOR_RED    = { 1.0f,  0.0f,  0.0f,  1.0f };

struct SampleWindow : DesktopWindow<SampleWindow>
{
    ComPtr<ID2D1SolidColorBrush> m_brush;
    ComPtr<ID2D1PathGeometry> m_path;
    D2D1_POINT_2F m_c1;
    D2D1_POINT_2F m_c2;
    D2D1_POINT_2F start;
    D2D1_POINT_2F end;

    void CreateDeviceIndependentResources()
    {
        m_factory->CreatePathGeometry(m_path.GetAddressOf());

        ComPtr<ID2D1GeometrySink> sink;
        m_path->Open(sink.GetAddressOf());
        
        start = Point2F(100.0f, 600.0f);
        end = Point2F(900.0f, 600.0f);
        m_c1 = Point2F(50.0f, 50.0f);
        m_c2 = Point2F(600.0f, 50.0f);
        
        sink->BeginFigure(start, D2D1_FIGURE_BEGIN_FILLED);
        sink->AddBezier(BezierSegment(m_c1, m_c2, end));
        sink->EndFigure(D2D1_FIGURE_END_OPEN);

        sink->BeginFigure(start, D2D1_FIGURE_BEGIN_FILLED);
        D2D1_QUADRATIC_BEZIER_SEGMENT quad[] = 
        {
            { { 400.0f, 0.0f }, { 400.0f, 300.0f } }, 
            { { 400.0f, 600.0f}, end }
        };
        sink->AddQuadraticBeziers(quad, _countof(quad));
        sink->EndFigure(D2D1_FIGURE_END_OPEN);

        sink->Close();
    }

    void CreateDeviceResources()
    {
        m_target->CreateSolidColorBrush(COLOR_WHITE, 
            m_brush.ReleaseAndGetAddressOf());
    }

    void Draw()
    {
        m_target->Clear(COLOR_BLUE);

        m_brush->SetColor(COLOR_WHITE);
        m_target->FillEllipse(Ellipse(m_c1, 5.0f, 5.0f), m_brush.Get());
        m_target->FillEllipse(Ellipse(m_c2, 5.0f, 5.0f), m_brush.Get());
        m_target->FillEllipse(Ellipse(Point2F(400.0f, 0.0f), 5.0f, 5.0f), m_brush.Get());
        m_target->FillEllipse(Ellipse(Point2F(400.0f, 300.0f), 5.0f, 5.0f), m_brush.Get());
        m_target->FillEllipse(Ellipse(Point2F(400.0f, 600.0f), 5.0f, 5.0f), m_brush.Get());

        m_target->DrawGeometry(m_path.Get(), m_brush.Get(), 3.0f);

        m_brush->SetColor(COLOR_RED);
        m_target->DrawLine(start, m_c1, m_brush.Get(), 1.0f);
        m_target->DrawLine(end, m_c2, m_brush.Get(), 1.0f);
        m_target->DrawLine(start, Point2F(400.0f, 0.0f), m_brush.Get(), 1.0f);
        m_target->DrawLine(Point2F(400.0f, 0.0f), Point2F(400.0f, 300.0f), m_brush.Get(),  1.0f);
        m_target->DrawLine(Point2F(400.0f, 300.0f), Point2F(400.0f, 600.0f), m_brush.Get(), 1.0f);
        m_target->DrawLine(Point2F(400.0f, 600.0f), end, m_brush.Get(), 1.0f);
    }
};

int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
    SampleWindow window;
    
    window.Run();
}

posted @ 2013-04-19 09:53  .NET骚操作  阅读(723)  评论(0编辑  收藏  举报