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