Direct2D 几何篇

微软文档:Geometries overview

本篇通过官方文档学习,整理出来的demo,初始样本请先创建一个普通的desktop app。

// Test_Direct2D_Brush.cpp : Defines the entry point for the application.
//

#include "framework.h"
#include "Test_Direct2D_Brush.h"
#include <d2d1.h>
#include <wincodec.h>

#pragma comment(lib, "D2d1.lib")
#pragma comment(lib, "Windowscodecs.lib")

#define MAX_LOADSTRING 100

template <class T> void SafeRelease(T** ppT)
{
    if (*ppT)
    {
        (*ppT)->Release();
        *ppT = NULL;
    }
}

HWND hWnd;
ID2D1Factory* l;
ID2D1HwndRenderTarget* m_pRenderTarget;
ID2D1SolidColorBrush* m_pSceneBrush;
ID2D1GradientStopCollection* pGradientStops = NULL;
ID2D1RadialGradientBrush* m_pRadialGradientBrush;
ID2D1EllipseGeometry* m_pEllipseGeometry1, * m_pEllipseGeometry2, * m_pEllipseGeometry3, * m_pEllipseGeometry4, *m_pCircleGeometry1,*m_pCircleGeometry2;
ID2D1GeometryGroup* m_pGeoGroup_AlternateFill,*m_pGeoGroup_WindingFill;
ID2D1RectangleGeometry* m_pRectangleGeometry;
ID2D1TransformedGeometry *m_pTransformedGeometry;
ID2D1GeometrySink* pGeometrySink = NULL;
ID2D1PathGeometry* m_pPathGeometryUnion,* m_pLeftMountainGeometry,* m_pRightMountainGeometry,* m_pSunGeometry,* m_pRiverGeometry;
ID2D1Geometry* pGeometry;
ID2D1SimplifiedGeometrySink* pGeometrySink1;

// Global Variables:
HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
void Render();
void DiscardGraphicsResources();
void Geometry();

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_TESTDIRECT2DBRUSH, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTDIRECT2DBRUSH));

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TESTDIRECT2DBRUSH));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_TESTDIRECT2DBRUSH);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable
   HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &l);
   hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
         //   PAINTSTRUCT ps;
         //   HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code that uses hdc here...
            Render();
            ValidateRect(hWnd, NULL);
         //   EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}


void Render()
{   
    RECT rc;
    GetClientRect(hWnd, &rc);

    D2D1_SIZE_U size = D2D1::SizeU(
        rc.right - rc.left,
        rc.bottom - rc.top
    );
    HRESULT hr = l->CreateHwndRenderTarget(
        D2D1::RenderTargetProperties(),
        D2D1::HwndRenderTargetProperties(hWnd, size),
        &m_pRenderTarget
    );

    m_pRenderTarget->BeginDraw();

    m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
/*************************************************************************************/
    Geometry();
    
/*************************************************************************************/
    hr = m_pRenderTarget->EndDraw();

    if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET)
    {
        DiscardGraphicsResources();
    }
}

void DiscardGraphicsResources()
{
    SafeRelease(&m_pRenderTarget);
}


void Geometry()
{ 
    HRESULT hr = l->CreateEllipseGeometry(
        D2D1::Ellipse(D2D1::Point2F(160.f, 120.f), 25.f, 25.f),
        &m_pEllipseGeometry1);
    if (SUCCEEDED(hr))
    {
        hr = l->CreateEllipseGeometry(
            D2D1::Ellipse(D2D1::Point2F(160.f, 120.f), 50.f, 50.f),
            &m_pEllipseGeometry2);
    }
    if (SUCCEEDED(hr))
    {
        hr = l->CreateEllipseGeometry(
            D2D1::Ellipse(D2D1::Point2F(160.f, 120.f), 75.f, 75.f),
            &m_pEllipseGeometry3);
    }
    if (SUCCEEDED(hr))
    {
        hr = l->CreateEllipseGeometry(
            D2D1::Ellipse(D2D1::Point2F(160.f, 120.f), 100.f, 100.f),
            &m_pEllipseGeometry4);
    }
    

    ID2D1Geometry* ppGeometries[] =
    {
        m_pEllipseGeometry1,
        m_pEllipseGeometry2,
        m_pEllipseGeometry3,
        m_pEllipseGeometry4
    };
    if (SUCCEEDED(hr))
    {
        hr = l->CreateGeometryGroup(
            D2D1_FILL_MODE_ALTERNATE,
            ppGeometries,
            ARRAYSIZE(ppGeometries),
            &m_pGeoGroup_AlternateFill
        );
    }

    if (SUCCEEDED(hr))
    {
        hr = l->CreateGeometryGroup(
            D2D1_FILL_MODE_WINDING,
            ppGeometries,
            ARRAYSIZE(ppGeometries),
            &m_pGeoGroup_WindingFill
        );
    }
    if (SUCCEEDED(hr))
    {
        hr = m_pRenderTarget->CreateSolidColorBrush(
            D2D1::ColorF(D2D1::ColorF::Black, 1.0F),
            &m_pBlackBrush);
    }
 //   m_pRenderTarget->DrawGeometry(m_pGeoGroup_AlternateFill, m_pBlackBrush, 2);
 //   m_pRenderTarget->DrawGeometry(m_pGeoGroup_WindingFill, m_pBlackBrush, 2);
/****************************************************************************************/
//变换后的几何
    hr = l->CreateRectangleGeometry(
        D2D1::RectF(150.f, 150.f, 200.f, 200.f),
        &m_pRectangleGeometry
    );
    // Draw the untransformed rectangle geometry.
 //   m_pRenderTarget->DrawGeometry(m_pRectangleGeometry, m_pBlackBrush, 1);
    //Transform the render target, then draw the rectangle geometry again.
    m_pRenderTarget->SetTransform(
        D2D1::Matrix3x2F::Scale(
            D2D1::SizeF(3.f, 3.f),
            D2D1::Point2F(175.f, 175.f)) //上面小矩形的中心点坐标
    );
 //   m_pRenderTarget->DrawGeometry(m_pRectangleGeometry, m_pBlackBrush, 1);

    hr = l->CreateTransformedGeometry(
        m_pRectangleGeometry,
        D2D1::Matrix3x2F::Scale(
            D2D1::SizeF(3.f, 3.f),
            D2D1::Point2F(175.f, 175.f)),
        &m_pTransformedGeometry
    );
    // Replace the previous render target transform.
    m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); //顾名思义,上面的m_pRenderTarget->SetTransform的设置无效了 

    // Draw the transformed geometry.
//    m_pRenderTarget->DrawGeometry(m_pTransformedGeometry, m_pBlackBrush, 1);  //另一种缩放方法,不同之处在于笔的粗细没有受影响
/*****************************************************************************************/
//组合几何
    // Create the first ellipse geometry to merge.
    const D2D1_ELLIPSE circle1 = D2D1::Ellipse(
        D2D1::Point2F(75.0f, 75.0f),
        50.0f,
        50.0f
    );
    hr = l->CreateEllipseGeometry(
        circle1,
        &m_pCircleGeometry1
    );
    if (SUCCEEDED(hr))
    {
        // Create the second ellipse geometry to merge.
        const D2D1_ELLIPSE circle2 = D2D1::Ellipse(
            D2D1::Point2F(125.0f, 75.0f),
            50.0f,
            50.0f
        );

        hr = l->CreateEllipseGeometry(circle2, &m_pCircleGeometry2);
    }
    if (SUCCEEDED(hr))
    {
        //
        // Use D2D1_COMBINE_MODE_UNION to combine the geometries.
        //
        hr = l->CreatePathGeometry(&m_pPathGeometryUnion);

        if (SUCCEEDED(hr))
        {
            hr = m_pPathGeometryUnion->Open(&pGeometrySink);

            if (SUCCEEDED(hr))
            {
                hr = m_pCircleGeometry1->CombineWithGeometry(
                    m_pCircleGeometry2,
                    D2D1_COMBINE_MODE_UNION,
                    NULL,
                    NULL,
                    pGeometrySink
                );
            }

            if (SUCCEEDED(hr))
            {
                hr = pGeometrySink->Close();
            }
           
            SafeRelease(&pGeometrySink);
        }
    }
//    m_pRenderTarget->DrawGeometry(m_pPathGeometryUnion, m_pBlackBrush, 1);

// https://docs.microsoft.com/en-us/windows/win32/direct2d/direct2d-geometries-overview#widen
//    widen方法还没实现
   /* hr = m_pPathGeometryUnion->Open(&pGeometrySink);
    if (SUCCEEDED(hr))
    {
        hr = pGeometry->Widen(
            2,
            NULL,
            NULL,
            pGeometrySink1
        );*/
/****************************************************************************/
//Create a Complex Drawing
    //左边山
    hr = l->CreatePathGeometry(&m_pLeftMountainGeometry);
    ID2D1GeometrySink* pSink = NULL;
    hr = m_pLeftMountainGeometry->Open(&pSink);
    pSink->SetFillMode(D2D1_FILL_MODE_WINDING);
    pSink->BeginFigure(
        D2D1::Point2F(346, 255),
        D2D1_FIGURE_BEGIN_FILLED
    );
    D2D1_POINT_2F points[5] = {
       D2D1::Point2F(267, 177),
       D2D1::Point2F(236, 192),
       D2D1::Point2F(212, 160),
       D2D1::Point2F(156, 255),
       D2D1::Point2F(346, 255),
    };
    pSink->AddLines(points, ARRAYSIZE(points));
    pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
    hr = pSink->Close();
   //右边山
    hr = l->CreatePathGeometry(&m_pRightMountainGeometry);
    if (SUCCEEDED(hr))
    {
        hr = m_pRightMountainGeometry->Open(&pSink);
        if (SUCCEEDED(hr))
        {
            pSink->SetFillMode(D2D1_FILL_MODE_WINDING);

            pSink->BeginFigure(
                D2D1::Point2F(575, 263),
                D2D1_FIGURE_BEGIN_FILLED
            );
            D2D1_POINT_2F points[] = {
               D2D1::Point2F(481, 146),
               D2D1::Point2F(449, 181),
               D2D1::Point2F(433, 159),
               D2D1::Point2F(401, 214),
               D2D1::Point2F(381, 199),
               D2D1::Point2F(323, 263),
               D2D1::Point2F(575, 263)
            };
            pSink->AddLines(points, ARRAYSIZE(points));
            pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
        }
        hr = pSink->Close();      
    }
    //太阳
    hr = l->CreatePathGeometry(&m_pSunGeometry);
    if (SUCCEEDED(hr))
    {
        hr = m_pSunGeometry->Open(&pSink);
        if (SUCCEEDED(hr))
        {
            pSink->SetFillMode(D2D1_FILL_MODE_WINDING);

            pSink->BeginFigure(
                D2D1::Point2F(270, 255),
                D2D1_FIGURE_BEGIN_FILLED
            );
            pSink->AddArc(
                D2D1::ArcSegment(
                    D2D1::Point2F(440, 255), // end point
                    D2D1::SizeF(85, 85),
                    0.0f, // rotation angle
                    D2D1_SWEEP_DIRECTION_CLOCKWISE,
                    D2D1_ARC_SIZE_SMALL
                ));
            pSink->EndFigure(D2D1_FIGURE_END_CLOSED);

            pSink->BeginFigure(
                D2D1::Point2F(299, 182),
                D2D1_FIGURE_BEGIN_HOLLOW
            );
            pSink->AddBezier(
                D2D1::BezierSegment(
                    D2D1::Point2F(299, 182),
                    D2D1::Point2F(294, 176),
                    D2D1::Point2F(285, 178)
                ));
            pSink->AddBezier(
                D2D1::BezierSegment(
                    D2D1::Point2F(276, 179),
                    D2D1::Point2F(272, 173),
                    D2D1::Point2F(272, 173)
                ));
            pSink->EndFigure(D2D1_FIGURE_END_OPEN);

            pSink->BeginFigure(
                D2D1::Point2F(354, 156),
                D2D1_FIGURE_BEGIN_HOLLOW
            );
            pSink->AddBezier(
                D2D1::BezierSegment(
                    D2D1::Point2F(354, 156),
                    D2D1::Point2F(358, 149),
                    D2D1::Point2F(354, 142)
                ));
            pSink->AddBezier(
                D2D1::BezierSegment(
                    D2D1::Point2F(349, 134),
                    D2D1::Point2F(354, 127),
                    D2D1::Point2F(354, 127)
                ));
            pSink->EndFigure(D2D1_FIGURE_END_OPEN);

            pSink->BeginFigure(
                D2D1::Point2F(322, 164),
                D2D1_FIGURE_BEGIN_HOLLOW
            );
            pSink->AddBezier(
                D2D1::BezierSegment(
                    D2D1::Point2F(322, 164),
                    D2D1::Point2F(322, 156),
                    D2D1::Point2F(314, 152)
                ));
            pSink->AddBezier(
                D2D1::BezierSegment(
                    D2D1::Point2F(306, 149),
                    D2D1::Point2F(305, 141),
                    D2D1::Point2F(305, 141)
                ));
            pSink->EndFigure(D2D1_FIGURE_END_OPEN);

            pSink->BeginFigure(
                D2D1::Point2F(385, 164),
                D2D1_FIGURE_BEGIN_HOLLOW
            );
            pSink->AddBezier(
                D2D1::BezierSegment(
                    D2D1::Point2F(385, 164),
                    D2D1::Point2F(392, 161),
                    D2D1::Point2F(394, 152)
                ));
            pSink->AddBezier(
                D2D1::BezierSegment(
                    D2D1::Point2F(395, 144),
                    D2D1::Point2F(402, 141),
                    D2D1::Point2F(402, 142)
                ));
            pSink->EndFigure(D2D1_FIGURE_END_OPEN);

            pSink->BeginFigure(
                D2D1::Point2F(408, 182),
                D2D1_FIGURE_BEGIN_HOLLOW
            );
            pSink->AddBezier(
                D2D1::BezierSegment(
                    D2D1::Point2F(408, 182),
                    D2D1::Point2F(416, 184),
                    D2D1::Point2F(422, 178)
                ));
            pSink->AddBezier(
                D2D1::BezierSegment(
                    D2D1::Point2F(428, 171),
                    D2D1::Point2F(435, 173),
                    D2D1::Point2F(435, 173)
                ));
            pSink->EndFigure(D2D1_FIGURE_END_OPEN);
        }
        hr = pSink->Close();
    }
    //河流
    hr = l->CreatePathGeometry(&m_pRiverGeometry);

    if (SUCCEEDED(hr))
    {
        hr = m_pRiverGeometry->Open(&pSink);
        if (SUCCEEDED(hr))
        {
            pSink->SetFillMode(D2D1_FILL_MODE_WINDING);
            pSink->BeginFigure(
                D2D1::Point2F(183, 392),
                D2D1_FIGURE_BEGIN_FILLED
            );
            pSink->AddBezier(
                D2D1::BezierSegment(
                    D2D1::Point2F(238, 284),
                    D2D1::Point2F(472, 345),
                    D2D1::Point2F(356, 303)
                ));
            pSink->AddBezier(
                D2D1::BezierSegment(
                    D2D1::Point2F(237, 261),
                    D2D1::Point2F(333, 256),
                    D2D1::Point2F(333, 256)
                ));
            pSink->AddBezier(
                D2D1::BezierSegment(
                    D2D1::Point2F(335, 257),
                    D2D1::Point2F(241, 261),
                    D2D1::Point2F(411, 306)
                ));
            pSink->AddBezier(
                D2D1::BezierSegment(
                    D2D1::Point2F(574, 350),
                    D2D1::Point2F(288, 324),
                    D2D1::Point2F(296, 392)
                ));
            pSink->EndFigure(D2D1_FIGURE_END_OPEN);
        }
        hr = pSink->Close();

        SafeRelease(&pSink);
    }
    //着色
    m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());

    m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
   
    //D2D1_SIZE_F rtSize = m_pRenderTarget->GetSize();
    //m_pRenderTarget->FillRectangle(
    //    D2D1::RectF(0, 0, rtSize.width, rtSize.height),
    //    m_pGridPatternBitmapBrush
    //);

    D2D1_GRADIENT_STOP gradientStops[2];
    gradientStops[0].color = D2D1::ColorF(D2D1::ColorF::Yellow, 1);
    gradientStops[0].position = 0.0f;
    gradientStops[1].color = D2D1::ColorF(D2D1::ColorF::OrangeRed, 1);
    gradientStops[1].position = 1.0f;
    hr = m_pRenderTarget->CreateGradientStopCollection(
        gradientStops,
        2,
        D2D1_GAMMA_2_2,
        D2D1_EXTEND_MODE_CLAMP,
        &pGradientStops
    );
    m_pRenderTarget->CreateRadialGradientBrush(
        D2D1::RadialGradientBrushProperties(
            D2D1::Point2F(355, 255),
            D2D1::Point2F(0, 0),
            85,
            85),
        pGradientStops,
        &m_pRadialGradientBrush
    );

    hr = m_pRenderTarget->CreateSolidColorBrush(
        D2D1::ColorF(D2D1::ColorF::Black, 1.0F),
        &m_pSceneBrush);
    m_pRenderTarget->FillGeometry(m_pSunGeometry, m_pRadialGradientBrush);

    m_pSceneBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Black, 1.f));
    m_pRenderTarget->DrawGeometry(m_pSunGeometry, m_pSceneBrush, 1.f);

    m_pSceneBrush->SetColor(D2D1::ColorF(D2D1::ColorF::OliveDrab, 1.f));
    m_pRenderTarget->FillGeometry(m_pLeftMountainGeometry, m_pSceneBrush);

    m_pSceneBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Black, 1.f));
    m_pRenderTarget->DrawGeometry(m_pLeftMountainGeometry, m_pSceneBrush, 1.f);

    m_pSceneBrush->SetColor(D2D1::ColorF(D2D1::ColorF::LightSkyBlue, 1.f));
    m_pRenderTarget->FillGeometry(m_pRiverGeometry, m_pSceneBrush);

    m_pSceneBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Black, 1.f));
    m_pRenderTarget->DrawGeometry(m_pRiverGeometry, m_pSceneBrush, 1.f);

    m_pSceneBrush->SetColor(D2D1::ColorF(D2D1::ColorF::YellowGreen, 1.f));
    m_pRenderTarget->FillGeometry(m_pRightMountainGeometry, m_pSceneBrush);

    m_pSceneBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Black, 1.f));
    m_pRenderTarget->DrawGeometry(m_pRightMountainGeometry, m_pSceneBrush, 1.f);
}

效果图:

 

 注意: 代码中创建的各种对象都没有释放,如在实际项目中使用该代码需要在使用完释放它们。

 几何部分的内容略多,我仅对几个常用的几何形状的代码进行了整理,并且因为窗口的大小问题,一些绘制其他几何的代码被我注释了,详细可见代码。

 拓展:Direct2D有专门的篇幅介绍了缩放问题,见: Scaling geometry realizations

posted @ 2021-01-29 17:03  strive-sun  阅读(177)  评论(0编辑  收藏  举报