| 
									
										
										
										
											2018-11-08 21:39:26 +08:00
										 |  |  |  | // Copyright (c) 2016-2018 Easy2D - Nomango
 | 
					
						
							|  |  |  |  | // 
 | 
					
						
							|  |  |  |  | // 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 "time.h"
 | 
					
						
							|  |  |  |  | #include "base.h"
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #pragma comment(lib, "d2d1.lib")
 | 
					
						
							|  |  |  |  | #pragma comment(lib, "dwrite.lib")
 | 
					
						
							|  |  |  |  | #pragma comment(lib, "windowscodecs.lib")
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | namespace easy2d | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	namespace render | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		_D2D_Resource D2D = { 0 }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-11 16:32:12 +08:00
										 |  |  |  | 		void easy2d::render::Initialize(HWND hwnd) | 
					
						
							| 
									
										
										
										
											2018-11-08 21:39:26 +08:00
										 |  |  |  | 		{ | 
					
						
							|  |  |  |  | 			if (D2D.Factory) | 
					
						
							|  |  |  |  | 				return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			ThrowIfFailed( | 
					
						
							|  |  |  |  | 				D2D1CreateFactory( | 
					
						
							|  |  |  |  | 					D2D1_FACTORY_TYPE_SINGLE_THREADED, | 
					
						
							|  |  |  |  | 					&D2D.Factory | 
					
						
							|  |  |  |  | 				) | 
					
						
							|  |  |  |  | 			); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			ThrowIfFailed( | 
					
						
							|  |  |  |  | 				CoCreateInstance( | 
					
						
							|  |  |  |  | 					CLSID_WICImagingFactory, | 
					
						
							|  |  |  |  | 					nullptr, | 
					
						
							|  |  |  |  | 					CLSCTX_INPROC_SERVER, | 
					
						
							|  |  |  |  | 					IID_IWICImagingFactory, | 
					
						
							|  |  |  |  | 					reinterpret_cast<void**>(&D2D.WICImagingFactory) | 
					
						
							|  |  |  |  | 				) | 
					
						
							|  |  |  |  | 			); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			ThrowIfFailed( | 
					
						
							|  |  |  |  | 				DWriteCreateFactory( | 
					
						
							|  |  |  |  | 					DWRITE_FACTORY_TYPE_SHARED, | 
					
						
							|  |  |  |  | 					__uuidof(IDWriteFactory), | 
					
						
							|  |  |  |  | 					reinterpret_cast<IUnknown**>(&D2D.DWriteFactory) | 
					
						
							|  |  |  |  | 				) | 
					
						
							|  |  |  |  | 			); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			auto stroke_style = D2D1::StrokeStyleProperties( | 
					
						
							|  |  |  |  | 				D2D1_CAP_STYLE_FLAT, | 
					
						
							|  |  |  |  | 				D2D1_CAP_STYLE_FLAT, | 
					
						
							|  |  |  |  | 				D2D1_CAP_STYLE_FLAT, | 
					
						
							|  |  |  |  | 				D2D1_LINE_JOIN_MITER, | 
					
						
							|  |  |  |  | 				2.0f, | 
					
						
							|  |  |  |  | 				D2D1_DASH_STYLE_SOLID, | 
					
						
							|  |  |  |  | 				0.0f | 
					
						
							|  |  |  |  | 			); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			ThrowIfFailed( | 
					
						
							|  |  |  |  | 				D2D.Factory->CreateStrokeStyle( | 
					
						
							|  |  |  |  | 					stroke_style, | 
					
						
							|  |  |  |  | 					nullptr, | 
					
						
							|  |  |  |  | 					0, | 
					
						
							|  |  |  |  | 					&D2D.MiterStrokeStyle | 
					
						
							|  |  |  |  | 				) | 
					
						
							|  |  |  |  | 			); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			ThrowIfFailed( | 
					
						
							|  |  |  |  | 				D2D.Factory->CreateStrokeStyle( | 
					
						
							|  |  |  |  | 					stroke_style, | 
					
						
							|  |  |  |  | 					nullptr, | 
					
						
							|  |  |  |  | 					0, | 
					
						
							|  |  |  |  | 					&D2D.BevelStrokeStyle | 
					
						
							|  |  |  |  | 				) | 
					
						
							|  |  |  |  | 			); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			ThrowIfFailed( | 
					
						
							|  |  |  |  | 				D2D.Factory->CreateStrokeStyle( | 
					
						
							|  |  |  |  | 					stroke_style, | 
					
						
							|  |  |  |  | 					nullptr, | 
					
						
							|  |  |  |  | 					0, | 
					
						
							|  |  |  |  | 					&D2D.RoundStrokeStyle | 
					
						
							|  |  |  |  | 				) | 
					
						
							|  |  |  |  | 			); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			CreateDeviceResources(hwnd); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-11 16:32:12 +08:00
										 |  |  |  | 		void easy2d::render::CreateDeviceResources(HWND hwnd) | 
					
						
							| 
									
										
										
										
											2018-11-08 21:39:26 +08:00
										 |  |  |  | 		{ | 
					
						
							|  |  |  |  | 			if (!D2D.HwndRenderTarget) | 
					
						
							|  |  |  |  | 			{ | 
					
						
							|  |  |  |  | 				RECT rc; | 
					
						
							|  |  |  |  | 				::GetClientRect(hwnd, &rc); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 				D2D1_SIZE_U size = D2D1::SizeU( | 
					
						
							|  |  |  |  | 					rc.right - rc.left, | 
					
						
							|  |  |  |  | 					rc.bottom - rc.top | 
					
						
							|  |  |  |  | 				); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 				// <20><><EFBFBD><EFBFBD><EFBFBD>豸<EFBFBD><E8B1B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD>Щ<EFBFBD><D0A9>ԴӦ<D4B4><D3A6> Direct2D <20>豸<EFBFBD><E8B1B8>ʧʱ<CAA7>ؽ<EFBFBD>
 | 
					
						
							|  |  |  |  | 				// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> Direct2D <20><>ȾĿ<C8BE><C4BF>
 | 
					
						
							|  |  |  |  | 				ThrowIfFailed( | 
					
						
							|  |  |  |  | 					D2D.Factory->CreateHwndRenderTarget( | 
					
						
							|  |  |  |  | 						D2D1::RenderTargetProperties(), | 
					
						
							|  |  |  |  | 						D2D1::HwndRenderTargetProperties( | 
					
						
							|  |  |  |  | 							hwnd, | 
					
						
							|  |  |  |  | 							size, | 
					
						
							|  |  |  |  | 							D2D1_PRESENT_OPTIONS_NONE), | 
					
						
							|  |  |  |  | 						&D2D.HwndRenderTarget | 
					
						
							|  |  |  |  | 					) | 
					
						
							|  |  |  |  | 				); | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			if (!D2D.SolidColorBrush) | 
					
						
							|  |  |  |  | 			{ | 
					
						
							|  |  |  |  | 				ThrowIfFailed( | 
					
						
							|  |  |  |  | 					D2D.HwndRenderTarget->CreateSolidColorBrush( | 
					
						
							|  |  |  |  | 						D2D1::ColorF(D2D1::ColorF::White), | 
					
						
							|  |  |  |  | 						&D2D.SolidColorBrush | 
					
						
							|  |  |  |  | 					) | 
					
						
							|  |  |  |  | 				); | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			if (!D2D.TextRenderer) | 
					
						
							|  |  |  |  | 			{ | 
					
						
							|  |  |  |  | 				ThrowIfFailed( | 
					
						
							|  |  |  |  | 					ITextRenderer::Create( | 
					
						
							|  |  |  |  | 						&D2D.TextRenderer, | 
					
						
							|  |  |  |  | 						D2D.Factory, | 
					
						
							|  |  |  |  | 						D2D.HwndRenderTarget, | 
					
						
							|  |  |  |  | 						D2D.SolidColorBrush | 
					
						
							|  |  |  |  | 					) | 
					
						
							|  |  |  |  | 				); | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-11 16:32:12 +08:00
										 |  |  |  | 		void easy2d::render::Uninitialize() | 
					
						
							| 
									
										
										
										
											2018-11-08 21:39:26 +08:00
										 |  |  |  | 		{ | 
					
						
							|  |  |  |  | 			SafeRelease(D2D.TextRenderer); | 
					
						
							|  |  |  |  | 			SafeRelease(D2D.SolidColorBrush); | 
					
						
							|  |  |  |  | 			SafeRelease(D2D.HwndRenderTarget); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			SafeRelease(D2D.MiterStrokeStyle); | 
					
						
							|  |  |  |  | 			SafeRelease(D2D.BevelStrokeStyle); | 
					
						
							|  |  |  |  | 			SafeRelease(D2D.RoundStrokeStyle); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			SafeRelease(D2D.WICImagingFactory); | 
					
						
							|  |  |  |  | 			SafeRelease(D2D.DWriteFactory); | 
					
						
							|  |  |  |  | 			SafeRelease(D2D.Factory); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		//-------------------------------------------------------
 | 
					
						
							|  |  |  |  | 		// GraphicsDevice
 | 
					
						
							|  |  |  |  | 		//-------------------------------------------------------
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		GraphicsDevice instance; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		GraphicsDevice::GraphicsDevice() | 
					
						
							|  |  |  |  | 			: fps_text_format_(nullptr) | 
					
						
							|  |  |  |  | 			, fps_text_layout_(nullptr) | 
					
						
							|  |  |  |  | 			, clear_color_(D2D1::ColorF(D2D1::ColorF::Black)) | 
					
						
							|  |  |  |  | 		{ | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		GraphicsDevice::~GraphicsDevice() | 
					
						
							|  |  |  |  | 		{ | 
					
						
							|  |  |  |  | 			SafeRelease(fps_text_format_); | 
					
						
							|  |  |  |  | 			SafeRelease(fps_text_layout_); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		void GraphicsDevice::BeginDraw(HWND hwnd) | 
					
						
							|  |  |  |  | 		{ | 
					
						
							|  |  |  |  | 			render::CreateDeviceResources(hwnd); | 
					
						
							|  |  |  |  | 			render::D2D.HwndRenderTarget->BeginDraw(); | 
					
						
							|  |  |  |  | 			render::D2D.HwndRenderTarget->Clear(clear_color_); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		void GraphicsDevice::EndDraw() | 
					
						
							|  |  |  |  | 		{ | 
					
						
							|  |  |  |  | 			HRESULT hr = render::D2D.HwndRenderTarget->EndDraw(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			if (hr == D2DERR_RECREATE_TARGET) | 
					
						
							|  |  |  |  | 			{ | 
					
						
							|  |  |  |  | 				// <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>Դ
 | 
					
						
							|  |  |  |  | 				// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>ε<EFBFBD><CEB5><EFBFBD>ʱ<EFBFBD>ؽ<EFBFBD><D8BD><EFBFBD>Դ
 | 
					
						
							|  |  |  |  | 				hr = S_OK; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 				SafeRelease(fps_text_format_); | 
					
						
							|  |  |  |  | 				SafeRelease(fps_text_layout_); | 
					
						
							|  |  |  |  | 				SafeRelease(render::D2D.TextRenderer); | 
					
						
							|  |  |  |  | 				SafeRelease(render::D2D.SolidColorBrush); | 
					
						
							|  |  |  |  | 				SafeRelease(render::D2D.HwndRenderTarget); | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			ThrowIfFailed(hr); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		void GraphicsDevice::SetBackgroundColor(const Color& color) | 
					
						
							|  |  |  |  | 		{ | 
					
						
							|  |  |  |  | 			clear_color_ = color; | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		void GraphicsDevice::DrawDebugInfo() | 
					
						
							|  |  |  |  | 		{ | 
					
						
							|  |  |  |  | 			static int render_times_ = 0; | 
					
						
							| 
									
										
										
										
											2018-11-11 16:32:12 +08:00
										 |  |  |  | 			static auto last_render_time_ = time::Now(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			int64_t duration = (time::Now() - last_render_time_).Milliseconds(); | 
					
						
							| 
									
										
										
										
											2018-11-08 21:39:26 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 			if (!fps_text_format_) | 
					
						
							|  |  |  |  | 			{ | 
					
						
							|  |  |  |  | 				ThrowIfFailed( | 
					
						
							|  |  |  |  | 					render::D2D.DWriteFactory->CreateTextFormat( | 
					
						
							|  |  |  |  | 						L"", | 
					
						
							|  |  |  |  | 						nullptr, | 
					
						
							|  |  |  |  | 						DWRITE_FONT_WEIGHT_NORMAL, | 
					
						
							|  |  |  |  | 						DWRITE_FONT_STYLE_NORMAL, | 
					
						
							|  |  |  |  | 						DWRITE_FONT_STRETCH_NORMAL, | 
					
						
							|  |  |  |  | 						20, | 
					
						
							|  |  |  |  | 						L"", | 
					
						
							|  |  |  |  | 						&fps_text_format_ | 
					
						
							|  |  |  |  | 					) | 
					
						
							|  |  |  |  | 				); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 				ThrowIfFailed( | 
					
						
							|  |  |  |  | 					fps_text_format_->SetWordWrapping( | 
					
						
							|  |  |  |  | 						DWRITE_WORD_WRAPPING_NO_WRAP | 
					
						
							|  |  |  |  | 					) | 
					
						
							|  |  |  |  | 				); | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			++render_times_; | 
					
						
							| 
									
										
										
										
											2018-11-11 16:32:12 +08:00
										 |  |  |  | 			if (duration >= 100LL) | 
					
						
							| 
									
										
										
										
											2018-11-08 21:39:26 +08:00
										 |  |  |  | 			{ | 
					
						
							|  |  |  |  | 				wchar_t fps_text[12] = {}; | 
					
						
							| 
									
										
										
										
											2018-11-11 16:32:12 +08:00
										 |  |  |  | 				int len = swprintf_s(fps_text, L"FPS: %.1f", 1000.f / static_cast<float>(duration) * render_times_); | 
					
						
							| 
									
										
										
										
											2018-11-08 21:39:26 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 				last_render_time_ = time::Now(); | 
					
						
							|  |  |  |  | 				render_times_ = 0; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 				SafeRelease(fps_text_layout_); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 				ThrowIfFailed( | 
					
						
							|  |  |  |  | 					render::D2D.DWriteFactory->CreateTextLayout( | 
					
						
							|  |  |  |  | 						fps_text, | 
					
						
							|  |  |  |  | 						static_cast<UINT32>(len), | 
					
						
							|  |  |  |  | 						fps_text_format_, | 
					
						
							|  |  |  |  | 						0, | 
					
						
							|  |  |  |  | 						0, | 
					
						
							|  |  |  |  | 						&fps_text_layout_ | 
					
						
							|  |  |  |  | 					) | 
					
						
							|  |  |  |  | 				); | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			if (fps_text_layout_) | 
					
						
							|  |  |  |  | 			{ | 
					
						
							|  |  |  |  | 				render::D2D.HwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); | 
					
						
							|  |  |  |  | 				render::D2D.SolidColorBrush->SetOpacity(1.0f); | 
					
						
							|  |  |  |  | 				render::D2D.TextRenderer->SetTextStyle( | 
					
						
							|  |  |  |  | 					D2D1::ColorF(D2D1::ColorF::White), | 
					
						
							|  |  |  |  | 					TRUE, | 
					
						
							|  |  |  |  | 					D2D1::ColorF(D2D1::ColorF::Black, 0.4f), | 
					
						
							|  |  |  |  | 					1.5f, | 
					
						
							|  |  |  |  | 					D2D1_LINE_JOIN_ROUND | 
					
						
							|  |  |  |  | 				); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 				fps_text_layout_->Draw(nullptr, render::D2D.TextRenderer, 10, 0); | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } |