2017-02-19 5 views
0

Я очень новичок в программировании 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); 
} 

Несмотря на то, что эта программа работает нормально, на ударе мяча появляется незначительное разрывание. Я видел this question, который ведет меня к this MSDN article. Несмотря на чтение статьи, я до сих пор не совсем понимаю, как реализовать двойную буферизацию, надеюсь, уменьшить разрыв. Может ли кто-нибудь дать краткий пример и объяснение ID2D1RenderTarget::CreateCompatibleRenderTarget, так как это высокоуровневое программирование на Windows сильно отличается от того, к чему я привык?

ответ

3

Check article here. Объекты ID2D1HwndRenderTarget дважды буферизуются по своей природе, а чертеж сначала выполняется в буфер вне экрана, а когда заканчивается рисование, он будет близок к экрану.

Смежные вопросы