【问题标题】:How should I handle the update rect/region/area in a Direct2D application?我应该如何处理 Direct2D 应用程序中的更新矩形/区域/区域?
【发布时间】:2015-10-14 15:13:01
【问题描述】:

在使用 GDI 绘制图形的传统 Windows 程序中,您将不得不担心只绘制需要重绘的窗口区域;这是“更新矩形”,可通过PAINTSTRUCT.rcPaint 或调用GetUpdateRect() 访问。 (这也可以通过其他方式以HRGN 的形式提供。)

我需要对 Direct2D 做同样的事情吗? MSDN上所有的例子都是乱画了整个客户区,网上搜索也没找到别的。

或者换句话说,如果我只在更新矩形内绘制,例如手动或使用PushAxisAlignedClip()PushLayer(),那么更新矩形之外的部分会发生什么不好的事情吗?

此外,ID2D1HwndRenderTarget::Resize() 的文档说

调用此方法后,即使在创建渲染目标时指定了 D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS 选项,也不会定义渲染目标的后台缓冲区的内容。

这是否意味着任何由调整大小引起的更新区域(例如由this page 显示的this picture)都是无效的,我应该在调整大小时重绘整个窗口(例如,通过调用InvalidateRect(NULL)) ?

谢谢。

【问题讨论】:

    标签: winapi direct2d


    【解决方案1】:

    是的。将PushAxisAlignedClipD2D1_ANTIALIAS_MODE_ALIASED 一起使用。

    调整窗口大小时调用ID2D1HwndRenderTarget::Resize。请注意它返回的 HRESULT。它可以返回D2DERR_RECREATE_TARGET,但你可能不知道它也可以返回D2DERR_DISPLAY_STATE_INVALID(也可以由EndDraw返回,顺便说一句)。是的,在那之后打电话给InvalidateRect(NULL)

    我还建议使用D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS,因为否则您会在一些愚蠢的驱动程序/硬件配置和其他事件中遇到令人讨厌的错误。不要问我为什么——没有这个,它的表现就不好。您将收到错误报告,表明您的整个渲染区域刚刚被黑色填充。我花了几个月的时间才弄清楚我所要做的就是使用那面旗帜。我永远无法在本地重现该问题。

    【讨论】:

    • (抱歉回复晚了。)好的,谢谢。而且我假设我还必须将RECT 转换为使用与设备无关的像素,对吗?我应该将D2DERR_DISPLAY_STATE_INVALID 视为等同于D2DERR_RECREATE_TARGET,还是应该对那个HRESULT 做出不同的反应?也感谢其他提示;我现在已经实现了RECREATE_TARGET
    • 在我的代码中,我处理D2DERR_DISPLAY_STATE_INVALID 的方式与D2DERR_RECREATE_TARGET 相同,并且没有人报告任何问题。 (这是我正在谈论的paint.net,它拥有数百万用户)我刚刚查看了我的代码,显然ERROR_INVALID_HANDLE 也会从EndDraw 中弹出,我也以同样的方式处理它。如果您想仔细查看,请安装最新的 Paint.NET 并在 PaintDotNet.Framework.dll 上使用 ILSpy 或 Reflector 并搜索名为 Direct2DControlHandler 的类。我的WM_PAINT 处理程序是在RelayGdiPaintImpl 方法中实现的。
    • 好的,谢谢。这仍然留下了是否将剪切矩形调整为 DIP 而不是逻辑单位的问题;我是不是该?我不确定你是否这样做(通过 ILSpy)...
    • Paint.NET 不会为任何类型的 DIP 配置 Direct2D:它总是被告知 96 DPI,并且在 UI 控件本身的更高级别上进行调整。所以你在反汇编中看到的任何东西都在使用像素。因此,如果您告诉 Direct2D 96 DPI 以外的任何内容,那么您将不得不自己进行转换。
    【解决方案2】:

    没有。你必须用 gdi 做几乎相同的事情。您必须使用 d2d 位图,而不是使用 HBITMAP 后缓冲区。在 wm_size 中,您可以调整和重绘 d2d 位图的大小,而在 wm_paint 而不是 bitblt 中,您必须使用渲染 drawbitmap 方法。并仅渲染paintstruct rect 成员的部分(希望对您有所帮助):

    全局或类成员:

    ID2D1Factory* g_pD2DFactory = NULL; 
    ID2D1HwndRenderTarget* g_pRenderTarget = NULL;
    ID2D1SolidColorBrush* g_pBlackBrush = NULL;
    ID2D1SolidColorBrush* g_pWhiteBrush = NULL; 
    ID2D1BitmapRenderTarget* g_bitmapRenderTarget = NULL; //for d2d bitmap
    

    全局或类静态 wndproc:

    case WM_CREATE: {
         if (FAILED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &g_pD2DFactory))) {
            throw;
        }
    
        LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
    
        HRESULT hr = g_pD2DFactory->CreateHwndRenderTarget(
             D2D1::RenderTargetProperties(), 
             D2D1::HwndRenderTargetProperties(hWnd, D2D1::SizeU(lpcs->cx, lpcs->cy)), 
             &g_pRenderTarget
        );
    
        if (FAILED(hr)) {
            throw;
        }
    
        if (FAILED(g_pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &g_pBlackBrush))) {
            throw;
        }
    
        if (FAILED(g_pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), &g_pWhiteBrush))) {
            throw;
        }
        break;
    }
    case WM_SIZE: {
        if(FAILED(g_pRenderTarget->Resize(D2D1::SizeU(LOWORD(lParam), HIWORD(lParam))))) {
            throw;
        }
    
        D2D_SAFE_RELEASE(g_bitmapRenderTarget)
    
        g_pRenderTarget->CreateCompatibleRenderTarget(&g_bitmapRenderTarget);
    
        g_bitmapRenderTarget->BeginDraw();
        g_bitmapRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::AliceBlue));
        g_bitmapRenderTarget->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(100,100), 50,50), g_pBlackBrush);
        g_bitmapRenderTarget->EndDraw();
        break;
    }
    case WM_PAINT: {
        HDC hDc;
        PAINTSTRUCT ps;
        LPCRECT lpRect;
        ID2D1Bitmap* bitmap;
        D2D1_RECT_F d2d1Rect;
        hDc = BeginPaint(hWnd, &ps);
        lpRect = &ps.rcPaint;
        d2d1Rect = D2D1::RectF(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
        g_bitmapRenderTarget->GetBitmap(&bitmap);
    
        g_pRenderTarget->BeginDraw();
        g_pRenderTarget->DrawBitmap(
            bitmap, d2d1Rect, 1.0f, D2D1_BITMAP_INTERPOLATION_MODE::D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, 
            d2d1Rect
        );
        g_pRenderTarget->EndDraw();
    
        EndPaint(hWnd, &ps);
        return 0;
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 2019-10-26
      • 2011-05-01
      • 1970-01-01
      • 2011-02-14
      • 1970-01-01
      • 2013-01-01
      相关资源
      最近更新 更多