// BKScreenD3D.cpp: определяет экспортированные функции для приложения DLL.
//
//ГЛЮЧИТ изменение размера. в результате мемлики получаются, и даже крах проги. Чё-то где-то как-то не согласуется между собой


#include "stdafx.h"
#include "Defines.h"
#include "BKMessageBox.h"

//эти вещи компилируются на лету, поэтому студия может ругаться, что инклуды не найдены
#include "PixelShader.hps"
#include "VertexShader.hvs"

#include <directxmath.h>
#include <directxcolors.h>
#include "BKScreenD3D.h"

#pragma comment (lib,"d3d11.lib")
#pragma comment (lib,"dxguid.lib")
#pragma comment (lib,"winmm.lib")

#ifdef _DEBUG
#include "..\DX11Err\DxErr.h"
#endif

using namespace DirectX;

struct SimpleVertex
{
	XMFLOAT3 Pos;
	XMFLOAT2 Tex;
};

struct CBNeverChanges
{
	XMMATRIX mView;
	XMMATRIX mProjection;

};

// struct CBChangeOnResize
// {
//  XMMATRIX mProjection;
// };

// struct CBChangesEveryFrame
// {
//  XMMATRIX mWorld;
// };


// CScreenD3D
BKEXTERN_C
{
	BKSCRDLL_API BKSCREENHANDLE APIENTRY GetBKScreen()
	{
		return new CScreenD3D;
	}

//	XMMATRIX                            g_World;
#ifdef _DEBUG
	const TCHAR *errstr;
#define DXERRORDESC_SIZE 1024
	TCHAR errdesc[DXERRORDESC_SIZE];
#endif

	CScreenD3D::CScreenD3D(void) : CBKScreen_Shared()
		, g_driverType(D3D_DRIVER_TYPE_NULL)
		, g_featureLevel(D3D_FEATURE_LEVEL_11_0)
		, g_pd3dDevice(nullptr)
		, g_pd3dDevice1(nullptr)
		, g_pImmediateContext(nullptr)
		, g_pImmediateContext1(nullptr)
		, g_pSwapChain(nullptr)
		, g_pSwapChain1(nullptr)
		, g_pRenderTargetView(nullptr)
//  , g_pDepthStencil(nullptr)
//  , g_pDepthStencilView(nullptr)
		, g_pVertexShader(nullptr)
		, g_pPixelShader(nullptr)
		, g_pVertexLayout(nullptr)
		, g_pVertexBuffer(nullptr)
		, g_pCBNeverChanges(nullptr)
//	, g_pCBChangeOnResize(nullptr)
//	, g_pCBChangesEveryFrame(nullptr)
		, m_pTexture(nullptr)
		, g_pTextureRV(nullptr)
		, g_pSamplerLinear(nullptr)
	{
		ZeroMemory(&m_fullScrMode, sizeof(DXGI_MODE_DESC));
		ZeroMemory(&m_windowMode, sizeof(DXGI_MODE_DESC));
	}

	CScreenD3D::~CScreenD3D()
	{
	}

// обработчики сообщений CScreenD3D

	void CScreenD3D::BKSS_OnSize(int cx, int cy)
	{
		if (m_hwndScreen && (cx | cy))
		{
			::GetClientRect(m_hwndScreen, &m_rectWnWnd);

			if (g_pSwapChain)
			{
				g_pImmediateContext->OMSetRenderTargets(0, nullptr, nullptr);
				// Release all outstanding references to the swap chain's buffers.
				g_pRenderTargetView->Release();
				HRESULT hr;
				// Preserve the existing buffer count and format.
				// Automatically choose the width and height to match the client rect for HWNDs.
				hr = g_pSwapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
				// Perform error handling here!
				// Get buffer and create a render-target-view.
				ID3D11Texture2D *pBuffer;
				hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&pBuffer);
				// Perform error handling here!
				hr = g_pd3dDevice->CreateRenderTargetView(pBuffer, nullptr, &g_pRenderTargetView);
				// Perform error handling here!
				pBuffer->Release();
				g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, nullptr);
				// Set up the viewport.
				D3D11_VIEWPORT vp;
//              vp.Width = (FLOAT)cx;
//              vp.Height = (FLOAT)cy;
				vp.Width = (FLOAT)m_rectWnWnd.right;
				vp.Height = (FLOAT)m_rectWnWnd.bottom;
				vp.MinDepth = 0.0f;
				vp.MaxDepth = 0.0f;
				vp.TopLeftX = 0;
				vp.TopLeftY = 0;
				g_pImmediateContext->RSSetViewports(1, &vp);
			}
		}
	}

	HRESULT CScreenD3D::BKSS_ScreenView_Init(ScrsParams & sspar, CWnd * pwndScr, CWnd * pwndFullScr)
	{
		CBKScreen_Shared::BKSS_ScreenView_Init(sspar, pwndScr, pwndFullScr);

		if (!m_hwndScreen)
		{
			return -1;
		}

		::GetClientRect(m_hwndScreen, &m_rectWnWnd);
		HRESULT hr = S_OK;
		UINT createDeviceFlags = 0;
#ifdef _DEBUG
		createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
		D3D_DRIVER_TYPE driverTypes[] =
		{
			D3D_DRIVER_TYPE_HARDWARE,
			D3D_DRIVER_TYPE_WARP,
			D3D_DRIVER_TYPE_REFERENCE,
		};
		UINT numDriverTypes = ARRAYSIZE(driverTypes);
		D3D_FEATURE_LEVEL featureLevels[] =
		{
			D3D_FEATURE_LEVEL_11_1,
			D3D_FEATURE_LEVEL_11_0,
			D3D_FEATURE_LEVEL_10_1,
			D3D_FEATURE_LEVEL_10_0,
			D3D_FEATURE_LEVEL_9_3,
			D3D_FEATURE_LEVEL_9_2,
			D3D_FEATURE_LEVEL_9_1
		};
		UINT numFeatureLevels = ARRAYSIZE(featureLevels);

		for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++)
		{
			g_driverType = driverTypes[driverTypeIndex];
			hr = D3D11CreateDevice(nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels,
			                       D3D11_SDK_VERSION, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext);

			if (hr == E_INVALIDARG)
			{
				// DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it
				hr = D3D11CreateDevice(nullptr, g_driverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1,
				                       D3D11_SDK_VERSION, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext);
			}

			if (SUCCEEDED(hr))
			{
				break;
			}
		}

		if (FAILED(hr))
		{
#ifdef _DEBUG
			errstr = DXGetErrorString(hr);
			DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
			CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
			AfxMessageBox(str, MB_OK);
#endif
			return hr;
		}

		// Obtain DXGI factory from device (since we used nullptr for pAdapter above)
		IDXGIFactory1 *dxgiFactory = nullptr;
		{
			IDXGIDevice *dxgiDevice = nullptr;
			hr = g_pd3dDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void **>(&dxgiDevice));

			if (SUCCEEDED(hr))
			{
				IDXGIAdapter *adapter = nullptr;
				hr = dxgiDevice->GetAdapter(&adapter);

				if (SUCCEEDED(hr))
				{
					hr = adapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast<void **>(&dxgiFactory));
					adapter->Release();
				}

				dxgiDevice->Release();
			}
		}

		if (FAILED(hr))
		{
#ifdef _DEBUG
			errstr = DXGetErrorString(hr);
			DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
			CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
			AfxMessageBox(str, MB_OK);
#endif
			return hr;
		}

		// Create swap chain
		IDXGIFactory2 *dxgiFactory2 = nullptr;
		hr = dxgiFactory->QueryInterface(__uuidof(IDXGIFactory2), reinterpret_cast<void **>(&dxgiFactory2));

		if (dxgiFactory2)
		{
			// DirectX 11.1 or later
			hr = g_pd3dDevice->QueryInterface(__uuidof(ID3D11Device1), reinterpret_cast<void **>(&g_pd3dDevice1));

			if (SUCCEEDED(hr))
			{
				(void)g_pImmediateContext->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void **>(&g_pImmediateContext1));
			}

			DXGI_SWAP_CHAIN_DESC1 sd;
			ZeroMemory(&sd, sizeof(sd));
			sd.Width = m_rectWnWnd.right;
			sd.Height = m_rectWnWnd.bottom;
			sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
			sd.SampleDesc.Count = 1;
			sd.SampleDesc.Quality = 0;
			sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
			sd.BufferCount = 2;
			sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
			sd.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
			DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsd;
			ZeroMemory(&fsd, sizeof(fsd));
			fsd.RefreshRate.Numerator = 60;
			fsd.RefreshRate.Denominator = 1;
			fsd.Scaling = DXGI_MODE_SCALING_CENTERED;
			fsd.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
			fsd.Windowed = TRUE;
			hr = dxgiFactory2->CreateSwapChainForHwnd(g_pd3dDevice, m_hwndScreen, &sd, &fsd, nullptr, &g_pSwapChain1);

			if (SUCCEEDED(hr))
			{
				hr = g_pSwapChain1->QueryInterface(__uuidof(IDXGISwapChain), reinterpret_cast<void **>(&g_pSwapChain));
			}

			dxgiFactory2->Release();
		}
		else
		{
			// DirectX 11.0 systems
			DXGI_SWAP_CHAIN_DESC sd;
			ZeroMemory(&sd, sizeof(sd));
			sd.BufferCount = 2;
			sd.BufferDesc.Width = m_rectWnWnd.right;
			sd.BufferDesc.Height = m_rectWnWnd.bottom;
			sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
			sd.BufferDesc.RefreshRate.Numerator = 60;
			sd.BufferDesc.RefreshRate.Denominator = 1;
			sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
			sd.OutputWindow = m_hwndScreen;
			sd.SampleDesc.Count = 1;
			sd.SampleDesc.Quality = 0;
			sd.Windowed = TRUE;
			sd.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
			sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
			hr = dxgiFactory->CreateSwapChain(g_pd3dDevice, &sd, &g_pSwapChain);
		}

		// Note this tutorial doesn't handle full-screen swapchains so we block the ALT+ENTER shortcut
		hr = dxgiFactory->MakeWindowAssociation(m_hwndScreen, DXGI_MWA_NO_ALT_ENTER);
		dxgiFactory->Release();

		if (FAILED(hr))
		{
#ifdef _DEBUG
			errstr = DXGetErrorString(hr);
			DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
			CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
			AfxMessageBox(str, MB_OK);
#endif
			return hr;
		}

		DXGI_SWAP_CHAIN_DESC swchDesc;
		hr = g_pSwapChain->GetDesc(&swchDesc);
		m_windowMode = swchDesc.BufferDesc;
		//ща поразбираемся с режимами
		IDXGIOutput *pOutput;
		hr = g_pSwapChain->GetContainingOutput(&pOutput);
		UINT numModes = -1;
		DXGI_MODE_DESC *pModes = nullptr;
		//Instead, use IDXGIOutput1::GetDisplayModeList1, which supports stereo display mode.
		//сперва узнаем сколько режимов вернёт функция
		hr = pOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &numModes, nullptr);

		if (numModes)
		{
			pModes = new DXGI_MODE_DESC[numModes];
			//теперь заполним массив
			hr = pOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &numModes, pModes);

			if (pModes)
			{
				UINT nModeNum = -1;
				UINT w = 0, h = 0;

				for (UINT i = 0; i < numModes; ++i)
				{
					if ((w < pModes[i].Width) || (h < pModes[i].Height))
					{
						//находим первое из наибольших разрешений
						w = pModes[i].Width;
						h = pModes[i].Height;
						nModeNum = i;
					}
				}

				m_fullScrMode = pModes[nModeNum];
				SAFE_DELETE_ARRAY(pModes);
			}
		}

		pOutput->Release();
		// Create a render target view
		ID3D11Texture2D *pBackBuffer = nullptr;
		hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&pBackBuffer));

		if (FAILED(hr))
		{
#ifdef _DEBUG
			errstr = DXGetErrorString(hr);
			DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
			CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
			AfxMessageBox(str, MB_OK);
#endif
			return hr;
		}

		hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_pRenderTargetView);
		pBackBuffer->Release();

		if (FAILED(hr))
		{
#ifdef _DEBUG
			errstr = DXGetErrorString(hr);
			DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
			CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
			AfxMessageBox(str, MB_OK);
#endif
			return hr;
		}

//      // Create depth stencil texture
//      D3D11_TEXTURE2D_DESC descDepth;
//      ZeroMemory(&descDepth, sizeof(descDepth));
//      descDepth.Width = m_rectWnWnd.right;
//      descDepth.Height = m_rectWnWnd.bottom;
//      descDepth.MipLevels = 1;
//      descDepth.ArraySize = 1;
//      descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
//      descDepth.SampleDesc.Count = 1;
//      descDepth.SampleDesc.Quality = 0;
//      descDepth.Usage = D3D11_USAGE_DEFAULT;
//      descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
//      descDepth.CPUAccessFlags = 0;
//      descDepth.MiscFlags = 0;
//      hr = g_pd3dDevice->CreateTexture2D(&descDepth, nullptr, &g_pDepthStencil);
//      if (FAILED(hr))
//      {
// #ifdef _DEBUG
//          errstr = DXGetErrorString(hr);
//          DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
//          CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
//          AfxMessageBox(str, MB_OK);
// #endif
//          return hr;
//      }
//
//      // Create the depth stencil view
//      D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
//      ZeroMemory(&descDSV, sizeof(descDSV));
//      descDSV.Format = descDepth.Format;
//      descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
//      descDSV.Texture2D.MipSlice = 0;
//      hr = g_pd3dDevice->CreateDepthStencilView(g_pDepthStencil, &descDSV, &g_pDepthStencilView);
//      if (FAILED(hr))
//      {
// #ifdef _DEBUG
//          errstr = DXGetErrorString(hr);
//          DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
//          CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
//          AfxMessageBox(str, MB_OK);
// #endif
//          return hr;
//      }
//		g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, g_pDepthStencilView);
		g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, nullptr);
		// Setup the viewport
		D3D11_VIEWPORT vp;
		vp.Width = (FLOAT)m_rectWnWnd.right;
		vp.Height = (FLOAT)m_rectWnWnd.bottom;
		vp.MinDepth = 0.0f;
		vp.MaxDepth = 0.0f;
		vp.TopLeftX = 0;
		vp.TopLeftY = 0;
		g_pImmediateContext->RSSetViewports(1, &vp);
		// Create the vertex shader
		hr = g_pd3dDevice->CreateVertexShader(g_vsshader, sizeof(g_vsshader), nullptr, &g_pVertexShader);

		if (FAILED(hr))
		{
#ifdef _DEBUG
			errstr = DXGetErrorString(hr);
			DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
			CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
			AfxMessageBox(str, MB_OK);
#endif
			return hr;
		}

		// Define the input layout
		D3D11_INPUT_ELEMENT_DESC layout[] =
		{
			{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
			{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		};
		UINT numElements = ARRAYSIZE(layout);
		// Create the input layout
		hr = g_pd3dDevice->CreateInputLayout(layout, numElements, g_vsshader, sizeof(g_vsshader), &g_pVertexLayout);

		if (FAILED(hr))
		{
#ifdef _DEBUG
			errstr = DXGetErrorString(hr);
			DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
			CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
			AfxMessageBox(str, MB_OK);
#endif
			return hr;
		}

		// Set the input layout
		g_pImmediateContext->IASetInputLayout(g_pVertexLayout);
		// Create the pixel shader
		hr = g_pd3dDevice->CreatePixelShader(g_psshader, sizeof(g_psshader), nullptr, &g_pPixelShader);

		if (FAILED(hr))
		{
#ifdef _DEBUG
			errstr = DXGetErrorString(hr);
			DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
			CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
			AfxMessageBox(str, MB_OK);
#endif
			return hr;
		}

		// Create vertex buffer
		SimpleVertex vertices[] =
		{
			{ XMFLOAT3(-1.0f,  1.0f, 0.0f), XMFLOAT2(0.0f, 0.0f) },
			{ XMFLOAT3(1.0f,  1.0f, 0.0f), XMFLOAT2(1.0f, 0.0f) },
			{ XMFLOAT3(-1.0f, -1.0f, 0.0f), XMFLOAT2(0.0f, 1.0f) },
			{ XMFLOAT3(1.0f, -1.0f, 0.0f), XMFLOAT2(1.0f, 1.0f) },
		};
		D3D11_BUFFER_DESC bd;
		ZeroMemory(&bd, sizeof(bd));
		bd.Usage = D3D11_USAGE_DEFAULT;
		bd.ByteWidth = sizeof(SimpleVertex) * ARRAYSIZE(vertices);
		bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		bd.CPUAccessFlags = 0;
		D3D11_SUBRESOURCE_DATA InitData;
		ZeroMemory(&InitData, sizeof(InitData));
		InitData.pSysMem = vertices;
		hr = g_pd3dDevice->CreateBuffer(&bd, &InitData, &g_pVertexBuffer);

		if (FAILED(hr))
		{
#ifdef _DEBUG
			errstr = DXGetErrorString(hr);
			DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
			CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
			AfxMessageBox(str, MB_OK);
#endif
			return hr;
		}

		// Set vertex buffer
		UINT stride = sizeof(SimpleVertex);
		UINT offset = 0;
		g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);
		// Set primitive topology
		g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
		// Create the constant buffers
		bd.Usage = D3D11_USAGE_DEFAULT;
		bd.ByteWidth = sizeof(CBNeverChanges);
		bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
		bd.CPUAccessFlags = 0;
		hr = g_pd3dDevice->CreateBuffer(&bd, nullptr, &g_pCBNeverChanges);

		if (FAILED(hr))
		{
#ifdef _DEBUG
			errstr = DXGetErrorString(hr);
			DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
			CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
			AfxMessageBox(str, MB_OK);
#endif
			return hr;
		}

//      bd.ByteWidth = sizeof(CBChangeOnResize);
//      hr = g_pd3dDevice->CreateBuffer(&bd, nullptr, &g_pCBChangeOnResize);
//      if (FAILED(hr))
//          return hr;
//      bd.ByteWidth = sizeof(CBChangesEveryFrame);
//      hr = g_pd3dDevice->CreateBuffer(&bd, nullptr, &g_pCBChangesEveryFrame);
//      if (FAILED(hr))
//          return hr;
		//создаём битмап
		SAFE_DELETE_ARRAY(m_bits); //на случай если будем пересоздавать этой функцией же.
		m_bits = new DWORD[m_nTextureWidth * m_nTextureHeight];
		ZeroMemory(m_bits, m_nTextureWidth * m_nTextureHeight * sizeof(DWORD));
		sspar.pBits = m_bits;
		//создаём текстуру
		D3D11_TEXTURE2D_DESC descTex;
		ZeroMemory(&descTex, sizeof(descTex));
		descTex.Width = m_nTextureWidth;
		descTex.Height = m_nTextureHeight;
		descTex.MipLevels = 1;
		descTex.ArraySize = 1;
		descTex.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
		descTex.SampleDesc.Count = 1;
		descTex.SampleDesc.Quality = 0;
		descTex.Usage = D3D11_USAGE_DEFAULT;
		descTex.BindFlags = D3D11_BIND_SHADER_RESOURCE;
		descTex.CPUAccessFlags = 0;
		descTex.MiscFlags = 0;
		hr = g_pd3dDevice->CreateTexture2D(&descTex, nullptr, &m_pTexture);

		if (FAILED(hr))
		{
#ifdef _DEBUG
			errstr = DXGetErrorString(hr);
			DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
			CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
			AfxMessageBox(str, MB_OK);
#endif
			return hr;
		}

		D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
		srvDesc.Format = descTex.Format;
		srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
		srvDesc.Texture2D.MipLevels = 1;
		srvDesc.Texture2D.MostDetailedMip = 0;
		hr = g_pd3dDevice->CreateShaderResourceView(m_pTexture, &srvDesc, &g_pTextureRV);

		if (FAILED(hr))
		{
#ifdef _DEBUG
			errstr = DXGetErrorString(hr);
			DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
			CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
			AfxMessageBox(str, MB_OK);
#endif
			return hr;
		}

		// Create the sample state
		D3D11_SAMPLER_DESC sampDesc;
		ZeroMemory(&sampDesc, sizeof(sampDesc));
		sampDesc.Filter = D3D11_FILTER_ANISOTROPIC; //D3D11_FILTER_MIN_MAG_MIP_POINT;
		sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
		sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
		sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
		sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
		sampDesc.MinLOD = 0;
		sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
		hr = g_pd3dDevice->CreateSamplerState(&sampDesc, &g_pSamplerLinear);

		if (FAILED(hr))
		{
#ifdef _DEBUG
			errstr = DXGetErrorString(hr);
			DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
			CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
			AfxMessageBox(str, MB_OK);
#endif
			return hr;
		}

		// Initialize the world matrices
		//g_World = XMMatrixIdentity();
		XMMATRIX g_View;
		XMMATRIX g_Projection;
		// Initialize the view matrix
		XMVECTOR Eye = XMVectorSet(0.0f, 0.0f, -1.0f, 0.0f);    // Точка из которой мы смотрим
		XMVECTOR At = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);      // Точка в которую смотрим
		XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);      // Где верх?
		g_View = XMMatrixLookAtLH(Eye, At, Up);
		CBNeverChanges cbNeverChanges;
		// Initialize the projection matrix
		//g_Projection = XMMatrixPerspectiveFovLH(XM_PIDIV4, 1.0f, 0.01f, 100.0f);
		g_Projection = XMMatrixOrthographicLH(2.0f, 2.0f, 0.0f, 1.0f);
		cbNeverChanges.mProjection = XMMatrixTranspose(g_Projection);
		cbNeverChanges.mView = XMMatrixTranspose(g_View);
		g_pImmediateContext->UpdateSubresource(g_pCBNeverChanges, 0, nullptr, &cbNeverChanges, 0, 0);
//      CBChangeOnResize cbChangesOnResize;
//      cbChangesOnResize.mProjection = XMMatrixTranspose(g_Projection);
//      g_pImmediateContext->UpdateSubresource(g_pCBChangeOnResize, 0, nullptr, &cbChangesOnResize, 0, 0);
		return S_OK;
	}

	void CScreenD3D::BKSS_ScreenView_Done()
	{
		if (g_pImmediateContext)
		{
			g_pImmediateContext->ClearState();
		}

		if (g_pSamplerLinear)
		{
			g_pSamplerLinear->Release();
		}

		if (g_pTextureRV)
		{
			g_pTextureRV->Release();
		}

		if (m_pTexture)
		{
			m_pTexture->Release();
		}

		if (g_pCBNeverChanges)
		{
			g_pCBNeverChanges->Release();
		}

//		if (g_pCBChangeOnResize) g_pCBChangeOnResize->Release();
//		if (g_pCBChangesEveryFrame) g_pCBChangesEveryFrame->Release();
		if (g_pVertexBuffer)
		{
			g_pVertexBuffer->Release();
		}

		if (g_pVertexLayout)
		{
			g_pVertexLayout->Release();
		}

		if (g_pVertexShader)
		{
			g_pVertexShader->Release();
		}

		if (g_pPixelShader)
		{
			g_pPixelShader->Release();
		}

//		if (g_pDepthStencil) g_pDepthStencil->Release();
//		if (g_pDepthStencilView) g_pDepthStencilView->Release();
		if (g_pRenderTargetView)
		{
			g_pRenderTargetView->Release();
		}

		if (g_pSwapChain1)
		{
			g_pSwapChain1->Release();
		}

		if (g_pSwapChain)
		{
			g_pSwapChain->Release();
		}

		if (g_pImmediateContext1)
		{
			g_pImmediateContext1->Release();
		}

		if (g_pImmediateContext)
		{
			g_pImmediateContext->Release();
		}

		if (g_pd3dDevice1)
		{
			g_pd3dDevice1->Release();
		}

		if (g_pd3dDevice)
		{
			g_pd3dDevice->Release();
		}

		SAFE_DELETE_ARRAY(m_bits);
	}

	void CScreenD3D::BKSS_DrawScreen()
	{
		// Source Row Pitch = [size of one element in bytes] * [number of elements in one row]
		// Source Depth Pitch = [Source Row Pitch] * [number of rows(height)]
		g_pImmediateContext->UpdateSubresource(m_pTexture, 0, nullptr, m_bits,
		                                       (sizeof(DWORD) * m_nTextureWidth),
		                                       (sizeof(DWORD) * m_nTextureWidth * m_nTextureHeight));
		// Update our time
//      static float t = 0.0f;
//      if (g_driverType == D3D_DRIVER_TYPE_REFERENCE)
//      {
//          t += (float)XM_PI * 0.0125f;
//      }
//      else
//      {
//          static ULONGLONG timeStart = 0;
//          ULONGLONG timeCur = GetTickCount64();
//          if (timeStart == 0)
//              timeStart = timeCur;
//          t = (timeCur - timeStart) / 1000.0f;
//      }
		//
		// Clear the back buffer
		//
		g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, Colors::Lime);
		//
		// Clear the depth buffer to 1.0 (max depth)
		//
		//g_pImmediateContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
		//
		// Update variables that change once per frame
		//
//      CBChangesEveryFrame cb;
//      cb.mWorld = XMMatrixRotationRollPitchYaw(t,t,t); //врааем по трём осям сразу
//      //cb.mWorld = XMMatrixTranspose(g_World);
//      g_pImmediateContext->UpdateSubresource(g_pCBChangesEveryFrame, 0, nullptr, &cb, 0, 0);
		//
		// Render the cube
		//
		g_pImmediateContext->VSSetShader(g_pVertexShader, nullptr, 0);
		g_pImmediateContext->VSSetConstantBuffers(0, 1, &g_pCBNeverChanges);
//		g_pImmediateContext->VSSetConstantBuffers(1, 1, &g_pCBChangeOnResize);
//		g_pImmediateContext->VSSetConstantBuffers(2, 1, &g_pCBChangesEveryFrame);
		g_pImmediateContext->PSSetShader(g_pPixelShader, nullptr, 0);
//		g_pImmediateContext->PSSetConstantBuffers(2, 1, &g_pCBChangesEveryFrame);
		g_pImmediateContext->PSSetShaderResources(0, 1, &g_pTextureRV);
		g_pImmediateContext->PSSetSamplers(0, 1, &g_pSamplerLinear);
		g_pImmediateContext->Draw(4, 0);
		//
		// Present our back buffer to our front buffer
		//
		g_pSwapChain->Present(0, 0);
	}

	bool CScreenD3D::BKSS_SetFullScreenMode()
	{
		bool bRet = false;

		if (!m_bFullScreen)
		{
			HRESULT hr;
			LONG_PTR r = SetWindowLongPtr(m_hwndScreen, GWL_STYLE, (GetWindowLongPtr(m_hwndScreen, GWL_STYLE) & ~WS_CHILD) | WS_POPUP | WS_OVERLAPPED);

			if (m_fullScrMode.Width)
			{
				RECT tRect;
				::GetClientRect(m_hwndScreen, &tRect);
				hr = g_pSwapChain->ResizeTarget(&m_fullScrMode);
				BKSS_OnSize(m_fullScrMode.Width, m_fullScrMode.Height);
				hr = g_pSwapChain->SetFullscreenState(TRUE, nullptr);

				if (SUCCEEDED(hr))
				{
					bRet = true;
					m_bFullScreen = true;
				}
				else
				{
#ifdef _DEBUG
					errstr = DXGetErrorString(hr);
					DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
					CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
					//AfxMessageBox(str, MB_OK);
#endif
					hr = g_pSwapChain->ResizeTarget(&m_windowMode);
					BKSS_OnSize(tRect.right, tRect.bottom);
				}
			}
		}

		return bRet;
	}

	bool CScreenD3D::BKSS_SetWindowMode()
	{
		bool bRet = false;

		if (m_bFullScreen)
		{
			HRESULT hr;
			SetWindowLongPtr(m_hwndScreen, GWL_STYLE, (GetWindowLongPtr(m_hwndScreen, GWL_STYLE) & ~(WS_POPUP | WS_OVERLAPPED)) | WS_CHILD);
			hr = g_pSwapChain->ResizeTarget(&m_windowMode);
			BKSS_OnSize(m_rectWnWnd.right, m_rectWnWnd.bottom);
			hr = g_pSwapChain->SetFullscreenState(FALSE, nullptr);

			if (SUCCEEDED(hr))
			{
				bRet = true;
				m_bFullScreen = false;
			}
			else
			{
#ifdef _DEBUG
				errstr = DXGetErrorString(hr);
				DXGetErrorDescription(hr, errdesc, DXERRORDESC_SIZE);
				CString str = CString(errstr) + _T("\r\n") + CString(errdesc);
				AfxMessageBox(str, MB_OK);
#endif
			}
		}

		return bRet;
	}

};
