Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Latest commit

 

History

History
431 lines (377 loc) · 15.6 KB

SDL_winrtrenderer.cpp

File metadata and controls

431 lines (377 loc) · 15.6 KB
 
Feb 3, 2013
Feb 3, 2013
1
2
3
4
5

#include <fstream>
#include <string>
#include <vector>
#include "SDLmain_WinRT_common.h"
Nov 19, 2012
Nov 19, 2012
6
#include "SDL_winrtrenderer.h"
7
8
9
using namespace DirectX;
using namespace Microsoft::WRL;
Feb 3, 2013
Feb 3, 2013
10
using namespace std;
11
using namespace Windows::UI::Core;
Nov 26, 2012
Nov 26, 2012
12
13
using namespace Windows::Foundation;
using namespace Windows::Graphics::Display;
Nov 26, 2012
Nov 26, 2012
15
// Constructor.
Nov 19, 2012
Nov 19, 2012
16
SDL_winrtrenderer::SDL_winrtrenderer() :
Dec 10, 2012
Dec 10, 2012
17
m_mainTextureHelperSurface(NULL),
Feb 3, 2013
Feb 3, 2013
18
m_sdlRenderer(NULL),
Feb 3, 2013
Feb 3, 2013
19
m_sdlRendererData(NULL)
Dec 10, 2012
Dec 10, 2012
23
24
25
26
27
28
29
30
SDL_winrtrenderer::~SDL_winrtrenderer()
{
if (m_mainTextureHelperSurface) {
SDL_FreeSurface(m_mainTextureHelperSurface);
m_mainTextureHelperSurface = NULL;
}
}
Nov 26, 2012
Nov 26, 2012
31
32
33
// Initialize the Direct3D resources required to run.
void SDL_winrtrenderer::Initialize(CoreWindow^ window)
{
Jan 9, 2013
Jan 9, 2013
34
35
36
37
m_window = window;
CreateDeviceResources();
CreateWindowSizeDependentResources();
Nov 26, 2012
Nov 26, 2012
38
39
40
41
42
}
// Recreate all device resources and set them back to the current state.
void SDL_winrtrenderer::HandleDeviceLost()
{
Jan 9, 2013
Jan 9, 2013
43
44
45
// Reset these member variables to ensure that UpdateForWindowSizeChange recreates all resources.
m_windowBounds.Width = 0;
m_windowBounds.Height = 0;
Feb 3, 2013
Feb 3, 2013
46
m_sdlRendererData->swapChain = nullptr;
Nov 26, 2012
Nov 26, 2012
47
Feb 3, 2013
Feb 3, 2013
48
// TODO, WinRT: reconnect HandleDeviceLost to SDL_Renderer
Jan 9, 2013
Jan 9, 2013
49
50
CreateDeviceResources();
UpdateForWindowSizeChange();
Nov 26, 2012
Nov 26, 2012
51
52
}
Feb 9, 2013
Feb 9, 2013
53
extern HRESULT WINRT_CreateDeviceResources(SDL_Renderer * renderer);
Feb 3, 2013
Feb 3, 2013
54
Nov 26, 2012
Nov 26, 2012
55
// These are the resources that depend on the device.
Nov 19, 2012
Nov 19, 2012
56
void SDL_winrtrenderer::CreateDeviceResources()
Feb 9, 2013
Feb 9, 2013
58
DX::ThrowIfFailed(WINRT_CreateDeviceResources(m_sdlRenderer));
Nov 26, 2012
Nov 26, 2012
61
62
// Allocate all memory resources that change on a window SizeChanged event.
void SDL_winrtrenderer::CreateWindowSizeDependentResources()
Jan 30, 2013
Jan 30, 2013
63
{
Jan 9, 2013
Jan 9, 2013
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// Store the window bounds so the next time we get a SizeChanged event we can
// avoid rebuilding everything if the size is identical.
m_windowBounds = m_window->Bounds;
// Calculate the necessary swap chain and render target size in pixels.
float windowWidth = ConvertDipsToPixels(m_windowBounds.Width);
float windowHeight = ConvertDipsToPixels(m_windowBounds.Height);
// The width and height of the swap chain must be based on the window's
// landscape-oriented width and height. If the window is in a portrait
// orientation, the dimensions must be reversed.
m_orientation = DisplayProperties::CurrentOrientation;
bool swapDimensions =
m_orientation == DisplayOrientations::Portrait ||
m_orientation == DisplayOrientations::PortraitFlipped;
m_renderTargetSize.Width = swapDimensions ? windowHeight : windowWidth;
m_renderTargetSize.Height = swapDimensions ? windowWidth : windowHeight;
Feb 3, 2013
Feb 3, 2013
82
if(m_sdlRendererData->swapChain != nullptr)
Jan 9, 2013
Jan 9, 2013
83
84
85
{
// If the swap chain already exists, resize it.
DX::ThrowIfFailed(
Feb 3, 2013
Feb 3, 2013
86
m_sdlRendererData->swapChain->ResizeBuffers(
Jan 9, 2013
Jan 9, 2013
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
2, // Double-buffered swap chain.
static_cast<UINT>(m_renderTargetSize.Width),
static_cast<UINT>(m_renderTargetSize.Height),
DXGI_FORMAT_B8G8R8A8_UNORM,
0
)
);
}
else
{
// Otherwise, create a new one using the same adapter as the existing Direct3D device.
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
swapChainDesc.Width = static_cast<UINT>(m_renderTargetSize.Width); // Match the size of the window.
swapChainDesc.Height = static_cast<UINT>(m_renderTargetSize.Height);
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
swapChainDesc.Stereo = false;
swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency.
Jan 30, 2013
Jan 30, 2013
107
108
109
110
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
swapChainDesc.Scaling = DXGI_SCALING_STRETCH; // On phone, only stretch and aspect-ratio stretch scaling are allowed.
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // On phone, no swap effects are supported.
#else
Jan 9, 2013
Jan 9, 2013
111
112
swapChainDesc.Scaling = DXGI_SCALING_NONE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect.
Jan 30, 2013
Jan 30, 2013
113
#endif
Jan 9, 2013
Jan 9, 2013
114
115
116
117
swapChainDesc.Flags = 0;
ComPtr<IDXGIDevice1> dxgiDevice;
DX::ThrowIfFailed(
Feb 3, 2013
Feb 3, 2013
118
m_sdlRendererData->d3dDevice.As(&dxgiDevice)
Jan 9, 2013
Jan 9, 2013
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
);
ComPtr<IDXGIAdapter> dxgiAdapter;
DX::ThrowIfFailed(
dxgiDevice->GetAdapter(&dxgiAdapter)
);
ComPtr<IDXGIFactory2> dxgiFactory;
DX::ThrowIfFailed(
dxgiAdapter->GetParent(
__uuidof(IDXGIFactory2),
&dxgiFactory
)
);
Windows::UI::Core::CoreWindow^ window = m_window.Get();
DX::ThrowIfFailed(
dxgiFactory->CreateSwapChainForCoreWindow(
Feb 3, 2013
Feb 3, 2013
137
m_sdlRendererData->d3dDevice.Get(),
Jan 9, 2013
Jan 9, 2013
138
139
140
reinterpret_cast<IUnknown*>(window),
&swapChainDesc,
nullptr, // Allow on all displays.
Feb 3, 2013
Feb 3, 2013
141
&m_sdlRendererData->swapChain
Jan 9, 2013
Jan 9, 2013
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
)
);
// Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
// ensures that the application will only render after each VSync, minimizing power consumption.
DX::ThrowIfFailed(
dxgiDevice->SetMaximumFrameLatency(1)
);
}
// Set the proper orientation for the swap chain, and generate the
// 3D matrix transformation for rendering to the rotated swap chain.
DXGI_MODE_ROTATION rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
switch (m_orientation)
{
case DisplayOrientations::Landscape:
rotation = DXGI_MODE_ROTATION_IDENTITY;
m_orientationTransform3D = XMFLOAT4X4( // 0-degree Z-rotation
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
break;
case DisplayOrientations::Portrait:
rotation = DXGI_MODE_ROTATION_ROTATE270;
m_orientationTransform3D = XMFLOAT4X4( // 90-degree Z-rotation
0.0f, 1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
break;
case DisplayOrientations::LandscapeFlipped:
rotation = DXGI_MODE_ROTATION_ROTATE180;
m_orientationTransform3D = XMFLOAT4X4( // 180-degree Z-rotation
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
break;
case DisplayOrientations::PortraitFlipped:
rotation = DXGI_MODE_ROTATION_ROTATE90;
m_orientationTransform3D = XMFLOAT4X4( // 270-degree Z-rotation
0.0f, -1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
break;
default:
throw ref new Platform::FailureException();
}
Jan 30, 2013
Jan 30, 2013
201
202
#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
// TODO, WinRT: Windows Phone does not have the IDXGISwapChain1::SetRotation method. Check if an alternative is available, or needed.
Jan 9, 2013
Jan 9, 2013
203
DX::ThrowIfFailed(
Feb 3, 2013
Feb 3, 2013
204
m_sdlRendererData->swapChain->SetRotation(rotation)
Jan 9, 2013
Jan 9, 2013
205
);
Jan 30, 2013
Jan 30, 2013
206
#endif
Jan 9, 2013
Jan 9, 2013
207
208
209
210
// Create a render target view of the swap chain back buffer.
ComPtr<ID3D11Texture2D> backBuffer;
DX::ThrowIfFailed(
Feb 3, 2013
Feb 3, 2013
211
m_sdlRendererData->swapChain->GetBuffer(
Jan 9, 2013
Jan 9, 2013
212
213
214
215
216
217
218
0,
__uuidof(ID3D11Texture2D),
&backBuffer
)
);
DX::ThrowIfFailed(
Feb 3, 2013
Feb 3, 2013
219
m_sdlRendererData->d3dDevice->CreateRenderTargetView(
Jan 9, 2013
Jan 9, 2013
220
221
backBuffer.Get(),
nullptr,
Feb 3, 2013
Feb 3, 2013
222
&m_sdlRendererData->renderTargetView
Jan 9, 2013
Jan 9, 2013
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
)
);
// Create a depth stencil view.
CD3D11_TEXTURE2D_DESC depthStencilDesc(
DXGI_FORMAT_D24_UNORM_S8_UINT,
static_cast<UINT>(m_renderTargetSize.Width),
static_cast<UINT>(m_renderTargetSize.Height),
1,
1,
D3D11_BIND_DEPTH_STENCIL
);
ComPtr<ID3D11Texture2D> depthStencil;
DX::ThrowIfFailed(
Feb 3, 2013
Feb 3, 2013
238
m_sdlRendererData->d3dDevice->CreateTexture2D(
Jan 9, 2013
Jan 9, 2013
239
240
241
242
243
244
245
246
247
248
249
250
251
252
&depthStencilDesc,
nullptr,
&depthStencil
)
);
// Set the rendering viewport to target the entire window.
CD3D11_VIEWPORT viewport(
0.0f,
0.0f,
m_renderTargetSize.Width,
m_renderTargetSize.Height
);
Feb 3, 2013
Feb 3, 2013
253
m_sdlRendererData->d3dContext->RSSetViewports(1, &viewport);
Nov 26, 2012
Nov 26, 2012
254
255
}
Nov 25, 2012
Nov 25, 2012
256
257
void SDL_winrtrenderer::ResizeMainTexture(int w, int h)
{
Dec 10, 2012
Dec 10, 2012
258
259
const int pixelSizeInBytes = 4;
Nov 25, 2012
Nov 25, 2012
260
D3D11_TEXTURE2D_DESC textureDesc = {0};
Jan 9, 2013
Jan 9, 2013
261
262
263
264
265
266
267
268
269
270
271
textureDesc.Width = w;
textureDesc.Height = h;
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 1;
textureDesc.Format = DXGI_FORMAT_B8G8R8X8_UNORM;
textureDesc.SampleDesc.Count = 1;
textureDesc.SampleDesc.Quality = 0;
textureDesc.Usage = D3D11_USAGE_DYNAMIC;
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
textureDesc.MiscFlags = 0;
Nov 25, 2012
Nov 25, 2012
272
Dec 10, 2012
Dec 10, 2012
273
274
275
276
277
278
279
280
281
282
283
const int numPixels = textureDesc.Width * textureDesc.Height;
std::vector<uint8> initialTexturePixels(numPixels * pixelSizeInBytes, 0x00);
// Fill the texture with a non-black color, for debugging purposes:
//for (int i = 0; i < (numPixels * pixelSizeInBytes); i += pixelSizeInBytes) {
// initialTexturePixels[i+0] = 0xff;
// initialTexturePixels[i+1] = 0xff;
// initialTexturePixels[i+2] = 0x00;
// initialTexturePixels[i+3] = 0xff;
//}
Jan 9, 2013
Jan 9, 2013
284
285
286
287
288
D3D11_SUBRESOURCE_DATA initialTextureData = {0};
initialTextureData.pSysMem = (void *)&(initialTexturePixels[0]);
initialTextureData.SysMemPitch = textureDesc.Width * pixelSizeInBytes;
initialTextureData.SysMemSlicePitch = numPixels * pixelSizeInBytes;
DX::ThrowIfFailed(
Feb 3, 2013
Feb 3, 2013
289
m_sdlRendererData->d3dDevice->CreateTexture2D(
Jan 9, 2013
Jan 9, 2013
290
291
&textureDesc,
&initialTextureData,
Feb 3, 2013
Feb 3, 2013
292
&m_sdlRendererData->mainTexture
Jan 9, 2013
Jan 9, 2013
293
294
)
);
Nov 25, 2012
Nov 25, 2012
295
Dec 10, 2012
Dec 10, 2012
296
297
298
299
300
301
302
303
304
305
306
307
308
309
if (m_mainTextureHelperSurface) {
SDL_FreeSurface(m_mainTextureHelperSurface);
m_mainTextureHelperSurface = NULL;
}
m_mainTextureHelperSurface = SDL_CreateRGBSurfaceFrom(
NULL,
textureDesc.Width, textureDesc.Height,
(pixelSizeInBytes * 8),
0, // Use an nil pitch for now. This'll be filled in when updating the texture.
0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000); // TODO, WinRT: calculate masks given the Direct3D-defined pixel format of the texture
if (m_mainTextureHelperSurface == NULL) {
DX::ThrowIfFailed(E_FAIL); // TODO, WinRT: generate a better error here, taking into account who's calling this function.
}
Jan 9, 2013
Jan 9, 2013
310
311
312
313
314
315
D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
resourceViewDesc.Format = textureDesc.Format;
resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
resourceViewDesc.Texture2D.MostDetailedMip = 0;
resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels;
DX::ThrowIfFailed(
Feb 3, 2013
Feb 3, 2013
316
317
m_sdlRendererData->d3dDevice->CreateShaderResourceView(
m_sdlRendererData->mainTexture.Get(),
Jan 9, 2013
Jan 9, 2013
318
&resourceViewDesc,
Feb 3, 2013
Feb 3, 2013
319
&m_sdlRendererData->mainTextureResourceView)
Jan 9, 2013
Jan 9, 2013
320
);
Nov 25, 2012
Nov 25, 2012
321
322
}
Nov 26, 2012
Nov 26, 2012
323
324
325
// This method is called in the event handler for the SizeChanged event.
void SDL_winrtrenderer::UpdateForWindowSizeChange()
{
Jan 9, 2013
Jan 9, 2013
326
327
328
329
330
if (m_window->Bounds.Width != m_windowBounds.Width ||
m_window->Bounds.Height != m_windowBounds.Height ||
m_orientation != DisplayProperties::CurrentOrientation)
{
ID3D11RenderTargetView* nullViews[] = {nullptr};
Feb 3, 2013
Feb 3, 2013
331
332
333
m_sdlRendererData->d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
m_sdlRendererData->renderTargetView = nullptr;
m_sdlRendererData->d3dContext->Flush();
Jan 9, 2013
Jan 9, 2013
334
335
CreateWindowSizeDependentResources();
}
Nov 26, 2012
Nov 26, 2012
336
337
}
Nov 22, 2012
Nov 22, 2012
338
void SDL_winrtrenderer::Render(SDL_Surface * surface, SDL_Rect * rects, int numrects)
Jan 9, 2013
Jan 9, 2013
340
const float blackColor[] = { 0.0f, 0.0f, 0.0f, 0.0f };
Feb 3, 2013
Feb 3, 2013
341
342
m_sdlRendererData->d3dContext->ClearRenderTargetView(
m_sdlRendererData->renderTargetView.Get(),
Jan 9, 2013
Jan 9, 2013
343
344
345
346
blackColor
);
// Only draw the screen once it is loaded (some loading is asynchronous).
Feb 9, 2013
Feb 9, 2013
347
if (!m_sdlRendererData->loadingComplete)
Jan 9, 2013
Jan 9, 2013
348
349
350
{
return;
}
Feb 3, 2013
Feb 3, 2013
351
if (!m_sdlRendererData->mainTextureResourceView)
Nov 25, 2012
Nov 25, 2012
352
353
354
{
return;
}
Jan 9, 2013
Jan 9, 2013
356
// Update the main texture (for SDL usage). Start by mapping the SDL
Dec 10, 2012
Dec 10, 2012
357
// window's main texture to CPU-accessible memory:
Jan 9, 2013
Jan 9, 2013
358
359
D3D11_MAPPED_SUBRESOURCE textureMemory = {0};
DX::ThrowIfFailed(
Feb 3, 2013
Feb 3, 2013
360
361
m_sdlRendererData->d3dContext->Map(
m_sdlRendererData->mainTexture.Get(),
Jan 9, 2013
Jan 9, 2013
362
363
364
365
366
0,
D3D11_MAP_WRITE_DISCARD,
0,
&textureMemory)
);
Nov 21, 2012
Nov 21, 2012
367
Dec 10, 2012
Dec 10, 2012
368
369
370
371
// Copy pixel data to the locked texture's memory:
m_mainTextureHelperSurface->pixels = textureMemory.pData;
m_mainTextureHelperSurface->pitch = textureMemory.RowPitch;
SDL_BlitSurface(surface, NULL, m_mainTextureHelperSurface, NULL);
Jan 9, 2013
Jan 9, 2013
372
// TODO, WinRT: only update the requested rects (passed to SDL_UpdateWindowSurface), rather than everything
Nov 21, 2012
Nov 21, 2012
373
Dec 10, 2012
Dec 10, 2012
374
375
376
// Clean up a bit, then commit the texture's memory back to Direct3D:
m_mainTextureHelperSurface->pixels = NULL;
m_mainTextureHelperSurface->pitch = 0;
Feb 3, 2013
Feb 3, 2013
377
378
m_sdlRendererData->d3dContext->Unmap(
m_sdlRendererData->mainTexture.Get(),
Jan 9, 2013
Jan 9, 2013
379
380
0);
Feb 3, 2013
Feb 3, 2013
381
m_sdlRendererData->d3dContext->OMSetRenderTargets(
Jan 9, 2013
Jan 9, 2013
382
1,
Feb 3, 2013
Feb 3, 2013
383
m_sdlRendererData->renderTargetView.GetAddressOf(),
Jan 9, 2013
Jan 9, 2013
384
385
386
387
388
nullptr
);
UINT stride = sizeof(VertexPositionColor);
UINT offset = 0;
Feb 3, 2013
Feb 3, 2013
389
m_sdlRendererData->d3dContext->IASetVertexBuffers(
Jan 9, 2013
Jan 9, 2013
390
391
0,
1,
Feb 3, 2013
Feb 3, 2013
392
m_sdlRendererData->vertexBuffer.GetAddressOf(),
Jan 9, 2013
Jan 9, 2013
393
394
395
396
&stride,
&offset
);
Feb 3, 2013
Feb 3, 2013
397
m_sdlRendererData->d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
Jan 9, 2013
Jan 9, 2013
398
Feb 3, 2013
Feb 3, 2013
399
m_sdlRendererData->d3dContext->IASetInputLayout(m_sdlRendererData->inputLayout.Get());
Jan 9, 2013
Jan 9, 2013
400
Feb 3, 2013
Feb 3, 2013
401
402
m_sdlRendererData->d3dContext->VSSetShader(
m_sdlRendererData->vertexShader.Get(),
Jan 9, 2013
Jan 9, 2013
403
404
405
406
nullptr,
0
);
Feb 3, 2013
Feb 3, 2013
407
408
m_sdlRendererData->d3dContext->PSSetShader(
m_sdlRendererData->pixelShader.Get(),
Jan 9, 2013
Jan 9, 2013
409
410
411
412
nullptr,
0
);
Feb 3, 2013
Feb 3, 2013
413
m_sdlRendererData->d3dContext->PSSetShaderResources(0, 1, m_sdlRendererData->mainTextureResourceView.GetAddressOf());
Jan 9, 2013
Jan 9, 2013
414
Feb 3, 2013
Feb 3, 2013
415
m_sdlRendererData->d3dContext->PSSetSamplers(0, 1, m_sdlRendererData->mainSampler.GetAddressOf());
Jan 9, 2013
Jan 9, 2013
416
Feb 3, 2013
Feb 3, 2013
417
m_sdlRendererData->d3dContext->Draw(4, 0);
Nov 26, 2012
Nov 26, 2012
419
420
421
422
// Method to deliver the final image to the display.
void SDL_winrtrenderer::Present()
{
Feb 3, 2013
Feb 3, 2013
423
SDL_RenderPresent(m_sdlRenderer);
Nov 26, 2012
Nov 26, 2012
424
425
426
427
428
}
// Method to convert a length in device-independent pixels (DIPs) to a length in physical pixels.
float SDL_winrtrenderer::ConvertDipsToPixels(float dips)
{
Jan 9, 2013
Jan 9, 2013
429
430
static const float dipsPerInch = 96.0f;
return floor(dips * DisplayProperties::LogicalDpi / dipsPerInch + 0.5f); // Round to nearest integer.
Nov 26, 2012
Nov 26, 2012
431
}