In today's post, we're going to walk through a simple demonstration of Direct2D. We're not going to cover advanced features, such as interop with GDI/GDI+ or Direct3D. More on that in upcoming posts.
Direct2D integrates seamlessly into the familiar Win32 programming paradigm, and follows a usage pattern which is similar to Direct3D. First, you create a factory...
HRESULT hr = D2D1CreateFactory(
Next, you use the factory to create resources that you need. One important distinction from GDI/GDI+ is that, since Direct2D is a lower-level API (like Direct3D), you need to be aware that some resources (eg. render targets, bitmaps, brushes, gradient stop collections, layers, etc) have a close association with the device on which they were created, while others (eg. geometries, meshes, stroke style, geometry sinks, tessellation sinks, etc) are not associated with a device. Also, like Direct3D, device-dependent resources need to be recreated in cases where the device is lost or undergoes a state change. Okay, now let's create a simple geometry. Geometries are examples of device-independent resources which can be used with any render target.
D2D1::Rect(20.f, 20.f, 30.f, 50.f),
Before we can draw this geometry, we're going to need a few other things. Let's create a render target . Direct2D will attempt to create a hardware render target and, if hardware isn't available, it will fall back to a software render target. We need to create a red brush to draw the geometry. Also, we're going to use Windows Imaging Codecs (WIC) to load an image from disk, convert it to 32bppPBGRA, and then create a Direct2D bitmap from it. Note that brushes and bitmaps are device-dependent resources that are associated with a render target.
HRESULT hr = S_OK;
D2D1_SIZE_U size = D2D1::SizeU(
rc.right - rc.left,
rc.bottom - rc.top);
//create a D2D render target
hr = spD2DFactory->CreateHwndRenderTarget(
//create a red brush
D2D1::ColorF(1.0f, 0.0f, 0.0f, 1.0f),
//create WIC factory
//load image using WIC
//get the initial frame
//format convert to 32bppPBGRA -- which D2D expects
//initialize the format converter
//create a D2D bitmap from the WIC bitmap.
At this point, we have the basic resources that we need to draw. What we need is a place to do it. Note that we're drawing in response to a WM_PAINT message, but we aren't using a GDI HDC at all.
Here is our render function. You've already seen the CreateDeviceResources function above. This is where you create any device-dependent resources. Note that creation of device resources is only done once. After a render target and its associated resources have been created, CreateDeviceResources does nothing. Our render function checks to see whether the render target is occluded (aka covered). This is an optimization which prevents unnecessary drawing in cases where the window is hidden from view. We call BeginDraw on the render target to initiate drawing. All drawing instructions must be bracketed between BeginDraw and EndDraw calls.
Next, we set an identity transform, which means that anything drawn will be relative to the origin in the top left hand corner of the render target. Next, we clear the render target with a white color. You need to clear the target; otherwise, the render target will be initialized with the content from the previous drawing operations. If none have been performed yet, the result is undefined. We draw a bitmap, and then set a transform and draw our red rectangle geometry. We call EndDraw on the render target to signify that drawing operations are complete. Finally,we check the return code from EndDraw to determine whether there was any kind of failure condition.
HRESULT Application::OnRender(const RECT &rcPaint)
HRESULT hr = S_OK;
//this is where we create device resources if they don't already
//exist (eg. m_spRT, m_spBitmap)
if (!(m_spRT->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED))
D2D1_SIZE_F size = m_spBitmap->GetSize();
D2D1::Rect<float>(0.0f, 0.0f, size.width, size.height));
D2D1::Matrix3x2F::Translation(rtSize.width - 200, 0));
hr = m_spRT->EndDraw();
if (hr == D2DERR_RECREATE_TARGET)
//if the device is lost, we need to discard all of the resources
//associated with that device (eg. m_spRT, m_spBitmap, etc). We will
//recreate the next time we need to paint
As mentioned above, Direct2D is a lower-level API, and there are scenarios under which the display device can be lost (eg. adapter removed, display resolution changed, etc). GDI handles these device lost scenarios transparently but, with Direct2D (as with Direct3D), you need to be aware of and handle these conditions. If the device is lost for any reason, Direct2D will let you know, and you should free any resources that are associated with that render target. Keep in mind that you don't have to release device-independent resources (eg. m_spRectangleGeometry).
Render Target Interfaces
Device-Independent Resource Interfaces
Device-Dependent Resource Interfaces