text: #include "SSVPCH.h"
  
  #include "RenderLayer.h"
  
  #include "Client/Core/Application.h"
  
  namespace SSV::Client::Renderer
  {
  	RenderLayer::RenderLayer(const std::string& name, const int32_t zIndex, const D2D1_SIZE_U layerSize, const D2D1::ColorF clearColor, const Microsoft::WRL::ComPtr<ID2D1DeviceContext5>& deviceContext, const Microsoft::WRL::ComPtr<IDXGIFactory2>& dxgiFactory,
  		const Microsoft::WRL::ComPtr<IDXGIDevice>& dxgiDevice)
  		: Entity(name, zIndex), m_ClearColor(clearColor), m_DxgiDevice(dxgiDevice), m_DeviceContext(deviceContext), m_DxgiFactory(dxgiFactory)
  	{
  		SetRect({ 0, 0, static_cast<long>(layerSize.width), static_cast<long>(layerSize.height) });
  
  		CreateSwapChain();
  		CreateRenderTarget();
  	}
  
  	void RenderLayer::CreateSwapChain()
  	{
  		DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
  		swapChainDesc.Width = 1600;
  		swapChainDesc.Height = 900;
  		swapChainDesc.Format = DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM;
  		swapChainDesc.SampleDesc.Count = 1;
  		swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
  		swapChainDesc.BufferCount = 2;
  		swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
  		swapChainDesc.AlphaMode = DXGI_ALPHA_MODE::DXGI_ALPHA_MODE_PREMULTIPLIED;
  
  		DXCall(m_DxgiFactory->CreateSwapChainForComposition(m_DxgiDevice.Get(), &swapChainDesc, nullptr, m_SwapChain.GetAddressOf()));
  	}
  
  	void RenderLayer::CreateRenderTarget()
  	{
  		Microsoft::WRL::ComPtr<IDXGISurface1> dxgiSurface;
  		DXCall(m_SwapChain->GetBuffer(0, IID_PPV_ARGS(dxgiSurface.GetAddressOf())));
  
  		D2D1_BITMAP_PROPERTIES1 bitmapProps = {};
  		bitmapProps.pixelFormat = D2D1_PIXEL_FORMAT(DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE::D2D1_ALPHA_MODE_PREMULTIPLIED);
  		bitmapProps.dpiX = 96.f;
  		bitmapProps.dpiY = 96.f;
  		bitmapProps.bitmapOptions = D2D1_BITMAP_OPTIONS::D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS::D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
  
  		DXCall(m_DeviceContext->CreateBitmapFromDxgiSurface(dxgiSurface.Get(), &bitmapProps, m_RenderTarget.GetAddressOf()));
  	}
  
  	void RenderLayer::Resize(const D2D1_SIZE_U newClientSize)
  	{
  		CalculateViewLayout(newClientSize);
  		
  		// Passing zero value as a size of the buffer to ResizeBuffers causes it to fail
  		if (!(newClientSize.width > 0 && newClientSize.height > 0))
  			return;
  
  		if (!(GetRect().right - GetRect().left > 0 && GetRect().bottom - GetRect().top > 0))
  			return;
  
  		// Reset all references to the backbuffer of the swapchain, otherwise ResizeBuffers fails
  		m_DeviceContext->SetTarget(nullptr);
  		m_RenderTarget.Reset();
  
  		// Resize buffers
  		DXCall(m_SwapChain->ResizeBuffers(0, GetRect().right - GetRect().left, GetRect().bottom - GetRect().top, DXGI_FORMAT::DXGI_FORMAT_UNKNOWN, 0));
  
  		CreateRenderTarget();
  	}
  
  	void RenderLayer::Render()
  	{
  		// Call internal render function only when this layer is enabled
  		if (IsEnabled())
  			InternalRender();
  	}
  
  	void RenderLayer::InternalRender()
  	{
  		/* --- Pre Render --- */
  		if (!m_RenderTarget)
  			CreateRenderTarget();
  
  		m_DeviceContext->SetTarget(m_RenderTarget.Get());
  
  		m_DeviceContext->BeginDraw();
  
  		m_DeviceContext->Clear(GetClearColor());
  
  		/* --- Render UI (background + foregound + views)--- */
  		RenderBackground(m_DeviceContext);
  
  		RenderViews();
  
  		RenderForeground(m_DeviceContext);
  
  		/* --- Post Render --- */
  		HRESULT hr;
  
  		hr = m_DeviceContext->EndDraw();
  		if (hr == D2DERR_RECREATE_TARGET)
  		{
  			CreateRenderTarget();
  		}
  		DXCall(hr);
  
  		hr = m_SwapChain->Present(0, 0);
  		if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
  		{
  			throw RendererException("Rendering device has been lost", hr);
  		}
  		DXCall(hr);
  	}
  
  	void RenderLayer::RenderBackground(const Microsoft::WRL::ComPtr<ID2D1DeviceContext5>& deviceContext)
  	{
  	}
  
  	void RenderLayer::RenderForeground(const Microsoft::WRL::ComPtr<ID2D1DeviceContext5>& deviceContext)
  	{
  	}
  
  	void RenderLayer::CalculateViewLayout(const D2D1_SIZE_U newClientSize)
  	{
  		CalculateEffectVisuals(newClientSize);
  
  		InternalCalculateViewLayout(newClientSize);
  
  		for (auto& view : m_ViewContainer.GetEntities())
  		{
  			view->CalculateWidgetLayout(view->GetLocation(), view->GetSize());
  		}
  	}
  
  	void RenderLayer::RenderViews()
  	{
  		// Render views that belong to this render layer
  		for (auto& view : m_ViewContainer.GetEntities())
  		{
  			view->Render(m_DeviceContext);
  		}
  	}
  
  	void RenderLayer::RenderDirtyView()
  	{
  		if (IsEnabled())
  			Render();
  	}
  
  	void RenderLayer::CreateResources()
  	{
  		CreateResourcesImpl();
  
  		for (auto& view : m_ViewContainer.GetEntities())
  		{
  			view->CreateResources(m_DeviceContext);
  		}
  	}
  
  	void RenderLayer::AddView(const std::shared_ptr<UI::View>& view)
  	{
  		view->SetLocation({ 0, 0 });
  		view->SetSize({ static_cast<uint32_t>(GetRect().right), static_cast<uint32_t>(GetRect().bottom) });
  		
  		m_ViewContainer.AddEntity(view);
  	}
  
  	void RenderLayer::SetClearColor(const D2D1::ColorF color)
  	{
  		m_ClearColor = color;
  	}
  
  	void RenderLayer::SetContentDeffered() const
  	{
  		DXCall(m_CompositionVisual->SetContent(m_SwapChain.Get()));
  	}
  
  	void RenderLayer::CreateEffectVisuals(const Microsoft::WRL::ComPtr<IDCompositionDesktopDevice>& device)
  	{
  	}
  
  	void RenderLayer::CalculateEffectVisuals(const D2D1_SIZE_U newClientSize)
  	{
  	}
  
  	void RenderLayer::OnMainWindowGainFocus()
  	{
  		m_IsMainWindowFocused = true;
  
  		OnMainWindowGainFocusImpl();
  		
  		for (auto& view : GetViewContainer().GetEntities())
  		{
  			view->OnMainWindowGainFocus();
  		}
  	}
  
  	void RenderLayer::OnMainWindowLostFocus()
  	{
  		m_IsMainWindowFocused = false;
  
  		OnMainWindowLostFocusImpl();
  
  		for (auto& view : GetViewContainer().GetEntities())
  		{
  			view->OnMainWindowLostFocus();
  		}
  	}
  
  	void RenderLayer::SetLocation(const D2D1_POINT_2L location)
  	{
  		m_Location = location;
  		m_Rect = { m_Location.x, m_Location.y, static_cast<long>(m_Location.x + m_Size.width), static_cast<long>(m_Location.y + m_Size.height) };
  
  		DXCall(m_CompositionVisual->SetOffsetX(static_cast<float>(m_Location.x)));
  		DXCall(m_CompositionVisual->SetOffsetY(static_cast<float>(m_Location.y)));
  
  		SetRect(m_Rect);
  	}
  
  	void RenderLayer::SetSize(const D2D1_SIZE_U size)
  	{
  		m_Size = size;
  		m_Rect = { m_Location.x, m_Location.y, static_cast<long>(m_Location.x + m_Size.width), static_cast<long>(m_Location.y + m_Size.height) };
  
  		SetRect(m_Rect);
  	}
  
  	void RenderLayer::SetZIndex(const int32_t zIndex)
  	{
  		m_ZIndex = zIndex;
  
  		SetZIndex(m_ZIndex);
  	}
  
  	void RenderLayer::OnEnabled()
  	{
  		for (auto& view : m_ViewContainer.GetEntities())
  		{
  			view->OnEnabled();
  			view->Setup();
  		}
  
  		DXCall(m_CompositionVisual->SetContent(m_SwapChain.Get()));
  	}
  
  	void RenderLayer::OnDisabled()
  	{
  		DXCall(m_CompositionVisual->SetContent(nullptr));
  
  		for (auto& view : m_ViewContainer.GetEntities())
  		{
  			view->OnDisabled();
  		}
  	}
  
  	void RenderLayer::CreateResourcesImpl()
  	{
  	}
  
  	void RenderLayer::OnMainWindowGainFocusImpl()
  	{
  	}
  
  	void RenderLayer::OnMainWindowLostFocusImpl()
  	{
  	}
  }
  
  