-
Notifications
You must be signed in to change notification settings - Fork 1
/
ImageRenderer.cpp
166 lines (138 loc) · 4.48 KB
/
ImageRenderer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//------------------------------------------------------------------------------
// <copyright file="ImageRenderer.cpp" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
#include "stdafx.h"
#include "ImageRenderer.h"
/// <summary>
/// Constructor
/// </summary>
ImageRenderer::ImageRenderer() :
m_hWnd(0),
m_sourceWidth(0),
m_sourceHeight(0),
m_sourceStride(0),
m_pD2DFactory(NULL),
m_pRenderTarget(NULL),
m_pBitmap(0)
{
}
/// <summary>
/// Destructor
/// </summary>
ImageRenderer::~ImageRenderer()
{
DiscardResources();
SafeRelease(m_pD2DFactory);
}
/// <summary>
/// Ensure necessary Direct2d resources are created
/// </summary>
/// <returns>indicates success or failure</returns>
HRESULT ImageRenderer::EnsureResources()
{
HRESULT hr = S_OK;
if (NULL == m_pRenderTarget)
{
D2D1_SIZE_U size = D2D1::SizeU(m_sourceWidth, m_sourceHeight);
D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties();
rtProps.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE);
rtProps.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE;
// Create a hWnd render target, in order to render to the window set in initialize
hr = m_pD2DFactory->CreateHwndRenderTarget(
rtProps,
D2D1::HwndRenderTargetProperties(m_hWnd, size),
&m_pRenderTarget
);
if (FAILED(hr))
{
return hr;
}
// Create a bitmap that we can copy image data into and then render to the target
hr = m_pRenderTarget->CreateBitmap(
size,
D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE)),
&m_pBitmap
);
if (FAILED(hr))
{
SafeRelease(m_pRenderTarget);
return hr;
}
}
return hr;
}
/// <summary>
/// Dispose of Direct2d resources
/// </summary>
void ImageRenderer::DiscardResources()
{
SafeRelease(m_pRenderTarget);
SafeRelease(m_pBitmap);
}
/// <summary>
/// Set the window to draw to as well as the video format
/// Implied bits per pixel is 32
/// </summary>
/// <param name="hWnd">window to draw to</param>
/// <param name="pD2DFactory">already created D2D factory object</param>
/// <param name="sourceWidth">width (in pixels) of image data to be drawn</param>
/// <param name="sourceHeight">height (in pixels) of image data to be drawn</param>
/// <param name="sourceStride">length (in bytes) of a single scanline</param>
/// <returns>indicates success or failure</returns>
HRESULT ImageRenderer::Initialize(HWND hWnd, ID2D1Factory* pD2DFactory, int sourceWidth, int sourceHeight, int sourceStride)
{
if (NULL == pD2DFactory)
{
return E_INVALIDARG;
}
m_hWnd = hWnd;
// One factory for the entire application so save a pointer here
m_pD2DFactory = pD2DFactory;
m_pD2DFactory->AddRef();
// Get the frame size
m_sourceWidth = sourceWidth;
m_sourceHeight = sourceHeight;
m_sourceStride = sourceStride;
return S_OK;
}
/// <summary>
/// Draws a 32 bit per pixel image of previously specified width, height, and stride to the associated hwnd
/// </summary>
/// <param name="pImage">image data in RGBX format</param>
/// <param name="cbImage">size of image data in bytes</param>
/// <returns>indicates success or failure</returns>
HRESULT ImageRenderer::Draw(BYTE* pImage, unsigned long cbImage)
{
// incorrectly sized image data passed in
if (cbImage < ((m_sourceHeight - 1) * m_sourceStride) + (m_sourceWidth * 4))
{
return E_INVALIDARG;
}
// create the resources for this draw device
// they will be recreated if previously lost
HRESULT hr = EnsureResources();
if (FAILED(hr))
{
return hr;
}
// Copy the image that was passed in into the direct2d bitmap
hr = m_pBitmap->CopyFromMemory(NULL, pImage, m_sourceStride);
if (FAILED(hr))
{
return hr;
}
m_pRenderTarget->BeginDraw();
// Draw the bitmap stretched to the size of the window
m_pRenderTarget->DrawBitmap(m_pBitmap);
hr = m_pRenderTarget->EndDraw();
// Device lost, need to recreate the render target
// We'll dispose it now and retry drawing
if (hr == D2DERR_RECREATE_TARGET)
{
hr = S_OK;
DiscardResources();
}
return hr;
}