0% found this document useful (0 votes)
18 views

C++ - Double Buffering in Direct2D - Stack Overflow

The document discusses implementing double buffering in a Direct2D application to reduce tearing when animating a bouncing ball. It includes code for a basic Direct2D application that draws a circle and bounces it but sees some tearing. It asks how to use ID2D1RenderTarget::CreateCompatibleRenderTarget to add double buffering and reduce tearing.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views

C++ - Double Buffering in Direct2D - Stack Overflow

The document discusses implementing double buffering in a Direct2D application to reduce tearing when animating a bouncing ball. It includes code for a basic Direct2D application that draws a circle and bounces it but sees some tearing. It asks how to use ID2D1RenderTarget::CreateCompatibleRenderTarget to add double buffering and reduce tearing.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 4

Double buffering in Direct2D?

Asked 7 years, 1 month ago Modified 7 years, 1 month ago Viewed 2k times

I'm very new to Direct2D programming and have been following a tutorial. I've adapted the example
given in the tutorial to a slightly more complicated program that bounces a ball off the boundaries of the
0 window.

My main program (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;
}

My header file (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);
};

My graphics functions (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);
}

While this program does work fine, there is some minor tearing on the ball's bounce. I have seen this
question which lead me to this MSDN article. Despite reading the article, I do still not fully understand
how to implement double buffering, to hopefully reduce tearing. Can someone provide a concise
example and explanation of the ID2D1RenderTarget::CreateCompatibleRenderTarget , as this high level
Windows programming is quite different from what I'm used to?

c++ drawing directx

Share Improve this question Follow asked Feb 19, 2017 at 19:56
carefulnow1
831 12 30

1 Answer Sorted by: Highest score (default)

Check article here. ID2D1HwndRenderTarget objects are double buffered by nature and drawing is done
to the offscreen buffer first and when drawing ends it will be blitted to the screen.
3
Share Improve this answer Follow edited Feb 19, 2017 at 20:10 answered Feb 19, 2017 at 20:02
user4581301 Janne
33.4k 7 34 56 1,705 15 22

You might also like