c++ - Direct2D 中的双缓冲?

标签 c++ drawing directx

我是 Direct2D 编程的新手,一直在学习教程。我已将教程中给出的示例改编为稍微复杂一些的程序,该程序将球弹离窗口边界。


我的主程序(main.cpp):

#include "Graphics.h"

Graphics* graphics;

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    // Exit handler

    if (uMsg == WM_DESTROY)
    {
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPWSTR cmd, int nCmdShow)
{
    WNDCLASSEX windowClass;
    SecureZeroMemory(&windowClass, sizeof(WNDCLASSEX));

    // Set up window

    windowClass.cbSize = sizeof(WNDCLASSEX);
    windowClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
    windowClass.hInstance = hInstance;
    windowClass.lpfnWndProc = WindowProc;
    windowClass.lpszClassName = "MainWindow";
    windowClass.style = CS_HREDRAW | CS_VREDRAW;

    // Register window class and handle

    RegisterClassEx(&windowClass);

    RECT rect = { 0, 0, 800, 600 };
    AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, false, WS_EX_OVERLAPPEDWINDOW);

    HWND windowHandle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "MainWindow", "Test Window", WS_OVERLAPPEDWINDOW, 100, 100,
        rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, hInstance, 0);

    if (!windowHandle)
        return -1;

    graphics = new Graphics();

    if (!graphics->Init(windowHandle))
    {
        delete graphics;
        return -1;
    }

    ShowWindow(windowHandle, nCmdShow);

    // Message loop

    float x = 51.0, xSpeed = 5.0f, y = 0.0, ySpeed = 5.0f;

    MSG message;
    message.message = WM_NULL;

    while (message.message != WM_QUIT)
    {
        if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
            DispatchMessage(&message);
        else
        {
            // Ball physics

            //xSpeed += 0.6f;
            x += xSpeed;

            ySpeed += 0.2f;
            y += ySpeed;

            if (y > rect.bottom - 50)
            {
                ySpeed = -ySpeed;
            }

            if (x > rect.right - 50)
            {
                xSpeed = -xSpeed;
            }
            else if (x < 50)
            {
                xSpeed = -xSpeed;
            }

            // Redraw ball

            graphics->beginDraw();

            graphics->clearScreen(0.0f, 0.0f, 0.5f);
            graphics->drawCircle(x, y, 50.0f, 1.0f, 1.0f, 1.0f, 1.0f);

            graphics->endDraw();
        }
    }

    delete graphics;

    return 0;
}

我的头文件(Graphics.h):

#pragma once

#include <Windows.h>
#include <d2d1.h>

class Graphics
{
    ID2D1Factory* factory;
    ID2D1HwndRenderTarget* renderTarget;
    ID2D1SolidColorBrush* brush;

public:
    Graphics();
    ~Graphics();

    bool Init(HWND windowHandle);

    void beginDraw() { renderTarget->BeginDraw(); }
    void endDraw() { renderTarget->EndDraw(); }

    void clearScreen(float r, float g, float b);
    void drawCircle(float x, float y, float radius, float r, float g, float b, float a);
};

我的图形函数(Graphics.cpp):

#include "Graphics.h"

#define CHECKRES if (res != S_OK) return false

Graphics::Graphics()
{
    factory = NULL;
    renderTarget = NULL;
    brush = NULL;
}

Graphics::~Graphics()
{
    if (factory)
        factory->Release();

    if (renderTarget)
        renderTarget->Release();

    if (brush)
        brush->Release();
}

bool Graphics::Init(HWND windowHandle)
{
    HRESULT res = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factory);

    CHECKRES;

    RECT rect;
    GetClientRect(windowHandle, &rect);

    res = factory->CreateHwndRenderTarget(
        D2D1::RenderTargetProperties(),
        D2D1::HwndRenderTargetProperties(windowHandle, D2D1::SizeU(rect.right, rect.bottom)),
        &renderTarget
    );

    CHECKRES;

    res = renderTarget->CreateSolidColorBrush(D2D1::ColorF(0, 0, 0, 0), &brush);

    CHECKRES;

    return true;
}

void Graphics::clearScreen(float r, float g, float b)
{
    renderTarget->Clear(D2D1::ColorF(r, g, b));
}

void Graphics::drawCircle(float x, float y, float radius, float r, float g, float b, float a)
{
    brush->SetColor(D2D1::ColorF(r, g, b, a));
    renderTarget->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(x, y), radius, radius), brush, 3.0f);
}

虽然这个程序运行良好,但球的弹跳有一些轻微的撕裂。我看过this question这导致我 this MSDN article .尽管阅读了这篇文章,但我仍然不完全理解如何实现双缓冲以减少撕裂。有人可以提供 ID2D1RenderTarget::CreateCompatibleRenderTarget 的简明示例和解释吗,因为这种高级 Windows 编程与我习惯的完全不同?

最佳答案

Check article here . ID2D1HwndRenderTarget 对象本质上是双缓冲的,绘制首先在屏幕外缓冲区完成,当绘制结束时,它将被 blit 到屏幕。

关于c++ - Direct2D 中的双缓冲?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42332131/

相关文章:

c++ - 过程硬件编程的错误处理技术

c++ - 如何从链接器错误转到源代码中的代码行?

java - 组件 Paint 方法未绘制到 JPanel 的中间?

java - 使用正弦和余弦绘制一个有角度的正方形

c++ - 尝试创建直接 x 11 窗口时出现链接器错误

c++ - 将 gSOAP 与 2 个不同的 wsdl 文件一起使用时出现链接器错误

c++ - (为什么)std::chrono文字是左值?

c++ - 如何避免 GDI+ 中的虚线破损?

c++ - DirectX11 D3D11_MAP 的差异

c++ - 如何检查显示器是否启用了纵横比自动调整