Lib
QOLを高める
graphics.cpp
Go to the documentation of this file.
1 #include "stdafx.h"
2 #include "include/graphics.h"
3 #include "include/debug.h"
4 #include "include/exceptions.h"
5 #include "include/file.h"
6 #include <d3dx11.h>
7 #pragma warning(push)
8 #pragma warning(disable: 4838)
9 #include <xnamath.h>
10 #pragma warning(pop)
11 
12 #pragma comment(lib, "d3d11.lib")
13 #pragma comment(lib, "d3dx11.lib")
14 
15 namespace yappy {
16 namespace graphics {
17 
18 using error::throwTrace;
20 using error::D3DError;
22 
23 namespace {
24 
25 struct SpriteVertex {
26  XMFLOAT3 Pos;
27  XMFLOAT2 Tex;
28 };
29 
30 struct CBNeverChanges {
31  XMMATRIX Projection;
32 };
33 
34 struct CBChanges {
35  XMMATRIX lrInv;
36  XMMATRIX udInv;
37  XMMATRIX DestScale;
38  XMMATRIX Centering;
39  XMMATRIX Scale;
40  XMMATRIX Rotation;
41  XMMATRIX Translate;
42  XMFLOAT2 uvOffset;
43  XMFLOAT2 uvSize;
44  XMFLOAT4 FontColor; // rgba
45  float Alpha;
46 };
47 
48 inline void createCBFromTask(CBChanges *out, const DrawTask &task)
49 {
50  // ax + by + cz + d = 0
51  // x = 0.5
52  XMVECTORF32 xMirror = { 1.0f, 0.0f, 0.0f, -0.5f };
53  // y = 0.5
54  XMVECTORF32 yMirror = { 0.0f, 1.0f, 0.0f, -0.5f };
55  out->lrInv = XMMatrixTranspose(
56  task.lrInv ? XMMatrixReflect(xMirror) : XMMatrixIdentity());
57  out->udInv = XMMatrixTranspose(
58  task.udInv ? XMMatrixReflect(yMirror) : XMMatrixIdentity());
59  out->DestScale = XMMatrixTranspose(XMMatrixScaling(
60  static_cast<float>(task.sw), static_cast<float>(task.sh), 1.0f));
61  out->Centering = XMMatrixTranspose(XMMatrixTranslation(
62  -static_cast<float>(task.cx), -static_cast<float>(task.cy), 0.0f));
63  out->Scale = XMMatrixTranspose(XMMatrixScaling(
64  task.scaleX, task.scaleY, 1.0f));
65  out->Rotation = XMMatrixTranspose(XMMatrixRotationZ(task.angle));
66  out->Translate = XMMatrixTranspose(XMMatrixTranslation(
67  static_cast<float>(task.dx), static_cast<float>(task.dy), 1.0f));
68  out->uvOffset = XMFLOAT2(
69  static_cast<float>(task.sx) / task.texW,
70  static_cast<float>(task.sy) / task.texH);
71  out->uvSize = XMFLOAT2(
72  static_cast<float>(task.sw) / task.texW,
73  static_cast<float>(task.sh) / task.texH);
74  out->FontColor = XMFLOAT4(
75  ((task.fontColor & 0x00ff0000) >> 16) / 255.0f,
76  ((task.fontColor & 0x0000ff00) >> 8) / 255.0f,
77  ((task.fontColor & 0x000000ff) >> 0) / 255.0f,
78  ((task.fontColor & 0xff000000) >> 24) / 255.0f);
79  out->Alpha = task.alpha;
80 }
81 
82 } // namespace
83 
85  m_param(param)
86 {
87  m_drawTaskList.reserve(DrawListMax);
88 
89  initializeD3D();
90 }
91 
92 void DGraphics::initializeD3D()
93 {
94  debug::writeLine(L"Initializing Direct3D 11...");
95 
96  HRESULT hr = S_OK;
97 
98  if (!::XMVerifyCPUSupport()) {
99  throwTrace<D3DError>("XMVerifyCPUSupport() failed", 0);
100  }
101 
102  // Create device etc.
103  {
104  UINT createDeviceFlags = 0;
105 #ifdef _DEBUG
106  createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
107 #endif
108  std::array<D3D_DRIVER_TYPE, 2> driverTypes{
109  D3D_DRIVER_TYPE_HARDWARE,
110  D3D_DRIVER_TYPE_WARP
111  };
112  std::array<D3D_FEATURE_LEVEL, 3> featureLevels{
113  D3D_FEATURE_LEVEL_11_0,
114  D3D_FEATURE_LEVEL_10_1,
115  D3D_FEATURE_LEVEL_10_0,
116  };
117 
118  DXGI_SWAP_CHAIN_DESC sd;
119  ZeroMemory(&sd, sizeof(sd));
120  sd.BufferCount = 1;
121  sd.BufferDesc.Width = m_param.w;
122  sd.BufferDesc.Height = m_param.h;
123  sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
124  sd.BufferDesc.RefreshRate.Numerator = m_param.refreshRate;
125  sd.BufferDesc.RefreshRate.Denominator = 1;
126  sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
127  sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
128  sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
129  sd.OutputWindow = m_param.hWnd;
130  sd.SampleDesc.Count = 1;
131  sd.SampleDesc.Quality = 0;
132  sd.Windowed = TRUE;
133  sd.Flags = SwapChainFlag;
134 
135  ID3D11Device *ptmpDevice = nullptr;
136  ID3D11DeviceContext *ptmpContext = nullptr;
137  IDXGISwapChain *ptmpSwapChain = nullptr;
138  D3D_FEATURE_LEVEL featureLevel = static_cast<D3D_FEATURE_LEVEL>(0);
139 
140  for (auto driverType : driverTypes) {
141  debug::writef(L"Creating device and swapchain... (driverType=%d)",
142  static_cast<int>(driverType));
143  hr = ::D3D11CreateDeviceAndSwapChain(nullptr, driverType, nullptr,
144  createDeviceFlags, featureLevels.data(), static_cast<UINT>(featureLevels.size()),
145  D3D11_SDK_VERSION, &sd,
146  &ptmpSwapChain, &ptmpDevice, &featureLevel, &ptmpContext);
147  if (SUCCEEDED(hr)) {
148  debug::writef(L"Creating device and swapchain OK (Feature level=0x%04x)",
149  static_cast<uint32_t>(featureLevel));
150  break;
151  }
152  else {
153  debug::writeLine(L"Creating device and swapchain: Failed");
154  }
155  }
156  checkDXResult<D3DError>(hr, "D3D11CreateDeviceAndSwapChain() failed");
157  m_pDevice.reset(ptmpDevice);
158  m_pContext.reset(ptmpContext);
159  m_pSwapChain.reset(ptmpSwapChain);
160  }
161 
162  // MaximumFrameLatency
163  {
164  debug::writeLine(L"SetMaximumFrameLatency...");
165 
166  IDXGIDevice1 *ptmpDXGIDevice = nullptr;
167  hr = m_pDevice->QueryInterface(__uuidof(IDXGIDevice1), (void **)&ptmpDXGIDevice);
168  checkDXResult<D3DError>(hr, "QueryInterface(IDXGIDevice1) failed");
169  util::ComPtr<IDXGIDevice1> pDXGIDevice(ptmpDXGIDevice);
170  hr = pDXGIDevice->SetMaximumFrameLatency(1);
171  checkDXResult<D3DError>(hr, "IDXGIDevice1::SetMaximumFrameLatency() failed");
172 
173  debug::writeLine(L"SetMaximumFrameLatency OK");
174  }
175 
176  initBackBuffer();
177 
178  // Vertex Shader
179  debug::writeLine(L"Creating vertex shader...");
180  {
181  file::Bytes bin = file::loadFile(VS_FileName);
182  ID3D11VertexShader *ptmpVS = nullptr;
183  hr = m_pDevice->CreateVertexShader(bin.data(), bin.size(), nullptr, &ptmpVS);
184  checkDXResult<D3DError>(hr, "ID3D11Device::CreateVertexShader() failed");
185  m_pVertexShader.reset(ptmpVS);
186 
187  // Create input layout
188  debug::writeLine(L"Creating input layout...");
189  D3D11_INPUT_ELEMENT_DESC layout[] = {
190  { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
191  { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
192  };
193  ID3D11InputLayout *ptmpInputLayout = nullptr;
194  hr = m_pDevice->CreateInputLayout(layout, _countof(layout), bin.data(),
195  bin.size(), &ptmpInputLayout);
196  checkDXResult<D3DError>(hr, "ID3D11Device::CreateInputLayout() failed");
197  m_pInputLayout.reset(ptmpInputLayout);
198  // Set input layout
199  m_pContext->IASetInputLayout(m_pInputLayout.get());
200  debug::writeLine(L"Creating input layout OK");
201  }
202  debug::writeLine(L"Creating vertex shader OK");
203  // Pixel Shader
204  debug::writeLine(L"Creating pixel shader...");
205  {
206  file::Bytes bin = file::loadFile(PS_FileName);
207  ID3D11PixelShader *ptmpPS = nullptr;
208  hr = m_pDevice->CreatePixelShader(bin.data(), bin.size(), nullptr, &ptmpPS);
209  checkDXResult<D3DError>(hr, "ID3D11Device::CreatePixelShader() failed");
210  m_pPixelShader.reset(ptmpPS);
211  }
212  debug::writeLine(L"Creating pixel shader OK");
213 
214  // Create vertex buffer
215  {
216  debug::writeLine(L"Creating vertex buffer...");
217 
218  SpriteVertex vertices[] = {
219  { XMFLOAT3(0.0f, 1.0f, 0.0f) , XMFLOAT2(0.0f, 1.0f) },
220  { XMFLOAT3(1.0f, 1.0f, 0.0f) , XMFLOAT2(1.0f, 1.0f) },
221  { XMFLOAT3(0.0f, 0.0f, 0.0f) , XMFLOAT2(0.0f, 0.0f) },
222  { XMFLOAT3(1.0f, 0.0f, 0.0f) , XMFLOAT2(1.0f, 0.0f) },
223  };
224  D3D11_BUFFER_DESC bd = { 0 };
225  bd.Usage = D3D11_USAGE_DEFAULT;
226  bd.ByteWidth = sizeof(vertices);
227  bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
228  bd.CPUAccessFlags = 0;
229  D3D11_SUBRESOURCE_DATA initData = { 0 };
230  initData.pSysMem = vertices;
231  ID3D11Buffer *ptmpVertexBuffer = nullptr;
232  hr = m_pDevice->CreateBuffer(&bd, &initData, &ptmpVertexBuffer);
233  checkDXResult<D3DError>(hr, "ID3D11Device::CreateBuffer() failed");
234  m_pVertexBuffer.reset(ptmpVertexBuffer);
235 
236  debug::writeLine(L"Creating vertex buffer OK");
237 
238  // Set vertex buffer
239  ID3D11Buffer *pVertexBuffer = m_pVertexBuffer.get();
240  UINT stride = sizeof(SpriteVertex);
241  UINT offset = 0;
242  m_pContext->IASetVertexBuffers(0, 1, &pVertexBuffer, &stride, &offset);
243  // Set primitive topology
244  m_pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
245 
246  debug::writeLine(L"Set vertex buffer OK");
247  }
248  // Create constant buffer
249  debug::writeLine(L"Creating constant buffer...");
250  {
251  CBNeverChanges buffer;
252  // Projection matrix: Window coord -> (-1, -1) .. (1, 1)
253  buffer.Projection = XMMatrixIdentity();
254  buffer.Projection._41 = -1.0f;
255  buffer.Projection._42 = 1.0f;
256  buffer.Projection._11 = 2.0f / m_param.w;
257  buffer.Projection._22 = -2.0f / m_param.h;
258  buffer.Projection = XMMatrixTranspose(buffer.Projection);
259  D3D11_BUFFER_DESC bd = { 0 };
260  bd.Usage = D3D11_USAGE_DEFAULT;
261  bd.ByteWidth = sizeof(CBNeverChanges);
262  bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
263  bd.CPUAccessFlags = 0;
264  D3D11_SUBRESOURCE_DATA initData = { 0 };
265  initData.pSysMem = &buffer;
266  ID3D11Buffer *ptmpCBNeverChanges = nullptr;
267  hr = m_pDevice->CreateBuffer(&bd, &initData, &ptmpCBNeverChanges);
268  checkDXResult<D3DError>(hr, "ID3D11Device::CreateBuffer() failed");
269  m_pCBNeverChanges.reset(ptmpCBNeverChanges);
270  }
271  {
272  D3D11_BUFFER_DESC bd = { 0 };
273  bd.Usage = D3D11_USAGE_DEFAULT;
274  bd.ByteWidth = sizeof(CBChanges);
275  bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
276  bd.CPUAccessFlags = 0;
277  ID3D11Buffer *ptmpCBChanges = nullptr;
278  hr = m_pDevice->CreateBuffer(&bd, nullptr, &ptmpCBChanges);
279  checkDXResult<D3DError>(hr, "ID3D11Device::CreateBuffer() failed");
280  m_pCBChanges.reset(ptmpCBChanges);
281  }
282  debug::writeLine(L"Creating constant buffer OK");
283 
284  // Create rasterizer state
285  debug::writeLine(L"Creating rasterizer state...");
286  {
287  D3D11_RASTERIZER_DESC rasterDesc;
288  ::ZeroMemory(&rasterDesc, sizeof(rasterDesc));
289  rasterDesc.FillMode = D3D11_FILL_SOLID;
290  rasterDesc.CullMode = D3D11_CULL_NONE;
291  ID3D11RasterizerState* ptmpRasterizerState = nullptr;
292  hr = m_pDevice->CreateRasterizerState(&rasterDesc, &ptmpRasterizerState);
293  checkDXResult<D3DError>(hr, "ID3D11Device::CreateBuffer() failed");
294  m_pRasterizerState.reset(ptmpRasterizerState);
295  }
296  debug::writeLine(L"Creating rasterizer state OK");
297  // Create sampler state
298  debug::writeLine(L"Creating sampler state...");
299  {
300  D3D11_SAMPLER_DESC sampDesc;
301  ::ZeroMemory(&sampDesc, sizeof(sampDesc));
302  sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
303  sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
304  sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
305  sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
306  sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
307  sampDesc.MinLOD = 0;
308  sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
309  ID3D11SamplerState *ptmpSamplerState = nullptr;
310  hr = m_pDevice->CreateSamplerState(&sampDesc, &ptmpSamplerState);
311  checkDXResult<D3DError>(hr, "ID3D11Device::CreateSamplerState() failed");
312  m_pSamplerState.reset(ptmpSamplerState);
313  }
314  debug::writeLine(L"Creating sampler state OK");
315  // Create blend state
316  debug::writeLine(L"Creating blend state...");
317  {
318  D3D11_BLEND_DESC blendDesc;
319  ::ZeroMemory(&blendDesc, sizeof(blendDesc));
320  blendDesc.AlphaToCoverageEnable = FALSE;
321  blendDesc.IndependentBlendEnable = FALSE;
322  blendDesc.RenderTarget[0].BlendEnable = TRUE;
323  blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
324  blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
325  blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
326  blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
327  blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
328  blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
329  blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
330  ID3D11BlendState* ptmpBlendState = nullptr;
331  hr = m_pDevice->CreateBlendState(&blendDesc, &ptmpBlendState);
332  checkDXResult<D3DError>(hr, "ID3D11Device::CreateBlendState() failed");
333  m_pBlendState.reset(ptmpBlendState);
334  }
335  debug::writeLine(L"Creating blend state OK");
336 
337  // Multithread
338  {
339  debug::writeLine(L"Set multithreading...");
340 
341  ID3D10Multithread *ptmpMt = nullptr;
342  hr = m_pDevice->QueryInterface(__uuidof(ID3D10Multithread), (void **)&ptmpMt);
343  checkDXResult<D3DError>(hr, "QueryInterface(IDXGIDevice1) failed");
345  pMt->SetMultithreadProtected(TRUE);
346 
347  debug::writeLine(L"Set multithreading OK");
348  }
349 
350  // fullscreen initially
351  /*
352  DXGI_ERROR_NOT_CURRENTLY_AVAILABLE (quote from dx11 document)
353  For instance:
354  - The application is running over Terminal Server.
355  - The output window is occluded.
356  - The output window does not have keyboard focus.
357  - Another application is already in full-screen mode.
358  */
359  if(m_param.fullScreen) {
360  debug::writeLine(L"Set fullscreen...");
361 
362  hr = m_pSwapChain->SetFullscreenState(TRUE, nullptr);
363  if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
364  debug::writeLine(L"Fullscreen mode is currently unavailable");
365  debug::writeLine(L"Launch on window mode...");
366  }
367  else {
368  checkDXResult<D3DError>(hr, "IDXGISwapChain::SetFullscreenState() failed");
369  }
370  }
371 
372  debug::writeLine(L"Initializing Direct3D 11 OK");
373 }
374 
375 void DGraphics::initBackBuffer()
376 {
377  debug::writeLine(L"initalizing BackBuffer...");
378 
379  HRESULT hr = S_OK;
380 
381  // Create a render target view
382  {
383  ID3D11Texture2D *ptmpBackBuffer = nullptr;
384  hr = m_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&ptmpBackBuffer);
385  checkDXResult<D3DError>(hr, "IDXGISwapChain::GetBuffer() failed");
386  // Release() at scope end
387  util::ComPtr<ID3D11Texture2D> pBackBuffer(ptmpBackBuffer);
388 
389  ID3D11RenderTargetView *ptmpRenderTargetView = nullptr;
390  hr = m_pDevice->CreateRenderTargetView(
391  pBackBuffer.get(), nullptr, &ptmpRenderTargetView);
392  checkDXResult<D3DError>(hr, "ID3D11Device::CreateRenderTargetView() failed");
393  m_pContext->OMSetRenderTargets(1, &ptmpRenderTargetView, nullptr);
394  m_pRenderTargetView.reset(ptmpRenderTargetView);
395 
396  debug::writeLine(L"SetRenderTarget OK");
397  }
398 
399  // Setup the viewport
400  {
401  D3D11_VIEWPORT vp;
402  vp.TopLeftX = 0;
403  vp.TopLeftY = 0;
404  vp.Width = static_cast<float>(m_param.w);
405  vp.Height = static_cast<float>(m_param.h);
406  vp.MinDepth = 0.0f;
407  vp.MaxDepth = 1.0f;
408  m_pContext->RSSetViewports(1, &vp);
409 
410  debug::writeLine(L"SetViewPort OK");
411  }
412 
413  debug::writeLine(L"initalizing BackBuffer OK");
414 }
415 
417 {
418  if (m_pContext != nullptr) {
419  m_pContext->ClearState();
420  }
421  if (m_pSwapChain != nullptr) {
422  m_pSwapChain->SetFullscreenState(FALSE, nullptr);
423  }
424  debug::writeLine(L"Finalize Application, Direct3D 11, window");
425 }
426 
427 LRESULT DGraphics::onSize(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
428 {
429  if (m_pSwapChain == nullptr || wParam == SIZE_MINIMIZED) {
430  debug::writeLine(L"!!!");
431  return 0;
432  }
433  debug::writef(L"WM_SIZE %d %d", LOWORD(lParam), HIWORD(lParam));
434 
435  HRESULT hr;
436  m_pContext->OMSetRenderTargets(0, nullptr, nullptr);
437  m_pRenderTargetView.reset();
438  hr = m_pSwapChain->ResizeBuffers(1, 0, 0, BufferFormat, SwapChainFlag);
439  checkDXResult<D3DError>(hr, "IDXGISwapChain::ResizeBuffers() failed");
440 
441  initBackBuffer();
442 
443  return DefWindowProc(hWnd, msg, wParam, lParam);
444 }
445 
447 {
448  // Clear target
449  m_pContext->ClearRenderTargetView(m_pRenderTargetView.get(), ClearColor);
450 
451  // VS, PS, constant buffer
452  m_pContext->VSSetShader(m_pVertexShader.get(), nullptr, 0);
453  m_pContext->PSSetShader(m_pPixelShader.get(), nullptr, 0);
454  ID3D11Buffer *pCBs[2] = { m_pCBNeverChanges.get(), m_pCBChanges.get() };
455  m_pContext->VSSetConstantBuffers(0, 2, pCBs);
456  // RasterizerState, SamplerState, BlendState
457  m_pContext->RSSetState(m_pRasterizerState.get());
458  ID3D11SamplerState *pSamplerState = m_pSamplerState.get();
459  m_pContext->PSSetSamplers(0, 1, &pSamplerState);
460  float blendFactor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
461  m_pContext->OMSetBlendState(m_pBlendState.get(), blendFactor, 0xffffffff);
462 
463  // Draw and clear list
464  for (auto &task : m_drawTaskList) {
465  // Set constant buffer
466  CBChanges cbChanges;
467  createCBFromTask(&cbChanges, task);
468  m_pContext->UpdateSubresource(m_pCBChanges.get(), 0, nullptr, &cbChanges, 0, 0);
469 
470  ID3D11ShaderResourceView *pView = task.pRV.get();
471  m_pContext->PSSetShaderResources(0, 1, &pView);
472 
473  m_pContext->Draw(4, 0);
474  }
475  m_drawTaskList.clear();
476 
477  // vsync and flip(blt)
478  m_pSwapChain->Present(m_param.vsync ? 1 : 0, 0);
479 }
480 
482 {
483  file::Bytes bin = file::loadFile(path);
484 
485  HRESULT hr = S_OK;
486 
487  D3DX11_IMAGE_INFO imageInfo = { 0 };
488  hr = ::D3DX11GetImageInfoFromMemory(bin.data(), bin.size(), nullptr,
489  &imageInfo, nullptr);
490  checkDXResult<D3DError>(hr, "D3DX11GetImageInfoFromMemory() failed");
491  if (imageInfo.ResourceDimension != D3D11_RESOURCE_DIMENSION_TEXTURE2D) {
492  throwTrace<D3DError>("Not 2D Texture", S_OK);
493  }
494 
495  ID3D11ShaderResourceView *ptmpRV = nullptr;
496  hr = ::D3DX11CreateShaderResourceViewFromMemory(m_pDevice.get(), bin.data(), bin.size(),
497  nullptr, nullptr, &ptmpRV, nullptr);
498  checkDXResult<D3DError>(hr, "D3DX11CreateShaderResourceViewFromMemory() failed");
499 
500  return std::make_shared<Texture>(
501  ptmpRV, imageInfo.Width, imageInfo.Height);
502 }
503 
505  int dx, int dy, bool lrInv, bool udInv,
506  int sx, int sy, int sw, int sh,
507  int cx, int cy, float angle, float scaleX, float scaleY,
508  float alpha)
509 {
510  sw = (sw == SrcSizeDefault) ? texture->w : sw;
511  sh = (sh == SrcSizeDefault) ? texture->h : sh;
512  m_drawTaskList.emplace_back(texture->pRV, texture->w, texture->h,
513  dx, dy, lrInv, udInv, sx, sy, sw, sh,
514  cx, cy, scaleX, scaleY, angle, 0x00000000, alpha);
515 }
516 
518  uint32_t startChar, uint32_t endChar, uint32_t w, uint32_t h)
519 {
520  HRESULT hr = S_OK;
521 
522  // Create font
523  HFONT htmpFont = ::CreateFont(
524  h, 0, 0, 0, 0, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
525  OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY,
526  FIXED_PITCH | FF_MODERN, fontName);
527  checkWin32Result(htmpFont != nullptr, "CreateFont() failed");
528  auto fontDel = [](HFONT hFont) { ::DeleteObject(hFont); };
529  std::unique_ptr<std::remove_pointer<HFONT>::type, decltype(fontDel)>
530  hFont(htmpFont, fontDel);
531  // Get DC
532  HDC htmpDC = ::GetDC(nullptr);
533  checkWin32Result(htmpDC != nullptr, "GetDC() failed");
534  auto dcRel = [](HDC hDC) { ::ReleaseDC(nullptr, hDC); };
535  std::unique_ptr<std::remove_pointer<HDC>::type, decltype(dcRel)>
536  hDC(htmpDC, dcRel);
537  // Select font
538  HFONT tmpOldFont = static_cast<HFONT>(::SelectObject(hDC.get(), hFont.get()));
539  checkWin32Result(tmpOldFont != nullptr, "SelectObject() failed");
540  auto restoreObj = [&hDC](HFONT oldFont) { ::SelectObject(hDC.get(), oldFont); };
541  std::unique_ptr<std::remove_pointer<HFONT>::type, decltype(restoreObj)>
542  hOldFont(tmpOldFont, restoreObj);
543 
544  TEXTMETRIC tm = { 0 };
545  checkWin32Result(::GetTextMetrics(hDC.get(), &tm) != FALSE,
546  "GetTextMetrics() failed");
547 
548  std::vector<FontTexture::TexPtr> texList;
549  std::vector<FontTexture::RvPtr> rvList;
550  texList.reserve(endChar - startChar + 1);
551  rvList.reserve(endChar - startChar + 1);
552 
553  for (uint32_t c = startChar; c <= endChar; c++) {
554  // Get font bitmap
555  GLYPHMETRICS gm = { 0 };
556  const MAT2 mat = { { 0, 1 },{ 0, 0 },{ 0, 0 },{ 0, 1 } };
557  DWORD bufSize = ::GetGlyphOutline(hDC.get(), c, GGO_GRAY8_BITMAP, &gm, 0, nullptr, &mat);
558  checkWin32Result(bufSize != GDI_ERROR, "GetGlyphOutline() failed");
559  auto buf = std::make_unique<uint8_t[]>(bufSize);
560  DWORD ret = ::GetGlyphOutline(hDC.get(), c, GGO_GRAY8_BITMAP, &gm, bufSize, buf.get(), &mat);
561  checkWin32Result(ret != GDI_ERROR, "GetGlyphOutline() failed");
562  uint32_t pitch = (gm.gmBlackBoxX + 3) / 4 * 4;
563  // Black box pos in while box
564  uint32_t destX = gm.gmptGlyphOrigin.x;
565  uint32_t destY = tm.tmAscent - gm.gmptGlyphOrigin.y;
566 
567  // Create texture
568  D3D11_TEXTURE2D_DESC desc = { 0 };
569  desc.Width = w;
570  desc.Height = h;
571  desc.MipLevels = 1;
572  desc.ArraySize = 1;
573  desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
574  desc.SampleDesc.Count = 1;
575  desc.Usage = D3D11_USAGE_DYNAMIC;
576  desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
577  desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
578  ID3D11Texture2D *ptmpTex = nullptr;
579  hr = m_pDevice->CreateTexture2D(&desc, nullptr, &ptmpTex);
580  checkDXResult<D3DError>(hr, "ID3D11Device::CreateTexture2D() failed");
581  // make unique_ptr and push
582  texList.emplace_back(ptmpTex);
583 
584  // Write
585  D3D11_MAPPED_SUBRESOURCE mapped;
586  UINT subres = ::D3D11CalcSubresource(0, 0, 1);
587  hr = m_pContext->Map(ptmpTex, subres, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
588  checkDXResult<D3DError>(hr, "ID3D11DeviceContext::Map() failed");
589  uint8_t *pTexels = static_cast<uint8_t *>(mapped.pData);
590  ::ZeroMemory(pTexels, w * h * 4);
591  for (uint32_t y = 0; y < gm.gmBlackBoxY; y++) {
592  for (uint32_t x = 0; x < gm.gmBlackBoxX; x++) {
593  if (destX + x >= w || destY + y >= h) {
594  continue;
595  }
596  uint32_t alpha = buf[y * pitch + x] * 255 / 64;
597  uint32_t destInd = (((destY + y) * w) + (destX + x)) * 4;
598  pTexels[destInd + 0] = 0;
599  pTexels[destInd + 1] = 0;
600  pTexels[destInd + 2] = 0;
601  pTexels[destInd + 3] = alpha;
602  }
603  }
604  m_pContext->Unmap(ptmpTex, subres);
605 
606  // Create resource view
607  ID3D11ShaderResourceView *ptmpRV = nullptr;
608  hr = m_pDevice->CreateShaderResourceView(ptmpTex, nullptr, &ptmpRV);
609  checkDXResult<D3DError>(hr, "ID3D11Device::CreateShaderResourceView() failed");
610  // make unique_ptr and push
611  rvList.emplace_back(ptmpRV);
612  }
613 
614  // add (id, FontTexture(...))
615  auto res = std::make_shared<FontTexture>(
616  w, h, startChar, endChar);
617  res->pTexList.swap(texList);
618  res->pRVList.swap(rvList);
619  return res;
620 }
621 
622 void DGraphics::drawChar(const FontResourcePtr &font, wchar_t c, int dx, int dy,
623  uint32_t color, float scaleX, float scaleY, float alpha,
624  int *nextx, int *nexty)
625 {
626  // skip if space
627  if (!::iswspace(c)) {
628  // Set alpha 0xff
629  color |= 0xff000000;
630  auto &pRV = font->pRVList.at(c - font->startChar);
631  m_drawTaskList.emplace_back(pRV, font->w, font->h,
632  dx, dy, false, false, 0, 0, font->w, font->h,
633  0, 0, scaleX, scaleY, 0.0f, color, alpha);
634  }
635 
636  if (nextx != nullptr) {
637  *nextx = dx + font->w;
638  }
639  if (nexty != nullptr) {
640  *nexty = dy + font->h;
641  }
642 }
643 
644 void DGraphics::drawString(const FontResourcePtr &font, const wchar_t *str, int dx, int dy,
645  uint32_t color, int ajustX, float scaleX, float scaleY, float alpha,
646  int *nextx, int *nexty)
647 {
648  while (*str != L'\0') {
649  drawChar(font, *str, dx, dy, color, scaleX, scaleY, alpha, &dx, nexty);
650  dx += ajustX;
651  str++;
652  }
653  if (nextx != nullptr) {
654  *nextx = dx;
655  }
656 }
657 
658 #pragma endregion
659 
660 } // namespace graphics
661 } // namespace yappy
XMMATRIX udInv
Definition: graphics.cpp:36
const char * str
Definition: input.cpp:197
sy
Definition: Memo.txt:67
Debug utilities.
sw
Definition: Memo.txt:67
FontResourcePtr loadFont(const wchar_t *fontName, uint32_t startChar, uint32_t endChar, uint32_t w, uint32_t h)
Definition: graphics.cpp:517
void writef(const wchar_t *fmt,...) noexcept
Write debug message using format string like printf.
Definition: debug.cpp:103
std::vector< uint8_t > loadFile(const wchar_t *fileName)
Load file from abstract file system.
Definition: file.cpp:103
XMFLOAT3 Pos
Definition: graphics.cpp:26
sh をピクセル座標からUV座標に offset
Definition: Memo.txt:71
void drawTexture(const TextureResourcePtr &texture, int dx, int dy, bool lrInv=false, bool udInv=false, int sx=0, int sy=0, int sw=SrcSizeDefault, int sh=SrcSizeDefault, int cx=0, int cy=0, float angle=0.0f, float scaleX=1.0f, float scaleY=1.0f, float alpha=1.0f)
Draw texture.
Definition: graphics.cpp:504
Definition: config.cpp:6
void checkDXResult(HRESULT hr, const std::string &msg)
Definition: exceptions.h:83
void writeLine(const wchar_t *str=L"") noexcept
Write debug string and new line.
Definition: debug.h:64
XMFLOAT4 FontColor
Definition: graphics.cpp:44
XMMATRIX Scale
Definition: graphics.cpp:39
XMFLOAT2 Tex
Definition: graphics.cpp:27
std::shared_ptr< FontResource > FontResourcePtr
Definition: graphics.h:85
XMMATRIX lrInv
Definition: graphics.cpp:35
XMMATRIX Projection
Definition: graphics.cpp:31
XMMATRIX Centering
Definition: graphics.cpp:38
XMMATRIX Rotation
Definition: graphics.cpp:40
LRESULT onSize(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
Definition: graphics.cpp:427
std::vector< uint8_t > Bytes
File byte sequence. Vector of uint8_t.
Definition: file.h:25
XMFLOAT2 uvOffset
Definition: graphics.cpp:42
char msg[LINE_DATA_SIZE-sizeof(LARGE_INTEGER)-sizeof(uint32_t)]
Definition: debug.cpp:159
void drawChar(const FontResourcePtr &font, wchar_t c, int dx, int dy, uint32_t color=0x000000, float scaleX=1.0f, float scaleY=1.0f, float alpha=1.0f, int *nextx=nullptr, int *nexty=nullptr)
Definition: graphics.cpp:622
std::shared_ptr< TextureResource > TextureResourcePtr
Definition: graphics.h:83
void checkWin32Result(bool cond, const std::string &msg)
Definition: exceptions.h:50
void drawString(const FontResourcePtr &font, const wchar_t *str, int dx, int dy, uint32_t color=0x000000, int ajustX=0, float scaleX=1.0f, float scaleY=1.0f, float alpha=1.0f, int *nextx=nullptr, int *nexty=nullptr)
Draw string.
Definition: graphics.cpp:644
static const int SrcSizeDefault
Use texture size.
Definition: graphics.h:90
TextureResourcePtr loadTexture(const wchar_t *path)
Load a texture.
Definition: graphics.cpp:481
XMMATRIX Translate
Definition: graphics.cpp:41
DGraphics(const GraphicsParam &param)
Definition: graphics.cpp:84
XMMATRIX DestScale
Definition: graphics.cpp:37
XMFLOAT2 uvSize
Definition: graphics.cpp:43
std::unique_ptr< T, ComDeleter > ComPtr
unique_ptr of IUnknown with ComDeleter.
Definition: util.h:88
float Alpha
Definition: graphics.cpp:45