Covellite++  Version: 2.3.0 Revision: ??? Platform: x64 Build: 23:13 04.01.2025
Кроссплатформенный фреймворк для разработки приложений на С++
Загрузка...
Поиск...
Не найдено
DirectX11.cpp
1
2#include "stdafx.h"
3#include "DirectX11.hpp"
4#include <glm/glm.force.hpp>
5#include <alicorn/std/vector.hpp>
6#include <alicorn/boost/lexical-cast.hpp>
7#include "DxCheck.hpp"
8#include "DirectX.hpp"
9#include <Covellite/Api/Vertex.hpp>
10
11#include <d3d11.h>
12#pragma comment(lib, "d3d11.lib")
13
14#include "Shaders/Shaders.hpp"
15#include <Covellite/Api/Defines.hpp>
16#include "Component.hpp"
17#include "GraphicApi.Constants.hpp"
18
19namespace covellite
20{
21
22namespace api
23{
24
25namespace renderer
26{
27
28// ************************************************************************** //
29
30class DirectX11::Buffer final
31{
32public:
33 template<class T>
34 class Support
35 {
36 public:
37 static constexpr UINT Flag = D3D11_BIND_VERTEX_BUFFER;
38 };
39
40 template<UINT TIndex>
41 class Constant
42 {
43 public:
44 static constexpr UINT Flag = D3D11_BIND_CONSTANT_BUFFER;
45 static constexpr UINT Index = TIndex;
46 };
47
48 template<>
49 class Support<::Camera> : public Constant<COVELLITE_BUFFER_INDEX_CAMERA> { };
50
51 template<>
52 class Support<::Object> : public Constant<COVELLITE_BUFFER_INDEX_OBJECT> { };
53
54 template<>
55 class Support<uint8_t> : public Constant<COVELLITE_BUFFER_INDEX_USER> { };
56
57 template<>
58 class Support<int>
59 {
60 public:
61 static constexpr UINT Flag = D3D11_BIND_INDEX_BUFFER;
62 };
63
64public:
65 template<class T>
66 static ComPtr_t<ID3D11Buffer> Create(
67 const ComPtr_t<ID3D11Device> & _pDevice,
68 const bool _IsDynamic,
69 const T * _pData,
70 size_t _Count)
71 {
72 D3D11_BUFFER_DESC Desc = { 0 };
73 Desc.Usage = _IsDynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
74 Desc.CPUAccessFlags = static_cast<UINT>(_IsDynamic ? D3D11_CPU_ACCESS_WRITE : 0);
75 Desc.ByteWidth = static_cast<decltype(Desc.ByteWidth)>(sizeof(T) * _Count);
76 Desc.BindFlags = Support<T>::Flag;
77
78 D3D11_SUBRESOURCE_DATA InitData = { 0 };
79 InitData.pSysMem = _pData;
80
81 const auto * const pInitData = (_pData == nullptr) ? nullptr : &InitData;
82
83 ComPtr_t<ID3D11Buffer> pBuffer;
84 DX_CHECK _pDevice->CreateBuffer(&Desc, pInitData, &pBuffer);
85 return pBuffer;
86 }
87
88 template<class T>
89 static ComPtr_t<ID3D11Buffer> Create(
90 const ComPtr_t<ID3D11Device> & _pDevice,
91 const ComPtr_t<ID3D11DeviceContext> & _pImmediateContext,
92 const T * _pData)
93 {
94 const auto pResult = Create(_pDevice, false, _pData, 1);
95
96 constexpr auto Index = Support<T>::Index;
97 _pImmediateContext->VSSetConstantBuffers(Index, 1, pResult.GetAddressOf());
98 _pImmediateContext->PSSetConstantBuffers(Index, 1, pResult.GetAddressOf());
99
100 return pResult;
101 }
102};
103
104template<class T>
105class DirectX11::ConstantBuffer final :
106 public Constants::Data<T>
107{
108public:
109 void Update(void) const override
110 {
111 m_pImmediateContext->UpdateSubresource(
112 m_pBuffer.Get(), 0, NULL, &m_Data, 0, 0);
113 }
114
115private:
116 const ComPtr_t<ID3D11DeviceContext> m_pImmediateContext;
117 const ComPtr_t<ID3D11Buffer> m_pBuffer;
118
119public:
120 ConstantBuffer(
121 const ComPtr_t<ID3D11Device> & _pDevice,
122 const ComPtr_t<ID3D11DeviceContext> & _pImmediateContext) :
123 m_pImmediateContext{ _pImmediateContext },
124 m_pBuffer{ Buffer::Create(_pDevice, _pImmediateContext, &m_Data) }
125 {
126 }
127};
128
129// ************************************************************************** //
130
131DirectX11::DirectX11(const Data_t & _Data)
132{
133 CreateDeviceAndSwapChain(_Data);
134
135 MakeConstants<ConstantBuffer>(m_pDevice, m_pImmediateContext);
136}
137
138DirectX11::~DirectX11(void) = default;
139
140DirectX11::String_t DirectX11::GetUsingApi(void) const /*override*/
141{
142 return uT("DirectX 11");
143}
144
145void DirectX11::PresentFrame(void) /*override*/
146{
147 m_pSwapChain->Present(0, 0);
148
149 GraphicApi::PresentFrame();
150}
151
152void DirectX11::ResizeWindow(const Rect & _ClientRect) /*override*/
153{
154 m_IsResizeWindow = true;
155 SetRenderTargetSize(static_cast<UINT>(_ClientRect.Width), static_cast<UINT>(_ClientRect.Height));
156}
157
158void DirectX11::CreateDeviceAndSwapChain(const Data_t & _Data)
159{
160 const D3D_FEATURE_LEVEL FeatureLevels[] =
161 {
162 D3D_FEATURE_LEVEL_11_1,
163 D3D_FEATURE_LEVEL_11_0
164 };
165
166 DXGI_SWAP_CHAIN_DESC sd = { 0 };
167 sd.OutputWindow = ::covellite::any_cast<HWND>(_Data.Handle);
168 sd.Windowed = (_Data.IsFullScreen) ? FALSE : TRUE;
169 sd.BufferCount = 2;
170 sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
171 sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
172 sd.SampleDesc.Count = 1;
173 //sd.SampleDesc.Quality = 0;
174
175 using ::alicorn::extension::cpp::IS_RELEASE_CONFIGURATION;
176
177 DX_CHECK D3D11CreateDeviceAndSwapChain(
178 NULL,
179 D3D_DRIVER_TYPE_HARDWARE,
180 NULL,
181 (IS_RELEASE_CONFIGURATION) ? 0 : D3D11_CREATE_DEVICE_DEBUG,
182 FeatureLevels, sizeof(FeatureLevels) / sizeof(FeatureLevels[0]),
183 D3D11_SDK_VERSION,
184 &sd,
185 &m_pSwapChain,
186 &m_pDevice,
187 NULL,
188 &m_pImmediateContext);
189
190 SetRenderTargetSize(static_cast<UINT>(_Data.ClientRect.Width),
191 static_cast<UINT>(_Data.ClientRect.Height));
192}
193
194void DirectX11::SetRenderTargetSize(const UINT _Width, const UINT _Height)
195{
196 CreateRenderTargetView(_Width, _Height);
197 CreateDepthStencilView(_Width, _Height);
198}
199
200void DirectX11::CreateRenderTargetView(const UINT _Width, const UINT _Height)
201{
202 if (m_pScreenRenderTargetView != nullptr)
203 {
204 m_pScreenRenderTargetView.Reset();
205
206 DX_CHECK m_pSwapChain->ResizeBuffers(2, _Width, _Height,
207 DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
208 }
209
210 ComPtr_t<ID3D11Texture2D> pBackBuffer;
211 DX_CHECK m_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
212 (void **)pBackBuffer.GetAddressOf());
213
214 DX_CHECK m_pDevice->CreateRenderTargetView(pBackBuffer.Get(), NULL,
215 &m_pScreenRenderTargetView);
216}
217
218void DirectX11::CreateDepthStencilView(const UINT _Width, const UINT _Height)
219{
220 m_pScreenDepthStencilView.Reset();
221
222 const DXGI_FORMAT DeptBufferFormat = DXGI_FORMAT_D32_FLOAT;
223
224 D3D11_TEXTURE2D_DESC TextureDesc = { 0 };
225 TextureDesc.Width = _Width;
226 TextureDesc.Height = _Height;
227 TextureDesc.MipLevels = 1;
228 TextureDesc.ArraySize = 1;
229 TextureDesc.Format = DeptBufferFormat;
230 TextureDesc.SampleDesc.Count = 1;
231 TextureDesc.SampleDesc.Quality = 0;
232 TextureDesc.Usage = D3D11_USAGE_DEFAULT;
233 TextureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
234
235 ComPtr_t<ID3D11Texture2D> pDepthBuffer;
236 DX_CHECK m_pDevice->CreateTexture2D(&TextureDesc, NULL, &pDepthBuffer);
237
238 D3D11_DEPTH_STENCIL_VIEW_DESC DeptStencilViewDesc = { 0 };
239 DeptStencilViewDesc.Format = DeptBufferFormat;
240 DeptStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
241
242 DX_CHECK m_pDevice->CreateDepthStencilView(pDepthBuffer.Get(),
243 &DeptStencilViewDesc, &m_pScreenDepthStencilView);
244}
245
246auto DirectX11::CreateCamera(const ComponentPtr_t & _pComponent) -> Render_t /*override*/
247{
248 const auto CameraId = _pComponent->Id;
249
250 using Size_t = ::std::tuple<UINT, UINT>;
251 using fnBkSurfaceSize_t = ::std::function<Size_t(void)>;
252
253 const auto pCamera = _pComponent;
254
255 const fnBkSurfaceSize_t GetScaleBkSurfaceSize = [=](void)
256 {
257 DXGI_SWAP_CHAIN_DESC Desc = { 0 };
258 DX_CHECK m_pSwapChain->GetDesc(&Desc);
259
260 const float Scale = (*pCamera)[uT("scale")];
261
262 return Size_t{ static_cast<UINT>(Scale * Desc.BufferDesc.Width),
263 static_cast<UINT>(Scale * Desc.BufferDesc.Height) };
264 };
265
266 const fnBkSurfaceSize_t GetWindowBkSurfaceSize = [=](void)
267 {
268 DXGI_SWAP_CHAIN_DESC Desc = { 0 };
269 DX_CHECK m_pSwapChain->GetDesc(&Desc);
270
271 return Size_t{ Desc.BufferDesc.Width, Desc.BufferDesc.Height };
272 };
273
274 const fnBkSurfaceSize_t GetUserBkSurfaceSize = [=](void)
275 {
276 DXGI_SWAP_CHAIN_DESC Desc = { 0 };
277 DX_CHECK m_pSwapChain->GetDesc(&Desc); // результат не используется, но
278 // так проще тестировать
279
280 const int Width = (*pCamera)[uT("width")];
281 const int Height = (*pCamera)[uT("height")];
282
283 return Size_t{ static_cast<UINT>(Width), static_cast<UINT>(Height) };
284 };
285
286 const auto IsScaleBkSurfaceSize =
287 (*pCamera)[uT("scale")].IsType<float>();
288 const auto IsUserBkSurfaceSize =
289 (*pCamera)[uT("width")].IsType<int>() &&
290 (*pCamera)[uT("height")].IsType<int>();
291
292 const auto GetBkSurfaceSize =
293 (IsScaleBkSurfaceSize) ? GetScaleBkSurfaceSize :
294 (IsUserBkSurfaceSize) ? GetUserBkSurfaceSize :
295 GetWindowBkSurfaceSize;
296
297 D3D11_VIEWPORT ViewPort = { 0 };
298 ViewPort.TopLeftX = 0;
299 ViewPort.TopLeftY = 0;
300 ::std::tie(ViewPort.Width, ViewPort.Height) = GetBkSurfaceSize();
301 ViewPort.MinDepth = 0.0f;
302 ViewPort.MaxDepth = 1.0f;
303 m_pImmediateContext->RSSetViewports(1, &ViewPort);
304
305 const auto SetDefaultRenderTarget = [=](void)
306 {
307 m_CurrentRenderTargets = { m_pScreenRenderTargetView.Get() };
308 m_pCurrentDepthStencilView = m_pScreenDepthStencilView;
309
310 D3D11_VIEWPORT ViewPort = { 0 };
311 ViewPort.TopLeftX = 0;
312 ViewPort.TopLeftY = 0;
313 ::std::tie(ViewPort.Width, ViewPort.Height) = GetBkSurfaceSize();
314 ViewPort.MinDepth = 0.0f;
315 ViewPort.MaxDepth = 1.0f;
316 m_pImmediateContext->RSSetViewports(1, &ViewPort);
317 };
318
319 const auto DisabledBlendRender = CreateBlendState(false);
320 const auto DisableDepthRender = GetDepthState(false, false, false);
321
322 const auto ServiceComponents = CapturingServiceComponent::Get(_pComponent,
323 {
324 { uT("Position"), api::Component::Make({}) },
325 { uT("Rotation"), api::Component::Make({}) },
326 });
327
328 const Render_t CameraOptographic = [=](void)
329 {
330 const Component::Position Pos{ *ServiceComponents[0] };
331
332 SetDefaultRenderTarget();
333 DisabledBlendRender();
334 DisableDepthRender();
335
336 UINT ViewportCount = 1;
337 D3D11_VIEWPORT Viewport = { 0 };
338 m_pImmediateContext->RSGetViewports(&ViewportCount, &Viewport);
339
340 auto & CameraMatrices = m_pConstants->Get<::Camera>();
341
342 CameraMatrices.Projection = ::glm::transpose(::glm::ortho(
343 Pos.X, Pos.X + Viewport.Width,
344 Pos.Y + Viewport.Height, Pos.Y,
345 1.0f, -1.0f));
346
347 const auto View = ::glm::identity<::glm::mat4>();
348 CameraMatrices.View = ::glm::transpose(View);
349 CameraMatrices.ViewInverse = ::glm::transpose(::glm::inverse(View));
350 m_pConstants->Update<::Camera>();
351
352 (*_pComponent)[uT("view")] = CameraMatrices.View;
353 (*_pComponent)[uT("projection")] = CameraMatrices.Projection;
354 };
355
356 const Render_t CameraPerspective = [=](void)
357 {
358 SetDefaultRenderTarget();
359 DisabledBlendRender();
360 DisableDepthRender();
361
362 UINT ViewportCount = 1;
363 D3D11_VIEWPORT Viewport = { 0 };
364 m_pImmediateContext->RSGetViewports(&ViewportCount, &Viewport);
365
366 auto & CameraMatrices = m_pConstants->Get<::Camera>();
367
368 // ************************** Матрица проекции ************************** //
369
370 const auto AngleY = (float)(*_pComponent)[uT("fov")].Default(90.0f) *
371 ::alicorn::extension::cpp::math::Constant<float>::DegreeToRadian;
372 const float zNear = (*_pComponent)[uT("znear")].Default(0.01f);
373 const float zFar = (*_pComponent)[uT("zfar")].Default(200.0f);
374
375 CameraMatrices.Projection = ::glm::transpose(::glm::perspectiveFovRH(AngleY,
376 (float)Viewport.Width, (float)Viewport.Height, zFar, zNear));
377
378 // **************************** Матрица вида **************************** //
379
380 // Точка, куда смотрит камера - задается как компонент Data.Position.
381 const Component::Position Look{ *ServiceComponents[0] };
382
383 const auto GetEye = [&](void) -> ::glm::vec3
384 {
385 // Расстояние от камеры до Look.
386 const float Distance = (*_pComponent)[uT("distance")].Default(0.0f);
387
388 // Точка, где расположена камера - вычисляется на основе Look, Distance и
389 // компонента Data.Rotation.
390
391 const Component::Position Rot{ *ServiceComponents[1] };
392
393 ::glm::mat4 Transform = ::glm::identity<::glm::mat4>();
394
395 Transform = ::glm::translate(Transform,
396 ::glm::vec3{ Look.X, Look.Y, Look.Z });
397 Transform = ::glm::rotate(Transform,
398 Rot.Z, ::glm::vec3{ 0.0f, 0.0f, 1.0f });
399 Transform = ::glm::rotate(Transform,
400 Rot.Y, ::glm::vec3{ 0.0f, 1.0f, 0.0f });
401 Transform = ::glm::rotate(Transform,
402 Rot.X, ::glm::vec3{ 1.0f, 0.0f, 0.0f });
403
404 return Transform * ::glm::vec4{ Distance + 0.1f, 0.0f, 0.0f, 1.0f };
405 };
406
407 const auto View = ::glm::lookAtRH(
408 GetEye(),
409 ::glm::vec3{ Look.X, Look.Y, Look.Z },
410 ::glm::vec3{ 0.0f, 0.0f, 1.0f }); // Up
411
412 CameraMatrices.View = ::glm::transpose(View);
413 CameraMatrices.ViewInverse = ::glm::transpose(::glm::inverse(View));
414 m_pConstants->Update<::Camera>();
415
416 (*_pComponent)[uT("view")] = CameraMatrices.View;
417 (*_pComponent)[uT("projection")] = CameraMatrices.Projection;
418 };
419
420 return (_pComponent->Kind == uT("Perspective")) ?
421 CameraPerspective : CameraOptographic;
422}
423
424class DirectX11::Texture final
425{
426public:
427 using Ptr_t = ::std::shared_ptr<Texture>;
428
429public:
430 const ComponentPtr_t m_pDataTexture;
431 const String_t m_Destination;
432 const UINT m_iDestination;
433 const bool m_IsUseMapper;
434 const DXGI_FORMAT m_Format;
435 ComPtr_t<ID3D11Texture2D> m_pTexture;
436 ComPtr_t<ID3D11Texture2D> m_pReadDataTexture;
437 ComPtr_t<ID3D11RenderTargetView> m_pRenderTargetView;
438 ComPtr_t<ID3D11DepthStencilView> m_pDepthStencilView;
439 ComPtr_t<ID3D11ShaderResourceView> m_pShaderResourceView;
440
441public:
442 void MakeTarget(
443 const ComPtr_t<ID3D11Device> & _pDevice,
444 const UINT _Width,
445 const UINT _Height)
446 {
447 m_pTexture = (m_Destination != uT("depth")) ?
448 MakeRGBATarget(_pDevice, _Width, _Height) :
449 MakeDepthTarget(_pDevice, _Width, _Height);
450
451 (*m_pDataTexture)[uT("width")] = static_cast<int>(_Width);
452 (*m_pDataTexture)[uT("height")] = static_cast<int>(_Height);
453
454 if (m_IsUseMapper)
455 {
456 m_pReadDataTexture = MakeRGBACopy(_pDevice, _Width, _Height);
457 }
458 }
459
460 void MakeSource(
461 const ComPtr_t<ID3D11Device> & _pDevice,
462 const ComPtr_t<ID3D11DeviceContext> & _pImmediateContext,
463 const UINT _Width,
464 const UINT _Height,
465 const void * _pData,
466 const bool _IsMipmapping)
467 {
468 m_pTexture = (_IsMipmapping) ?
469 MakeRGBAMipSource(_pDevice, _pImmediateContext, _Width, _Height, _pData) :
470 MakeRGBASource(_pDevice, _pImmediateContext, _Width, _Height, _pData);
471 }
472
473 ComPtr_t<ID3D11Texture2D> MakeRGBACopy(
474 const ComPtr_t<ID3D11Device> & _pDevice,
475 const UINT _Width, const UINT _Height) const
476 {
477 D3D11_TEXTURE2D_DESC textureDesc = { 0 };
478 textureDesc.Width = _Width;
479 textureDesc.Height = _Height;
480 textureDesc.MipLevels = 1;
481 textureDesc.ArraySize = 1;
482 textureDesc.Format = m_Format;
483 textureDesc.Usage = D3D11_USAGE_STAGING;
484 textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
485 textureDesc.SampleDesc.Count = 1;
486
487 ComPtr_t<ID3D11Texture2D> pTexture;
488 DX_CHECK _pDevice->CreateTexture2D(&textureDesc, nullptr, &pTexture);
489 return pTexture;
490 }
491
492private:
493 ComPtr_t<ID3D11Texture2D> MakeRGBASource(
494 const ComPtr_t<ID3D11Device> & _pDevice,
495 const ComPtr_t<ID3D11DeviceContext> & _pImmediateContext,
496 const UINT _Width,
497 const UINT _Height,
498 const void * _pData)
499 {
500 D3D11_TEXTURE2D_DESC TextureDesc = { 0 };
501 TextureDesc.Width = _Width;
502 TextureDesc.Height = _Height;
503 TextureDesc.MipLevels = 1;
504 TextureDesc.ArraySize = 1;
505 TextureDesc.Format = m_Format;
506 TextureDesc.Usage = D3D11_USAGE_DEFAULT;
507 TextureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
508 TextureDesc.MiscFlags = 0;
509 TextureDesc.SampleDesc.Count = 1;
510 TextureDesc.SampleDesc.Quality = 0;
511
512 ComPtr_t<ID3D11Texture2D> pTexture2D;
513 DX_CHECK _pDevice->CreateTexture2D(&TextureDesc, nullptr, &pTexture2D);
514
515 _pImmediateContext->UpdateSubresource(pTexture2D.Get(), 0, NULL,
516 _pData, _Width * 4, 0);
517
518 D3D11_SHADER_RESOURCE_VIEW_DESC SrvDesc = { 0 };
519 SrvDesc.Format = TextureDesc.Format;
520 SrvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
521 SrvDesc.Texture2D.MipLevels = TextureDesc.MipLevels;
522
523 DX_CHECK _pDevice->CreateShaderResourceView(pTexture2D.Get(), &SrvDesc,
524 &m_pShaderResourceView);
525
526 return pTexture2D;
527 }
528
529 ComPtr_t<ID3D11Texture2D> MakeRGBAMipSource(
530 const ComPtr_t<ID3D11Device> & _pDevice,
531 const ComPtr_t<ID3D11DeviceContext> & _pImmediateContext,
532 const UINT _Width,
533 const UINT _Height,
534 const void * _pData)
535 {
536 D3D11_TEXTURE2D_DESC TextureDesc = { 0 };
537 TextureDesc.Width = _Width;
538 TextureDesc.Height = _Height;
539 TextureDesc.MipLevels = 0;
540 TextureDesc.ArraySize = 1;
541 TextureDesc.Format = m_Format;
542 TextureDesc.Usage = D3D11_USAGE_DEFAULT;
543 TextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
544 TextureDesc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;
545 TextureDesc.SampleDesc.Count = 1;
546 TextureDesc.SampleDesc.Quality = 0;
547
548 ComPtr_t<ID3D11Texture2D> pTexture2D;
549 DX_CHECK _pDevice->CreateTexture2D(&TextureDesc, nullptr, &pTexture2D);
550
551 _pImmediateContext->UpdateSubresource(pTexture2D.Get(), 0, NULL,
552 _pData, _Width * 4, 0);
553
554 D3D11_SHADER_RESOURCE_VIEW_DESC SrvDesc = { 0 };
555 SrvDesc.Format = TextureDesc.Format;
556 SrvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
557 SrvDesc.Texture2D.MipLevels = static_cast<UINT>(-1);
558
559 DX_CHECK _pDevice->CreateShaderResourceView(pTexture2D.Get(), &SrvDesc,
560 &m_pShaderResourceView);
561
562 _pImmediateContext->GenerateMips(m_pShaderResourceView.Get());
563
564 return pTexture2D;
565 }
566
567private:
568 ComPtr_t<ID3D11Texture2D> MakeRGBATarget(
569 const ComPtr_t<ID3D11Device> & _pDevice,
570 const UINT _Width, const UINT _Height)
571 {
572 D3D11_TEXTURE2D_DESC TextureDesc = { 0 };
573 TextureDesc.Width = _Width;
574 TextureDesc.Height = _Height;
575 TextureDesc.MipLevels = 1;
576 TextureDesc.ArraySize = 1;
577 TextureDesc.Format = m_Format;
578 TextureDesc.Usage = D3D11_USAGE_DEFAULT;
579 TextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
580 TextureDesc.MiscFlags = 0;
581 TextureDesc.SampleDesc.Count = 1;
582 TextureDesc.SampleDesc.Quality = 0;
583
584 ComPtr_t<ID3D11Texture2D> pTexture2D;
585 DX_CHECK _pDevice->CreateTexture2D(&TextureDesc, nullptr, &pTexture2D);
586
587 D3D11_SHADER_RESOURCE_VIEW_DESC SrvDesc = { 0 };
588 SrvDesc.Format = TextureDesc.Format;
589 SrvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
590 SrvDesc.Texture2D.MipLevels = TextureDesc.MipLevels;
591
592 DX_CHECK _pDevice->CreateShaderResourceView(pTexture2D.Get(), &SrvDesc,
593 &m_pShaderResourceView);
594
595 D3D11_RENDER_TARGET_VIEW_DESC TargetDesc = { 0 };
596 TargetDesc.Format = TextureDesc.Format;
597 TargetDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
598
599 ComPtr_t<ID3D11RenderTargetView> pRenderTargetView;
600 DX_CHECK _pDevice->CreateRenderTargetView(pTexture2D.Get(),
601 &TargetDesc, &m_pRenderTargetView);
602
603 return pTexture2D;
604 }
605
606 ComPtr_t<ID3D11Texture2D> MakeDepthTarget(
607 const ComPtr_t<ID3D11Device> & _pDevice,
608 const UINT _Width, const UINT _Height)
609 {
610 D3D11_TEXTURE2D_DESC TextureDesc = { 0 };
611 TextureDesc.Width = _Width;
612 TextureDesc.Height = _Height;
613 TextureDesc.MipLevels = 1;
614 TextureDesc.ArraySize = 1;
615 TextureDesc.Format = DXGI_FORMAT_R24G8_TYPELESS;
616 TextureDesc.Usage = D3D11_USAGE_DEFAULT;
617 TextureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
618 TextureDesc.MiscFlags = 0;
619 TextureDesc.SampleDesc.Count = 1;
620 TextureDesc.SampleDesc.Quality = 0;
621
622 ComPtr_t<ID3D11Texture2D> pTexture2D;
623 DX_CHECK _pDevice->CreateTexture2D(&TextureDesc, nullptr, &pTexture2D);
624
625 D3D11_SHADER_RESOURCE_VIEW_DESC SrvDesc = { 0 };
626 SrvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
627 SrvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
628 SrvDesc.Texture2D.MipLevels = TextureDesc.MipLevels;
629
630 DX_CHECK _pDevice->CreateShaderResourceView(pTexture2D.Get(), &SrvDesc,
631 &m_pShaderResourceView);
632
633 D3D11_DEPTH_STENCIL_VIEW_DESC Desc = { 0 };
634 Desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
635 Desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
636
637 ComPtr_t<ID3D11DepthStencilView> pDepthStencilView;
638 DX_CHECK _pDevice->CreateDepthStencilView(pTexture2D.Get(),
639 &Desc, &m_pDepthStencilView);
640
641 return pTexture2D;
642 }
643
644private:
645 static UINT GetDestinationIndex(const ComponentPtr_t & _pData)
646 {
647 const int Index = (*_pData)[uT("index")].Default(-1);
648 if (Index >= 0) return static_cast<UINT>(Index);
649
650 static const ::std::vector<String_t> Destinations =
651 {
652 uT("albedo"),
653 uT("metalness"),
654 uT("roughness"),
655 uT("normal"),
656 uT("occlusion"),
657 uT("depth"),
658 };
659
660 const String_t Destination =
661 (*_pData)[uT("destination")].Default(uT("albedo"));
662
663 const auto itDestination =
664 ::std::find(Destinations.cbegin(), Destinations.cend(), Destination);
665 if (itDestination == Destinations.cend())
666 {
667 throw STD_EXCEPTION << "Unexpected destination texture: " << Destination;
668 }
669
670 return static_cast<UINT>(
671 ::std::distance(Destinations.cbegin(), itDestination));
672 };
673
674 static DXGI_FORMAT GetFormat(const ComponentPtr_t & _pData)
675 {
676 const int Capacity = (*_pData)[uT("capacity")].Default(8);
677
678 return
679 (Capacity == 32) ? DXGI_FORMAT_R32G32B32A32_FLOAT :
680 (Capacity == 16) ? DXGI_FORMAT_R16G16B16A16_FLOAT :
681 DXGI_FORMAT_R8G8B8A8_UNORM;
682 }
683
684public:
685 explicit Texture(const ComponentPtr_t & _pDataTexture) :
686 m_pDataTexture{ _pDataTexture },
687 m_Destination{ (*_pDataTexture)[uT("destination")].Default(uT("albedo")) },
688 m_iDestination{ GetDestinationIndex(_pDataTexture) },
689 m_IsUseMapper{ (*_pDataTexture)[uT("mapper")].IsType<const cbBufferMap_t<const void> &>() },
690 m_Format{ GetFormat(_pDataTexture) }
691 {
692
693 }
694 Texture(const Texture &) = delete;
695 Texture(Texture &&) = delete;
696 Texture & operator= (const Texture &) = delete;
697 Texture & operator= (Texture &&) = delete;
698 ~Texture(void) = default;
699};
700
701auto DirectX11::CreateBkSurface(const ComponentPtr_t & _pComponent) -> Render_t /*override*/
702{
703 using Size_t = ::std::tuple<UINT, UINT>;
704 using fnBkSurfaceSize_t = ::std::function<Size_t(void)>;
705
706 const auto pBkSurface = _pComponent;
707
708 const fnBkSurfaceSize_t GetBkSurfaceSize = [=](void)
709 {
710 UINT ViewportCount = 1;
711 D3D11_VIEWPORT Viewport = { 0 };
712 m_pImmediateContext->RSGetViewports(&ViewportCount, &Viewport);
713
714 const int Width = static_cast<int>(Viewport.Width);
715 const int Height = static_cast<int>(Viewport.Height);
716
717 (*pBkSurface)[uT("width")] = Width;
718 (*pBkSurface)[uT("height")] = Height;
719
720 return Size_t{ static_cast<UINT>(Width), static_cast<UINT>(Height) };
721 };
722
723 const auto [Width, Height] = GetBkSurfaceSize();
724
725 const auto pBkSurfaceTextures =
726 ::std::make_shared<::std::vector<Texture::Ptr_t>>();
727
728 const auto DoDataTexture = [&](const ComponentPtr_t & _pDataTexture)
729 {
730 auto pTexture = ::std::make_shared<Texture>(_pDataTexture);
731 pTexture->MakeTarget(m_pDevice, Width, Height);
732
733 // Лучше избавиться от weak_ptr<> и неопределенности с тем, что если
734 // объект текстуры внеэкранной поверхности не будет использован как
735 // source, то будет утечка памяти - см. как то же самое реализовано
736 // у OpenGL.
737 (*_pDataTexture)[uT("entity")] = ::std::weak_ptr<Texture>(pTexture);
738
739 pBkSurfaceTextures->push_back(pTexture);
740 };
741
742 CapturingServiceComponent::Process(_pComponent,
743 {
744 { uT("Texture"), DoDataTexture },
745 });
746
747 return [=](void)
748 {
749 const auto [Width, Height] = GetBkSurfaceSize();
750
751 // 08 Сентябрь 2020 11:25 (unicornum.verum@gmail.com)
752 TODO("Хранить размеры текстур в них самих и пересоздавать при расхождении размеров");
753 // Кстати, первый раз внеэкранную поверхность также можно создавать при
754 // первом вызове рендера.
755
756 if (m_IsResizeWindow)
757 {
758 for (auto & pTexture : *pBkSurfaceTextures)
759 {
760 pTexture->MakeTarget(m_pDevice, Width, Height);
761 }
762 }
763
764 m_CurrentRenderTargets.clear();
765
766 for (auto & pTexture : *pBkSurfaceTextures)
767 {
768 if (pTexture->m_pRenderTargetView)
769 {
770 m_CurrentRenderTargets.push_back(pTexture->m_pRenderTargetView.Get());
771 }
772
773 if (pTexture->m_pDepthStencilView)
774 {
775 m_pCurrentDepthStencilView = pTexture->m_pDepthStencilView;
776 }
777
778 static ID3D11ShaderResourceView * NullResourceView[1] = { nullptr };
779 m_pImmediateContext->PSSetShaderResources(
780 pTexture->m_iDestination, 1, NullResourceView);
781 }
782
783 if (m_CurrentRenderTargets.empty())
784 {
785 m_CurrentRenderTargets = { nullptr };
786 }
787
788 m_pImmediateContext->OMSetRenderTargets(
789 static_cast<UINT>(m_CurrentRenderTargets.size()),
790 &m_CurrentRenderTargets[0], nullptr);
791 };
792}
793
794auto DirectX11::CreateState(const ComponentPtr_t & _pComponent) -> Render_t /*override*/
795{
796 const auto CreateSamplerState = [&](void)
797 {
798 D3D11_SAMPLER_DESC SamplerDesc = { 0 };
799 SamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
800 SamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
801 SamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
802 SamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
803 SamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
804 SamplerDesc.MinLOD = 0;
805 SamplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
806
807 ComPtr_t<ID3D11SamplerState> pSamplerState;
808 DX_CHECK m_pDevice->CreateSamplerState(&SamplerDesc, &pSamplerState);
809
810 return [=](void)
811 {
812 m_pImmediateContext->PSSetSamplers(0, 1, pSamplerState.GetAddressOf());
813 };
814 };
815
816 const auto CreateScissorState = [&](void)
817 {
818 const Component::Scissor ScissorData{ *_pComponent };
819
820 D3D11_RASTERIZER_DESC rasterDesc = { 0 };
821 rasterDesc.FillMode = D3D11_FILL_SOLID;
822 rasterDesc.CullMode = D3D11_CULL_BACK;
823 rasterDesc.FrontCounterClockwise = TRUE;
824 rasterDesc.ScissorEnable = (ScissorData.IsEnabled) ? TRUE : FALSE;
825
826 ComPtr_t<ID3D11RasterizerState> pScissor;
827 DX_CHECK m_pDevice->CreateRasterizerState(&rasterDesc, &pScissor);
828
829 const auto pScissorRect = CapturingServiceComponent::Get(_pComponent,
830 { {uT("Rect"), _pComponent} })[0];
831
832 Render_t ScissorEnabled = [=](void)
833 {
834 const Component::Scissor ScissorRect{ *pScissorRect };
835
836 D3D11_RECT Rect = { 0 };
837 Rect.left = ScissorRect.Left;
838 Rect.right = ScissorRect.Right;
839 Rect.top = ScissorRect.Top;
840 Rect.bottom = ScissorRect.Bottom;
841
842 m_pImmediateContext->RSSetScissorRects(1, &Rect);
843 m_pImmediateContext->RSSetState(pScissor.Get());
844 };
845
846 Render_t ScissorDisabled = [=](void)
847 {
848 m_pImmediateContext->RSSetState(pScissor.Get());
849 };
850
851 return (ScissorData.IsEnabled) ? ScissorEnabled : ScissorDisabled;
852 };
853
854 const auto CreateDepthState = [&](void)
855 {
856 return GetDepthState(
857 (*_pComponent)[uT("enabled")].Default(false),
858 (*_pComponent)[uT("clear")].Default(false),
859 (*_pComponent)[uT("overwrite")].Default(true));
860 };
861
862 const auto CreateClearState = [&](void)
863 {
864 const auto ARGBtoFloat4 = [](const uint32_t _HexColor)
865 {
866 return ::std::vector<FLOAT>
867 {
868 ((_HexColor & 0x00FF0000) >> 16) / 255.0f,
869 ((_HexColor & 0x0000FF00) >> 8) / 255.0f,
870 ((_HexColor & 0x000000FF) >> 0) / 255.0f,
871 ((_HexColor & 0xFF000000) >> 24) / 255.0f,
872 };
873 };
874 const auto BackgroundColor =
875 ARGBtoFloat4((*_pComponent)[uT("color")].Default(0xFF000000));
876
877 return [=](void)
878 {
879 for (auto * pRenderTargetView : m_CurrentRenderTargets)
880 {
881 m_pImmediateContext->ClearRenderTargetView(
882 pRenderTargetView, BackgroundColor.data());
883 }
884 };
885 };
886
887 const auto CreateAlphaTestState = [&](void)
888 {
889 return nullptr;
890 };
891
892 ::std::map<String_t, ::std::function<Render_t(void)>> Creators =
893 {
894 { uT("Blend"), [&](void) { return CreateBlendState(true); } },
895 { uT("Sampler"), CreateSamplerState },
896 { uT("Scissor"), CreateScissorState },
897 { uT("Depth"), CreateDepthState },
898 { uT("Clear"), CreateClearState },
899 { uT("AlphaTest"), CreateAlphaTestState },
900 };
901
902 return Creators[_pComponent->Kind]();
903}
904
905auto DirectX11::CreateTexture(const ComponentPtr_t & _pComponent) -> Render_t /*override*/
906{
907 using BufferMapper_t = cbBufferMap_t<const void>;
908
909 const auto pTextureData = CapturingServiceComponent::Get(_pComponent,
910 { { uT("Texture"), _pComponent } })[0];
911
912 const Component::Texture TextureData{ *pTextureData, uT("albedo") };
913
914 Texture::Ptr_t pTexture;
915
916 ::std::weak_ptr<Texture> wpTexture = (*pTextureData)[uT("entity")]
917 .Default(::std::weak_ptr<Texture>{});
918 if (wpTexture.lock() == nullptr)
919 {
920 pTexture = ::std::make_shared<Texture>(pTextureData);
921 pTexture->MakeSource(m_pDevice, m_pImmediateContext,
922 static_cast<UINT>(TextureData.Width), static_cast<UINT>(TextureData.Height),
923 TextureData.Data.data(), TextureData.IsUsingMipmapping);
924 }
925 else
926 {
927 pTexture = wpTexture.lock();
928 (*pTextureData)[uT("entity")] = ::std::weak_ptr<Texture>{};
929 }
930
931 if (pTexture->m_pReadDataTexture == nullptr)
932 {
933 return [=](void)
934 {
935 m_pImmediateContext->PSSetShaderResources(pTexture->m_iDestination, 1,
936 pTexture->m_pShaderResourceView.GetAddressOf());
937 };
938 }
939
940 const BufferMapper_t cbBufferMapper =
941 (*pTextureData)[uT("mapper")].Default(BufferMapper_t{});
942
943 return [=](void)
944 {
945 if (cbBufferMapper(nullptr))
946 {
947 m_pImmediateContext->CopyResource(
948 pTexture->m_pReadDataTexture.Get(), pTexture->m_pTexture.Get());
949
950 D3D11_MAPPED_SUBRESOURCE Resource = { 0 };
951 DX_CHECK m_pImmediateContext->Map(pTexture->m_pReadDataTexture.Get(), 0,
952 D3D11_MAP_READ, 0, &Resource);
953 cbBufferMapper(Resource.pData);
954 m_pImmediateContext->Unmap(pTexture->m_pReadDataTexture.Get(), 0);
955 }
956
957 m_pImmediateContext->PSSetShaderResources(pTexture->m_iDestination, 1,
958 pTexture->m_pShaderResourceView.GetAddressOf());
959 };
960}
961
962auto DirectX11::CreateShader(const ComponentPtr_t & _pComponent) -> Render_t /*override*/
963{
964 using namespace ::alicorn::extension::std;
965
966 const auto pShaderDataComponent = CapturingServiceComponent::Get(_pComponent,
967 { { uT("Shader"), _pComponent } })[0];
968
969 const Component::Shader ShaderData{ *pShaderDataComponent, ::Default };
970
971 ::std::string Define =
972 "#define COVELLITE_SHADER_DESKTOP\r\n"
973 "#define COVELLITE_SHADER_HLSL\r\n"
974 "#define COVELLITE_SHADER_VERTEX\r\n";
975 const auto HeaderShaderText = ::Predefined + ::Data +
976 ShaderData.GetInstanceInput(::Input);
977 auto ShaderText = ShaderData.Data;
978 ::std::string Entry = ShaderData.Entry;
979
980 if (ShaderData.Kind == uT("Pixel"))
981 {
982 Define =
983 "#define COVELLITE_SHADER_DESKTOP\r\n"
984 "#define COVELLITE_SHADER_HLSL\r\n"
985 "#define COVELLITE_SHADER_PIXEL\r\n";
986
987 if (ShaderData.ReturnType == "float4" ||
988 ShaderData.ReturnType == "vec4")
989 {
990 ShaderText += DirectX::Shader::Convert(
991 "float4 psMain(Pixel _Value) : SV_Target\r\n"
992 "{\r\n"
993 " return " + Entry + "(_Value);\r\n"
994 "}\r\n");
995 Entry = "psMain";
996 }
997 }
998
999 const auto pCompiledShader = DirectX::Shader::Compile(
1000 DirectX::Shader::Convert(Define) + HeaderShaderText, ShaderText,
1001 Entry.c_str(), DirectX::Shader::GetVersion(ShaderData.Kind).c_str());
1002
1003 const auto VertexShader =
1004 [&](const ::std::vector<D3D11_INPUT_ELEMENT_DESC> & _LayoutDesc)
1005 {
1006 const auto * const pData = pCompiledShader->GetBufferPointer();
1007 const auto DataSize = pCompiledShader->GetBufferSize();
1008
1009 ComPtr_t<ID3D11InputLayout> pVertexLayout;
1010 DX_CHECK m_pDevice->CreateInputLayout(
1011 _LayoutDesc.data(), static_cast<UINT>(_LayoutDesc.size()),
1012 pData, DataSize,
1013 &pVertexLayout);
1014
1015 ComPtr_t<ID3D11VertexShader> pVertexShader;
1016 DX_CHECK m_pDevice->CreateVertexShader(
1017 pData, DataSize,
1018 NULL, &pVertexShader);
1019
1020 return [=](void)
1021 {
1022 m_pImmediateContext->IASetInputLayout(pVertexLayout.Get());
1023 m_pImmediateContext->VSSetShader(pVertexShader.Get(), NULL, 0);
1024 };
1025 };
1026
1027 if (ShaderData.Kind == uT("Polygon"))
1028 {
1029 return VertexShader(
1030 {
1031 { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
1032 { "COLOR", 0, DXGI_FORMAT_R32_UINT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 },
1033 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
1034 });
1035 }
1036 else if (ShaderData.Kind == uT("Polyhedron"))
1037 {
1038 return VertexShader(
1039 {
1040 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
1041 { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
1042 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
1043 });
1044 }
1045 else if (ShaderData.Kind == uT("Vertex"))
1046 {
1047 ::std::vector<D3D11_INPUT_ELEMENT_DESC> LayoutDesc =
1048 {
1049 { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
1050 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0 },
1051 { "NORMAL", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
1052 };
1053
1054 for (UINT i = 0; i < static_cast<UINT>(ShaderData.Instance.size()); i++)
1055 {
1056 const auto Type = ShaderData.Instance[i];
1057 const auto Format =
1058 (Type == uT("f")) ? DXGI_FORMAT_R32G32B32A32_FLOAT :
1059 (Type == uT("i")) ? DXGI_FORMAT_R32G32B32A32_SINT :
1060 DXGI_FORMAT_UNKNOWN;
1061 const auto Size = i * 4 * static_cast<UINT>(
1062 (Type == uT("f")) ? sizeof(float) :
1063 // cppcheck-suppress sizeofDereferencedVoidPointer
1064 (Type == uT("i")) ? sizeof(int) :
1065 0);
1066
1067 LayoutDesc.push_back(
1068 {
1069 "TEXCOORD", i + 1, Format, 1, Size, D3D11_INPUT_PER_INSTANCE_DATA, 1
1070 });
1071 }
1072
1073 return VertexShader(LayoutDesc);
1074 }
1075
1076 ComPtr_t<ID3D11PixelShader> pPixelShader;
1077 DX_CHECK m_pDevice->CreatePixelShader(
1078 pCompiledShader->GetBufferPointer(), pCompiledShader->GetBufferSize(),
1079 NULL, &pPixelShader);
1080
1081 return [=](void)
1082 {
1083 m_pImmediateContext->PSSetShader(pPixelShader.Get(), NULL, 0);
1084 };
1085}
1086
1087auto DirectX11::CreateBuffer(const ComponentPtr_t & _pComponent) -> Render_t /*override*/
1088{
1089 const auto pBufferData = CapturingServiceComponent::Get(_pComponent,
1090 { { uT("Buffer"), _pComponent } })[0];
1091
1092 if ((*pBufferData)[uT("content")].IsType<Buffer_t<::covellite::api::Vertex>>())
1093 {
1094 using BufferMapper_t = cbBufferMap_t<::covellite::api::Vertex>;
1095
1096 const Component::Buffer<::covellite::api::Vertex> VertexData{ *pBufferData };
1097
1098 const BufferMapper_t & cbBufferMapper =
1099 (*_pComponent)[uT("mapper")].Default(BufferMapper_t{});
1100
1101 auto pBuffer = Buffer::Create(m_pDevice, (cbBufferMapper != nullptr),
1102 VertexData.Data.data(), VertexData.Data.size());
1103
1104 const Render_t StaticRender = [=](void)
1105 {
1106 constexpr UINT Stride = sizeof(::covellite::api::Vertex);
1107 constexpr UINT Offset = 0;
1108 m_pImmediateContext->IASetVertexBuffers(0, 1,
1109 pBuffer.GetAddressOf(), &Stride, &Offset);
1110 };
1111
1112 const Render_t DynamicRender = [=](void)
1113 {
1114 const auto IsDirty = cbBufferMapper(nullptr);
1115 if (IsDirty)
1116 {
1117 D3D11_MAPPED_SUBRESOURCE Resource = { 0 };
1118 DX_CHECK m_pImmediateContext->Map(pBuffer.Get(), 0,
1119 D3D11_MAP_WRITE_NO_OVERWRITE, 0, &Resource);
1120 cbBufferMapper(static_cast<::covellite::api::Vertex *>(Resource.pData));
1121 m_pImmediateContext->Unmap(pBuffer.Get(), 0);
1122 }
1123
1124 StaticRender();
1125 };
1126
1127 return (cbBufferMapper == nullptr) ? StaticRender : DynamicRender;
1128 }
1129 else if ((*_pComponent)[uT("mapper")].IsType<const cbBufferMap_t<void> &>())
1130 {
1131 using BufferMap_t = cbBufferMap_t<void>;
1132
1133 const BufferMap_t cbBufferMapper =
1134 (*_pComponent)[uT("mapper")].Default(BufferMap_t{});
1135 if (!cbBufferMapper)
1136 {
1137 throw STD_EXCEPTION << "Unexpected empty mapper: " << _pComponent->Id;
1138 }
1139
1140 const ::std::size_t BufferSize =
1141 (*pBufferData)[uT("size")].Default((::std::size_t)0);
1142 if (BufferSize == 0)
1143 {
1144 throw STD_EXCEPTION << "Unexpected zero size: " << _pComponent->Id;
1145 }
1146
1147 const auto pData =
1148 ::std::make_shared<BinaryData_t>(BufferSize, (uint8_t)0x00);
1149 const auto pBuffer = Buffer::Create(
1150 m_pDevice, false, pData->data(), pData->size());
1151 constexpr auto BufferIndex =
1152 Buffer::Support<BinaryData_t::value_type>::Index;
1153
1154 return [=](void)
1155 {
1156 // Получение константного буфера по имени: https://docs.microsoft.com/en-us/windows/win32/api/d3d11shader/nf-d3d11shader-id3d11shaderreflection-getconstantbufferbyname
1157 cbBufferMapper(pData->data());
1158
1159 // Поскольку каждый буфер индивидуален, но работает через один и тот же
1160 // слот, то и активировать его нужно каждый раз.
1161 m_pImmediateContext->VSSetConstantBuffers(
1162 BufferIndex, 1, pBuffer.GetAddressOf());
1163 m_pImmediateContext->PSSetConstantBuffers(
1164 BufferIndex, 1, pBuffer.GetAddressOf());
1165
1166 m_pImmediateContext->UpdateSubresource(
1167 pBuffer.Get(), 0, NULL, pData->data(), 0, 0);
1168 };
1169 }
1170
1171 throw STD_EXCEPTION << "Unexpected buffer type: " << _pComponent->Id;
1172}
1173
1174auto DirectX11::CreateTransform(const ComponentPtr_t & _pComponent) -> Render_t /*override*/
1175{
1176 const auto BuildTransformMatrix =
1177 (_pComponent->Kind == uT("Unknown")) ? CreateDefaultTransformRender<::Object>(_pComponent) :
1178 (_pComponent->Kind == uT("Static")) ? CreateStaticTransformRender<::Object>(_pComponent) :
1179 (_pComponent->Kind == uT("Billboard")) ? CreateBillboardTransformRender<::Camera, ::Object>(_pComponent) :
1180 throw STD_EXCEPTION << "Unexpected transform component: " <<
1181 " [id=" << _pComponent->Id << ", kind=" << _pComponent->Kind << "].";
1182
1183 return [=](void)
1184 {
1185 BuildTransformMatrix();
1186 m_pConstants->Update<::Object>();
1187 };
1188}
1189
1190auto DirectX11::CreatePresentBuffer(const ComponentPtr_t & _pComponent) ->Render_t /*override*/
1191{
1192 using BufferMapperMaxSize_t = ::std::function<bool(void *)>;
1193 using BufferMapperChangeSize_t = ::std::function<bool(void *, ::std::size_t &)>;
1194
1195 ComponentPtr_t pIndexBufferData = _pComponent;
1196 ComponentPtr_t pInstanceBufferData = nullptr;
1197
1198 const auto SaveBuffer = [&](const ComponentPtr_t & _pBufferData)
1199 {
1200 if ((*_pBufferData)[uT("content")].IsType<Buffer_t<int>>())
1201 {
1202 pIndexBufferData = _pBufferData;
1203 }
1204 else if ((*_pBufferData)[uT("mapper")].IsType<const BufferMapperMaxSize_t &>())
1205 {
1206 pInstanceBufferData = _pBufferData;
1207 }
1208 else if ((*_pBufferData)[uT("mapper")].IsType<const BufferMapperChangeSize_t &>())
1209 {
1210 pInstanceBufferData = _pBufferData;
1211 }
1212 else
1213 {
1214 throw STD_EXCEPTION << "Unexpected buffer data component.";
1215 }
1216 };
1217
1218 CapturingServiceComponent::Process(_pComponent,
1219 {
1220 { uT("Buffer"), SaveBuffer },
1221 });
1222
1223 const Component::Buffer<int> IndexBufferData{ *pIndexBufferData };
1224
1225 const auto pIndexBuffer = Buffer::Create(m_pDevice, false,
1226 IndexBufferData.Data.data(), IndexBufferData.Data.size());
1227 const auto IndexCount = static_cast<DWORD>(IndexBufferData.Data.size());
1228
1229 if (pInstanceBufferData == nullptr)
1230 {
1231 return [=](void)
1232 {
1233 m_pImmediateContext->IASetIndexBuffer(
1234 pIndexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);
1235 m_pImmediateContext->IASetPrimitiveTopology(
1236 D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
1237 m_pImmediateContext->DrawIndexed(IndexCount, 0, 0);
1238 };
1239 }
1240
1241 const ::std::size_t BufferSize = (*pInstanceBufferData)[uT("size")];
1242 if (BufferSize % 16 != 0)
1243 {
1244 throw STD_EXCEPTION << _pComponent->Id << ": size % 16 != 0";
1245 }
1246
1247 const ::std::size_t MaxInstanceCount = (*pInstanceBufferData)[uT("count")];
1248 if (BufferSize % MaxInstanceCount != 0)
1249 {
1250 throw STD_EXCEPTION << _pComponent->Id << ": size % count != 0";
1251 }
1252
1253 const auto Stride = static_cast<UINT>(BufferSize / MaxInstanceCount);
1254
1255 const auto pInstanceBuffer =
1256 Buffer::Create<int8_t>(m_pDevice, true, nullptr, BufferSize);
1257
1258 if ((*pInstanceBufferData)[uT("mapper")].IsType<BufferMapperMaxSize_t>())
1259 {
1260 const BufferMapperMaxSize_t cbBufferMapper =
1261 (*pInstanceBufferData)[uT("mapper")];
1262
1263 return [=](void)
1264 {
1265 const auto IsDirty = cbBufferMapper(nullptr);
1266 if (IsDirty)
1267 {
1268 D3D11_MAPPED_SUBRESOURCE Resource = { 0 };
1269 DX_CHECK m_pImmediateContext->Map(pInstanceBuffer.Get(), 0,
1270 D3D11_MAP_WRITE_NO_OVERWRITE, 0, &Resource);
1271 cbBufferMapper(Resource.pData);
1272 m_pImmediateContext->Unmap(pInstanceBuffer.Get(), 0);
1273 }
1274
1275 constexpr UINT Offset = 0;
1276 m_pImmediateContext->IASetVertexBuffers(
1277 1, 1, pInstanceBuffer.GetAddressOf(), &Stride, &Offset);
1278 m_pImmediateContext->IASetIndexBuffer(
1279 pIndexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);
1280 m_pImmediateContext->IASetPrimitiveTopology(
1281 D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
1282 m_pImmediateContext->DrawIndexedInstanced(
1283 IndexCount, static_cast<UINT>(MaxInstanceCount), 0, 0, 0);
1284 };
1285 }
1286
1287 const BufferMapperChangeSize_t cbBufferMapper =
1288 (*pInstanceBufferData)[uT("mapper")];
1289
1290 return [=](void)
1291 {
1292 auto InstanceCount = MaxInstanceCount;
1293
1294 const auto IsDirty = cbBufferMapper(nullptr, InstanceCount);
1295 if (IsDirty)
1296 {
1297 D3D11_MAPPED_SUBRESOURCE Resource = { 0 };
1298 DX_CHECK m_pImmediateContext->Map(pInstanceBuffer.Get(), 0,
1299 D3D11_MAP_WRITE_NO_OVERWRITE, 0, &Resource);
1300 cbBufferMapper(Resource.pData, InstanceCount);
1301 m_pImmediateContext->Unmap(pInstanceBuffer.Get(), 0);
1302 }
1303
1304 InstanceCount = ::std::min(InstanceCount, MaxInstanceCount);
1305
1306 constexpr UINT Offset = 0;
1307 m_pImmediateContext->IASetVertexBuffers(
1308 1, 1, pInstanceBuffer.GetAddressOf(), &Stride, &Offset);
1309 m_pImmediateContext->IASetIndexBuffer(
1310 pIndexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);
1311 m_pImmediateContext->IASetPrimitiveTopology(
1312 D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
1313 m_pImmediateContext->DrawIndexedInstanced(
1314 IndexCount, static_cast<UINT>(InstanceCount), 0, 0, 0);
1315 };
1316}
1317
1318auto DirectX11::CreateBlendState(bool _IsEnabled) -> Render_t
1319{
1320 ComPtr_t<ID3D11BlendState> pBlendState;
1321
1322 if (_IsEnabled)
1323 {
1324 D3D11_BLEND_DESC BlendDesc = { 0 };
1325 BlendDesc.AlphaToCoverageEnable = FALSE;
1326 BlendDesc.IndependentBlendEnable = FALSE;
1327
1328 for (auto & RenderTarget : BlendDesc.RenderTarget)
1329 {
1330 RenderTarget.BlendEnable = TRUE;
1331 RenderTarget.SrcBlend = D3D11_BLEND_SRC_ALPHA;
1332 RenderTarget.DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
1333 RenderTarget.BlendOp = D3D11_BLEND_OP_ADD;
1334 RenderTarget.SrcBlendAlpha = D3D11_BLEND_ONE;
1335 RenderTarget.DestBlendAlpha = D3D11_BLEND_ZERO;
1336 RenderTarget.BlendOpAlpha = D3D11_BLEND_OP_ADD;
1337 RenderTarget.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
1338 }
1339
1340 DX_CHECK m_pDevice->CreateBlendState(&BlendDesc, &pBlendState);
1341 }
1342
1343 return [=](void)
1344 {
1345 const FLOAT BlendFactor[] = { 0.0f, 0.0f, 0.0f, 0.0f };
1346 m_pImmediateContext->OMSetBlendState(
1347 pBlendState.Get(), BlendFactor, 0xFFFFFFFF);
1348 };
1349}
1350
1352 const bool _IsEnabled,
1353 const bool _IsClear,
1354 const bool _IsOverwrite) -> Render_t
1355{
1356 if (!_IsEnabled)
1357 {
1358 return [=](void)
1359 {
1360 m_pImmediateContext->OMSetRenderTargets(
1361 static_cast<UINT>(m_CurrentRenderTargets.size()),
1362 &m_CurrentRenderTargets[0], nullptr);
1363 };
1364 }
1365
1366 D3D11_DEPTH_STENCIL_DESC DeptStencilDesc = { 0 };
1367 DeptStencilDesc.DepthEnable = true;
1368 DeptStencilDesc.DepthWriteMask = _IsOverwrite ?
1369 D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
1370 DeptStencilDesc.DepthFunc = D3D11_COMPARISON_GREATER;
1371 DeptStencilDesc.StencilEnable = false;
1372
1373 ComPtr_t<ID3D11DepthStencilState> pDSState;
1374 DX_CHECK m_pDevice->CreateDepthStencilState(&DeptStencilDesc, &pDSState);
1375
1376 Render_t RenderDepthEnabled = [=](void)
1377 {
1378 // 12 Октябрь 2019 16:04 (unicornum.verum@gmail.com)
1379 TODO("Тест того, что если BkSurface не устанавливает буфер глубины, то используется буфер глубины экрана");
1380
1381 m_pImmediateContext->OMSetDepthStencilState(pDSState.Get(), 1);
1382 m_pImmediateContext->OMSetRenderTargets(
1383 static_cast<UINT>(m_CurrentRenderTargets.size()),
1384 &m_CurrentRenderTargets[0], m_pCurrentDepthStencilView.Get());
1385 };
1386
1387 Render_t RenderDepthClear = [=](void)
1388 {
1389 // 12 Октябрь 2019 16:04 (unicornum.verum@gmail.com)
1390 TODO("Тест того, что если BkSurface не устанавливает буфер глубины, то используется буфер глубины экрана");
1391
1392 m_pImmediateContext->OMSetDepthStencilState(pDSState.Get(), 1);
1393 m_pImmediateContext->OMSetRenderTargets(
1394 static_cast<UINT>(m_CurrentRenderTargets.size()),
1395 &m_CurrentRenderTargets[0], m_pCurrentDepthStencilView.Get());
1396 m_pImmediateContext->ClearDepthStencilView(m_pCurrentDepthStencilView.Get(),
1397 D3D11_CLEAR_DEPTH, 0.0f, 0);
1398 };
1399
1400 return _IsClear ? RenderDepthClear : RenderDepthEnabled;
1401}
1402
1403template<class TConstantBuffer>
1404auto DirectX11::CreateDefaultTransformRender(
1405 const ComponentPtr_t & _pComponent) -> Render_t
1406{
1407 ::std::deque<Render_t> PreRenders;
1408
1409 auto CreatePosition = [&](const ComponentPtr_t & _pPosition)
1410 {
1411 PreRenders.push_front([=](void)
1412 {
1413 auto & World = m_pConstants->Get<TConstantBuffer>().World;
1414
1415 const Component::Position Position{ *_pPosition };
1416
1417 World = ::glm::translate(World,
1418 ::glm::vec3{ Position.X, Position.Y, Position.Z });
1419 });
1420 };
1421
1422 auto CreateRotation = [&](const ComponentPtr_t & _pRotation)
1423 {
1424 PreRenders.push_front([=](void)
1425 {
1426 auto & World = m_pConstants->Get<::Object>().World;
1427
1428 const Component::Rotation Rotation{ *_pRotation };
1429
1430 World = ::glm::rotate(World, Rotation.Z, ::glm::vec3{ 0.0f, 0.0f, 1.0f });
1431 World = ::glm::rotate(World, Rotation.Y, ::glm::vec3{ 0.0f, 1.0f, 0.0f });
1432 World = ::glm::rotate(World, Rotation.X, ::glm::vec3{ 1.0f, 0.0f, 0.0f });
1433 });
1434 };
1435
1436 auto CreateScale = [&](const ComponentPtr_t & _pScale)
1437 {
1438 PreRenders.push_front([=](void)
1439 {
1440 auto & World = m_pConstants->Get<::Object>().World;
1441
1442 const Component::Scale Scale{ *_pScale };
1443
1444 World = ::glm::scale(World, ::glm::vec3{ Scale.X, Scale.Y, Scale.Z });
1445 });
1446 };
1447
1448 PreRenders.push_front([=](void)
1449 {
1450 m_pConstants->Get<::Object>().World =
1451 ::glm::transpose(m_pConstants->Get<::Object>().World);
1452 });
1453
1454 CapturingServiceComponent::Process(_pComponent,
1455 {
1456 { uT("Position"), CreatePosition },
1457 { uT("Rotation"), CreateRotation },
1458 { uT("Scale"), CreateScale },
1459 });
1460
1461 PreRenders.push_front([=](void)
1462 {
1463 m_pConstants->Get<::Object>().World = ::glm::identity<::glm::mat4>();
1464 });
1465
1466 return [PreRenders](void)
1467 {
1468 for (auto & Render : PreRenders) Render();
1469 };
1470}
1471
1472template<class TConstantBuffer>
1473auto DirectX11::CreateStaticTransformRender(const ComponentPtr_t & _pComponent) -> Render_t
1474{
1475 CreateDefaultTransformRender<TConstantBuffer>(_pComponent)();
1476 const auto World = m_pConstants->Get<TConstantBuffer>().World;
1477
1478 return [=](void)
1479 {
1480 m_pConstants->Get<TConstantBuffer>().World = World;
1481 };
1482}
1483
1484template<class TCamera, class TConstantBuffer>
1485auto DirectX11::CreateBillboardTransformRender(const ComponentPtr_t & _pComponent) -> Render_t
1486{
1487 ::std::deque<Render_t> PreRenders;
1488
1489 auto CreatePosition = [&](const ComponentPtr_t & _pPosition)
1490 {
1491 PreRenders.push_front([=](void)
1492 {
1493 auto & World = m_pConstants->Get<TConstantBuffer>().World;
1494
1495 const Component::Position Position{ *_pPosition };
1496
1497 World = ::glm::translate(World,
1498 ::glm::vec3{ Position.X, Position.Y, Position.Z });
1499 });
1500 };
1501
1502 PreRenders.push_front([=](void)
1503 {
1504 m_pConstants->Get<TConstantBuffer>().World =
1505 ::glm::transpose(m_pConstants->Get<TConstantBuffer>().World);
1506 });
1507
1508 CapturingServiceComponent::Process(_pComponent,
1509 { { uT("Position"), CreatePosition } });
1510
1511 PreRenders.push_front([=](void)
1512 {
1513 auto & World = m_pConstants->Get<TConstantBuffer>().World;
1514
1515 // Матрица View уже траспонированная!
1516 World = m_pConstants->Get<::Camera>().View;
1517
1518 World[0][3] = 0.0f;
1519 World[1][3] = 0.0f;
1520 World[2][3] = 0.0f;
1521 World[3][0] = 0.0f;
1522 World[3][1] = 0.0f;
1523 World[3][2] = 0.0f;
1524 World[3][3] = 1.0f;
1525 });
1526
1527 return [PreRenders](void)
1528 {
1529 for (auto & Render : PreRenders) Render();
1530 };
1531}
1532
1533} // namespace renderer
1534
1535} // namespace api
1536
1537} // namespace covellite
#define DX_CHECK
Класс входит в проект Covellite.Api Макрос проверок вызова функций DirectX.
Definition DxCheck.hpp:59
static ComponentPtr_t Make(const SourceParams_t &)
Функция создания объектов компонентов.
Definition Component.inl:29
Render_t GetDepthState(const bool, const bool, const bool)
Definition DirectX11.cpp:1351
Render_t CreateBkSurface(const ComponentPtr_t &) override
Definition DirectX11.cpp:701
Класс входит в проект Covellite.Api Класс формата вертексного буфера.
Definition Vertex.hpp:34