2017-02-19 4 views
0

Je suis très nouveau dans la programmation Direct2D et j'ai suivi un tutoriel. J'ai adapté l'exemple donné dans le tutoriel à un programme légèrement plus compliqué qui rebondit une balle hors des limites de la fenêtre.Double mise en mémoire tampon dans Direct2D?


Mon programme principal (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; 
} 

Mon fichier d'en-tête (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); 
}; 

Mes fonctions graphiques (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); 
} 

Bien que ce programme fonctionne bien, il y a quelques petites déchirures sur le rebond de la balle. J'ai vu this question qui m'a conduit à this MSDN article. Malgré la lecture de l'article, je ne comprends toujours pas comment implémenter le double tampon, pour réduire les déchirures. Quelqu'un peut-il fournir un exemple concis et une explication de la ID2D1RenderTarget::CreateCompatibleRenderTarget, comme cette programmation de haut niveau de Windows est assez différente de ce que je suis habitué?

Répondre

3

Check article here. Les objets ID2D1HwndRenderTarget sont en double mémoire tampon par nature et le dessin est effectué dans le tampon hors écran en premier et lorsque le dessin se termine, il est envoyé à l'écran.