繁体   English   中英

Direct2D中的双缓冲?

[英]Double buffering in Direct2D?

我是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);
}

尽管此程序确实可以正常工作,但球的反弹还是有些轻微的撕裂。 我已经看到了这个问题 ,这使我想到了这篇MSDN文章 尽管阅读了这篇文章,但我仍然不完全了解如何实现双重缓冲,以期减少撕裂。 有人可以提供ID2D1RenderTarget::CreateCompatibleRenderTarget的简洁示例和说明,因为这种高级Windows编程与我以前的编程完全不同吗?

在这里查看文章 ID2D1HwndRenderTarget对象本质上是双重缓冲的,并且首先对屏幕外缓冲区进行绘制,并且当绘制结束时,它将对屏幕进行缓冲处理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM