Reputation: 841
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 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?
Upvotes: 0
Views: 2101
Reputation: 1725
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.
Upvotes: 3