| 
									
										
										
										
											2019-04-11 14:40:54 +08:00
										 |  |  |  | // Copyright (c) 2016-2018 Kiwano - Nomango
 | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | // 
 | 
					
						
							|  |  |  |  | // Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					
						
							|  |  |  |  | // of this software and associated documentation files (the "Software"), to deal
 | 
					
						
							|  |  |  |  | // in the Software without restriction, including without limitation the rights
 | 
					
						
							|  |  |  |  | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
					
						
							|  |  |  |  | // copies of the Software, and to permit persons to whom the Software is
 | 
					
						
							|  |  |  |  | // furnished to do so, subject to the following conditions:
 | 
					
						
							|  |  |  |  | // 
 | 
					
						
							|  |  |  |  | // The above copyright notice and this permission notice shall be included in
 | 
					
						
							|  |  |  |  | // all copies or substantial portions of the Software.
 | 
					
						
							|  |  |  |  | // 
 | 
					
						
							|  |  |  |  | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					
						
							|  |  |  |  | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					
						
							|  |  |  |  | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
					
						
							|  |  |  |  | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					
						
							|  |  |  |  | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
					
						
							|  |  |  |  | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
					
						
							|  |  |  |  | // THE SOFTWARE.
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include "render.h"
 | 
					
						
							|  |  |  |  | #include "../base/logs.h"
 | 
					
						
							| 
									
										
										
										
											2019-07-30 15:27:01 +08:00
										 |  |  |  | #include "../base/window.h"
 | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-11 14:40:54 +08:00
										 |  |  |  | namespace kiwano | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | { | 
					
						
							|  |  |  |  | 	Renderer::Renderer() | 
					
						
							|  |  |  |  | 		: hwnd_(nullptr) | 
					
						
							|  |  |  |  | 		, antialias_(true) | 
					
						
							|  |  |  |  | 		, vsync_(true) | 
					
						
							| 
									
										
										
										
											2019-08-13 14:44:37 +08:00
										 |  |  |  | 		, text_antialias_(TextAntialias::GrayScale) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 		, clear_color_(Color::Black) | 
					
						
							|  |  |  |  | 		, opacity_(1.f) | 
					
						
							| 
									
										
										
										
											2019-07-29 09:40:39 +08:00
										 |  |  |  | 		, collecting_status_(false) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		status_.primitives = 0; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	Renderer::~Renderer() | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-12 14:51:54 +08:00
										 |  |  |  | 	void Renderer::SetupComponent() | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-04-11 14:40:54 +08:00
										 |  |  |  | 		KGE_LOG(L"Creating device resources"); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-30 15:27:01 +08:00
										 |  |  |  | 		hwnd_ = Window::Instance()->GetHandle(); | 
					
						
							| 
									
										
										
										
											2019-04-22 13:21:12 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 		ThrowIfFailed(hwnd_ ? S_OK : E_FAIL); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2019-07-30 00:41:06 +08:00
										 |  |  |  | 		d2d_res_ = nullptr; | 
					
						
							|  |  |  |  | 		d3d_res_ = nullptr; | 
					
						
							| 
									
										
										
										
											2019-04-22 13:21:12 +08:00
										 |  |  |  | 		drawing_state_block_ = nullptr; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		ThrowIfFailed( | 
					
						
							| 
									
										
										
										
											2019-07-30 00:41:06 +08:00
										 |  |  |  | 			ID2DDeviceResources::Create( | 
					
						
							|  |  |  |  | 				&d2d_res_ | 
					
						
							|  |  |  |  | 			) | 
					
						
							|  |  |  |  | 		); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		ThrowIfFailed( | 
					
						
							|  |  |  |  | #if defined(KGE_USE_DIRECTX10)
 | 
					
						
							|  |  |  |  | 			ID3D10DeviceResources::Create( | 
					
						
							|  |  |  |  | 				&d3d_res_, | 
					
						
							|  |  |  |  | 				d2d_res_.Get(), | 
					
						
							|  |  |  |  | 				hwnd_ | 
					
						
							|  |  |  |  | 			) | 
					
						
							|  |  |  |  | #else
 | 
					
						
							|  |  |  |  | 			ID3D11DeviceResources::Create( | 
					
						
							|  |  |  |  | 				&d3d_res_, | 
					
						
							|  |  |  |  | 				d2d_res_.Get(), | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 				hwnd_ | 
					
						
							| 
									
										
										
										
											2019-04-22 13:21:12 +08:00
										 |  |  |  | 			) | 
					
						
							| 
									
										
										
										
											2019-07-30 00:41:06 +08:00
										 |  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-04-22 13:21:12 +08:00
										 |  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-30 00:41:06 +08:00
										 |  |  |  | 		device_context_ = d2d_res_->GetDeviceContext(); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 13:21:12 +08:00
										 |  |  |  | 		ThrowIfFailed( | 
					
						
							| 
									
										
										
										
											2019-07-30 00:41:06 +08:00
										 |  |  |  | 			d2d_res_->GetFactory()->CreateDrawingStateBlock( | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 				&drawing_state_block_ | 
					
						
							| 
									
										
										
										
											2019-04-22 13:21:12 +08:00
										 |  |  |  | 			) | 
					
						
							|  |  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 13:21:12 +08:00
										 |  |  |  | 		ThrowIfFailed( | 
					
						
							|  |  |  |  | 			CreateDeviceResources() | 
					
						
							|  |  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-30 15:27:01 +08:00
										 |  |  |  | 		output_size_ = Window::Instance()->GetSize(); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	void Renderer::DestroyComponent() | 
					
						
							|  |  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-04-11 14:40:54 +08:00
										 |  |  |  | 		KGE_LOG(L"Destroying device resources"); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 		drawing_state_block_.Reset(); | 
					
						
							|  |  |  |  | 		solid_color_brush_.Reset(); | 
					
						
							| 
									
										
										
										
											2019-07-30 00:41:06 +08:00
										 |  |  |  | 		d2d_res_.Reset(); | 
					
						
							|  |  |  |  | 		d3d_res_.Reset(); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-30 13:32:10 +08:00
										 |  |  |  | 	void Renderer::BeforeRender() | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		ThrowIfFailed( | 
					
						
							|  |  |  |  | 			BeginDraw() | 
					
						
							|  |  |  |  | 		); | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	void Renderer::AfterRender() | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		ThrowIfFailed( | 
					
						
							|  |  |  |  | 			EndDraw() | 
					
						
							|  |  |  |  | 		); | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	void Renderer::HandleMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		switch (msg) | 
					
						
							|  |  |  |  | 		{ | 
					
						
							|  |  |  |  | 		case WM_SIZE: | 
					
						
							|  |  |  |  | 		{ | 
					
						
							|  |  |  |  | 			UINT width = LOWORD(lparam); | 
					
						
							|  |  |  |  | 			UINT height = HIWORD(lparam); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			Resize(width, height); | 
					
						
							|  |  |  |  | 			break; | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 	HRESULT Renderer::CreateDeviceResources() | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		HRESULT hr = S_OK; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		hr = device_context_->CreateSolidColorBrush( | 
					
						
							|  |  |  |  | 			D2D1::ColorF(D2D1::ColorF::White), | 
					
						
							|  |  |  |  | 			&solid_color_brush_ | 
					
						
							|  |  |  |  | 		); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if (SUCCEEDED(hr)) | 
					
						
							|  |  |  |  | 		{ | 
					
						
							|  |  |  |  | 			hr = ITextRenderer::Create( | 
					
						
							|  |  |  |  | 				&text_renderer_, | 
					
						
							|  |  |  |  | 				device_context_.Get() | 
					
						
							|  |  |  |  | 			); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if (SUCCEEDED(hr)) | 
					
						
							|  |  |  |  | 		{ | 
					
						
							|  |  |  |  | 			SetAntialiasMode(antialias_); | 
					
						
							|  |  |  |  | 			SetTextAntialiasMode(text_antialias_); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		return hr; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::HandleDeviceLost() | 
					
						
							|  |  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-07-30 00:41:06 +08:00
										 |  |  |  | 		HRESULT hr = d3d_res_->HandleDeviceLost(); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if (SUCCEEDED(hr)) | 
					
						
							|  |  |  |  | 		{ | 
					
						
							|  |  |  |  | 			hr = CreateDeviceResources(); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		return hr; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::BeginDraw() | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!device_context_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-29 09:40:39 +08:00
										 |  |  |  | 		if (collecting_status_) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-04-09 02:25:17 +08:00
										 |  |  |  | 			status_.start = Time::Now(); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 			status_.primitives = 0; | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		device_context_->SaveDrawingState(drawing_state_block_.Get()); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		device_context_->BeginDraw(); | 
					
						
							| 
									
										
										
										
											2019-08-07 20:47:41 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 		HRESULT hr = d3d_res_->ClearRenderTarget(clear_color_); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		return hr; | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::EndDraw() | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!device_context_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		HRESULT hr = device_context_->EndDraw(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		device_context_->RestoreDrawingState(drawing_state_block_.Get()); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if (SUCCEEDED(hr)) | 
					
						
							|  |  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-07-30 00:41:06 +08:00
										 |  |  |  | 			hr = d3d_res_->Present(vsync_); | 
					
						
							| 
									
										
										
										
											2019-07-29 09:40:39 +08:00
										 |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) | 
					
						
							|  |  |  |  | 		{ | 
					
						
							|  |  |  |  | 			// <20><><EFBFBD><EFBFBD> Direct3D <20>豸<EFBFBD><E8B1B8>ִ<EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD>豸<EFBFBD><E8B1B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ
 | 
					
						
							|  |  |  |  | 			hr = HandleDeviceLost(); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-29 09:40:39 +08:00
										 |  |  |  | 		if (collecting_status_) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-04-09 02:25:17 +08:00
										 |  |  |  | 			status_.duration = Time::Now() - status_.start; | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 		} | 
					
						
							|  |  |  |  | 		return hr; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::CreateLayer(ComPtr<ID2D1Layer>& layer) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!device_context_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		layer = nullptr; | 
					
						
							|  |  |  |  | 		return device_context_->CreateLayer(&layer); | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::DrawGeometry( | 
					
						
							|  |  |  |  | 		ComPtr<ID2D1Geometry> const& geometry, | 
					
						
							|  |  |  |  | 		Color const& stroke_color, | 
					
						
							|  |  |  |  | 		float stroke_width, | 
					
						
							|  |  |  |  | 		StrokeStyle stroke | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!solid_color_brush_ || !device_context_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		solid_color_brush_->SetColor(DX::ConvertToColorF(stroke_color)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		device_context_->DrawGeometry( | 
					
						
							|  |  |  |  | 			geometry.Get(), | 
					
						
							|  |  |  |  | 			solid_color_brush_.Get(), | 
					
						
							|  |  |  |  | 			stroke_width, | 
					
						
							| 
									
										
										
										
											2019-07-30 00:41:06 +08:00
										 |  |  |  | 			d2d_res_->GetStrokeStyle(stroke) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 		); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-29 09:40:39 +08:00
										 |  |  |  | 		if (collecting_status_) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 			++status_.primitives; | 
					
						
							|  |  |  |  | 		return S_OK; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::FillGeometry(ComPtr<ID2D1Geometry> const & geometry, Color const& fill_color) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!solid_color_brush_ || !device_context_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		solid_color_brush_->SetColor(DX::ConvertToColorF(fill_color)); | 
					
						
							|  |  |  |  | 		device_context_->FillGeometry( | 
					
						
							|  |  |  |  | 			geometry.Get(), | 
					
						
							|  |  |  |  | 			solid_color_brush_.Get() | 
					
						
							|  |  |  |  | 		); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		return S_OK; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-31 10:12:59 +08:00
										 |  |  |  | 	HRESULT Renderer::DrawRectangle(Rect const& rect, const Color& stroke_color, float stroke_width, StrokeStyle stroke) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!solid_color_brush_ || !device_context_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		solid_color_brush_->SetColor(DX::ConvertToColorF(stroke_color)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		device_context_->DrawRectangle( | 
					
						
							|  |  |  |  | 			DX::ConvertToRectF(rect), | 
					
						
							|  |  |  |  | 			solid_color_brush_.Get(), | 
					
						
							|  |  |  |  | 			stroke_width, | 
					
						
							|  |  |  |  | 			d2d_res_->GetStrokeStyle(stroke) | 
					
						
							|  |  |  |  | 		); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if (collecting_status_) | 
					
						
							|  |  |  |  | 			++status_.primitives; | 
					
						
							|  |  |  |  | 		return S_OK; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::FillRectangle(Rect const& rect, Color const& fill_color) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!solid_color_brush_ || !device_context_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		solid_color_brush_->SetColor(DX::ConvertToColorF(fill_color)); | 
					
						
							|  |  |  |  | 		device_context_->FillRectangle( | 
					
						
							|  |  |  |  | 			DX::ConvertToRectF(rect), | 
					
						
							|  |  |  |  | 			solid_color_brush_.Get() | 
					
						
							|  |  |  |  | 		); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		return S_OK; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-14 22:37:05 +08:00
										 |  |  |  | 	HRESULT Renderer::DrawBitmap(ComPtr<ID2D1Bitmap> const & bitmap, Rect const& src_rect, Rect const& dest_rect) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!device_context_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if (!bitmap) | 
					
						
							|  |  |  |  | 			return S_OK; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		device_context_->DrawBitmap( | 
					
						
							|  |  |  |  | 			bitmap.Get(), | 
					
						
							| 
									
										
										
										
											2019-04-14 22:37:05 +08:00
										 |  |  |  | 			DX::ConvertToRectF(dest_rect), | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 			opacity_, | 
					
						
							|  |  |  |  | 			D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, | 
					
						
							| 
									
										
										
										
											2019-04-14 22:37:05 +08:00
										 |  |  |  | 			DX::ConvertToRectF(src_rect) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 		); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-29 09:40:39 +08:00
										 |  |  |  | 		if (collecting_status_) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 		++status_.primitives; | 
					
						
							|  |  |  |  | 		return S_OK; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::DrawTextLayout(ComPtr<IDWriteTextLayout> const& text_layout) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!text_renderer_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-29 09:40:39 +08:00
										 |  |  |  | 		if (collecting_status_) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 			++status_.primitives; | 
					
						
							|  |  |  |  | 		return text_layout->Draw(nullptr, text_renderer_.Get(), 0, 0); | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	void Renderer::SetVSyncEnabled(bool enabled) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		vsync_ = enabled; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::PushClip(const Matrix & clip_matrix, const Size & clip_size) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!device_context_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		device_context_->SetTransform(DX::ConvertToMatrix3x2F(clip_matrix)); | 
					
						
							|  |  |  |  | 		device_context_->PushAxisAlignedClip( | 
					
						
							|  |  |  |  | 			D2D1::RectF(0, 0, clip_size.x, clip_size.y), | 
					
						
							|  |  |  |  | 			D2D1_ANTIALIAS_MODE_PER_PRIMITIVE | 
					
						
							|  |  |  |  | 		); | 
					
						
							|  |  |  |  | 		return S_OK; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::PopClip() | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!device_context_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		device_context_->PopAxisAlignedClip(); | 
					
						
							|  |  |  |  | 		return S_OK; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::PushLayer(ComPtr<ID2D1Layer> const& layer, LayerProperties const& properties) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!device_context_ || !solid_color_brush_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		device_context_->PushLayer( | 
					
						
							|  |  |  |  | 			D2D1::LayerParameters( | 
					
						
							|  |  |  |  | 				DX::ConvertToRectF(properties.area), | 
					
						
							|  |  |  |  | 				nullptr, | 
					
						
							|  |  |  |  | 				D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, | 
					
						
							|  |  |  |  | 				D2D1::Matrix3x2F::Identity(), | 
					
						
							|  |  |  |  | 				properties.opacity, | 
					
						
							|  |  |  |  | 				solid_color_brush_.Get(), | 
					
						
							|  |  |  |  | 				D2D1_LAYER_OPTIONS_NONE | 
					
						
							|  |  |  |  | 			), | 
					
						
							|  |  |  |  | 			layer.Get() | 
					
						
							|  |  |  |  | 		); | 
					
						
							|  |  |  |  | 		return S_OK; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::PopLayer() | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!device_context_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		device_context_->PopLayer(); | 
					
						
							|  |  |  |  | 		return S_OK; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::Resize(UINT width, UINT height) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		output_size_.x = static_cast<float>(width); | 
					
						
							|  |  |  |  | 		output_size_.y = static_cast<float>(height); | 
					
						
							| 
									
										
										
										
											2019-07-30 00:41:06 +08:00
										 |  |  |  | 		if (d3d_res_) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-07-30 00:41:06 +08:00
										 |  |  |  | 			return d3d_res_->SetLogicalSize(output_size_); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 		} | 
					
						
							|  |  |  |  | 		return S_OK; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-29 09:40:39 +08:00
										 |  |  |  | 	void Renderer::SetCollectingStatus(bool collecting) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-07-29 09:40:39 +08:00
										 |  |  |  | 		collecting_status_ = collecting; | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	void Renderer::SetClearColor(const Color & color) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		clear_color_ = color; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::SetTransform(const Matrix & matrix) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!device_context_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-29 14:48:17 +08:00
										 |  |  |  | 		device_context_->SetTransform(DX::ConvertToMatrix3x2F(&matrix)); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 		return S_OK; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-31 10:12:59 +08:00
										 |  |  |  | 	HRESULT Renderer::SetOpacity(float opacity) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-07-31 10:12:59 +08:00
										 |  |  |  | 		if (!solid_color_brush_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 		if (opacity_ != opacity) | 
					
						
							|  |  |  |  | 		{ | 
					
						
							|  |  |  |  | 			opacity_ = opacity; | 
					
						
							|  |  |  |  | 			solid_color_brush_->SetOpacity(opacity); | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-07-31 10:12:59 +08:00
										 |  |  |  | 		return S_OK; | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::SetTextStyle( | 
					
						
							| 
									
										
										
										
											2019-08-03 23:28:45 +08:00
										 |  |  |  | 		float opacity, | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 		Color const& color, | 
					
						
							|  |  |  |  | 		bool has_outline, | 
					
						
							|  |  |  |  | 		Color const& outline_color, | 
					
						
							|  |  |  |  | 		float outline_width, | 
					
						
							|  |  |  |  | 		StrokeStyle outline_stroke | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-07-30 00:41:06 +08:00
										 |  |  |  | 		if (!text_renderer_ || !d3d_res_) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		text_renderer_->SetTextStyle( | 
					
						
							| 
									
										
										
										
											2019-08-03 23:28:45 +08:00
										 |  |  |  | 			opacity, | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 			DX::ConvertToColorF(color), | 
					
						
							|  |  |  |  | 			has_outline, | 
					
						
							|  |  |  |  | 			DX::ConvertToColorF(outline_color), | 
					
						
							|  |  |  |  | 			outline_width, | 
					
						
							| 
									
										
										
										
											2019-07-30 00:41:06 +08:00
										 |  |  |  | 			d2d_res_->GetStrokeStyle(outline_stroke) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  |  | 		); | 
					
						
							|  |  |  |  | 		return S_OK; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::SetAntialiasMode(bool enabled) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!device_context_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		device_context_->SetAntialiasMode( | 
					
						
							|  |  |  |  | 			enabled ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED | 
					
						
							|  |  |  |  | 		); | 
					
						
							|  |  |  |  | 		antialias_ = enabled; | 
					
						
							|  |  |  |  | 		return S_OK; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	HRESULT Renderer::SetTextAntialiasMode(TextAntialias mode) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		if (!device_context_) | 
					
						
							|  |  |  |  | 			return E_UNEXPECTED; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		text_antialias_ = mode; | 
					
						
							|  |  |  |  | 		D2D1_TEXT_ANTIALIAS_MODE antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; | 
					
						
							|  |  |  |  | 		switch (text_antialias_) | 
					
						
							|  |  |  |  | 		{ | 
					
						
							|  |  |  |  | 		case TextAntialias::Default: | 
					
						
							|  |  |  |  | 			antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; | 
					
						
							|  |  |  |  | 			break; | 
					
						
							|  |  |  |  | 		case TextAntialias::ClearType: | 
					
						
							|  |  |  |  | 			antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; | 
					
						
							|  |  |  |  | 			break; | 
					
						
							|  |  |  |  | 		case TextAntialias::GrayScale: | 
					
						
							|  |  |  |  | 			antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; | 
					
						
							|  |  |  |  | 			break; | 
					
						
							|  |  |  |  | 		case TextAntialias::None: | 
					
						
							|  |  |  |  | 			antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED; | 
					
						
							|  |  |  |  | 			break; | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			break; | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		device_context_->SetTextAntialiasMode(antialias_mode); | 
					
						
							|  |  |  |  | 		return S_OK; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | } |