[deploy] Merge pull request #37 from KiwanoEngine/dev
Add InterpolationMode && ResourceCache supports Font and GifImage
This commit is contained in:
		
						commit
						f202cb2c57
					
				|  | @ -12,7 +12,6 @@ | ||||||
|     <ClInclude Include="..\src\kiwano\2d\Frame.h" /> |     <ClInclude Include="..\src\kiwano\2d\Frame.h" /> | ||||||
|     <ClInclude Include="..\src\kiwano\2d\GifSprite.h" /> |     <ClInclude Include="..\src\kiwano\2d\GifSprite.h" /> | ||||||
|     <ClInclude Include="..\src\kiwano\base\Director.h" /> |     <ClInclude Include="..\src\kiwano\base\Director.h" /> | ||||||
|     <ClInclude Include="..\src\kiwano\base\types.h" /> |  | ||||||
|     <ClInclude Include="..\src\kiwano\core\basic_json.hpp" /> |     <ClInclude Include="..\src\kiwano\core\basic_json.hpp" /> | ||||||
|     <ClInclude Include="..\src\kiwano\core\function.hpp" /> |     <ClInclude Include="..\src\kiwano\core\function.hpp" /> | ||||||
|     <ClInclude Include="..\src\kiwano\core\core.h" /> |     <ClInclude Include="..\src\kiwano\core\core.h" /> | ||||||
|  | @ -70,8 +69,9 @@ | ||||||
|     <ClInclude Include="..\src\kiwano\renderer\FontCollection.h" /> |     <ClInclude Include="..\src\kiwano\renderer\FontCollection.h" /> | ||||||
|     <ClInclude Include="..\src\kiwano\renderer\Geometry.h" /> |     <ClInclude Include="..\src\kiwano\renderer\Geometry.h" /> | ||||||
|     <ClInclude Include="..\src\kiwano\renderer\GifImage.h" /> |     <ClInclude Include="..\src\kiwano\renderer\GifImage.h" /> | ||||||
|     <ClInclude Include="..\src\kiwano\renderer\Image.h" /> |     <ClInclude Include="..\src\kiwano\renderer\StrokeStyle.h" /> | ||||||
|     <ClInclude Include="..\src\kiwano\renderer\ImageCache.h" /> |     <ClInclude Include="..\src\kiwano\renderer\Texture.h" /> | ||||||
|  |     <ClInclude Include="..\src\kiwano\renderer\TextureCache.h" /> | ||||||
|     <ClInclude Include="..\src\kiwano\renderer\LayerArea.h" /> |     <ClInclude Include="..\src\kiwano\renderer\LayerArea.h" /> | ||||||
|     <ClInclude Include="..\src\kiwano\renderer\Renderer.h" /> |     <ClInclude Include="..\src\kiwano\renderer\Renderer.h" /> | ||||||
|     <ClInclude Include="..\src\kiwano\renderer\RenderTarget.h" /> |     <ClInclude Include="..\src\kiwano\renderer\RenderTarget.h" /> | ||||||
|  | @ -132,8 +132,8 @@ | ||||||
|     <ClCompile Include="..\src\kiwano\renderer\FontCollection.cpp" /> |     <ClCompile Include="..\src\kiwano\renderer\FontCollection.cpp" /> | ||||||
|     <ClCompile Include="..\src\kiwano\renderer\Geometry.cpp" /> |     <ClCompile Include="..\src\kiwano\renderer\Geometry.cpp" /> | ||||||
|     <ClCompile Include="..\src\kiwano\renderer\GifImage.cpp" /> |     <ClCompile Include="..\src\kiwano\renderer\GifImage.cpp" /> | ||||||
|     <ClCompile Include="..\src\kiwano\renderer\Image.cpp" /> |     <ClCompile Include="..\src\kiwano\renderer\Texture.cpp" /> | ||||||
|     <ClCompile Include="..\src\kiwano\renderer\ImageCache.cpp" /> |     <ClCompile Include="..\src\kiwano\renderer\TextureCache.cpp" /> | ||||||
|     <ClCompile Include="..\src\kiwano\renderer\LayerArea.cpp" /> |     <ClCompile Include="..\src\kiwano\renderer\LayerArea.cpp" /> | ||||||
|     <ClCompile Include="..\src\kiwano\renderer\Renderer.cpp" /> |     <ClCompile Include="..\src\kiwano\renderer\Renderer.cpp" /> | ||||||
|     <ClCompile Include="..\src\kiwano\renderer\RenderTarget.cpp" /> |     <ClCompile Include="..\src\kiwano\renderer\RenderTarget.cpp" /> | ||||||
|  |  | ||||||
|  | @ -150,9 +150,6 @@ | ||||||
|     <ClInclude Include="..\src\kiwano\utils\FileUtil.h"> |     <ClInclude Include="..\src\kiwano\utils\FileUtil.h"> | ||||||
|       <Filter>utils</Filter> |       <Filter>utils</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|     <ClInclude Include="..\src\kiwano\base\types.h"> |  | ||||||
|       <Filter>base</Filter> |  | ||||||
|     </ClInclude> |  | ||||||
|     <ClInclude Include="..\src\kiwano\2d\GifSprite.h"> |     <ClInclude Include="..\src\kiwano\2d\GifSprite.h"> | ||||||
|       <Filter>2d</Filter> |       <Filter>2d</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|  | @ -258,12 +255,6 @@ | ||||||
|     <ClInclude Include="..\src\kiwano\renderer\GifImage.h"> |     <ClInclude Include="..\src\kiwano\renderer\GifImage.h"> | ||||||
|       <Filter>renderer</Filter> |       <Filter>renderer</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|     <ClInclude Include="..\src\kiwano\renderer\Image.h"> |  | ||||||
|       <Filter>renderer</Filter> |  | ||||||
|     </ClInclude> |  | ||||||
|     <ClInclude Include="..\src\kiwano\renderer\ImageCache.h"> |  | ||||||
|       <Filter>renderer</Filter> |  | ||||||
|     </ClInclude> |  | ||||||
|     <ClInclude Include="..\src\kiwano\renderer\LayerArea.h"> |     <ClInclude Include="..\src\kiwano\renderer\LayerArea.h"> | ||||||
|       <Filter>renderer</Filter> |       <Filter>renderer</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|  | @ -306,6 +297,15 @@ | ||||||
|     <ClInclude Include="..\src\kiwano\2d\Transform.h"> |     <ClInclude Include="..\src\kiwano\2d\Transform.h"> | ||||||
|       <Filter>2d</Filter> |       <Filter>2d</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|  |     <ClInclude Include="..\src\kiwano\renderer\Texture.h"> | ||||||
|  |       <Filter>renderer</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="..\src\kiwano\renderer\TextureCache.h"> | ||||||
|  |       <Filter>renderer</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="..\src\kiwano\renderer\StrokeStyle.h"> | ||||||
|  |       <Filter>renderer</Filter> | ||||||
|  |     </ClInclude> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClCompile Include="..\src\kiwano\ui\Button.cpp"> |     <ClCompile Include="..\src\kiwano\ui\Button.cpp"> | ||||||
|  | @ -443,12 +443,6 @@ | ||||||
|     <ClCompile Include="..\src\kiwano\renderer\GifImage.cpp"> |     <ClCompile Include="..\src\kiwano\renderer\GifImage.cpp"> | ||||||
|       <Filter>renderer</Filter> |       <Filter>renderer</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|     <ClCompile Include="..\src\kiwano\renderer\Image.cpp"> |  | ||||||
|       <Filter>renderer</Filter> |  | ||||||
|     </ClCompile> |  | ||||||
|     <ClCompile Include="..\src\kiwano\renderer\ImageCache.cpp"> |  | ||||||
|       <Filter>renderer</Filter> |  | ||||||
|     </ClCompile> |  | ||||||
|     <ClCompile Include="..\src\kiwano\renderer\LayerArea.cpp"> |     <ClCompile Include="..\src\kiwano\renderer\LayerArea.cpp"> | ||||||
|       <Filter>renderer</Filter> |       <Filter>renderer</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|  | @ -482,5 +476,11 @@ | ||||||
|     <ClCompile Include="..\src\kiwano\2d\Transform.cpp"> |     <ClCompile Include="..\src\kiwano\2d\Transform.cpp"> | ||||||
|       <Filter>2d</Filter> |       <Filter>2d</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|  |     <ClCompile Include="..\src\kiwano\renderer\Texture.cpp"> | ||||||
|  |       <Filter>renderer</Filter> | ||||||
|  |     </ClCompile> | ||||||
|  |     <ClCompile Include="..\src\kiwano\renderer\TextureCache.cpp"> | ||||||
|  |       <Filter>renderer</Filter> | ||||||
|  |     </ClCompile> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| </Project> | </Project> | ||||||
|  | @ -65,8 +65,7 @@ namespace kiwano | ||||||
| 				Close(); | 				Close(); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			Transcoder transcoder; | 			HRESULT hr = transcoder_.LoadMediaFile(file_path); | ||||||
| 			HRESULT hr = transcoder.LoadMediaFile(file_path); |  | ||||||
| 
 | 
 | ||||||
| 			if (FAILED(hr)) | 			if (FAILED(hr)) | ||||||
| 			{ | 			{ | ||||||
|  | @ -74,7 +73,7 @@ namespace kiwano | ||||||
| 				return false; | 				return false; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			hr = Audio::GetInstance()->CreateVoice(&voice_, transcoder.GetBuffer().format); | 			hr = Audio::GetInstance()->CreateVoice(&voice_, transcoder_.GetBuffer().format); | ||||||
| 			if (FAILED(hr)) | 			if (FAILED(hr)) | ||||||
| 			{ | 			{ | ||||||
| 				Close(); | 				Close(); | ||||||
|  | @ -94,8 +93,7 @@ namespace kiwano | ||||||
| 				Close(); | 				Close(); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			Transcoder transcoder; | 			HRESULT hr = transcoder_.LoadMediaResource(res); | ||||||
| 			HRESULT hr = transcoder.LoadMediaResource(res); |  | ||||||
| 
 | 
 | ||||||
| 			if (FAILED(hr)) | 			if (FAILED(hr)) | ||||||
| 			{ | 			{ | ||||||
|  | @ -103,7 +101,7 @@ namespace kiwano | ||||||
| 				return false; | 				return false; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			hr = Audio::GetInstance()->CreateVoice(&voice_, transcoder.GetBuffer().format); | 			hr = Audio::GetInstance()->CreateVoice(&voice_, transcoder_.GetBuffer().format); | ||||||
| 			if (FAILED(hr)) | 			if (FAILED(hr)) | ||||||
| 			{ | 			{ | ||||||
| 				Close(); | 				Close(); | ||||||
|  |  | ||||||
|  | @ -247,20 +247,20 @@ namespace kiwano | ||||||
| 			if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) | 			if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) | ||||||
| 				return; | 				return; | ||||||
| 
 | 
 | ||||||
| 			MouseCursor cursor = MouseCursor::Arrow; | 			CursorType cursor = CursorType::Arrow; | ||||||
| 			switch (ImGui::GetMouseCursor()) | 			switch (ImGui::GetMouseCursor()) | ||||||
| 			{ | 			{ | ||||||
| 			case ImGuiMouseCursor_Arrow:        cursor = MouseCursor::Arrow; break; | 			case ImGuiMouseCursor_Arrow:        cursor = CursorType::Arrow; break; | ||||||
| 			case ImGuiMouseCursor_TextInput:    cursor = MouseCursor::TextInput; break; | 			case ImGuiMouseCursor_TextInput:    cursor = CursorType::TextInput; break; | ||||||
| 			case ImGuiMouseCursor_ResizeAll:    cursor = MouseCursor::SizeAll; break; | 			case ImGuiMouseCursor_ResizeAll:    cursor = CursorType::SizeAll; break; | ||||||
| 			case ImGuiMouseCursor_ResizeEW:     cursor = MouseCursor::SizeWE; break; | 			case ImGuiMouseCursor_ResizeEW:     cursor = CursorType::SizeWE; break; | ||||||
| 			case ImGuiMouseCursor_ResizeNS:     cursor = MouseCursor::SizeNS; break; | 			case ImGuiMouseCursor_ResizeNS:     cursor = CursorType::SizeNS; break; | ||||||
| 			case ImGuiMouseCursor_ResizeNESW:   cursor = MouseCursor::SizeNESW; break; | 			case ImGuiMouseCursor_ResizeNESW:   cursor = CursorType::SizeNESW; break; | ||||||
| 			case ImGuiMouseCursor_ResizeNWSE:   cursor = MouseCursor::SizeNWSE; break; | 			case ImGuiMouseCursor_ResizeNWSE:   cursor = CursorType::SizeNWSE; break; | ||||||
| 			case ImGuiMouseCursor_Hand:         cursor = MouseCursor::Hand; break; | 			case ImGuiMouseCursor_Hand:         cursor = CursorType::Hand; break; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			Window::GetInstance()->SetMouseCursor(cursor); | 			Window::GetInstance()->SetCursor(cursor); | ||||||
| 		} | 		} | ||||||
| 		void ImGuiModule::UpdateGamepads() | 		void ImGuiModule::UpdateGamepads() | ||||||
| 		{ | 		{ | ||||||
|  |  | ||||||
|  | @ -31,7 +31,7 @@ namespace kiwano | ||||||
| 		, stroke_color_(Color::White) | 		, stroke_color_(Color::White) | ||||||
| 		, stroke_style_(StrokeStyle::Miter) | 		, stroke_style_(StrokeStyle::Miter) | ||||||
| 	{ | 	{ | ||||||
| 		Renderer::GetInstance()->CreateImageRenderTarget(rt_); | 		Renderer::GetInstance()->CreateTextureRenderTarget(rt_); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Canvas::~Canvas() | 	Canvas::~Canvas() | ||||||
|  | @ -53,12 +53,12 @@ namespace kiwano | ||||||
| 	{ | 	{ | ||||||
| 		UpdateCache(); | 		UpdateCache(); | ||||||
| 		 | 		 | ||||||
| 		if (image_cached_.IsValid()) | 		if (texture_cached_.IsValid()) | ||||||
| 		{ | 		{ | ||||||
| 			PrepareRender(rt); | 			PrepareRender(rt); | ||||||
| 
 | 
 | ||||||
| 			Rect bitmap_rect(0.f, 0.f, image_cached_.GetWidth(), image_cached_.GetHeight()); | 			Rect bitmap_rect(0.f, 0.f, texture_cached_.GetWidth(), texture_cached_.GetHeight()); | ||||||
| 			rt->DrawImage(image_cached_, bitmap_rect, bitmap_rect); | 			rt->DrawTexture(texture_cached_, bitmap_rect, bitmap_rect); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -245,11 +245,11 @@ namespace kiwano | ||||||
| 		cache_expired_ = true; | 		cache_expired_ = true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Canvas::DrawImage(Image const& image, const Rect* src_rect, const Rect* dest_rect) | 	void Canvas::DrawTexture(Texture const& texture, const Rect* src_rect, const Rect* dest_rect) | ||||||
| 	{ | 	{ | ||||||
| 		if (image.IsValid()) | 		if (texture.IsValid()) | ||||||
| 		{ | 		{ | ||||||
| 			rt_.DrawImage(image, src_rect, dest_rect); | 			rt_.DrawTexture(texture, src_rect, dest_rect); | ||||||
| 			cache_expired_ = true; | 			cache_expired_ = true; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -326,17 +326,17 @@ namespace kiwano | ||||||
| 		cache_expired_ = true; | 		cache_expired_ = true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Image Canvas::ExportToImage() const | 	Texture Canvas::ExportToTexture() const | ||||||
| 	{ | 	{ | ||||||
| 		UpdateCache(); | 		UpdateCache(); | ||||||
| 		return image_cached_; | 		return texture_cached_; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Canvas::UpdateCache() const | 	void Canvas::UpdateCache() const | ||||||
| 	{ | 	{ | ||||||
| 		if (cache_expired_) | 		if (cache_expired_) | ||||||
| 		{ | 		{ | ||||||
| 			image_cached_ = rt_.GetOutput(); | 			texture_cached_ = rt_.GetOutput(); | ||||||
| 			cache_expired_ = false; | 			cache_expired_ = false; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -95,9 +95,9 @@ namespace kiwano | ||||||
| 			Vec2 const& radius | 			Vec2 const& radius | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		// »Í¼Æ¬
 | 		// »Í¼
 | ||||||
| 		void DrawImage( | 		void DrawTexture( | ||||||
| 			Image const& image, | 			Texture const& texture, | ||||||
| 			const Rect* src_rect = nullptr, | 			const Rect* src_rect = nullptr, | ||||||
| 			const Rect* dest_rect = nullptr | 			const Rect* dest_rect = nullptr | ||||||
| 		); | 		); | ||||||
|  | @ -232,7 +232,7 @@ namespace kiwano | ||||||
| 		Float32 GetBrushOpacity() const; | 		Float32 GetBrushOpacity() const; | ||||||
| 
 | 
 | ||||||
| 		// 导出为图片
 | 		// 导出为图片
 | ||||||
| 		Image ExportToImage() const; | 		Texture ExportToTexture() const; | ||||||
| 
 | 
 | ||||||
| 		void OnRender(RenderTarget* rt) override; | 		void OnRender(RenderTarget* rt) override; | ||||||
| 
 | 
 | ||||||
|  | @ -247,9 +247,9 @@ namespace kiwano | ||||||
| 		TextStyle			text_style_; | 		TextStyle			text_style_; | ||||||
| 		StrokeStyle			stroke_style_; | 		StrokeStyle			stroke_style_; | ||||||
| 		GeometrySink		geo_sink_; | 		GeometrySink		geo_sink_; | ||||||
| 		ImageRenderTarget	rt_; | 		TextureRenderTarget	rt_; | ||||||
| 
 | 
 | ||||||
| 		mutable bool		cache_expired_; | 		mutable bool		cache_expired_; | ||||||
| 		mutable Image		image_cached_; | 		mutable Texture		texture_cached_; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -127,7 +127,16 @@ namespace kiwano | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		debug_text_->SetText(ss.str()); | 		debug_text_->SetText(ss.str()); | ||||||
| 		SetSize(Size{ 20 + debug_text_->GetSize().x, 20 + debug_text_->GetSize().y }); | 
 | ||||||
|  | 		if (debug_text_->GetWidth() > GetWidth() - 20) | ||||||
|  | 		{ | ||||||
|  | 			SetWidth(20 + debug_text_->GetWidth()); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (debug_text_->GetHeight() > GetHeight() - 20) | ||||||
|  | 		{ | ||||||
|  | 			SetHeight(20 + debug_text_->GetHeight()); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ | ||||||
| // THE SOFTWARE.
 | // THE SOFTWARE.
 | ||||||
| 
 | 
 | ||||||
| #include "Frame.h" | #include "Frame.h" | ||||||
| #include "../renderer/ImageCache.h" | #include "../renderer/TextureCache.h" | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
|  | @ -37,17 +37,17 @@ namespace kiwano | ||||||
| 		Load(res); | 		Load(res); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Frame::Frame(Image const& image) | 	Frame::Frame(Texture const& texture) | ||||||
| 	{ | 	{ | ||||||
| 		SetImage(image); | 		SetTexture(texture); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool Frame::Load(String const& file_path) | 	bool Frame::Load(String const& file_path) | ||||||
| 	{ | 	{ | ||||||
| 		Image image = ImageCache::GetInstance()->AddOrGetImage(file_path); | 		Texture texture = TextureCache::GetInstance()->AddOrGetTexture(file_path); | ||||||
| 		if (image.IsValid()) | 		if (texture.IsValid()) | ||||||
| 		{ | 		{ | ||||||
| 			SetImage(image); | 			SetTexture(texture); | ||||||
| 			return true; | 			return true; | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
|  | @ -55,10 +55,10 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 	bool Frame::Load(Resource const& res) | 	bool Frame::Load(Resource const& res) | ||||||
| 	{ | 	{ | ||||||
| 		Image image = ImageCache::GetInstance()->AddOrGetImage(res); | 		Texture texture = TextureCache::GetInstance()->AddOrGetTexture(res); | ||||||
| 		if (image.IsValid()) | 		if (texture.IsValid()) | ||||||
| 		{ | 		{ | ||||||
| 			SetImage(image); | 			SetTexture(texture); | ||||||
| 			return true; | 			return true; | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
|  | @ -66,9 +66,9 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 	void Frame::SetCropRect(Rect const& crop_rect) | 	void Frame::SetCropRect(Rect const& crop_rect) | ||||||
| 	{ | 	{ | ||||||
| 		if (image_.IsValid()) | 		if (texture_.IsValid()) | ||||||
| 		{ | 		{ | ||||||
| 			auto bitmap_size = image_.GetSize(); | 			auto bitmap_size = texture_.GetSize(); | ||||||
| 			crop_rect_.left_top.x = std::min(std::max(crop_rect.left_top.x, 0.f), bitmap_size.x); | 			crop_rect_.left_top.x = std::min(std::max(crop_rect.left_top.x, 0.f), bitmap_size.x); | ||||||
| 			crop_rect_.left_top.y = std::min(std::max(crop_rect.left_top.y, 0.f), bitmap_size.y); | 			crop_rect_.left_top.y = std::min(std::max(crop_rect.left_top.y, 0.f), bitmap_size.y); | ||||||
| 			crop_rect_.right_bottom.x = std::min(std::max(crop_rect.right_bottom.x, 0.f), bitmap_size.x); | 			crop_rect_.right_bottom.x = std::min(std::max(crop_rect.right_bottom.x, 0.f), bitmap_size.x); | ||||||
|  | @ -76,14 +76,14 @@ namespace kiwano | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Frame::SetImage(Image const& image) | 	void Frame::SetTexture(Texture const& texture) | ||||||
| 	{ | 	{ | ||||||
| 		image_ = image; | 		texture_ = texture; | ||||||
| 		if (image_.IsValid()) | 		if (texture_.IsValid()) | ||||||
| 		{ | 		{ | ||||||
| 			crop_rect_.left_top.x = crop_rect_.left_top.y = 0; | 			crop_rect_.left_top.x = crop_rect_.left_top.y = 0; | ||||||
| 			crop_rect_.right_bottom.x = image_.GetWidth(); | 			crop_rect_.right_bottom.x = texture_.GetWidth(); | ||||||
| 			crop_rect_.right_bottom.y = image_.GetHeight(); | 			crop_rect_.right_bottom.y = texture_.GetHeight(); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ | ||||||
| // THE SOFTWARE.
 | // THE SOFTWARE.
 | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| #include "../renderer/Image.h" | #include "../renderer/Texture.h" | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
|  | @ -39,7 +39,7 @@ namespace kiwano | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		explicit Frame( | 		explicit Frame( | ||||||
| 			Image const& image | 			Texture const& texture | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		bool Load( | 		bool Load( | ||||||
|  | @ -55,31 +55,31 @@ namespace kiwano | ||||||
| 			Rect const& crop_rect	/* 裁剪矩形 */ | 			Rect const& crop_rect	/* 裁剪矩形 */ | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		// ÉèÖÃλͼ
 | 		// ÉèÖÃÎÆÀí
 | ||||||
| 		void SetImage( | 		void SetTexture( | ||||||
| 			Image const& image | 			Texture const& texture | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		// 获取宽度
 | 		// 获取宽度
 | ||||||
| 		Float32 GetWidth() const				{ return crop_rect_.GetWidth(); } | 		Float32 GetWidth() const					{ return crop_rect_.GetWidth(); } | ||||||
| 
 | 
 | ||||||
| 		// 获取高度
 | 		// 获取高度
 | ||||||
| 		Float32 GetHeight() const				{ return crop_rect_.GetHeight(); } | 		Float32 GetHeight() const					{ return crop_rect_.GetHeight(); } | ||||||
| 
 | 
 | ||||||
| 		// 获取大小
 | 		// 获取大小
 | ||||||
| 		Size GetSize() const					{ return crop_rect_.GetSize(); } | 		Size GetSize() const						{ return crop_rect_.GetSize(); } | ||||||
| 
 | 
 | ||||||
| 		// 获取裁剪位置
 | 		// 获取裁剪位置
 | ||||||
| 		Point GetCropPoint() const				{ return crop_rect_.GetLeftTop(); } | 		Point GetCropPoint() const					{ return crop_rect_.GetLeftTop(); } | ||||||
| 
 | 
 | ||||||
| 		// 获取裁剪矩形
 | 		// 获取裁剪矩形
 | ||||||
| 		inline Rect const& GetCropRect() const	{ return crop_rect_; } | 		inline Rect const& GetCropRect() const		{ return crop_rect_; } | ||||||
| 
 | 
 | ||||||
| 		// »ñȡλͼ
 | 		// »ñÈ¡ÎÆÀí
 | ||||||
| 		inline Image const& GetImage() const	{ return image_; } | 		inline Texture const& GetTexture() const	{ return texture_; } | ||||||
| 
 | 
 | ||||||
| 	protected: | 	protected: | ||||||
| 		Image image_; | 		Texture texture_; | ||||||
| 		Rect crop_rect_; | 		Rect crop_rect_; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -54,8 +54,8 @@ namespace kiwano | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			frames_.reserve(frames_.size() + frames.size()); | 			frames_.reserve(frames_.size() + frames.size()); | ||||||
| 			for (const auto& image : frames) | 			for (const auto& texture : frames) | ||||||
| 				AddFrame(image); | 				AddFrame(texture); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -20,7 +20,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "GifSprite.h" | #include "GifSprite.h" | ||||||
| #include "../base/Logger.h" | #include "../base/Logger.h" | ||||||
| #include "../renderer/ImageCache.h" | #include "../renderer/TextureCache.h" | ||||||
| #include "../renderer/Renderer.h" | #include "../renderer/Renderer.h" | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
|  | @ -30,7 +30,6 @@ namespace kiwano | ||||||
| 		, next_index_(0) | 		, next_index_(0) | ||||||
| 		, total_loop_count_(1) | 		, total_loop_count_(1) | ||||||
| 		, loop_count_(0) | 		, loop_count_(0) | ||||||
| 		, disposal_type_(DisposalType::Unknown) |  | ||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -45,41 +44,41 @@ namespace kiwano | ||||||
| 		Load(res); | 		Load(res); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	GifSprite::GifSprite(GifImage image) | 	GifSprite::GifSprite(GifImage gif) | ||||||
| 	{ | 	{ | ||||||
| 		Load(image); | 		Load(gif); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool GifSprite::Load(String const& file_path) | 	bool GifSprite::Load(String const& file_path) | ||||||
| 	{ | 	{ | ||||||
| 		GifImage image = ImageCache::GetInstance()->AddOrGetGifImage(file_path); | 		GifImage texture = TextureCache::GetInstance()->AddOrGetGifImage(file_path); | ||||||
| 		return Load(image); | 		return Load(texture); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool GifSprite::Load(Resource const& res) | 	bool GifSprite::Load(Resource const& res) | ||||||
| 	{ | 	{ | ||||||
| 		GifImage image = ImageCache::GetInstance()->AddOrGetGifImage(res); | 		GifImage texture = TextureCache::GetInstance()->AddOrGetGifImage(res); | ||||||
| 		return Load(image); | 		return Load(texture); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool GifSprite::Load(GifImage image) | 	bool GifSprite::Load(GifImage gif) | ||||||
| 	{ | 	{ | ||||||
| 		if (image.IsValid()) | 		if (gif.IsValid()) | ||||||
| 		{ | 		{ | ||||||
| 			image_ = image; | 			gif_ = gif; | ||||||
| 
 | 
 | ||||||
| 			next_index_ = 0; | 			next_index_ = 0; | ||||||
| 			loop_count_ = 0; | 			loop_count_ = 0; | ||||||
| 			disposal_type_ = DisposalType::None; | 			frame_.disposal_type = GifImage::DisposalType::None; | ||||||
| 
 | 
 | ||||||
| 			SetSize(Size{ static_cast<Float32>(image_.GetWidthInPixels()), static_cast<Float32>(image_.GetHeightInPixels()) }); | 			SetSize(Size{ static_cast<Float32>(gif_.GetWidthInPixels()), static_cast<Float32>(gif_.GetHeightInPixels()) }); | ||||||
| 
 | 
 | ||||||
| 			if (!frame_rt_.IsValid()) | 			if (!frame_rt_.IsValid()) | ||||||
| 			{ | 			{ | ||||||
| 				Renderer::GetInstance()->CreateImageRenderTarget(frame_rt_); | 				Renderer::GetInstance()->CreateTextureRenderTarget(frame_rt_); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (image_.GetFramesCount() > 0) | 			if (gif_.GetFramesCount() > 0) | ||||||
| 			{ | 			{ | ||||||
| 				ComposeNextFrame(); | 				ComposeNextFrame(); | ||||||
| 			} | 			} | ||||||
|  | @ -90,11 +89,11 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 	void GifSprite::OnRender(RenderTarget* rt) | 	void GifSprite::OnRender(RenderTarget* rt) | ||||||
| 	{ | 	{ | ||||||
| 		if (frame_.IsValid() && rt->CheckVisibility(GetBounds(), GetTransformMatrix())) | 		if (frame_.raw.IsValid() && rt->CheckVisibility(GetBounds(), GetTransformMatrix())) | ||||||
| 		{ | 		{ | ||||||
| 			PrepareRender(rt); | 			PrepareRender(rt); | ||||||
| 
 | 
 | ||||||
| 			rt->DrawImage(frame_); | 			rt->DrawTexture(frame_.raw, &frame_.rect, nullptr); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -102,24 +101,30 @@ namespace kiwano | ||||||
| 	{ | 	{ | ||||||
| 		Actor::Update(dt); | 		Actor::Update(dt); | ||||||
| 
 | 
 | ||||||
| 		if (image_.IsValid() && animating_) | 		if (gif_.IsValid() && animating_) | ||||||
| 		{ | 		{ | ||||||
| 			frame_elapsed_ += dt; | 			frame_elapsed_ += dt; | ||||||
| 			if (frame_delay_ <= frame_elapsed_) | 			if (frame_.delay <= frame_elapsed_) | ||||||
| 			{ | 			{ | ||||||
| 				frame_delay_ -= frame_elapsed_; | 				frame_.delay -= frame_elapsed_; | ||||||
| 				frame_elapsed_ = 0; | 				frame_elapsed_ = 0; | ||||||
| 				ComposeNextFrame(); | 				ComposeNextFrame(); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	void GifSprite::SetGifImage(GifImage const& gif) | ||||||
|  | 	{ | ||||||
|  | 		gif_ = gif; | ||||||
|  | 		RestartAnimation(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	void GifSprite::RestartAnimation() | 	void GifSprite::RestartAnimation() | ||||||
| 	{ | 	{ | ||||||
| 		animating_ = true; | 		animating_ = true; | ||||||
| 		next_index_ = 0; | 		next_index_ = 0; | ||||||
| 		loop_count_ = 0; | 		loop_count_ = 0; | ||||||
| 		disposal_type_ = DisposalType::None; | 		frame_.disposal_type = GifImage::DisposalType::None; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void GifSprite::ComposeNextFrame() | 	void GifSprite::ComposeNextFrame() | ||||||
|  | @ -130,27 +135,27 @@ namespace kiwano | ||||||
| 			{ | 			{ | ||||||
| 				DisposeCurrentFrame(); | 				DisposeCurrentFrame(); | ||||||
| 				OverlayNextFrame(); | 				OverlayNextFrame(); | ||||||
| 			} while (frame_delay_.IsZero() && !IsLastFrame()); | 			} while (frame_.delay.IsZero() && !IsLastFrame()); | ||||||
| 
 | 
 | ||||||
| 			animating_ = (!EndOfAnimation() && image_.GetFramesCount() > 1); | 			animating_ = (!EndOfAnimation() && gif_.GetFramesCount() > 1); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void GifSprite::DisposeCurrentFrame() | 	void GifSprite::DisposeCurrentFrame() | ||||||
| 	{ | 	{ | ||||||
| 		switch (disposal_type_) | 		switch (frame_.disposal_type) | ||||||
| 		{ | 		{ | ||||||
| 		case DisposalType::Unknown: | 		case GifImage::DisposalType::Unknown: | ||||||
| 		case DisposalType::None: | 		case GifImage::DisposalType::None: | ||||||
| 			break; | 			break; | ||||||
| 
 | 
 | ||||||
| 		case DisposalType::Background: | 		case GifImage::DisposalType::Background: | ||||||
| 		{ | 		{ | ||||||
| 			ClearCurrentFrameArea(); | 			ClearCurrentFrameArea(); | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		case DisposalType::Previous: | 		case GifImage::DisposalType::Previous: | ||||||
| 		{ | 		{ | ||||||
| 			RestoreSavedFrame(); | 			RestoreSavedFrame(); | ||||||
| 			break; | 			break; | ||||||
|  | @ -163,43 +168,30 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 	void GifSprite::OverlayNextFrame() | 	void GifSprite::OverlayNextFrame() | ||||||
| 	{ | 	{ | ||||||
| 		Image raw_image; | 		Renderer::GetInstance()->CreateGifImageFrame(frame_, gif_, next_index_); | ||||||
| 		 | 		 | ||||||
| 		HRESULT hr = image_.GetRawFrame(next_index_, raw_image, frame_rect_, frame_delay_, disposal_type_); | 		if (frame_.disposal_type == GifImage::DisposalType::Previous) | ||||||
| 		 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ | 		{ | ||||||
| 			if (disposal_type_ == DisposalType::Previous) | 			SaveComposedFrame(); | ||||||
| 			{ |  | ||||||
| 				SaveComposedFrame(); |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr)) | 		if (frame_rt_.IsValid()) | ||||||
| 		{ | 		{ | ||||||
| 			frame_rt_.BeginDraw(); | 			frame_rt_.BeginDraw(); | ||||||
| 
 | 
 | ||||||
| 			if (next_index_ == 0) | 			if (next_index_ == 0) | ||||||
| 			{ | 			{ | ||||||
| 				// ÖØÐ»æÖƱ³¾°
 |  | ||||||
| 				frame_rt_.Clear(image_.GetBackgroundColor()); |  | ||||||
| 				loop_count_++; | 				loop_count_++; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			frame_rt_.DrawImage(raw_image, nullptr, &frame_rect_); | 			frame_rt_.DrawTexture(frame_.raw, nullptr, &frame_.rect); | ||||||
| 			frame_rt_.EndDraw(); | 			frame_rt_.EndDraw(); | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr)) | 			Texture frame_to_render = frame_rt_.GetOutput(); | ||||||
| 		{ | 			if (frame_to_render.IsValid()) | ||||||
| 			Image frame_to_render = frame_rt_.GetOutput(); |  | ||||||
| 
 |  | ||||||
| 			hr = frame_to_render.IsValid() ? S_OK : E_FAIL; |  | ||||||
| 
 |  | ||||||
| 			if (SUCCEEDED(hr)) |  | ||||||
| 			{ | 			{ | ||||||
| 				frame_ = frame_to_render; | 				frame_.raw = frame_to_render; | ||||||
| 				next_index_ = (++next_index_) % image_.GetFramesCount(); | 				next_index_ = (++next_index_) % gif_.GetFramesCount(); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -212,13 +204,11 @@ namespace kiwano | ||||||
| 		{ | 		{ | ||||||
| 			done_cb_(); | 			done_cb_(); | ||||||
| 		} | 		} | ||||||
| 
 |  | ||||||
| 		ThrowIfFailed(hr); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void GifSprite::SaveComposedFrame() | 	void GifSprite::SaveComposedFrame() | ||||||
| 	{ | 	{ | ||||||
| 		Image frame_to_be_saved = frame_rt_.GetOutput(); | 		Texture frame_to_be_saved = frame_rt_.GetOutput(); | ||||||
| 
 | 
 | ||||||
| 		HRESULT hr = frame_to_be_saved.IsValid() ? S_OK : E_FAIL; | 		HRESULT hr = frame_to_be_saved.IsValid() ? S_OK : E_FAIL; | ||||||
| 
 | 
 | ||||||
|  | @ -253,7 +243,7 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr)) | 		if (SUCCEEDED(hr)) | ||||||
| 		{ | 		{ | ||||||
| 			Image frame_to_copy_to = frame_rt_.GetOutput(); | 			Texture frame_to_copy_to = frame_rt_.GetOutput(); | ||||||
| 
 | 
 | ||||||
| 			hr = frame_to_copy_to.IsValid() ? S_OK : E_FAIL; | 			hr = frame_to_copy_to.IsValid() ? S_OK : E_FAIL; | ||||||
| 
 | 
 | ||||||
|  | @ -270,8 +260,8 @@ namespace kiwano | ||||||
| 	{ | 	{ | ||||||
| 		frame_rt_.BeginDraw(); | 		frame_rt_.BeginDraw(); | ||||||
| 
 | 
 | ||||||
| 		frame_rt_.PushClipRect(frame_rect_); | 		frame_rt_.PushClipRect(frame_.rect); | ||||||
| 		frame_rt_.Clear(image_.GetBackgroundColor()); | 		frame_rt_.Clear(); | ||||||
| 		frame_rt_.PopClipRect(); | 		frame_rt_.PopClipRect(); | ||||||
| 
 | 
 | ||||||
| 		return frame_rt_.EndDraw(); | 		return frame_rt_.EndDraw(); | ||||||
|  |  | ||||||
|  | @ -31,7 +31,6 @@ namespace kiwano | ||||||
| 		: public Actor | 		: public Actor | ||||||
| 	{ | 	{ | ||||||
| 	public: | 	public: | ||||||
| 		using DisposalType		= GifImage::DisposalType; |  | ||||||
| 		using LoopDoneCallback	= Function<void(Int32)>; | 		using LoopDoneCallback	= Function<void(Int32)>; | ||||||
| 		using DoneCallback		= Function<void()>; | 		using DoneCallback		= Function<void()>; | ||||||
| 
 | 
 | ||||||
|  | @ -46,7 +45,7 @@ namespace kiwano | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		GifSprite( | 		GifSprite( | ||||||
| 			GifImage image | 			GifImage gif | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		bool Load( | 		bool Load( | ||||||
|  | @ -58,7 +57,7 @@ namespace kiwano | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		bool Load( | 		bool Load( | ||||||
| 			GifImage image | 			GifImage gif | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		// 设置 GIF 动画循环次数
 | 		// 设置 GIF 动画循环次数
 | ||||||
|  | @ -70,12 +69,17 @@ namespace kiwano | ||||||
| 		// 设置 GIF 动画结束回调函数
 | 		// 设置 GIF 动画结束回调函数
 | ||||||
| 		inline void SetDoneCallback(DoneCallback const& cb)			{ done_cb_ = cb; } | 		inline void SetDoneCallback(DoneCallback const& cb)			{ done_cb_ = cb; } | ||||||
| 
 | 
 | ||||||
|  | 		// ÉèÖà GIF ͼÏñ
 | ||||||
|  | 		void SetGifImage(GifImage const& gif); | ||||||
|  | 
 | ||||||
| 		// 重新播放动画
 | 		// 重新播放动画
 | ||||||
| 		void RestartAnimation(); | 		void RestartAnimation(); | ||||||
| 
 | 
 | ||||||
| 		inline LoopDoneCallback GetLoopDoneCallback() const			{ return loop_cb_; } | 		inline LoopDoneCallback	GetLoopDoneCallback() const			{ return loop_cb_; } | ||||||
| 
 | 
 | ||||||
| 		inline DoneCallback GetDoneCallback() const					{ return done_cb_; } | 		inline DoneCallback		GetDoneCallback() const				{ return done_cb_; } | ||||||
|  | 
 | ||||||
|  | 		inline GifImage const&	GetGifImage() const					{ return gif_; } | ||||||
| 
 | 
 | ||||||
| 		void OnRender(RenderTarget* rt) override; | 		void OnRender(RenderTarget* rt) override; | ||||||
| 
 | 
 | ||||||
|  | @ -103,15 +107,12 @@ namespace kiwano | ||||||
| 		Int32				total_loop_count_; | 		Int32				total_loop_count_; | ||||||
| 		Int32				loop_count_; | 		Int32				loop_count_; | ||||||
| 		UInt32				next_index_; | 		UInt32				next_index_; | ||||||
| 		Duration			frame_delay_; |  | ||||||
| 		Duration			frame_elapsed_; | 		Duration			frame_elapsed_; | ||||||
| 		DisposalType		disposal_type_; |  | ||||||
| 		LoopDoneCallback	loop_cb_; | 		LoopDoneCallback	loop_cb_; | ||||||
| 		DoneCallback		done_cb_; | 		DoneCallback		done_cb_; | ||||||
| 		GifImage			image_; | 		GifImage			gif_; | ||||||
| 		Image				frame_; | 		GifImage::Frame		frame_; | ||||||
| 		Rect				frame_rect_; | 		Texture				saved_frame_; | ||||||
| 		Image				saved_frame_; | 		TextureRenderTarget	frame_rt_; | ||||||
| 		ImageRenderTarget	frame_rt_; |  | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ | ||||||
| #pragma once | #pragma once | ||||||
| #include "Actor.h" | #include "Actor.h" | ||||||
| #include "../renderer/Geometry.h" | #include "../renderer/Geometry.h" | ||||||
|  | #include "../renderer/StrokeStyle.h" | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -108,7 +108,7 @@ namespace kiwano | ||||||
| 		{ | 		{ | ||||||
| 			PrepareRender(rt); | 			PrepareRender(rt); | ||||||
| 
 | 
 | ||||||
| 			rt->DrawImage(frame_->GetImage(), &frame_->GetCropRect(), nullptr); | 			rt->DrawTexture(frame_->GetTexture(), &frame_->GetCropRect(), nullptr); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -38,12 +38,12 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 	void Stage::OnEnter() | 	void Stage::OnEnter() | ||||||
| 	{ | 	{ | ||||||
| 		KGE_LOG(L"Stage entered"); | 		// KGE_LOG(L"Stage entered");
 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Stage::OnExit() | 	void Stage::OnExit() | ||||||
| 	{ | 	{ | ||||||
| 		KGE_LOG(L"Stage exited"); | 		// KGE_LOG(L"Stage exited");
 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -126,11 +126,11 @@ namespace kiwano | ||||||
| 		style_.color = color; | 		style_.color = color; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Text::SetItalic(bool val) | 	void Text::SetItalic(bool italic) | ||||||
| 	{ | 	{ | ||||||
| 		if (font_.italic != val) | 		if (font_.italic != italic) | ||||||
| 		{ | 		{ | ||||||
| 			font_.italic = val; | 			font_.italic = italic; | ||||||
| 			format_dirty_ = true; | 			format_dirty_ = true; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -102,7 +102,7 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 		// 设置文字斜体(默认值为 false)
 | 		// 设置文字斜体(默认值为 false)
 | ||||||
| 		void SetItalic( | 		void SetItalic( | ||||||
| 			bool val | 			bool italic | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		// 设置文本自动换行的宽度(默认为 0)
 | 		// 设置文本自动换行的宽度(默认为 0)
 | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| #include "include-forwards.h" | #include "include-forwards.h" | ||||||
|  | #include "../renderer/StrokeStyle.h" | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -51,8 +51,8 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 		if (status_ == Status::NotStarted) | 		if (status_ == Status::NotStarted) | ||||||
| 		{ | 		{ | ||||||
| 			Init(target); |  | ||||||
| 			status_ = delay_.IsZero() ? Status::Started : Status::Delayed; | 			status_ = delay_.IsZero() ? Status::Started : Status::Delayed; | ||||||
|  | 			Init(target); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		switch (status_) | 		switch (status_) | ||||||
|  |  | ||||||
|  | @ -62,7 +62,7 @@ namespace kiwano | ||||||
| 	{ | 	{ | ||||||
| 		if (!path_) | 		if (!path_) | ||||||
| 		{ | 		{ | ||||||
| 			Complete(target); | 			Done(); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -52,6 +52,7 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 	void Animation::Init(ActorPtr target) | 	void Animation::Init(ActorPtr target) | ||||||
| 	{ | 	{ | ||||||
|  | 		KGE_ASSERT(frame_seq_ && "Animation::Init() failed: FrameSequence is NULL!"); | ||||||
| 		if (!frame_seq_ || frame_seq_->GetFrames().empty()) | 		if (!frame_seq_ || frame_seq_->GetFrames().empty()) | ||||||
| 		{ | 		{ | ||||||
| 			Done(); | 			Done(); | ||||||
|  | @ -59,6 +60,8 @@ namespace kiwano | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		auto sprite_target = dynamic_cast<Sprite*>(target.get()); | 		auto sprite_target = dynamic_cast<Sprite*>(target.get()); | ||||||
|  | 		KGE_ASSERT(sprite_target && "Animation only supports Sprites!"); | ||||||
|  | 
 | ||||||
| 		if (sprite_target && frame_seq_) | 		if (sprite_target && frame_seq_) | ||||||
| 		{ | 		{ | ||||||
| 			sprite_target->SetFrame(frame_seq_->GetFrames()[0]); | 			sprite_target->SetFrame(frame_seq_->GetFrames()[0]); | ||||||
|  | @ -69,13 +72,14 @@ namespace kiwano | ||||||
| 	{ | 	{ | ||||||
| 		auto sprite_target = dynamic_cast<Sprite*>(target.get()); | 		auto sprite_target = dynamic_cast<Sprite*>(target.get()); | ||||||
| 
 | 
 | ||||||
| 		KGE_ASSERT(sprite_target && "Animation only supports Sprites"); | 		if (sprite_target && frame_seq_) | ||||||
|  | 		{ | ||||||
|  | 			const auto& frames = frame_seq_->GetFrames(); | ||||||
|  | 			auto size = frames.size(); | ||||||
|  | 			auto index = std::min(static_cast<UInt32>(math::Floor(size * percent)), size - 1); | ||||||
| 
 | 
 | ||||||
| 		const auto& frames = frame_seq_->GetFrames(); | 			sprite_target->SetFrame(frames[index]); | ||||||
| 		auto size = frames.size(); | 		} | ||||||
| 		auto index = std::min(static_cast<UInt32>(math::Floor(size * percent)), size - 1); |  | ||||||
| 
 |  | ||||||
| 		sprite_target->SetFrame(frames[index]); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ActionPtr Animation::Clone() const | 	ActionPtr Animation::Clone() const | ||||||
|  |  | ||||||
|  | @ -24,7 +24,6 @@ | ||||||
| #include "../base/RefCounter.hpp" | #include "../base/RefCounter.hpp" | ||||||
| #include "../base/SmartPtr.hpp" | #include "../base/SmartPtr.hpp" | ||||||
| #include "../base/ObjectBase.h" | #include "../base/ObjectBase.h" | ||||||
| #include "../base/types.h" |  | ||||||
| #include "../math/math.h" | #include "../math/math.h" | ||||||
| #include "../renderer/Color.h" | #include "../renderer/Color.h" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "Window.h" | #include "Window.h" | ||||||
| #include "Logger.h" | #include "Logger.h" | ||||||
|  | #include "../platform/Application.h" | ||||||
| 
 | 
 | ||||||
| #define WINDOW_FIXED_STYLE		WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | #define WINDOW_FIXED_STYLE		WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | ||||||
| #define WINDOW_RESIZABLE_STYLE	WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX | #define WINDOW_RESIZABLE_STYLE	WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX | ||||||
|  | @ -39,6 +40,16 @@ namespace kiwano | ||||||
| 		void RestoreResolution(WCHAR* device_name); | 		void RestoreResolution(WCHAR* device_name); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	WindowConfig::WindowConfig(String const& title, UInt32 width, UInt32 height, UInt32 icon, bool resizable, bool fullscreen) | ||||||
|  | 		: title(title) | ||||||
|  | 		, width(width) | ||||||
|  | 		, height(height) | ||||||
|  | 		, icon(icon) | ||||||
|  | 		, resizable(resizable) | ||||||
|  | 		, fullscreen(fullscreen) | ||||||
|  | 	{ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	Window::Window() | 	Window::Window() | ||||||
| 		: handle_(nullptr) | 		: handle_(nullptr) | ||||||
| 		, width_(0) | 		, width_(0) | ||||||
|  | @ -46,7 +57,7 @@ namespace kiwano | ||||||
| 		, device_name_(nullptr) | 		, device_name_(nullptr) | ||||||
| 		, is_fullscreen_(false) | 		, is_fullscreen_(false) | ||||||
| 		, resizable_(false) | 		, resizable_(false) | ||||||
| 		, mouse_cursor_(MouseCursor::Arrow) | 		, mouse_cursor_(CursorType::Arrow) | ||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -68,7 +79,7 @@ namespace kiwano | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Window::Init(String const& title, Int32 width, Int32 height, UInt32 icon, bool resizable, bool fullscreen, WNDPROC proc) | 	void Window::Init(WindowConfig const& config, WNDPROC proc) | ||||||
| 	{ | 	{ | ||||||
| 		HINSTANCE hinst		= GetModuleHandleW(nullptr); | 		HINSTANCE hinst		= GetModuleHandleW(nullptr); | ||||||
| 		WNDCLASSEX wcex		= { 0 }; | 		WNDCLASSEX wcex		= { 0 }; | ||||||
|  | @ -84,9 +95,10 @@ namespace kiwano | ||||||
| 		wcex.lpszMenuName	= nullptr; | 		wcex.lpszMenuName	= nullptr; | ||||||
| 		wcex.hCursor		= ::LoadCursorW(hinst, IDC_ARROW); | 		wcex.hCursor		= ::LoadCursorW(hinst, IDC_ARROW); | ||||||
| 
 | 
 | ||||||
| 		if (icon) | 		if (config.icon) | ||||||
| 		{ | 		{ | ||||||
| 			wcex.hIcon = (HICON)::LoadImageW(hinst, MAKEINTRESOURCE(icon), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE); | 			wcex.hIcon = (HICON)::LoadImageW(hinst, MAKEINTRESOURCE(config.icon), IMAGE_ICON, 0, 0, | ||||||
|  | 				LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		::RegisterClassExW(&wcex); | 		::RegisterClassExW(&wcex); | ||||||
|  | @ -105,22 +117,24 @@ namespace kiwano | ||||||
| 		device_name_ = new WCHAR[len + 1]; | 		device_name_ = new WCHAR[len + 1]; | ||||||
| 		lstrcpyW(device_name_, monitor_info_ex.szDevice); | 		lstrcpyW(device_name_, monitor_info_ex.szDevice); | ||||||
| 
 | 
 | ||||||
|  | 		UInt32 width = config.width; | ||||||
|  | 		UInt32 height = config.height; | ||||||
| 		Int32 left = -1; | 		Int32 left = -1; | ||||||
| 		Int32 top = -1; | 		Int32 top = -1; | ||||||
| 
 | 
 | ||||||
| 		resizable_ = resizable; | 		resizable_ = config.resizable; | ||||||
| 		is_fullscreen_ = fullscreen; | 		is_fullscreen_ = config.fullscreen; | ||||||
| 
 | 
 | ||||||
| 		if (is_fullscreen_) | 		if (is_fullscreen_) | ||||||
| 		{ | 		{ | ||||||
| 			top = monitor_info_ex.rcMonitor.top; | 			top = monitor_info_ex.rcMonitor.top; | ||||||
| 			left = monitor_info_ex.rcMonitor.left; | 			left = monitor_info_ex.rcMonitor.left; | ||||||
| 
 | 
 | ||||||
| 			if (width > monitor_info_ex.rcWork.right - left) | 			if (width > static_cast<UInt32>(monitor_info_ex.rcWork.right - left)) | ||||||
| 				width = monitor_info_ex.rcWork.right - left; | 				width = static_cast<UInt32>(monitor_info_ex.rcWork.right - left); | ||||||
| 
 | 
 | ||||||
| 			if (height > monitor_info_ex.rcWork.bottom - top) | 			if (height > static_cast<UInt32>(monitor_info_ex.rcWork.bottom - top)) | ||||||
| 				height = monitor_info_ex.rcWork.bottom - top; | 				height = static_cast<UInt32>(monitor_info_ex.rcWork.bottom - top); | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
|  | @ -145,7 +159,7 @@ namespace kiwano | ||||||
| 		handle_ = ::CreateWindowExW( | 		handle_ = ::CreateWindowExW( | ||||||
| 			is_fullscreen_ ? WS_EX_TOPMOST : 0, | 			is_fullscreen_ ? WS_EX_TOPMOST : 0, | ||||||
| 			KGE_WND_CLASS_NAME, | 			KGE_WND_CLASS_NAME, | ||||||
| 			title.c_str(), | 			config.title.c_str(), | ||||||
| 			GetWindowStyle(), | 			GetWindowStyle(), | ||||||
| 			left, | 			left, | ||||||
| 			top, | 			top, | ||||||
|  | @ -222,7 +236,7 @@ namespace kiwano | ||||||
| 		if (handle_) | 		if (handle_) | ||||||
| 		{ | 		{ | ||||||
| 			HINSTANCE hinstance = GetModuleHandle(nullptr); | 			HINSTANCE hinstance = GetModuleHandle(nullptr); | ||||||
| 			HICON icon = (HICON)::LoadImage( | 			HICON icon = (HICON)::LoadImageW( | ||||||
| 				hinstance, | 				hinstance, | ||||||
| 				MAKEINTRESOURCE(icon_resource), | 				MAKEINTRESOURCE(icon_resource), | ||||||
| 				IMAGE_ICON, | 				IMAGE_ICON, | ||||||
|  | @ -295,7 +309,7 @@ namespace kiwano | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Window::SetMouseCursor(MouseCursor cursor) | 	void Window::SetCursor(CursorType cursor) | ||||||
| 	{ | 	{ | ||||||
| 		mouse_cursor_ = cursor; | 		mouse_cursor_ = cursor; | ||||||
| 	} | 	} | ||||||
|  | @ -327,14 +341,14 @@ namespace kiwano | ||||||
| 		LPTSTR win32_cursor = IDC_ARROW; | 		LPTSTR win32_cursor = IDC_ARROW; | ||||||
| 		switch (mouse_cursor_) | 		switch (mouse_cursor_) | ||||||
| 		{ | 		{ | ||||||
| 		case MouseCursor::Arrow:		win32_cursor = IDC_ARROW; break; | 		case CursorType::Arrow:		win32_cursor = IDC_ARROW; break; | ||||||
| 		case MouseCursor::TextInput:	win32_cursor = IDC_IBEAM; break; | 		case CursorType::TextInput:	win32_cursor = IDC_IBEAM; break; | ||||||
| 		case MouseCursor::SizeAll:		win32_cursor = IDC_SIZEALL; break; | 		case CursorType::SizeAll:	win32_cursor = IDC_SIZEALL; break; | ||||||
| 		case MouseCursor::SizeWE:		win32_cursor = IDC_SIZEWE; break; | 		case CursorType::SizeWE:	win32_cursor = IDC_SIZEWE; break; | ||||||
| 		case MouseCursor::SizeNS:		win32_cursor = IDC_SIZENS; break; | 		case CursorType::SizeNS:	win32_cursor = IDC_SIZENS; break; | ||||||
| 		case MouseCursor::SizeNESW:		win32_cursor = IDC_SIZENESW; break; | 		case CursorType::SizeNESW:	win32_cursor = IDC_SIZENESW; break; | ||||||
| 		case MouseCursor::SizeNWSE:		win32_cursor = IDC_SIZENWSE; break; | 		case CursorType::SizeNWSE:	win32_cursor = IDC_SIZENWSE; break; | ||||||
| 		case MouseCursor::Hand:			win32_cursor = IDC_HAND; break; | 		case CursorType::Hand:		win32_cursor = IDC_HAND; break; | ||||||
| 		} | 		} | ||||||
| 		::SetCursor(::LoadCursorW(nullptr, win32_cursor)); | 		::SetCursor(::LoadCursorW(nullptr, win32_cursor)); | ||||||
| 	} | 	} | ||||||
|  | @ -417,4 +431,5 @@ namespace kiwano | ||||||
| 			::ChangeDisplaySettingsExW(device_name, NULL, NULL, 0, NULL); | 			::ChangeDisplaySettingsExW(device_name, NULL, NULL, 0, NULL); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -22,10 +22,44 @@ | ||||||
| #include "../macros.h" | #include "../macros.h" | ||||||
| #include "../core/core.h" | #include "../core/core.h" | ||||||
| #include "../math/math.h" | #include "../math/math.h" | ||||||
| #include "types.h" |  | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
|  | 	// 鼠标指针类型
 | ||||||
|  | 	enum class CursorType | ||||||
|  | 	{ | ||||||
|  | 		Arrow,		/* 指针 */ | ||||||
|  | 		TextInput,	/* 文本 */ | ||||||
|  | 		Hand,		/* 手指 */ | ||||||
|  | 		SizeAll, | ||||||
|  | 		SizeNESW, | ||||||
|  | 		SizeNS, | ||||||
|  | 		SizeNWSE, | ||||||
|  | 		SizeWE, | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	// 窗口设置
 | ||||||
|  | 	struct WindowConfig | ||||||
|  | 	{ | ||||||
|  | 		String	title;				// 标题
 | ||||||
|  | 		UInt32	width;				// 宽度
 | ||||||
|  | 		UInt32	height;				// 高度
 | ||||||
|  | 		UInt32	icon;				// 图标资源 ID
 | ||||||
|  | 		bool	resizable;			// 窗口大小可拉伸
 | ||||||
|  | 		bool	fullscreen;			// 全屏模式
 | ||||||
|  | 
 | ||||||
|  | 		WindowConfig( | ||||||
|  | 			String const& title = L"Kiwano Game", | ||||||
|  | 			UInt32 width = 640, | ||||||
|  | 			UInt32 height = 480, | ||||||
|  | 			UInt32 icon = 0, | ||||||
|  | 			bool resizable = false, | ||||||
|  | 			bool fullscreen = false | ||||||
|  | 		); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	// 窗口
 | ||||||
| 	class KGE_API Window | 	class KGE_API Window | ||||||
| 		: public Singleton<Window> | 		: public Singleton<Window> | ||||||
| 	{ | 	{ | ||||||
|  | @ -56,19 +90,11 @@ namespace kiwano | ||||||
| 		// 设置全屏模式
 | 		// 设置全屏模式
 | ||||||
| 		void SetFullscreen(bool fullscreen, Int32 width, Int32 height); | 		void SetFullscreen(bool fullscreen, Int32 width, Int32 height); | ||||||
| 
 | 
 | ||||||
| 		// 譜崔報炎峺寞
 | 		// 设置鼠标指针类型
 | ||||||
| 		void SetMouseCursor(MouseCursor cursor); | 		void SetCursor(CursorType cursor); | ||||||
| 
 | 
 | ||||||
| 	public: | 	public: | ||||||
| 		void Init( | 		void Init(WindowConfig const& config, WNDPROC proc); | ||||||
| 			String const&	title, |  | ||||||
| 			Int32			width, |  | ||||||
| 			Int32			height, |  | ||||||
| 			UInt32			icon, |  | ||||||
| 			bool			resizable, |  | ||||||
| 			bool			fullscreen, |  | ||||||
| 			WNDPROC			proc |  | ||||||
| 		); |  | ||||||
| 
 | 
 | ||||||
| 		void Prepare(); | 		void Prepare(); | ||||||
| 
 | 
 | ||||||
|  | @ -94,6 +120,6 @@ namespace kiwano | ||||||
| 		Int32		width_; | 		Int32		width_; | ||||||
| 		Int32		height_; | 		Int32		height_; | ||||||
| 		WCHAR*		device_name_; | 		WCHAR*		device_name_; | ||||||
| 		MouseCursor	mouse_cursor_; | 		CursorType	mouse_cursor_; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| //-----------------------------------------------------------------------------
 | //-----------------------------------------------------------------------------
 | ||||||
| // Compile-time options for Kiwano
 | // Compile-time configurations for Kiwano
 | ||||||
| //-----------------------------------------------------------------------------
 | //-----------------------------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
|  | @ -19,3 +19,6 @@ | ||||||
| 
 | 
 | ||||||
| //---- Define DirectX version. Defaults to using Direct3D11
 | //---- Define DirectX version. Defaults to using Direct3D11
 | ||||||
| //#define KGE_USE_DIRECTX10
 | //#define KGE_USE_DIRECTX10
 | ||||||
|  | 
 | ||||||
|  | //---- Define to enable DirectX debug layer
 | ||||||
|  | //#define KGE_ENABLE_DX_DEBUG
 | ||||||
|  |  | ||||||
|  | @ -61,12 +61,12 @@ | ||||||
| 
 | 
 | ||||||
| #include "renderer/Color.h" | #include "renderer/Color.h" | ||||||
| #include "renderer/Font.h" | #include "renderer/Font.h" | ||||||
| #include "renderer/Image.h" | #include "renderer/Texture.h" | ||||||
| #include "renderer/GifImage.h" | #include "renderer/GifImage.h" | ||||||
| #include "renderer/TextLayout.h" | #include "renderer/TextLayout.h" | ||||||
| #include "renderer/Geometry.h" | #include "renderer/Geometry.h" | ||||||
| #include "renderer/LayerArea.h" | #include "renderer/LayerArea.h" | ||||||
| #include "renderer/ImageCache.h" | #include "renderer/TextureCache.h" | ||||||
| #include "renderer/Renderer.h" | #include "renderer/Renderer.h" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -20,12 +20,10 @@ | ||||||
| 
 | 
 | ||||||
| #include "Application.h" | #include "Application.h" | ||||||
| #include "modules.h" | #include "modules.h" | ||||||
| #include "../base/Window.h" |  | ||||||
| #include "../base/Logger.h" | #include "../base/Logger.h" | ||||||
| #include "../base/input.h" | #include "../base/input.h" | ||||||
| #include "../base/Director.h" | #include "../base/Director.h" | ||||||
| #include "../renderer/ImageCache.h" | #include "../renderer/TextureCache.h" | ||||||
| #include "../renderer/Renderer.h" |  | ||||||
| #include "../utils/ResourceCache.h" | #include "../utils/ResourceCache.h" | ||||||
| #include <windowsx.h>  // GET_X_LPARAM, GET_Y_LPARAM
 | #include <windowsx.h>  // GET_X_LPARAM, GET_Y_LPARAM
 | ||||||
| #include <imm.h>  // ImmAssociateContext
 | #include <imm.h>  // ImmAssociateContext
 | ||||||
|  | @ -43,17 +41,19 @@ namespace kiwano | ||||||
| 		Queue<FunctionToPerform> functions_to_perform_; | 		Queue<FunctionToPerform> functions_to_perform_; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Options::Options(String const& title, Int32 width, Int32 height, UInt32 icon, Color clear_color, bool vsync, bool resizable, bool fullscreen, bool debug) | 	Config::Config(String const& title, UInt32 width, UInt32 height, UInt32 icon) | ||||||
| 		: title(title) | 	{ | ||||||
| 		, width(width) | 		window.title = title; | ||||||
| 		, height(height) | 		window.width = width; | ||||||
| 		, icon(icon) | 		window.height = height; | ||||||
| 		, clear_color(clear_color) | 		window.icon = icon; | ||||||
| 		, vsync(vsync) | 	} | ||||||
| 		, resizable(resizable) | 
 | ||||||
| 		, fullscreen(fullscreen) | 	Config::Config(WindowConfig const& wnd_config, RenderConfig const& render_config) | ||||||
| 		, debug(debug) | 	{ | ||||||
| 	{} | 		window = wnd_config; | ||||||
|  | 		render = render_config; | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
|  | @ -79,20 +79,10 @@ namespace kiwano | ||||||
| 		::CoUninitialize(); | 		::CoUninitialize(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Application::Init(const Options& options) | 	void Application::Init(const Config& config) | ||||||
| 	{ | 	{ | ||||||
| 		Window::GetInstance()->Init( | 		Window::GetInstance()->Init(config.window, Application::WndProc); | ||||||
| 			options.title, | 		Renderer::GetInstance()->Init(config.render); | ||||||
| 			options.width, |  | ||||||
| 			options.height, |  | ||||||
| 			options.icon, |  | ||||||
| 			options.resizable, |  | ||||||
| 			options.fullscreen, |  | ||||||
| 			Application::WndProc |  | ||||||
| 		); |  | ||||||
| 
 |  | ||||||
| 		Renderer::GetInstance()->SetClearColor(options.clear_color); |  | ||||||
| 		Renderer::GetInstance()->SetVSyncEnabled(options.vsync); |  | ||||||
| 
 | 
 | ||||||
| 		// Setup all components
 | 		// Setup all components
 | ||||||
| 		for (Component* c : components_) | 		for (Component* c : components_) | ||||||
|  | @ -100,7 +90,7 @@ namespace kiwano | ||||||
| 			c->SetupComponent(); | 			c->SetupComponent(); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (options.debug) | 		if (config.debug) | ||||||
| 		{ | 		{ | ||||||
| 			Director::GetInstance()->ShowDebugInfo(true); | 			Director::GetInstance()->ShowDebugInfo(true); | ||||||
| 			Renderer::GetInstance()->SetCollectingStatus(true); | 			Renderer::GetInstance()->SetCollectingStatus(true); | ||||||
|  | @ -150,7 +140,7 @@ namespace kiwano | ||||||
| 		// Clear all resources
 | 		// Clear all resources
 | ||||||
| 		Director::GetInstance()->ClearStages(); | 		Director::GetInstance()->ClearStages(); | ||||||
| 		ResourceCache::GetInstance()->Clear(); | 		ResourceCache::GetInstance()->Clear(); | ||||||
| 		ImageCache::GetInstance()->Clear(); | 		TextureCache::GetInstance()->Clear(); | ||||||
| 
 | 
 | ||||||
| 		if (inited_) | 		if (inited_) | ||||||
| 		{ | 		{ | ||||||
|  | @ -166,7 +156,7 @@ namespace kiwano | ||||||
| 		// Destroy all instances
 | 		// Destroy all instances
 | ||||||
| 		Director::DestroyInstance(); | 		Director::DestroyInstance(); | ||||||
| 		ResourceCache::DestroyInstance(); | 		ResourceCache::DestroyInstance(); | ||||||
| 		ImageCache::DestroyInstance(); | 		TextureCache::DestroyInstance(); | ||||||
| 		Input::DestroyInstance(); | 		Input::DestroyInstance(); | ||||||
| 		Renderer::DestroyInstance(); | 		Renderer::DestroyInstance(); | ||||||
| 		Window::DestroyInstance(); | 		Window::DestroyInstance(); | ||||||
|  | @ -299,10 +289,11 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 	LRESULT CALLBACK Application::WndProc(HWND hwnd, UInt32 msg, WPARAM wparam, LPARAM lparam) | 	LRESULT CALLBACK Application::WndProc(HWND hwnd, UInt32 msg, WPARAM wparam, LPARAM lparam) | ||||||
| 	{ | 	{ | ||||||
| 		Application * app = reinterpret_cast<Application*>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hwnd, GWLP_USERDATA))); | 		Application* app = reinterpret_cast<Application*>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hwnd, GWLP_USERDATA))); | ||||||
| 
 | 		if (app == nullptr) | ||||||
| 		if (!app) | 		{ | ||||||
| 			return ::DefWindowProcW(hwnd, msg, wparam, lparam); | 			return ::DefWindowProcW(hwnd, msg, wparam, lparam); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		// Handle Message
 | 		// Handle Message
 | ||||||
| 		for (Component* c : app->components_) | 		for (Component* c : app->components_) | ||||||
|  |  | ||||||
|  | @ -23,32 +23,27 @@ | ||||||
| #include "../base/time.h" | #include "../base/time.h" | ||||||
| #include "../base/Component.h" | #include "../base/Component.h" | ||||||
| #include "../base/Event.hpp" | #include "../base/Event.hpp" | ||||||
| #include "../renderer/Color.h" | #include "../base/Window.h" | ||||||
|  | #include "../renderer/Renderer.h" | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
| 	struct Options | 	struct Config | ||||||
| 	{ | 	{ | ||||||
| 		String	title;				// 标题
 | 		WindowConfig window;	// ´°¿ÚÉèÖÃ
 | ||||||
| 		Int32	width;				// 宽度
 | 		RenderConfig render;	// äÖȾÉèÖÃ
 | ||||||
| 		Int32	height;				// 高度
 | 		bool debug;				// µ÷ÊÔģʽ
 | ||||||
| 		UInt32	icon;				// 图标资源 ID
 |  | ||||||
| 		Color	clear_color;		// 清屏颜色
 |  | ||||||
| 		bool	vsync;				// 垂直同步
 |  | ||||||
| 		bool	resizable;			// 窗口大小可拉伸
 |  | ||||||
| 		bool	fullscreen;			// 全屏模式
 |  | ||||||
| 		bool	debug;				// 调试模式
 |  | ||||||
| 
 | 
 | ||||||
| 		Options( | 		Config( | ||||||
| 			String const& title	= L"Kiwano Game", | 			String const& title	= L"Kiwano Game", | ||||||
| 			Int32 width			= 640, | 			UInt32 width		= 640, | ||||||
| 			Int32 height		= 480, | 			UInt32 height		= 480, | ||||||
| 			UInt32 icon			= 0, | 			UInt32 icon			= 0 | ||||||
| 			Color clear_color	= Color::Black, | 		); | ||||||
| 			bool vsync			= true, | 
 | ||||||
| 			bool resizable		= false, | 		Config( | ||||||
| 			bool fullscreen		= false, | 			WindowConfig const& wnd_config, | ||||||
| 			bool debug			= false | 			RenderConfig const& render_config = RenderConfig() | ||||||
| 		); | 		); | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
|  | @ -64,7 +59,7 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 		// 初始化
 | 		// 初始化
 | ||||||
| 		void Init( | 		void Init( | ||||||
| 			Options const& options = Options{} | 			Config const& config = Config() | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		// 初始化成功时
 | 		// 初始化成功时
 | ||||||
|  |  | ||||||
|  | @ -22,7 +22,16 @@ | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
| 	Font::Font(const String& family, Float32 size, UInt32 weight, bool italic, FontCollection collection) | 	Font::Font(String const& family, Float32 size, UInt32 weight, bool italic) | ||||||
|  | 		: family(family) | ||||||
|  | 		, size(size) | ||||||
|  | 		, weight(weight) | ||||||
|  | 		, italic(italic) | ||||||
|  | 		, collection() | ||||||
|  | 	{ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	Font::Font(FontCollection collection, String const& family, Float32 size, UInt32 weight, bool italic) | ||||||
| 		: family(family) | 		: family(family) | ||||||
| 		, size(size) | 		, size(size) | ||||||
| 		, weight(weight) | 		, weight(weight) | ||||||
|  |  | ||||||
|  | @ -49,11 +49,18 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 	public: | 	public: | ||||||
| 		Font( | 		Font( | ||||||
| 			const String& family		= L"", | 			String const& family		= L"", | ||||||
| 			Float32 size				= 18, | 			Float32 size				= 18, | ||||||
| 			UInt32 weight				= FontWeight::Normal, | 			UInt32 weight				= FontWeight::Normal, | ||||||
| 			bool italic					= false, | 			bool italic					= false | ||||||
| 			FontCollection collection	= FontCollection() | 		); | ||||||
|  | 
 | ||||||
|  | 		Font( | ||||||
|  | 			FontCollection collection, | ||||||
|  | 			String const& family		= L"", | ||||||
|  | 			Float32 size				= 18, | ||||||
|  | 			UInt32 weight				= FontWeight::Normal, | ||||||
|  | 			bool italic					= false | ||||||
| 		); | 		); | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -50,24 +50,30 @@ namespace kiwano | ||||||
| 	bool FontCollection::Load(String const& file) | 	bool FontCollection::Load(String const& file) | ||||||
| 	{ | 	{ | ||||||
| 		Renderer::GetInstance()->CreateFontCollection(*this, { file }); | 		Renderer::GetInstance()->CreateFontCollection(*this, { file }); | ||||||
| 		return false; | 		return IsValid(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool FontCollection::Load(Vector<String> const& files) | 	bool FontCollection::Load(Vector<String> const& files) | ||||||
| 	{ | 	{ | ||||||
| 		Renderer::GetInstance()->CreateFontCollection(*this, files); | 		Renderer::GetInstance()->CreateFontCollection(*this, files); | ||||||
| 		return false; | 		return IsValid(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool FontCollection::Load(Resource const& res) | 	bool FontCollection::Load(Resource const& res) | ||||||
| 	{ | 	{ | ||||||
| 		Renderer::GetInstance()->CreateFontCollection(*this, { res }); | 		Renderer::GetInstance()->CreateFontCollection(*this, { res }); | ||||||
| 		return false; | 		return IsValid(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool FontCollection::Load(Vector<Resource> const& res_arr) | 	bool FontCollection::Load(Vector<Resource> const& res_arr) | ||||||
| 	{ | 	{ | ||||||
| 		Renderer::GetInstance()->CreateFontCollection(*this, res_arr); | 		Renderer::GetInstance()->CreateFontCollection(*this, res_arr); | ||||||
| 		return false; | 		return IsValid(); | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	bool FontCollection::IsValid() const | ||||||
|  | 	{ | ||||||
|  | 		return collection_ != nullptr; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -51,6 +51,8 @@ namespace kiwano | ||||||
| 		// 从多个资源加载字体
 | 		// 从多个资源加载字体
 | ||||||
| 		bool Load(Vector<Resource> const& res_arr); | 		bool Load(Vector<Resource> const& res_arr); | ||||||
| 
 | 
 | ||||||
|  | 		bool IsValid() const; | ||||||
|  | 
 | ||||||
| 	public: | 	public: | ||||||
| 		inline ComPtr<IDWriteFontCollection> GetFontCollection() const			{ return collection_; } | 		inline ComPtr<IDWriteFontCollection> GetFontCollection() const			{ return collection_; } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -28,7 +28,6 @@ namespace kiwano | ||||||
| 		: frames_count_(0) | 		: frames_count_(0) | ||||||
| 		, width_in_pixels_(0) | 		, width_in_pixels_(0) | ||||||
| 		, height_in_pixels_(0) | 		, height_in_pixels_(0) | ||||||
| 		, bg_color_{} |  | ||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -82,15 +81,6 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 	HRESULT GifImage::GetGlobalMetadata() | 	HRESULT GifImage::GetGlobalMetadata() | ||||||
| 	{ | 	{ | ||||||
| 		UInt32 width = 0; |  | ||||||
| 		UInt32 height = 0; |  | ||||||
| 
 |  | ||||||
| 		PROPVARIANT prop_val; |  | ||||||
| 		::PropVariantInit(&prop_val); |  | ||||||
| 
 |  | ||||||
| 		ComPtr<IWICMetadataQueryReader> metadata_reader; |  | ||||||
| 
 |  | ||||||
| 		// 获取帧数量
 |  | ||||||
| 		HRESULT hr = decoder_ ? S_OK : E_FAIL; | 		HRESULT hr = decoder_ ? S_OK : E_FAIL; | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr)) | 		if (SUCCEEDED(hr)) | ||||||
|  | @ -100,317 +90,91 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr)) | 		if (SUCCEEDED(hr)) | ||||||
| 		{ | 		{ | ||||||
|  | 			ComPtr<IWICMetadataQueryReader> metadata_reader; | ||||||
| 			hr = decoder_->GetMetadataQueryReader(&metadata_reader); | 			hr = decoder_->GetMetadataQueryReader(&metadata_reader); | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			// 获取背景色
 |  | ||||||
| 			if (FAILED(GetBackgroundColor(metadata_reader.get()))) |  | ||||||
| 			{ |  | ||||||
| 				// 如果未能获得颜色,则默认为透明
 |  | ||||||
| 				bg_color_ = Color(0, 0.f); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// 获取全局 frame 大小
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			// 获取宽度
 |  | ||||||
| 			hr = metadata_reader->GetMetadataByName(L"/logscrdesc/Width", &prop_val); |  | ||||||
| 
 | 
 | ||||||
| 			if (SUCCEEDED(hr)) | 			if (SUCCEEDED(hr)) | ||||||
| 			{ | 			{ | ||||||
| 				hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL); | 				UInt32 width = 0; | ||||||
|  | 				UInt32 height = 0; | ||||||
|  | 
 | ||||||
|  | 				PROPVARIANT prop_val; | ||||||
|  | 				::PropVariantInit(&prop_val); | ||||||
|  | 
 | ||||||
|  | 				// 获取全局 frame 大小
 | ||||||
| 				if (SUCCEEDED(hr)) | 				if (SUCCEEDED(hr)) | ||||||
| 				{ | 				{ | ||||||
| 					width = prop_val.uiVal; | 					// 获取宽度
 | ||||||
| 				} | 					hr = metadata_reader->GetMetadataByName(L"/logscrdesc/Width", &prop_val); | ||||||
| 				::PropVariantClear(&prop_val); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			// 获取高度
 |  | ||||||
| 			hr = metadata_reader->GetMetadataByName(L"/logscrdesc/Height", &prop_val); |  | ||||||
| 
 |  | ||||||
| 			if (SUCCEEDED(hr)) |  | ||||||
| 			{ |  | ||||||
| 				hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL); |  | ||||||
| 				if (SUCCEEDED(hr)) |  | ||||||
| 				{ |  | ||||||
| 					height = prop_val.uiVal; |  | ||||||
| 				} |  | ||||||
| 				::PropVariantClear(&prop_val); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			// 获得像素纵横比
 |  | ||||||
| 			hr = metadata_reader->GetMetadataByName(L"/logscrdesc/PixelAspectRatio", &prop_val); |  | ||||||
| 
 |  | ||||||
| 			if (SUCCEEDED(hr)) |  | ||||||
| 			{ |  | ||||||
| 				hr = (prop_val.vt == VT_UI1 ? S_OK : E_FAIL); |  | ||||||
| 				if (SUCCEEDED(hr)) |  | ||||||
| 				{ |  | ||||||
| 					if (prop_val.bVal != 0) |  | ||||||
| 					{ |  | ||||||
| 						// 需要计算比率
 |  | ||||||
| 						// 最高像素 1:4,最宽像素 4:1,增量为 1/64
 |  | ||||||
| 						Float32 pixel_asp_ratio = (prop_val.bVal + 15.f) / 64.f; |  | ||||||
| 
 |  | ||||||
| 						// 根据像素长宽比计算像素中的图像宽度和高度,只缩小图像
 |  | ||||||
| 						if (pixel_asp_ratio > 1.f) |  | ||||||
| 						{ |  | ||||||
| 							width_in_pixels_ = width; |  | ||||||
| 							height_in_pixels_ = static_cast<UInt32>(height / pixel_asp_ratio); |  | ||||||
| 						} |  | ||||||
| 						else |  | ||||||
| 						{ |  | ||||||
| 							width_in_pixels_ = static_cast<UInt32>(width * pixel_asp_ratio); |  | ||||||
| 							height_in_pixels_ = height; |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 					else |  | ||||||
| 					{ |  | ||||||
| 						// 值为 0, 所以像素比为 1
 |  | ||||||
| 						width_in_pixels_ = width; |  | ||||||
| 						height_in_pixels_ = height; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 				::PropVariantClear(&prop_val); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		::PropVariantClear(&prop_val); |  | ||||||
| 		return hr; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	HRESULT GifImage::GetBackgroundColor(ComPtr<IWICMetadataQueryReader> metadata_reader) |  | ||||||
| 	{ |  | ||||||
| 		UChar bg_index = 0; |  | ||||||
| 		WICColor bgcolors[256]; |  | ||||||
| 		UInt32 colors_copied = 0; |  | ||||||
| 		ComPtr<IWICPalette> wic_palette; |  | ||||||
| 
 |  | ||||||
| 		PROPVARIANT prop_val; |  | ||||||
| 		PropVariantInit(&prop_val); |  | ||||||
| 
 |  | ||||||
| 		HRESULT hr = metadata_reader->GetMetadataByName(L"/logscrdesc/GlobalColorTableFlag", &prop_val); |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = (prop_val.vt != VT_BOOL || !prop_val.boolVal) ? E_FAIL : S_OK; |  | ||||||
| 			::PropVariantClear(&prop_val); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = metadata_reader->GetMetadataByName(L"/logscrdesc/BackgroundColorIndex", &prop_val); |  | ||||||
| 
 |  | ||||||
| 			if (SUCCEEDED(hr)) |  | ||||||
| 			{ |  | ||||||
| 				hr = (prop_val.vt != VT_UI1) ? E_FAIL : S_OK; |  | ||||||
| 				if (SUCCEEDED(hr)) |  | ||||||
| 				{ |  | ||||||
| 					bg_index = prop_val.bVal; |  | ||||||
| 				} |  | ||||||
| 				::PropVariantClear(&prop_val); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			auto factory = Renderer::GetInstance()->GetD2DDeviceResources()->GetWICImagingFactory(); |  | ||||||
| 			hr = factory->CreatePalette(&wic_palette); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = decoder_->CopyPalette(wic_palette.get()); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = wic_palette->GetColors( |  | ||||||
| 				ARRAYSIZE(bgcolors), |  | ||||||
| 				bgcolors, |  | ||||||
| 				&colors_copied); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = (bg_index >= colors_copied) ? E_FAIL : S_OK; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			// 转换为 ARGB 格式
 |  | ||||||
| 			Float32 alpha = (bgcolors[bg_index] >> 24) / 255.f; |  | ||||||
| 			bg_color_ = Color(bgcolors[bg_index], alpha); |  | ||||||
| 		} |  | ||||||
| 		return hr; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	HRESULT GifImage::GetRawFrame(UInt32 frame_index, Image& raw_frame, Rect& frame_rect, Duration& delay, DisposalType& disposal_type) |  | ||||||
| 	{ |  | ||||||
| 		ComPtr<IWICFormatConverter> converter; |  | ||||||
| 		ComPtr<IWICBitmapFrameDecode> wic_frame; |  | ||||||
| 		ComPtr<IWICMetadataQueryReader> metadata_reader; |  | ||||||
| 
 |  | ||||||
| 		PROPVARIANT prop_val; |  | ||||||
| 		PropVariantInit(&prop_val); |  | ||||||
| 
 |  | ||||||
| 		// Retrieve the current frame
 |  | ||||||
| 		HRESULT hr = decoder_->GetFrame(frame_index, &wic_frame); |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			// Format convert to 32bppPBGRA which D2D expects
 |  | ||||||
| 			auto factory = Renderer::GetInstance()->GetD2DDeviceResources()->GetWICImagingFactory(); |  | ||||||
| 			hr = factory->CreateFormatConverter(&converter); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = converter->Initialize( |  | ||||||
| 				wic_frame.get(), |  | ||||||
| 				GUID_WICPixelFormat32bppPBGRA, |  | ||||||
| 				WICBitmapDitherTypeNone, |  | ||||||
| 				nullptr, |  | ||||||
| 				0.f, |  | ||||||
| 				WICBitmapPaletteTypeCustom); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			auto ctx = Renderer::GetInstance()->GetD2DDeviceResources()->GetDeviceContext(); |  | ||||||
| 
 |  | ||||||
| 			// Create a D2DBitmap from IWICBitmapSource
 |  | ||||||
| 			ComPtr<ID2D1Bitmap> raw_bitmap; |  | ||||||
| 			hr = ctx->CreateBitmapFromWicBitmap( |  | ||||||
| 				converter.get(), |  | ||||||
| 				nullptr, |  | ||||||
| 				&raw_bitmap |  | ||||||
| 			); |  | ||||||
| 
 |  | ||||||
| 			if (SUCCEEDED(hr)) |  | ||||||
| 			{ |  | ||||||
| 				raw_frame.SetBitmap(raw_bitmap); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			// Get Metadata Query Reader from the frame
 |  | ||||||
| 			hr = wic_frame->GetMetadataQueryReader(&metadata_reader); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// Get the Metadata for the current frame
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = metadata_reader->GetMetadataByName(L"/imgdesc/Left", &prop_val); |  | ||||||
| 			if (SUCCEEDED(hr)) |  | ||||||
| 			{ |  | ||||||
| 				hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL); |  | ||||||
| 				if (SUCCEEDED(hr)) |  | ||||||
| 				{ |  | ||||||
| 					frame_rect.left_top.x = static_cast<Float32>(prop_val.uiVal); |  | ||||||
| 				} |  | ||||||
| 				PropVariantClear(&prop_val); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = metadata_reader->GetMetadataByName(L"/imgdesc/Top", &prop_val); |  | ||||||
| 			if (SUCCEEDED(hr)) |  | ||||||
| 			{ |  | ||||||
| 				hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL); |  | ||||||
| 				if (SUCCEEDED(hr)) |  | ||||||
| 				{ |  | ||||||
| 					frame_rect.left_top.y = static_cast<Float32>(prop_val.uiVal); |  | ||||||
| 				} |  | ||||||
| 				PropVariantClear(&prop_val); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = metadata_reader->GetMetadataByName(L"/imgdesc/Width", &prop_val); |  | ||||||
| 			if (SUCCEEDED(hr)) |  | ||||||
| 			{ |  | ||||||
| 				hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL); |  | ||||||
| 				if (SUCCEEDED(hr)) |  | ||||||
| 				{ |  | ||||||
| 					frame_rect.right_bottom.x = frame_rect.left_top.x + static_cast<Float32>(prop_val.uiVal); |  | ||||||
| 				} |  | ||||||
| 				PropVariantClear(&prop_val); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = metadata_reader->GetMetadataByName(L"/imgdesc/Height", &prop_val); |  | ||||||
| 			if (SUCCEEDED(hr)) |  | ||||||
| 			{ |  | ||||||
| 				hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL); |  | ||||||
| 				if (SUCCEEDED(hr)) |  | ||||||
| 				{ |  | ||||||
| 					frame_rect.right_bottom.y = frame_rect.left_top.y + static_cast<Float32>(prop_val.uiVal); |  | ||||||
| 				} |  | ||||||
| 				PropVariantClear(&prop_val); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = metadata_reader->GetMetadataByName(L"/grctlext/Delay", &prop_val); |  | ||||||
| 
 |  | ||||||
| 			if (SUCCEEDED(hr)) |  | ||||||
| 			{ |  | ||||||
| 				hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL); |  | ||||||
| 
 |  | ||||||
| 				if (SUCCEEDED(hr)) |  | ||||||
| 				{ |  | ||||||
| 					UInt32 udelay = 0; |  | ||||||
| 					hr = UIntMult(prop_val.uiVal, 10, &udelay); |  | ||||||
| 					if (SUCCEEDED(hr)) | 					if (SUCCEEDED(hr)) | ||||||
| 					{ | 					{ | ||||||
| 						delay.SetMilliseconds(static_cast<long>(udelay)); | 						hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL); | ||||||
|  | 						if (SUCCEEDED(hr)) | ||||||
|  | 						{ | ||||||
|  | 							width = prop_val.uiVal; | ||||||
|  | 						} | ||||||
|  | 						::PropVariantClear(&prop_val); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 				PropVariantClear(&prop_val); |  | ||||||
| 			} |  | ||||||
| 			else |  | ||||||
| 			{ |  | ||||||
| 				delay = 0; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = metadata_reader->GetMetadataByName(L"/grctlext/Disposal", &prop_val); |  | ||||||
| 
 |  | ||||||
| 			if (SUCCEEDED(hr)) |  | ||||||
| 			{ |  | ||||||
| 				hr = (prop_val.vt == VT_UI1) ? S_OK : E_FAIL; |  | ||||||
| 				if (SUCCEEDED(hr)) | 				if (SUCCEEDED(hr)) | ||||||
| 				{ | 				{ | ||||||
| 					disposal_type = DisposalType(prop_val.bVal); | 					// 获取高度
 | ||||||
|  | 					hr = metadata_reader->GetMetadataByName(L"/logscrdesc/Height", &prop_val); | ||||||
|  | 
 | ||||||
|  | 					if (SUCCEEDED(hr)) | ||||||
|  | 					{ | ||||||
|  | 						hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL); | ||||||
|  | 						if (SUCCEEDED(hr)) | ||||||
|  | 						{ | ||||||
|  | 							height = prop_val.uiVal; | ||||||
|  | 						} | ||||||
|  | 						::PropVariantClear(&prop_val); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (SUCCEEDED(hr)) | ||||||
|  | 				{ | ||||||
|  | 					// 获得像素纵横比
 | ||||||
|  | 					hr = metadata_reader->GetMetadataByName(L"/logscrdesc/PixelAspectRatio", &prop_val); | ||||||
|  | 
 | ||||||
|  | 					if (SUCCEEDED(hr)) | ||||||
|  | 					{ | ||||||
|  | 						hr = (prop_val.vt == VT_UI1 ? S_OK : E_FAIL); | ||||||
|  | 						if (SUCCEEDED(hr)) | ||||||
|  | 						{ | ||||||
|  | 							if (prop_val.bVal != 0) | ||||||
|  | 							{ | ||||||
|  | 								// 需要计算比率
 | ||||||
|  | 								// 最高像素 1:4,最宽像素 4:1,增量为 1/64
 | ||||||
|  | 								Float32 pixel_asp_ratio = (prop_val.bVal + 15.f) / 64.f; | ||||||
|  | 
 | ||||||
|  | 								// 根据像素长宽比计算像素中的图像宽度和高度,只缩小图像
 | ||||||
|  | 								if (pixel_asp_ratio > 1.f) | ||||||
|  | 								{ | ||||||
|  | 									width_in_pixels_ = width; | ||||||
|  | 									height_in_pixels_ = static_cast<UInt32>(height / pixel_asp_ratio); | ||||||
|  | 								} | ||||||
|  | 								else | ||||||
|  | 								{ | ||||||
|  | 									width_in_pixels_ = static_cast<UInt32>(width * pixel_asp_ratio); | ||||||
|  | 									height_in_pixels_ = height; | ||||||
|  | 								} | ||||||
|  | 							} | ||||||
|  | 							else | ||||||
|  | 							{ | ||||||
|  | 								// 值为 0, 所以像素比为 1
 | ||||||
|  | 								width_in_pixels_ = width; | ||||||
|  | 								height_in_pixels_ = height; | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 						::PropVariantClear(&prop_val); | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 				::PropVariantClear(&prop_val); | 				::PropVariantClear(&prop_val); | ||||||
| 			} | 			} | ||||||
| 			else |  | ||||||
| 			{ |  | ||||||
| 				// 获取 DisposalType 失败,可能图片是只有一帧的图片
 |  | ||||||
| 				disposal_type = DisposalType::Unknown; |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 
 |  | ||||||
| 		::PropVariantClear(&prop_val); |  | ||||||
| 		return hr; | 		return hr; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ | ||||||
| // THE SOFTWARE.
 | // THE SOFTWARE.
 | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| #include "Image.h" | #include "Texture.h" | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
|  | @ -43,9 +43,7 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 		inline UInt32 GetHeightInPixels() const	{ return height_in_pixels_; } | 		inline UInt32 GetHeightInPixels() const	{ return height_in_pixels_; } | ||||||
| 
 | 
 | ||||||
| 		inline UInt32 GetFramesCount() const		{ return frames_count_; } | 		inline UInt32 GetFramesCount() const	{ return frames_count_; } | ||||||
| 
 |  | ||||||
| 		inline Color GetBackgroundColor() const	{ return bg_color_; } |  | ||||||
| 
 | 
 | ||||||
| 	public: | 	public: | ||||||
| 		enum class DisposalType | 		enum class DisposalType | ||||||
|  | @ -56,13 +54,15 @@ namespace kiwano | ||||||
| 			Previous | 			Previous | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		HRESULT GetRawFrame( | 		struct Frame | ||||||
| 			UInt32 frame_index, | 		{ | ||||||
| 			Image& raw_frame, | 			Duration delay; | ||||||
| 			Rect& frame_rect, | 			Texture raw; | ||||||
| 			Duration& delay, | 			Rect rect; | ||||||
| 			DisposalType& disposal_type | 			DisposalType disposal_type; | ||||||
| 		); | 
 | ||||||
|  | 			Frame() : disposal_type(DisposalType::Unknown) {} | ||||||
|  | 		}; | ||||||
| 
 | 
 | ||||||
| 		inline ComPtr<IWICBitmapDecoder> GetDecoder() const			{ return decoder_; } | 		inline ComPtr<IWICBitmapDecoder> GetDecoder() const			{ return decoder_; } | ||||||
| 
 | 
 | ||||||
|  | @ -71,16 +71,11 @@ namespace kiwano | ||||||
| 	protected: | 	protected: | ||||||
| 		HRESULT GetGlobalMetadata(); | 		HRESULT GetGlobalMetadata(); | ||||||
| 
 | 
 | ||||||
| 		HRESULT GetBackgroundColor( |  | ||||||
| 			ComPtr<IWICMetadataQueryReader> metadata_reader |  | ||||||
| 		); |  | ||||||
| 
 |  | ||||||
| 	protected: | 	protected: | ||||||
| 		UInt32	frames_count_; | 		UInt32	frames_count_; | ||||||
| 		UInt32	width_in_pixels_; | 		UInt32	width_in_pixels_; | ||||||
| 		UInt32	height_in_pixels_; | 		UInt32	height_in_pixels_; | ||||||
| 		Color	bg_color_; |  | ||||||
| 
 | 
 | ||||||
| 		ComPtr<IWICBitmapDecoder>	decoder_; | 		ComPtr<IWICBitmapDecoder> decoder_; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -30,8 +30,9 @@ namespace kiwano | ||||||
| 	RenderTarget::RenderTarget() | 	RenderTarget::RenderTarget() | ||||||
| 		: opacity_(1.f) | 		: opacity_(1.f) | ||||||
| 		, collecting_status_(false) | 		, collecting_status_(false) | ||||||
|  | 		, fast_global_transform_(true) | ||||||
| 		, antialias_(true) | 		, antialias_(true) | ||||||
| 		, text_antialias_(TextAntialias::GrayScale) | 		, text_antialias_(TextAntialiasMode::GrayScale) | ||||||
| 	{ | 	{ | ||||||
| 		status_.primitives = 0; | 		status_.primitives = 0; | ||||||
| 	} | 	} | ||||||
|  | @ -133,7 +134,7 @@ namespace kiwano | ||||||
| 				geometry.GetGeometry().get(), | 				geometry.GetGeometry().get(), | ||||||
| 				default_brush_.get(), | 				default_brush_.get(), | ||||||
| 				stroke_width, | 				stroke_width, | ||||||
| 				device_resources_->GetStrokeStyle(stroke) | 				GetStrokeStyle(stroke).get() | ||||||
| 			); | 			); | ||||||
| 
 | 
 | ||||||
| 			IncreasePrimitivesCount(); | 			IncreasePrimitivesCount(); | ||||||
|  | @ -179,7 +180,7 @@ namespace kiwano | ||||||
| 				DX::ConvertToPoint2F(point2), | 				DX::ConvertToPoint2F(point2), | ||||||
| 				default_brush_.get(), | 				default_brush_.get(), | ||||||
| 				stroke_width, | 				stroke_width, | ||||||
| 				device_resources_->GetStrokeStyle(stroke) | 				GetStrokeStyle(stroke).get() | ||||||
| 			); | 			); | ||||||
| 
 | 
 | ||||||
| 			IncreasePrimitivesCount(); | 			IncreasePrimitivesCount(); | ||||||
|  | @ -204,7 +205,7 @@ namespace kiwano | ||||||
| 				DX::ConvertToRectF(rect), | 				DX::ConvertToRectF(rect), | ||||||
| 				default_brush_.get(), | 				default_brush_.get(), | ||||||
| 				stroke_width, | 				stroke_width, | ||||||
| 				device_resources_->GetStrokeStyle(stroke) | 				GetStrokeStyle(stroke).get() | ||||||
| 			); | 			); | ||||||
| 
 | 
 | ||||||
| 			IncreasePrimitivesCount(); | 			IncreasePrimitivesCount(); | ||||||
|  | @ -253,7 +254,7 @@ namespace kiwano | ||||||
| 				), | 				), | ||||||
| 				default_brush_.get(), | 				default_brush_.get(), | ||||||
| 				stroke_width, | 				stroke_width, | ||||||
| 				device_resources_->GetStrokeStyle(stroke) | 				GetStrokeStyle(stroke).get() | ||||||
| 			); | 			); | ||||||
| 
 | 
 | ||||||
| 			IncreasePrimitivesCount(); | 			IncreasePrimitivesCount(); | ||||||
|  | @ -306,7 +307,7 @@ namespace kiwano | ||||||
| 				), | 				), | ||||||
| 				default_brush_.get(), | 				default_brush_.get(), | ||||||
| 				stroke_width, | 				stroke_width, | ||||||
| 				device_resources_->GetStrokeStyle(stroke) | 				GetStrokeStyle(stroke).get() | ||||||
| 			); | 			); | ||||||
| 
 | 
 | ||||||
| 			IncreasePrimitivesCount(); | 			IncreasePrimitivesCount(); | ||||||
|  | @ -339,12 +340,12 @@ namespace kiwano | ||||||
| 		ThrowIfFailed(hr); | 		ThrowIfFailed(hr); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void RenderTarget::DrawImage(Image const& image, Rect const& src_rect, Rect const& dest_rect) const | 	void RenderTarget::DrawTexture(Texture const& texture, Rect const& src_rect, Rect const& dest_rect) const | ||||||
| 	{ | 	{ | ||||||
| 		DrawImage(image, &src_rect, &dest_rect); | 		DrawTexture(texture, &src_rect, &dest_rect); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void RenderTarget::DrawImage(Image const& image, const Rect* src_rect, const Rect* dest_rect) const | 	void RenderTarget::DrawTexture(Texture const& texture, const Rect* src_rect, const Rect* dest_rect) const | ||||||
| 	{ | 	{ | ||||||
| 		HRESULT hr = S_OK; | 		HRESULT hr = S_OK; | ||||||
| 		if (!render_target_) | 		if (!render_target_) | ||||||
|  | @ -352,13 +353,17 @@ namespace kiwano | ||||||
| 			hr = E_UNEXPECTED; | 			hr = E_UNEXPECTED; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr) && image.IsValid()) | 		if (SUCCEEDED(hr) && texture.IsValid()) | ||||||
| 		{ | 		{ | ||||||
|  | 			auto mode = (texture.GetBitmapInterpolationMode() == InterpolationMode::Linear) | ||||||
|  | 				? D2D1_BITMAP_INTERPOLATION_MODE_LINEAR | ||||||
|  | 				: D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR; | ||||||
|  | 
 | ||||||
| 			render_target_->DrawBitmap( | 			render_target_->DrawBitmap( | ||||||
| 				image.GetBitmap().get(), | 				texture.GetBitmap().get(), | ||||||
| 				dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr, | 				dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr, | ||||||
| 				opacity_, | 				opacity_, | ||||||
| 				D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, | 				mode, | ||||||
| 				src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr | 				src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr | ||||||
| 			); | 			); | ||||||
| 
 | 
 | ||||||
|  | @ -384,7 +389,7 @@ namespace kiwano | ||||||
| 				layout.GetTextStyle().outline, | 				layout.GetTextStyle().outline, | ||||||
| 				DX::ConvertToColorF(layout.GetTextStyle().outline_color), | 				DX::ConvertToColorF(layout.GetTextStyle().outline_color), | ||||||
| 				layout.GetTextStyle().outline_width, | 				layout.GetTextStyle().outline_width, | ||||||
| 				device_resources_->GetStrokeStyle(layout.GetTextStyle().outline_stroke) | 				GetStrokeStyle(layout.GetTextStyle().outline_stroke).get() | ||||||
| 			); | 			); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -537,7 +542,18 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 	Matrix3x2 RenderTarget::GetGlobalTransform() const | 	Matrix3x2 RenderTarget::GetGlobalTransform() const | ||||||
| 	{ | 	{ | ||||||
| 		return global_matrix_; | 		return global_transform_; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ComPtr<ID2D1StrokeStyle> RenderTarget::GetStrokeStyle(StrokeStyle style) const | ||||||
|  | 	{ | ||||||
|  | 		switch (style) | ||||||
|  | 		{ | ||||||
|  | 		case StrokeStyle::Miter: return device_resources_->GetMiterStrokeStyle(); break; | ||||||
|  | 		case StrokeStyle::Bevel: return device_resources_->GetBevelStrokeStyle(); break; | ||||||
|  | 		case StrokeStyle::Round: return device_resources_->GetRoundStrokeStyle(); break; | ||||||
|  | 		} | ||||||
|  | 		return nullptr; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void RenderTarget::SetTransform(const Matrix3x2& matrix) | 	void RenderTarget::SetTransform(const Matrix3x2& matrix) | ||||||
|  | @ -550,8 +566,16 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr)) | 		if (SUCCEEDED(hr)) | ||||||
| 		{ | 		{ | ||||||
| 			Matrix3x2 result = matrix * global_matrix_; | 			if (fast_global_transform_) | ||||||
| 			render_target_->SetTransform(DX::ConvertToMatrix3x2F(&result)); | 			{ | ||||||
|  | 				render_target_->SetTransform(DX::ConvertToMatrix3x2F(&matrix)); | ||||||
|  | 
 | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				Matrix3x2 result = matrix * global_transform_; | ||||||
|  | 				render_target_->SetTransform(DX::ConvertToMatrix3x2F(&result)); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		ThrowIfFailed(hr); | 		ThrowIfFailed(hr); | ||||||
|  | @ -559,7 +583,20 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 	void RenderTarget::SetGlobalTransform(const Matrix3x2& matrix) | 	void RenderTarget::SetGlobalTransform(const Matrix3x2& matrix) | ||||||
| 	{ | 	{ | ||||||
| 		global_matrix_ = matrix; | 		SetGlobalTransform(&matrix); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void RenderTarget::SetGlobalTransform(const Matrix3x2* matrix) | ||||||
|  | 	{ | ||||||
|  | 		if (matrix) | ||||||
|  | 		{ | ||||||
|  | 			global_transform_ = *matrix; | ||||||
|  | 			fast_global_transform_ = false; | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			fast_global_transform_ = true; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void RenderTarget::SetOpacity(Float32 opacity) | 	void RenderTarget::SetOpacity(Float32 opacity) | ||||||
|  | @ -601,7 +638,7 @@ namespace kiwano | ||||||
| 		ThrowIfFailed(hr); | 		ThrowIfFailed(hr); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void RenderTarget::SetTextAntialiasMode(TextAntialias mode) | 	void RenderTarget::SetTextAntialiasMode(TextAntialiasMode mode) | ||||||
| 	{ | 	{ | ||||||
| 		HRESULT hr = S_OK; | 		HRESULT hr = S_OK; | ||||||
| 		if (!render_target_) | 		if (!render_target_) | ||||||
|  | @ -615,16 +652,16 @@ namespace kiwano | ||||||
| 			D2D1_TEXT_ANTIALIAS_MODE antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; | 			D2D1_TEXT_ANTIALIAS_MODE antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; | ||||||
| 			switch (text_antialias_) | 			switch (text_antialias_) | ||||||
| 			{ | 			{ | ||||||
| 			case TextAntialias::Default: | 			case TextAntialiasMode::Default: | ||||||
| 				antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; | 				antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; | ||||||
| 				break; | 				break; | ||||||
| 			case TextAntialias::ClearType: | 			case TextAntialiasMode::ClearType: | ||||||
| 				antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; | 				antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; | ||||||
| 				break; | 				break; | ||||||
| 			case TextAntialias::GrayScale: | 			case TextAntialiasMode::GrayScale: | ||||||
| 				antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; | 				antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; | ||||||
| 				break; | 				break; | ||||||
| 			case TextAntialias::None: | 			case TextAntialiasMode::None: | ||||||
| 				antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED; | 				antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED; | ||||||
| 				break; | 				break; | ||||||
| 			default: | 			default: | ||||||
|  | @ -638,9 +675,12 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 	bool RenderTarget::CheckVisibility(Rect const& bounds, Matrix3x2 const& transform) | 	bool RenderTarget::CheckVisibility(Rect const& bounds, Matrix3x2 const& transform) | ||||||
| 	{ | 	{ | ||||||
| 		return Rect{ Point{}, reinterpret_cast<const Size&>(render_target_->GetSize()) }.Intersects( | 		Rect visible_size = { Point{}, reinterpret_cast<const Size&>(render_target_->GetSize()) }; | ||||||
| 			Matrix3x2(transform * global_matrix_).Transform(bounds) | 		if (fast_global_transform_) | ||||||
| 		); | 		{ | ||||||
|  | 			return visible_size.Intersects(transform.Transform(bounds)); | ||||||
|  | 		} | ||||||
|  | 		return visible_size.Intersects(Matrix3x2(transform * global_transform_).Transform(bounds)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void RenderTarget::SetCollectingStatus(bool collecting) | 	void RenderTarget::SetCollectingStatus(bool collecting) | ||||||
|  | @ -658,14 +698,14 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	//
 | 	//
 | ||||||
| 	// ImageRenderTarget
 | 	// TextureRenderTarget
 | ||||||
| 	//
 | 	//
 | ||||||
| 
 | 
 | ||||||
| 	ImageRenderTarget::ImageRenderTarget() | 	TextureRenderTarget::TextureRenderTarget() | ||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Image ImageRenderTarget::GetOutput() const | 	Texture TextureRenderTarget::GetOutput() const | ||||||
| 	{ | 	{ | ||||||
| 		HRESULT hr = E_FAIL; | 		HRESULT hr = E_FAIL; | ||||||
| 
 | 
 | ||||||
|  | @ -681,13 +721,13 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 				if (SUCCEEDED(hr)) | 				if (SUCCEEDED(hr)) | ||||||
| 				{ | 				{ | ||||||
| 					return Image(bitmap); | 					return Texture(bitmap); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		ThrowIfFailed(hr); | 		ThrowIfFailed(hr); | ||||||
| 		return Image(); | 		return Texture(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -20,7 +20,7 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| #include "../base/time.h" | #include "../base/time.h" | ||||||
| #include "Image.h" | #include "Texture.h" | ||||||
| #include "Geometry.h" | #include "Geometry.h" | ||||||
| #include "TextLayout.h" | #include "TextLayout.h" | ||||||
| #include "LayerArea.h" | #include "LayerArea.h" | ||||||
|  | @ -28,6 +28,16 @@ | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
|  | 	// 文字抗锯齿模式
 | ||||||
|  | 	enum class TextAntialiasMode | ||||||
|  | 	{ | ||||||
|  | 		Default,	// 系统默认
 | ||||||
|  | 		ClearType,	// ClearType 抗锯齿
 | ||||||
|  | 		GrayScale,	// 灰度抗锯齿
 | ||||||
|  | 		None		// 不启用抗锯齿
 | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 	// 渲染目标
 | 	// 渲染目标
 | ||||||
| 	class KGE_API RenderTarget | 	class KGE_API RenderTarget | ||||||
| 		: public noncopyable | 		: public noncopyable | ||||||
|  | @ -103,14 +113,14 @@ namespace kiwano | ||||||
| 			Color const& fill_color | 			Color const& fill_color | ||||||
| 		) const; | 		) const; | ||||||
| 
 | 
 | ||||||
| 		void DrawImage( | 		void DrawTexture( | ||||||
| 			Image const& image, | 			Texture const& texture, | ||||||
| 			Rect const& src_rect, | 			Rect const& src_rect, | ||||||
| 			Rect const& dest_rect | 			Rect const& dest_rect | ||||||
| 		) const; | 		) const; | ||||||
| 
 | 
 | ||||||
| 		void DrawImage( | 		void DrawTexture( | ||||||
| 			Image const& image, | 			Texture const& texture, | ||||||
| 			const Rect* src_rect = nullptr, | 			const Rect* src_rect = nullptr, | ||||||
| 			const Rect* dest_rect = nullptr | 			const Rect* dest_rect = nullptr | ||||||
| 		) const; | 		) const; | ||||||
|  | @ -154,6 +164,10 @@ namespace kiwano | ||||||
| 			const Matrix3x2& matrix | 			const Matrix3x2& matrix | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
|  | 		void SetGlobalTransform( | ||||||
|  | 			const Matrix3x2* matrix | ||||||
|  | 		); | ||||||
|  | 
 | ||||||
| 		// 设置抗锯齿模式
 | 		// 设置抗锯齿模式
 | ||||||
| 		void SetAntialiasMode( | 		void SetAntialiasMode( | ||||||
| 			bool enabled | 			bool enabled | ||||||
|  | @ -161,9 +175,10 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 		// 设置文字抗锯齿模式
 | 		// 设置文字抗锯齿模式
 | ||||||
| 		void SetTextAntialiasMode( | 		void SetTextAntialiasMode( | ||||||
| 			TextAntialias mode | 			TextAntialiasMode mode | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
|  | 		// 检查边界是否在视区内
 | ||||||
| 		bool CheckVisibility( | 		bool CheckVisibility( | ||||||
| 			Rect const& bounds, | 			Rect const& bounds, | ||||||
| 			Matrix3x2 const& transform | 			Matrix3x2 const& transform | ||||||
|  | @ -181,11 +196,13 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 		void IncreasePrimitivesCount() const; | 		void IncreasePrimitivesCount() const; | ||||||
| 
 | 
 | ||||||
| 		inline Status const& GetStatus() const						{ return status_; } | 		inline Status const&				GetStatus() const			{ return status_; } | ||||||
| 
 | 
 | ||||||
| 		inline ComPtr<ID2D1RenderTarget> GetRenderTarget() const	{ KGE_ASSERT(render_target_); return render_target_; } | 		inline ComPtr<ID2D1RenderTarget>	GetRenderTarget() const		{ KGE_ASSERT(render_target_); return render_target_; } | ||||||
| 
 | 
 | ||||||
| 		inline ComPtr<ITextRenderer> GetTextRenderer() const		{ KGE_ASSERT(text_renderer_); return text_renderer_; } | 		inline ComPtr<ITextRenderer>		GetTextRenderer() const		{ KGE_ASSERT(text_renderer_); return text_renderer_; } | ||||||
|  | 
 | ||||||
|  | 		ComPtr<ID2D1StrokeStyle>			GetStrokeStyle(StrokeStyle style) const; | ||||||
| 
 | 
 | ||||||
| 	public: | 	public: | ||||||
| 		RenderTarget(); | 		RenderTarget(); | ||||||
|  | @ -200,25 +217,26 @@ namespace kiwano | ||||||
| 	protected: | 	protected: | ||||||
| 		Float32							opacity_; | 		Float32							opacity_; | ||||||
| 		bool							antialias_; | 		bool							antialias_; | ||||||
|  | 		bool							fast_global_transform_; | ||||||
| 		mutable bool					collecting_status_; | 		mutable bool					collecting_status_; | ||||||
| 		mutable Status					status_; | 		mutable Status					status_; | ||||||
| 		TextAntialias					text_antialias_; | 		TextAntialiasMode				text_antialias_; | ||||||
| 		ComPtr<ITextRenderer>			text_renderer_; | 		ComPtr<ITextRenderer>			text_renderer_; | ||||||
| 		ComPtr<ID2D1RenderTarget>		render_target_; | 		ComPtr<ID2D1RenderTarget>		render_target_; | ||||||
| 		ComPtr<ID2D1SolidColorBrush>	default_brush_; | 		ComPtr<ID2D1SolidColorBrush>	default_brush_; | ||||||
| 		ComPtr<ID2D1Brush>				current_brush_; | 		ComPtr<ID2D1Brush>				current_brush_; | ||||||
| 		ComPtr<ID2DDeviceResources>		device_resources_; | 		ComPtr<ID2DDeviceResources>		device_resources_; | ||||||
| 		Matrix3x2						global_matrix_; | 		Matrix3x2						global_transform_; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	// 位图渲染目标
 | 	// 位图渲染目标
 | ||||||
| 	class KGE_API ImageRenderTarget | 	class KGE_API TextureRenderTarget | ||||||
| 		: public RenderTarget | 		: public RenderTarget | ||||||
| 	{ | 	{ | ||||||
| 	public: | 	public: | ||||||
| 		ImageRenderTarget(); | 		TextureRenderTarget(); | ||||||
| 
 | 
 | ||||||
| 		Image GetOutput() const; | 		Texture GetOutput() const; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -25,6 +25,12 @@ | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
|  | 	RenderConfig::RenderConfig(Color clear_color, bool vsync) | ||||||
|  | 		: clear_color(clear_color) | ||||||
|  | 		, vsync(vsync) | ||||||
|  | 	{ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	Renderer::Renderer() | 	Renderer::Renderer() | ||||||
| 		: hwnd_(nullptr) | 		: hwnd_(nullptr) | ||||||
| 		, vsync_(true) | 		, vsync_(true) | ||||||
|  | @ -37,6 +43,12 @@ namespace kiwano | ||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	void Renderer::Init(RenderConfig const& config) | ||||||
|  | 	{ | ||||||
|  | 		SetClearColor(config.clear_color); | ||||||
|  | 		SetVSyncEnabled(config.vsync); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	void Renderer::SetupComponent() | 	void Renderer::SetupComponent() | ||||||
| 	{ | 	{ | ||||||
| 		KGE_LOG(L"Creating device resources"); | 		KGE_LOG(L"Creating device resources"); | ||||||
|  | @ -245,57 +257,7 @@ namespace kiwano | ||||||
| 		return hr; | 		return hr; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Renderer::CreateImage(Image& image, String const& file_path) | 	void Renderer::CreateTexture(Texture& texture, String const& file_path) | ||||||
| 	{ |  | ||||||
| 		HRESULT hr = S_OK; |  | ||||||
| 		if (!d2d_res_) |  | ||||||
| 		{ |  | ||||||
| 			hr = E_UNEXPECTED; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			ComPtr<ID2D1Bitmap> bitmap; |  | ||||||
| 			hr = d2d_res_->CreateBitmapFromFile(bitmap, file_path); |  | ||||||
| 
 |  | ||||||
| 			if (SUCCEEDED(hr)) |  | ||||||
| 			{ |  | ||||||
| 				image.SetBitmap(bitmap); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (FAILED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			KGE_WARNING_LOG(L"Load image failed with HRESULT of %08X!", hr); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	void Renderer::CreateImage(Image& image, Resource const& res) |  | ||||||
| 	{ |  | ||||||
| 		HRESULT hr = S_OK; |  | ||||||
| 		if (!d2d_res_) |  | ||||||
| 		{ |  | ||||||
| 			hr = E_UNEXPECTED; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			ComPtr<ID2D1Bitmap> bitmap; |  | ||||||
| 			hr = d2d_res_->CreateBitmapFromResource(bitmap, res); |  | ||||||
| 
 |  | ||||||
| 			if (SUCCEEDED(hr)) |  | ||||||
| 			{ |  | ||||||
| 				image.SetBitmap(bitmap); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (FAILED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			KGE_WARNING_LOG(L"Load image failed with HRESULT of %08X!", hr); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	void Renderer::CreateGifImage(GifImage& image, String const& file_path) |  | ||||||
| 	{ | 	{ | ||||||
| 		HRESULT hr = S_OK; | 		HRESULT hr = S_OK; | ||||||
| 		if (!d2d_res_) | 		if (!d2d_res_) | ||||||
|  | @ -305,34 +267,58 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 		if (!FileUtil::ExistsFile(file_path)) | 		if (!FileUtil::ExistsFile(file_path)) | ||||||
| 		{ | 		{ | ||||||
| 			KGE_WARNING_LOG(L"Gif image file '%s' not found!", file_path.c_str()); | 			KGE_WARNING_LOG(L"Texture file '%s' not found!", file_path.c_str()); | ||||||
| 			hr = E_FAIL; | 			hr = E_FAIL; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr)) | 		if (SUCCEEDED(hr)) | ||||||
| 		{ | 		{ | ||||||
| 			ComPtr<IWICBitmapDecoder> decoder; | 			ComPtr<IWICBitmapDecoder> decoder; | ||||||
| 			hr = d2d_res_->GetWICImagingFactory()->CreateDecoderFromFilename( | 			hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, file_path); | ||||||
| 				file_path.c_str(), |  | ||||||
| 				nullptr, |  | ||||||
| 				GENERIC_READ, |  | ||||||
| 				WICDecodeMetadataCacheOnLoad, |  | ||||||
| 				&decoder |  | ||||||
| 			); |  | ||||||
| 
 | 
 | ||||||
| 			if (SUCCEEDED(hr)) | 			if (SUCCEEDED(hr)) | ||||||
| 			{ | 			{ | ||||||
| 				image.SetDecoder(decoder); | 				ComPtr<IWICBitmapFrameDecode> source; | ||||||
|  | 				hr = decoder->GetFrame(0, &source); | ||||||
|  | 
 | ||||||
|  | 				if (SUCCEEDED(hr)) | ||||||
|  | 				{ | ||||||
|  | 					ComPtr<IWICFormatConverter> converter; | ||||||
|  | 					hr = d2d_res_->CreateBitmapConverter( | ||||||
|  | 						converter, | ||||||
|  | 						source, | ||||||
|  | 						GUID_WICPixelFormat32bppPBGRA, | ||||||
|  | 						WICBitmapDitherTypeNone, | ||||||
|  | 						nullptr, | ||||||
|  | 						0.f, | ||||||
|  | 						WICBitmapPaletteTypeMedianCut | ||||||
|  | 					); | ||||||
|  | 
 | ||||||
|  | 					if (SUCCEEDED(hr)) | ||||||
|  | 					{ | ||||||
|  | 						ComPtr<ID2D1Bitmap> bitmap; | ||||||
|  | 						hr = d2d_res_->CreateBitmapFromConverter( | ||||||
|  | 							bitmap, | ||||||
|  | 							nullptr, | ||||||
|  | 							converter | ||||||
|  | 						); | ||||||
|  | 
 | ||||||
|  | 						if (SUCCEEDED(hr)) | ||||||
|  | 						{ | ||||||
|  | 							texture.SetBitmap(bitmap); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (FAILED(hr)) | 		if (FAILED(hr)) | ||||||
| 		{ | 		{ | ||||||
| 			KGE_WARNING_LOG(L"Load GIF image failed with HRESULT of %08X!", hr); | 			KGE_WARNING_LOG(L"Load texture failed with HRESULT of %08X!", hr); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Renderer::CreateGifImage(GifImage& image, Resource const& res) | 	void Renderer::CreateTexture(Texture& texture, Resource const& resource) | ||||||
| 	{ | 	{ | ||||||
| 		HRESULT hr = S_OK; | 		HRESULT hr = S_OK; | ||||||
| 		if (!d2d_res_) | 		if (!d2d_res_) | ||||||
|  | @ -340,43 +326,273 @@ namespace kiwano | ||||||
| 			hr = E_UNEXPECTED; | 			hr = E_UNEXPECTED; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		Resource::Data res_data = res.GetData(); |  | ||||||
| 
 |  | ||||||
| 		hr = res_data ? S_OK : E_FAIL; |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) | 		if (SUCCEEDED(hr)) | ||||||
| 		{ | 		{ | ||||||
| 			ComPtr<IWICStream> stream; | 			ComPtr<IWICBitmapDecoder> decoder; | ||||||
| 			hr = d2d_res_->GetWICImagingFactory()->CreateStream(&stream); | 			hr = d2d_res_->CreateBitmapDecoderFromResource(decoder, resource); | ||||||
| 
 | 
 | ||||||
| 			if (SUCCEEDED(hr)) | 			if (SUCCEEDED(hr)) | ||||||
| 			{ | 			{ | ||||||
| 				hr = stream->InitializeFromMemory( | 				ComPtr<IWICBitmapFrameDecode> source; | ||||||
| 					static_cast<WICInProcPointer>(res_data.buffer), | 				hr = decoder->GetFrame(0, &source); | ||||||
| 					res_data.size |  | ||||||
| 				); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			if (SUCCEEDED(hr)) |  | ||||||
| 			{ |  | ||||||
| 				ComPtr<IWICBitmapDecoder> decoder; |  | ||||||
| 				hr = d2d_res_->GetWICImagingFactory()->CreateDecoderFromStream( |  | ||||||
| 					stream.get(), |  | ||||||
| 					nullptr, |  | ||||||
| 					WICDecodeMetadataCacheOnLoad, |  | ||||||
| 					&decoder |  | ||||||
| 				); |  | ||||||
| 
 | 
 | ||||||
| 				if (SUCCEEDED(hr)) | 				if (SUCCEEDED(hr)) | ||||||
| 				{ | 				{ | ||||||
| 					image.SetDecoder(decoder); | 					ComPtr<IWICFormatConverter> converter; | ||||||
|  | 					hr = d2d_res_->CreateBitmapConverter( | ||||||
|  | 						converter, | ||||||
|  | 						source, | ||||||
|  | 						GUID_WICPixelFormat32bppPBGRA, | ||||||
|  | 						WICBitmapDitherTypeNone, | ||||||
|  | 						nullptr, | ||||||
|  | 						0.f, | ||||||
|  | 						WICBitmapPaletteTypeMedianCut | ||||||
|  | 					); | ||||||
|  | 
 | ||||||
|  | 					if (SUCCEEDED(hr)) | ||||||
|  | 					{ | ||||||
|  | 						ComPtr<ID2D1Bitmap> bitmap; | ||||||
|  | 						hr = d2d_res_->CreateBitmapFromConverter( | ||||||
|  | 							bitmap, | ||||||
|  | 							nullptr, | ||||||
|  | 							converter | ||||||
|  | 						); | ||||||
|  | 
 | ||||||
|  | 						if (SUCCEEDED(hr)) | ||||||
|  | 						{ | ||||||
|  | 							texture.SetBitmap(bitmap); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (FAILED(hr)) | 		if (FAILED(hr)) | ||||||
| 		{ | 		{ | ||||||
| 			KGE_WARNING_LOG(L"Load GIF image failed with HRESULT of %08X!", hr); | 			KGE_WARNING_LOG(L"Load texture failed with HRESULT of %08X!", hr); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void Renderer::CreateGifImage(GifImage& gif, String const& file_path) | ||||||
|  | 	{ | ||||||
|  | 		HRESULT hr = S_OK; | ||||||
|  | 		if (!d2d_res_) | ||||||
|  | 		{ | ||||||
|  | 			hr = E_UNEXPECTED; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (!FileUtil::ExistsFile(file_path)) | ||||||
|  | 		{ | ||||||
|  | 			KGE_WARNING_LOG(L"Gif texture file '%s' not found!", file_path.c_str()); | ||||||
|  | 			hr = E_FAIL; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (SUCCEEDED(hr)) | ||||||
|  | 		{ | ||||||
|  | 			ComPtr<IWICBitmapDecoder> decoder; | ||||||
|  | 			hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, file_path); | ||||||
|  | 
 | ||||||
|  | 			if (SUCCEEDED(hr)) | ||||||
|  | 			{ | ||||||
|  | 				gif.SetDecoder(decoder); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (FAILED(hr)) | ||||||
|  | 		{ | ||||||
|  | 			KGE_WARNING_LOG(L"Load GIF texture failed with HRESULT of %08X!", hr); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void Renderer::CreateGifImage(GifImage& gif, Resource const& resource) | ||||||
|  | 	{ | ||||||
|  | 		HRESULT hr = S_OK; | ||||||
|  | 		if (!d2d_res_) | ||||||
|  | 		{ | ||||||
|  | 			hr = E_UNEXPECTED; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (SUCCEEDED(hr)) | ||||||
|  | 		{ | ||||||
|  | 			ComPtr<IWICBitmapDecoder> decoder; | ||||||
|  | 			hr = d2d_res_->CreateBitmapDecoderFromResource(decoder, resource); | ||||||
|  | 
 | ||||||
|  | 			if (SUCCEEDED(hr)) | ||||||
|  | 			{ | ||||||
|  | 				gif.SetDecoder(decoder); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (FAILED(hr)) | ||||||
|  | 		{ | ||||||
|  | 			KGE_WARNING_LOG(L"Load GIF texture failed with HRESULT of %08X!", hr); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void Renderer::CreateGifImageFrame(GifImage::Frame& frame, GifImage const& gif, UInt32 frame_index) | ||||||
|  | 	{ | ||||||
|  | 		HRESULT hr = S_OK; | ||||||
|  | 		if (!d2d_res_) | ||||||
|  | 		{ | ||||||
|  | 			hr = E_UNEXPECTED; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (gif.GetDecoder() == nullptr) | ||||||
|  | 		{ | ||||||
|  | 			hr = E_INVALIDARG; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (SUCCEEDED(hr)) | ||||||
|  | 		{ | ||||||
|  | 			ComPtr<IWICBitmapFrameDecode> wic_frame; | ||||||
|  | 			HRESULT hr = gif.GetDecoder()->GetFrame(frame_index, &wic_frame); | ||||||
|  | 
 | ||||||
|  | 			if (SUCCEEDED(hr)) | ||||||
|  | 			{ | ||||||
|  | 				ComPtr<IWICFormatConverter> converter; | ||||||
|  | 				d2d_res_->CreateBitmapConverter( | ||||||
|  | 					converter, | ||||||
|  | 					wic_frame, | ||||||
|  | 					GUID_WICPixelFormat32bppPBGRA, | ||||||
|  | 					WICBitmapDitherTypeNone, | ||||||
|  | 					nullptr, | ||||||
|  | 					0.f, | ||||||
|  | 					WICBitmapPaletteTypeCustom | ||||||
|  | 				); | ||||||
|  | 
 | ||||||
|  | 				if (SUCCEEDED(hr)) | ||||||
|  | 				{ | ||||||
|  | 					ComPtr<ID2D1Bitmap> raw_bitmap; | ||||||
|  | 					hr = d2d_res_->CreateBitmapFromConverter( | ||||||
|  | 						raw_bitmap, | ||||||
|  | 						nullptr, | ||||||
|  | 						converter | ||||||
|  | 					); | ||||||
|  | 
 | ||||||
|  | 					if (SUCCEEDED(hr)) | ||||||
|  | 					{ | ||||||
|  | 						frame.raw.SetBitmap(raw_bitmap); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (SUCCEEDED(hr)) | ||||||
|  | 			{ | ||||||
|  | 				PROPVARIANT prop_val; | ||||||
|  | 				PropVariantInit(&prop_val); | ||||||
|  | 
 | ||||||
|  | 				// Get Metadata Query Reader from the frame
 | ||||||
|  | 				ComPtr<IWICMetadataQueryReader> metadata_reader; | ||||||
|  | 				hr = wic_frame->GetMetadataQueryReader(&metadata_reader); | ||||||
|  | 
 | ||||||
|  | 				// Get the Metadata for the current frame
 | ||||||
|  | 				if (SUCCEEDED(hr)) | ||||||
|  | 				{ | ||||||
|  | 					hr = metadata_reader->GetMetadataByName(L"/imgdesc/Left", &prop_val); | ||||||
|  | 					if (SUCCEEDED(hr)) | ||||||
|  | 					{ | ||||||
|  | 						hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL); | ||||||
|  | 						if (SUCCEEDED(hr)) | ||||||
|  | 						{ | ||||||
|  | 							frame.rect.left_top.x = static_cast<Float32>(prop_val.uiVal); | ||||||
|  | 						} | ||||||
|  | 						PropVariantClear(&prop_val); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (SUCCEEDED(hr)) | ||||||
|  | 				{ | ||||||
|  | 					hr = metadata_reader->GetMetadataByName(L"/imgdesc/Top", &prop_val); | ||||||
|  | 					if (SUCCEEDED(hr)) | ||||||
|  | 					{ | ||||||
|  | 						hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL); | ||||||
|  | 						if (SUCCEEDED(hr)) | ||||||
|  | 						{ | ||||||
|  | 							frame.rect.left_top.y = static_cast<Float32>(prop_val.uiVal); | ||||||
|  | 						} | ||||||
|  | 						PropVariantClear(&prop_val); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (SUCCEEDED(hr)) | ||||||
|  | 				{ | ||||||
|  | 					hr = metadata_reader->GetMetadataByName(L"/imgdesc/Width", &prop_val); | ||||||
|  | 					if (SUCCEEDED(hr)) | ||||||
|  | 					{ | ||||||
|  | 						hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL); | ||||||
|  | 						if (SUCCEEDED(hr)) | ||||||
|  | 						{ | ||||||
|  | 							frame.rect.right_bottom.x = frame.rect.left_top.x + static_cast<Float32>(prop_val.uiVal); | ||||||
|  | 						} | ||||||
|  | 						PropVariantClear(&prop_val); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (SUCCEEDED(hr)) | ||||||
|  | 				{ | ||||||
|  | 					hr = metadata_reader->GetMetadataByName(L"/imgdesc/Height", &prop_val); | ||||||
|  | 					if (SUCCEEDED(hr)) | ||||||
|  | 					{ | ||||||
|  | 						hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL); | ||||||
|  | 						if (SUCCEEDED(hr)) | ||||||
|  | 						{ | ||||||
|  | 							frame.rect.right_bottom.y = frame.rect.left_top.y + static_cast<Float32>(prop_val.uiVal); | ||||||
|  | 						} | ||||||
|  | 						PropVariantClear(&prop_val); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (SUCCEEDED(hr)) | ||||||
|  | 				{ | ||||||
|  | 					hr = metadata_reader->GetMetadataByName(L"/grctlext/Delay", &prop_val); | ||||||
|  | 
 | ||||||
|  | 					if (SUCCEEDED(hr)) | ||||||
|  | 					{ | ||||||
|  | 						hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL); | ||||||
|  | 
 | ||||||
|  | 						if (SUCCEEDED(hr)) | ||||||
|  | 						{ | ||||||
|  | 							UInt32 udelay = 0; | ||||||
|  | 							hr = UIntMult(prop_val.uiVal, 10, &udelay); | ||||||
|  | 							if (SUCCEEDED(hr)) | ||||||
|  | 							{ | ||||||
|  | 								frame.delay.SetMilliseconds(static_cast<long>(udelay)); | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 						PropVariantClear(&prop_val); | ||||||
|  | 					} | ||||||
|  | 					else | ||||||
|  | 					{ | ||||||
|  | 						frame.delay = 0; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (SUCCEEDED(hr)) | ||||||
|  | 				{ | ||||||
|  | 					hr = metadata_reader->GetMetadataByName(L"/grctlext/Disposal", &prop_val); | ||||||
|  | 
 | ||||||
|  | 					if (SUCCEEDED(hr)) | ||||||
|  | 					{ | ||||||
|  | 						hr = (prop_val.vt == VT_UI1) ? S_OK : E_FAIL; | ||||||
|  | 						if (SUCCEEDED(hr)) | ||||||
|  | 						{ | ||||||
|  | 							frame.disposal_type = GifImage::DisposalType(prop_val.bVal); | ||||||
|  | 						} | ||||||
|  | 						::PropVariantClear(&prop_val); | ||||||
|  | 					} | ||||||
|  | 					else | ||||||
|  | 					{ | ||||||
|  | 						frame.disposal_type = GifImage::DisposalType::Unknown; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				::PropVariantClear(&prop_val); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (FAILED(hr)) | ||||||
|  | 		{ | ||||||
|  | 			KGE_WARNING_LOG(L"Load GIF frame failed with HRESULT of %08X!", hr); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -490,7 +706,7 @@ namespace kiwano | ||||||
| 		ThrowIfFailed(hr); | 		ThrowIfFailed(hr); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Renderer::CreateTextLayout(TextLayout& layout, String const& text, TextStyle const& style, TextFormat const& format) | 	void Renderer::CreateTextLayout(TextLayout& layout, String const& text, TextFormat const& format) | ||||||
| 	{ | 	{ | ||||||
| 		HRESULT hr = S_OK; | 		HRESULT hr = S_OK; | ||||||
| 		if (!d2d_res_) | 		if (!d2d_res_) | ||||||
|  | @ -504,7 +720,6 @@ namespace kiwano | ||||||
| 			hr = d2d_res_->CreateTextLayout( | 			hr = d2d_res_->CreateTextLayout( | ||||||
| 				output, | 				output, | ||||||
| 				text, | 				text, | ||||||
| 				style, |  | ||||||
| 				format.GetTextFormat() | 				format.GetTextFormat() | ||||||
| 			); | 			); | ||||||
| 		} | 		} | ||||||
|  | @ -653,7 +868,7 @@ namespace kiwano | ||||||
| 		ThrowIfFailed(hr); | 		ThrowIfFailed(hr); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Renderer::CreateImageRenderTarget(ImageRenderTarget& render_target) | 	void Renderer::CreateTextureRenderTarget(TextureRenderTarget& render_target) | ||||||
| 	{ | 	{ | ||||||
| 		HRESULT hr = S_OK; | 		HRESULT hr = S_OK; | ||||||
| 		if (!d2d_res_) | 		if (!d2d_res_) | ||||||
|  | @ -732,7 +947,7 @@ namespace kiwano | ||||||
| 		{ | 		{ | ||||||
| 		case ResolutionMode::Fixed: | 		case ResolutionMode::Fixed: | ||||||
| 		{ | 		{ | ||||||
| 			SetGlobalTransform(Matrix3x2{}); | 			SetGlobalTransform(nullptr); | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -39,6 +39,32 @@ namespace kiwano | ||||||
| 	typedef ID3D11DeviceResources ID3DDeviceResources; | 	typedef ID3D11DeviceResources ID3DDeviceResources; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | 	// 渲染设置
 | ||||||
|  | 	struct RenderConfig | ||||||
|  | 	{ | ||||||
|  | 		Color	clear_color;	// 清屏颜色
 | ||||||
|  | 		bool	vsync;			// 垂直同步
 | ||||||
|  | 
 | ||||||
|  | 		RenderConfig( | ||||||
|  | 			Color clear_color	= Color::Black, | ||||||
|  | 			bool vsync			= true | ||||||
|  | 		); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	// 分辨率模式
 | ||||||
|  | 	// 分辨率模式决定了将画面渲染到视区上的方式
 | ||||||
|  | 	// Fixed (固定): 分辨率不随视区改变, 且画面始终与视区边界对齐(默认)
 | ||||||
|  | 	// Center (居中): 分辨率不随视区改变, 且画面始终在视区上居中
 | ||||||
|  | 	// Stretch (拉伸): 分辨率始终随视区等比例拉伸
 | ||||||
|  | 	// Adaptive (宽高自适应): 分辨率始终保持宽高比, 且尽可能的填充视区, 可能会出现黑色边界
 | ||||||
|  | 	enum class ResolutionMode | ||||||
|  | 	{ | ||||||
|  | 		Fixed,		/* 固定 */ | ||||||
|  | 		Center,		/* 居中 */ | ||||||
|  | 		Stretch,	/* 拉伸 */ | ||||||
|  | 		Adaptive,	/* 宽高自适应 */ | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
| 	class KGE_API Renderer | 	class KGE_API Renderer | ||||||
| 		: public Singleton<Renderer> | 		: public Singleton<Renderer> | ||||||
| 		, public Component | 		, public Component | ||||||
|  | @ -57,25 +83,41 @@ namespace kiwano | ||||||
| 			bool enabled | 			bool enabled | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
|  | 		// 设置画面分辨率
 | ||||||
|  | 		void SetResolution( | ||||||
|  | 			Size const& resolution | ||||||
|  | 		); | ||||||
|  | 
 | ||||||
|  | 		// 设置分辨率模式
 | ||||||
|  | 		void SetResolutionMode( | ||||||
|  | 			ResolutionMode mode | ||||||
|  | 		); | ||||||
|  | 
 | ||||||
| 	public: | 	public: | ||||||
| 		void CreateImage( | 		void CreateTexture( | ||||||
| 			Image& image, | 			Texture& texture, | ||||||
| 			String const& file_path | 			String const& file_path | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		void CreateImage( | 		void CreateTexture( | ||||||
| 			Image& image, | 			Texture& texture, | ||||||
| 			Resource const& res | 			Resource const& resource | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		void CreateGifImage( | 		void CreateGifImage( | ||||||
| 			GifImage& image, | 			GifImage& gif, | ||||||
| 			String const& file_path | 			String const& file_path | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		void CreateGifImage( | 		void CreateGifImage( | ||||||
| 			GifImage& image, | 			GifImage& gif, | ||||||
| 			Resource const& res | 			Resource const& resource | ||||||
|  | 		); | ||||||
|  | 
 | ||||||
|  | 		void CreateGifImageFrame( | ||||||
|  | 			GifImage::Frame& frame, | ||||||
|  | 			GifImage const& gif, | ||||||
|  | 			UInt32 frame_index | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		void CreateFontCollection( | 		void CreateFontCollection( | ||||||
|  | @ -96,7 +138,6 @@ namespace kiwano | ||||||
| 		void CreateTextLayout( | 		void CreateTextLayout( | ||||||
| 			TextLayout& layout, | 			TextLayout& layout, | ||||||
| 			String const& text, | 			String const& text, | ||||||
| 			TextStyle const& style, |  | ||||||
| 			TextFormat const& format | 			TextFormat const& format | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
|  | @ -127,19 +168,13 @@ namespace kiwano | ||||||
| 			GeometrySink& sink | 			GeometrySink& sink | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		void CreateImageRenderTarget( | 		void CreateTextureRenderTarget( | ||||||
| 			ImageRenderTarget& render_target | 			TextureRenderTarget& render_target | ||||||
| 		); |  | ||||||
| 
 |  | ||||||
| 		void SetResolution( |  | ||||||
| 			Size const& resolution |  | ||||||
| 		); |  | ||||||
| 
 |  | ||||||
| 		void SetResolutionMode( |  | ||||||
| 			ResolutionMode mode |  | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 	public: | 	public: | ||||||
|  | 		void Init(RenderConfig const& config); | ||||||
|  | 
 | ||||||
| 		void SetupComponent() override; | 		void SetupComponent() override; | ||||||
| 
 | 
 | ||||||
| 		void DestroyComponent() override; | 		void DestroyComponent() override; | ||||||
|  |  | ||||||
|  | @ -23,41 +23,10 @@ | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
| 	// ÏßÌõÑùʽ
 | 	// ÏßÌõÑùʽ
 | ||||||
| 	enum class StrokeStyle : Int32 | 	enum class StrokeStyle | ||||||
| 	{ | 	{ | ||||||
| 		Miter = 0,	/* бÇÐ */ | 		Miter = 0,	/* бÇÐ */ | ||||||
| 		Bevel = 1,	/* б½Ç */ | 		Bevel = 1,	/* б½Ç */ | ||||||
| 		Round = 2	/* Ô²½Ç */ | 		Round = 2	/* Ô²½Ç */ | ||||||
| 	}; | 	}; | ||||||
| 
 |  | ||||||
| 	// 鼠标指针
 |  | ||||||
| 	enum class MouseCursor : Int32 |  | ||||||
| 	{ |  | ||||||
| 		Arrow,		/* 指针 */ |  | ||||||
| 		TextInput,	/* 输入文本 */ |  | ||||||
| 		Hand,		/* 手指 */ |  | ||||||
| 		SizeAll, |  | ||||||
| 		SizeNESW, |  | ||||||
| 		SizeNS, |  | ||||||
| 		SizeNWSE, |  | ||||||
| 		SizeWE, |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	// 文字抗锯齿属性
 |  | ||||||
| 	enum class TextAntialias |  | ||||||
| 	{ |  | ||||||
| 		Default,	// 系统默认
 |  | ||||||
| 		ClearType,	// ClearType 抗锯齿
 |  | ||||||
| 		GrayScale,	// 灰度抗锯齿
 |  | ||||||
| 		None		// 不启用抗锯齿
 |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	// 分辨率模式
 |  | ||||||
| 	enum class ResolutionMode |  | ||||||
| 	{ |  | ||||||
| 		Fixed,		/* 固定 */ |  | ||||||
| 		Center,		/* 居中 */ |  | ||||||
| 		Stretch,	/* 拉伸 */ |  | ||||||
| 		Adaptive,	/* 宽高自适应 */ |  | ||||||
| 	}; |  | ||||||
| } | } | ||||||
|  | @ -76,9 +76,73 @@ namespace kiwano | ||||||
| 		Renderer::GetInstance()->CreateTextLayout( | 		Renderer::GetInstance()->CreateTextLayout( | ||||||
| 			*this, | 			*this, | ||||||
| 			text, | 			text, | ||||||
| 			style, |  | ||||||
| 			text_format_ | 			text_format_ | ||||||
| 		); | 		); | ||||||
|  | 
 | ||||||
|  | 		HRESULT hr = text_layout_ ? S_OK : E_FAIL; | ||||||
|  | 
 | ||||||
|  | 		if (SUCCEEDED(hr)) | ||||||
|  | 		{ | ||||||
|  | 			if (style.line_spacing == 0.f) | ||||||
|  | 			{ | ||||||
|  | 				hr = text_layout_->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				hr = text_layout_->SetLineSpacing( | ||||||
|  | 					DWRITE_LINE_SPACING_METHOD_UNIFORM, | ||||||
|  | 					style.line_spacing, | ||||||
|  | 					style.line_spacing * 0.8f | ||||||
|  | 				); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (SUCCEEDED(hr)) | ||||||
|  | 		{ | ||||||
|  | 			hr = text_layout_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(style.alignment)); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (SUCCEEDED(hr)) | ||||||
|  | 		{ | ||||||
|  | 			hr = text_layout_->SetWordWrapping((style.wrap_width > 0) ? DWRITE_WORD_WRAPPING_WRAP : DWRITE_WORD_WRAPPING_NO_WRAP); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (SUCCEEDED(hr)) | ||||||
|  | 		{ | ||||||
|  | 			if (style.underline) | ||||||
|  | 			{ | ||||||
|  | 				hr = text_layout_->SetUnderline(true, { 0, text.length() }); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (SUCCEEDED(hr)) | ||||||
|  | 		{ | ||||||
|  | 			if (style.strikethrough) | ||||||
|  | 			{ | ||||||
|  | 				text_layout_->SetStrikethrough(true, { 0, text.length() }); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (SUCCEEDED(hr)) | ||||||
|  | 		{ | ||||||
|  | 			if (style.wrap_width > 0) | ||||||
|  | 			{ | ||||||
|  | 				hr = text_layout_->SetMaxWidth(style.wrap_width); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				// Fix the layout width when the text does not wrap
 | ||||||
|  | 				DWRITE_TEXT_METRICS metrics; | ||||||
|  | 				hr = text_layout_->GetMetrics(&metrics); | ||||||
|  | 
 | ||||||
|  | 				if (SUCCEEDED(hr)) | ||||||
|  | 				{ | ||||||
|  | 					hr = text_layout_->SetMaxWidth(metrics.width); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		ThrowIfFailed(hr); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	UInt32 TextLayout::GetLineCount() | 	UInt32 TextLayout::GetLineCount() | ||||||
|  |  | ||||||
|  | @ -18,53 +18,59 @@ | ||||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | ||||||
| // THE SOFTWARE.
 | // THE SOFTWARE.
 | ||||||
| 
 | 
 | ||||||
| #include "Image.h" | #include "Texture.h" | ||||||
| #include "Renderer.h" | #include "Renderer.h" | ||||||
| #include "../base/Logger.h" | #include "../base/Logger.h" | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
| 	Image::Image() | 	InterpolationMode	Texture::default_interpolation_mode_ = InterpolationMode::Linear; | ||||||
|  | 
 | ||||||
|  | 	Texture::Texture() | ||||||
|  | 		: interpolation_mode_(default_interpolation_mode_) | ||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Image::Image(String const& file_path) | 	Texture::Texture(String const& file_path) | ||||||
|  | 		: Texture() | ||||||
| 	{ | 	{ | ||||||
| 		Load(file_path); | 		Load(file_path); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Image::Image(Resource const& res) | 	Texture::Texture(Resource const& res) | ||||||
|  | 		: Texture() | ||||||
| 	{ | 	{ | ||||||
| 		Load(res); | 		Load(res); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Image::Image(ComPtr<ID2D1Bitmap> const & bitmap) | 	Texture::Texture(ComPtr<ID2D1Bitmap> const & bitmap) | ||||||
|  | 		: Texture() | ||||||
| 	{ | 	{ | ||||||
| 		SetBitmap(bitmap); | 		SetBitmap(bitmap); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Image::~Image() | 	Texture::~Texture() | ||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool Image::Load(String const& file_path) | 	bool Texture::Load(String const& file_path) | ||||||
| 	{ | 	{ | ||||||
| 		Renderer::GetInstance()->CreateImage(*this, file_path); | 		Renderer::GetInstance()->CreateTexture(*this, file_path); | ||||||
| 		return IsValid(); | 		return IsValid(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool Image::Load(Resource const& res) | 	bool Texture::Load(Resource const& res) | ||||||
| 	{ | 	{ | ||||||
| 		Renderer::GetInstance()->CreateImage(*this, res); | 		Renderer::GetInstance()->CreateTexture(*this, res); | ||||||
| 		return IsValid(); | 		return IsValid(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool Image::IsValid() const | 	bool Texture::IsValid() const | ||||||
| 	{ | 	{ | ||||||
| 		return bitmap_ != nullptr; | 		return bitmap_ != nullptr; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Float32 Image::GetWidth() const | 	Float32 Texture::GetWidth() const | ||||||
| 	{ | 	{ | ||||||
| 		if (bitmap_) | 		if (bitmap_) | ||||||
| 		{ | 		{ | ||||||
|  | @ -73,7 +79,7 @@ namespace kiwano | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Float32 Image::GetHeight() const | 	Float32 Texture::GetHeight() const | ||||||
| 	{ | 	{ | ||||||
| 		if (bitmap_) | 		if (bitmap_) | ||||||
| 		{ | 		{ | ||||||
|  | @ -82,7 +88,7 @@ namespace kiwano | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Size Image::GetSize() const | 	Size Texture::GetSize() const | ||||||
| 	{ | 	{ | ||||||
| 		if (bitmap_) | 		if (bitmap_) | ||||||
| 		{ | 		{ | ||||||
|  | @ -92,7 +98,7 @@ namespace kiwano | ||||||
| 		return Size{}; | 		return Size{}; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	UInt32 Image::GetWidthInPixels() const | 	UInt32 Texture::GetWidthInPixels() const | ||||||
| 	{ | 	{ | ||||||
| 		if (bitmap_) | 		if (bitmap_) | ||||||
| 		{ | 		{ | ||||||
|  | @ -101,7 +107,7 @@ namespace kiwano | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	UInt32 Image::GetHeightInPixels() const | 	UInt32 Texture::GetHeightInPixels() const | ||||||
| 	{ | 	{ | ||||||
| 		if (bitmap_) | 		if (bitmap_) | ||||||
| 		{ | 		{ | ||||||
|  | @ -110,7 +116,7 @@ namespace kiwano | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	math::Vec2T<UInt32> Image::GetSizeInPixels() const | 	math::Vec2T<UInt32> Texture::GetSizeInPixels() const | ||||||
| 	{ | 	{ | ||||||
| 		if (bitmap_) | 		if (bitmap_) | ||||||
| 		{ | 		{ | ||||||
|  | @ -120,7 +126,12 @@ namespace kiwano | ||||||
| 		return math::Vec2T<UInt32>{}; | 		return math::Vec2T<UInt32>{}; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Image::CopyFrom(Image const& copy_from) | 	InterpolationMode Texture::GetBitmapInterpolationMode() const | ||||||
|  | 	{ | ||||||
|  | 		return interpolation_mode_; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void Texture::CopyFrom(Texture const& copy_from) | ||||||
| 	{ | 	{ | ||||||
| 		if (IsValid() && copy_from.IsValid()) | 		if (IsValid() && copy_from.IsValid()) | ||||||
| 		{ | 		{ | ||||||
|  | @ -130,7 +141,7 @@ namespace kiwano | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Image::CopyFrom(Image const& copy_from, Rect const& src_rect, Point const& dest_point) | 	void Texture::CopyFrom(Texture const& copy_from, Rect const& src_rect, Point const& dest_point) | ||||||
| 	{ | 	{ | ||||||
| 		if (IsValid() && copy_from.IsValid()) | 		if (IsValid() && copy_from.IsValid()) | ||||||
| 		{ | 		{ | ||||||
|  | @ -148,7 +159,21 @@ namespace kiwano | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	D2D1_PIXEL_FORMAT Image::GetPixelFormat() const | 	void Texture::SetInterpolationMode(InterpolationMode mode) | ||||||
|  | 	{ | ||||||
|  | 		interpolation_mode_ = mode; | ||||||
|  | 		switch (mode) | ||||||
|  | 		{ | ||||||
|  | 		case InterpolationMode::Linear: | ||||||
|  | 			break; | ||||||
|  | 		case InterpolationMode::Nearest: | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	D2D1_PIXEL_FORMAT Texture::GetPixelFormat() const | ||||||
| 	{ | 	{ | ||||||
| 		if (bitmap_) | 		if (bitmap_) | ||||||
| 		{ | 		{ | ||||||
|  | @ -157,14 +182,18 @@ namespace kiwano | ||||||
| 		return D2D1_PIXEL_FORMAT(); | 		return D2D1_PIXEL_FORMAT(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ComPtr<ID2D1Bitmap> Image::GetBitmap() const | 	ComPtr<ID2D1Bitmap> Texture::GetBitmap() const | ||||||
| 	{ | 	{ | ||||||
| 		return bitmap_; | 		return bitmap_; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Image::SetBitmap(ComPtr<ID2D1Bitmap> bitmap) | 	void Texture::SetBitmap(ComPtr<ID2D1Bitmap> bitmap) | ||||||
| 	{ | 	{ | ||||||
| 		bitmap_ = bitmap; | 		bitmap_ = bitmap; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	void Texture::SetDefaultInterpolationMode(InterpolationMode mode) | ||||||
|  | 	{ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | @ -23,25 +23,36 @@ | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
| 	// 图像
 | 	// 插值模式
 | ||||||
| 	class KGE_API Image | 	// 插值模式指定了位图在缩放和旋转时像素颜色的计算方式
 | ||||||
|  | 	// Linear (双线性插值): 对周围四个像素进行两次线性插值计算, 在图像放大时可能会模糊(默认)
 | ||||||
|  | 	// Nearest (最邻近插值): 取最邻近的像素点的颜色值
 | ||||||
|  | 	enum class InterpolationMode | ||||||
|  | 	{ | ||||||
|  | 		Linear,		// 双线性插值
 | ||||||
|  | 		Nearest,	// 最邻近插值
 | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	// 纹理
 | ||||||
|  | 	class KGE_API Texture | ||||||
| 	{ | 	{ | ||||||
| 	public: | 	public: | ||||||
| 		Image(); | 		Texture(); | ||||||
| 
 | 
 | ||||||
| 		explicit Image( | 		explicit Texture( | ||||||
| 			String const& file_path | 			String const& file_path | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		explicit Image( | 		explicit Texture( | ||||||
| 			Resource const& res | 			Resource const& res | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		explicit Image( | 		explicit Texture( | ||||||
| 			ComPtr<ID2D1Bitmap> const& bitmap | 			ComPtr<ID2D1Bitmap> const& bitmap | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		virtual ~Image(); | 		virtual ~Texture(); | ||||||
| 
 | 
 | ||||||
| 		// 加载本地文件
 | 		// 加载本地文件
 | ||||||
| 		bool Load( | 		bool Load( | ||||||
|  | @ -56,29 +67,38 @@ namespace kiwano | ||||||
| 		// 资源是否有效
 | 		// 资源是否有效
 | ||||||
| 		bool IsValid() const; | 		bool IsValid() const; | ||||||
| 
 | 
 | ||||||
| 		// 获取位图宽度
 | 		// 获取宽度
 | ||||||
| 		Float32 GetWidth() const; | 		Float32 GetWidth() const; | ||||||
| 
 | 
 | ||||||
| 		// 获取位图高度
 | 		// 获取高度
 | ||||||
| 		Float32 GetHeight() const; | 		Float32 GetHeight() const; | ||||||
| 
 | 
 | ||||||
| 		// 获取位图大小
 | 		// 获取大小
 | ||||||
| 		Size GetSize() const; | 		Size GetSize() const; | ||||||
| 
 | 
 | ||||||
| 		// 获取位图像素宽度
 | 		// 获取像素宽度
 | ||||||
| 		UInt32 GetWidthInPixels() const; | 		UInt32 GetWidthInPixels() const; | ||||||
| 
 | 
 | ||||||
| 		// 获取位图像素高度
 | 		// 获取像素高度
 | ||||||
| 		UInt32 GetHeightInPixels() const; | 		UInt32 GetHeightInPixels() const; | ||||||
| 
 | 
 | ||||||
| 		// 获取位图像素大小
 | 		// 获取像素大小
 | ||||||
| 		math::Vec2T<UInt32> GetSizeInPixels() const; | 		math::Vec2T<UInt32> GetSizeInPixels() const; | ||||||
| 
 | 
 | ||||||
| 		// 拷贝位图内存
 | 		// 获取像素插值方式
 | ||||||
| 		void CopyFrom(Image const& copy_from); | 		InterpolationMode GetBitmapInterpolationMode() const; | ||||||
| 
 | 
 | ||||||
| 		// 拷贝位图内存
 | 		// 拷贝位图内存
 | ||||||
| 		void CopyFrom(Image const& copy_from, Rect const& src_rect, Point const& dest_point); | 		void CopyFrom(Texture const& copy_from); | ||||||
|  | 
 | ||||||
|  | 		// 拷贝位图内存
 | ||||||
|  | 		void CopyFrom(Texture const& copy_from, Rect const& src_rect, Point const& dest_point); | ||||||
|  | 
 | ||||||
|  | 		// 设置像素插值方式
 | ||||||
|  | 		void SetInterpolationMode(InterpolationMode mode); | ||||||
|  | 
 | ||||||
|  | 		// 设置默认的像素插值方式
 | ||||||
|  | 		static void SetDefaultInterpolationMode(InterpolationMode mode); | ||||||
| 
 | 
 | ||||||
| 	public: | 	public: | ||||||
| 		// 获取源位图
 | 		// 获取源位图
 | ||||||
|  | @ -92,5 +112,8 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 	protected: | 	protected: | ||||||
| 		ComPtr<ID2D1Bitmap>	bitmap_; | 		ComPtr<ID2D1Bitmap>	bitmap_; | ||||||
|  | 		InterpolationMode	interpolation_mode_; | ||||||
|  | 
 | ||||||
|  | 		static InterpolationMode default_interpolation_mode_; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  | @ -18,7 +18,7 @@ | ||||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | ||||||
| // THE SOFTWARE.
 | // THE SOFTWARE.
 | ||||||
| 
 | 
 | ||||||
| #include "ImageCache.h" | #include "TextureCache.h" | ||||||
| #include "Renderer.h" | #include "Renderer.h" | ||||||
| #include "../base/Logger.h" | #include "../base/Logger.h" | ||||||
| 
 | 
 | ||||||
|  | @ -33,12 +33,12 @@ namespace kiwano | ||||||
| 			return iter->second; | 			return iter->second; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		_Ty image; | 		_Ty texture; | ||||||
| 		if (image.Load(path)) | 		if (texture.Load(path)) | ||||||
| 		{ | 		{ | ||||||
| 			cache.insert(std::make_pair(hash, image)); | 			cache.insert(std::make_pair(hash, texture)); | ||||||
| 		} | 		} | ||||||
| 		return image; | 		return texture; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	template <typename _CacheTy> | 	template <typename _CacheTy> | ||||||
|  | @ -51,58 +51,58 @@ namespace kiwano | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ImageCache::ImageCache() | 	TextureCache::TextureCache() | ||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ImageCache::~ImageCache() | 	TextureCache::~TextureCache() | ||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Image ImageCache::AddOrGetImage(String const& file_path) | 	Texture TextureCache::AddOrGetTexture(String const& file_path) | ||||||
| 	{ | 	{ | ||||||
| 		return CreateOrGetCache<Image>(image_cache_, file_path, file_path.hash()); | 		return CreateOrGetCache<Texture>(texture_cache_, file_path, file_path.hash()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Image ImageCache::AddOrGetImage(Resource const& res) | 	Texture TextureCache::AddOrGetTexture(Resource const& res) | ||||||
| 	{ | 	{ | ||||||
| 		return CreateOrGetCache<Image>(image_cache_, res, res.GetId()); | 		return CreateOrGetCache<Texture>(texture_cache_, res, res.GetId()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	GifImage ImageCache::AddOrGetGifImage(String const& file_path) | 	GifImage TextureCache::AddOrGetGifImage(String const& file_path) | ||||||
| 	{ | 	{ | ||||||
| 		return CreateOrGetCache<GifImage>(gif_image_cache_, file_path, file_path.hash()); | 		return CreateOrGetCache<GifImage>(gif_texture_cache_, file_path, file_path.hash()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	GifImage ImageCache::AddOrGetGifImage(Resource const& res) | 	GifImage TextureCache::AddOrGetGifImage(Resource const& res) | ||||||
| 	{ | 	{ | ||||||
| 		return CreateOrGetCache<GifImage>(gif_image_cache_, res, res.GetId()); | 		return CreateOrGetCache<GifImage>(gif_texture_cache_, res, res.GetId()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void ImageCache::RemoveImage(String const& file_path) | 	void TextureCache::RemoveTexture(String const& file_path) | ||||||
| 	{ | 	{ | ||||||
| 		RemoveCache(image_cache_, file_path.hash()); | 		RemoveCache(texture_cache_, file_path.hash()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void ImageCache::RemoveImage(Resource const& res) | 	void TextureCache::RemoveTexture(Resource const& res) | ||||||
| 	{ | 	{ | ||||||
| 		RemoveCache(image_cache_, res.GetId()); | 		RemoveCache(texture_cache_, res.GetId()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void ImageCache::RemoveGifImage(String const& file_path) | 	void TextureCache::RemoveGifImage(String const& file_path) | ||||||
| 	{ | 	{ | ||||||
| 		RemoveCache(gif_image_cache_, file_path.hash()); | 		RemoveCache(gif_texture_cache_, file_path.hash()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void ImageCache::RemoveGifImage(Resource const& res) | 	void TextureCache::RemoveGifImage(Resource const& res) | ||||||
| 	{ | 	{ | ||||||
| 		RemoveCache(gif_image_cache_, res.GetId()); | 		RemoveCache(gif_texture_cache_, res.GetId()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void ImageCache::Clear() | 	void TextureCache::Clear() | ||||||
| 	{ | 	{ | ||||||
| 		image_cache_.clear(); | 		texture_cache_.clear(); | ||||||
| 		gif_image_cache_.clear(); | 		gif_texture_cache_.clear(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | @ -19,39 +19,39 @@ | ||||||
| // THE SOFTWARE.
 | // THE SOFTWARE.
 | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| #include "Image.h" | #include "Texture.h" | ||||||
| #include "GifImage.h" | #include "GifImage.h" | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
| 	class KGE_API ImageCache | 	class KGE_API TextureCache | ||||||
| 		: public Singleton<ImageCache> | 		: public Singleton<TextureCache> | ||||||
| 	{ | 	{ | ||||||
| 		KGE_DECLARE_SINGLETON(ImageCache); | 		KGE_DECLARE_SINGLETON(TextureCache); | ||||||
| 
 | 
 | ||||||
| 	public: | 	public: | ||||||
| 		Image AddOrGetImage(String const& file_path); | 		Texture AddOrGetTexture(String const& file_path); | ||||||
| 		Image AddOrGetImage(Resource const& res); | 		Texture AddOrGetTexture(Resource const& res); | ||||||
| 		GifImage AddOrGetGifImage(String const& file_path); | 		GifImage AddOrGetGifImage(String const& file_path); | ||||||
| 		GifImage AddOrGetGifImage(Resource const& res); | 		GifImage AddOrGetGifImage(Resource const& res); | ||||||
| 
 | 
 | ||||||
| 		void RemoveImage(String const& file_path); | 		void RemoveTexture(String const& file_path); | ||||||
| 		void RemoveImage(Resource const& res); | 		void RemoveTexture(Resource const& res); | ||||||
| 		void RemoveGifImage(String const& file_path); | 		void RemoveGifImage(String const& file_path); | ||||||
| 		void RemoveGifImage(Resource const& res); | 		void RemoveGifImage(Resource const& res); | ||||||
| 
 | 
 | ||||||
| 		void Clear(); | 		void Clear(); | ||||||
| 
 | 
 | ||||||
| 	protected: | 	protected: | ||||||
| 		ImageCache(); | 		TextureCache(); | ||||||
| 
 | 
 | ||||||
| 		virtual ~ImageCache(); | 		virtual ~TextureCache(); | ||||||
| 
 | 
 | ||||||
| 	protected: | 	protected: | ||||||
| 		using ImageMap = UnorderedMap<UInt32, Image>; | 		using TextureMap = UnorderedMap<UInt32, Texture>; | ||||||
| 		ImageMap image_cache_; | 		TextureMap texture_cache_; | ||||||
| 
 | 
 | ||||||
| 		using GifImageMap = UnorderedMap<UInt32, GifImage>; | 		using GifImageMap = UnorderedMap<UInt32, GifImage>; | ||||||
| 		GifImageMap gif_image_cache_; | 		GifImageMap gif_texture_cache_; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  | @ -20,7 +20,6 @@ | ||||||
| 
 | 
 | ||||||
| #include "D2DDeviceResources.h" | #include "D2DDeviceResources.h" | ||||||
| #include "../../base/Logger.h" | #include "../../base/Logger.h" | ||||||
| #include "../../utils/FileUtil.h" |  | ||||||
| 
 | 
 | ||||||
| #pragma comment(lib, "d2d1.lib") | #pragma comment(lib, "d2d1.lib") | ||||||
| #pragma comment(lib, "dwrite.lib") | #pragma comment(lib, "dwrite.lib") | ||||||
|  | @ -38,14 +37,30 @@ namespace kiwano | ||||||
| 		HRESULT CreateDeviceIndependentResources(); | 		HRESULT CreateDeviceIndependentResources(); | ||||||
| 
 | 
 | ||||||
| 	public: | 	public: | ||||||
| 		HRESULT CreateBitmapFromFile( | 		HRESULT CreateBitmapConverter( | ||||||
| 			_Out_ ComPtr<ID2D1Bitmap>& bitmap, | 			_Out_ ComPtr<IWICFormatConverter>& converter, | ||||||
| 			_In_ String const& file_path | 			_In_opt_ ComPtr<IWICBitmapSource> source, | ||||||
|  | 			_In_ REFWICPixelFormatGUID format, | ||||||
|  | 			WICBitmapDitherType dither, | ||||||
|  | 			_In_opt_ ComPtr<IWICPalette> palette, | ||||||
|  | 			double alpha_threshold_percent, | ||||||
|  | 			WICBitmapPaletteType palette_translate | ||||||
| 		) override; | 		) override; | ||||||
| 
 | 
 | ||||||
| 		HRESULT CreateBitmapFromResource( | 		HRESULT CreateBitmapFromConverter( | ||||||
| 			_Out_ ComPtr<ID2D1Bitmap>& bitmap, | 			_Out_ ComPtr<ID2D1Bitmap>& bitmap, | ||||||
| 			_In_ Resource const& res | 			_In_opt_ const D2D1_BITMAP_PROPERTIES* properties, | ||||||
|  | 			_In_ ComPtr<IWICFormatConverter> converter | ||||||
|  | 		) override; | ||||||
|  | 
 | ||||||
|  | 		HRESULT CreateBitmapDecoderFromFile( | ||||||
|  | 			_Out_ ComPtr<IWICBitmapDecoder>& decoder, | ||||||
|  | 			const String& file_path | ||||||
|  | 		) override; | ||||||
|  | 
 | ||||||
|  | 		HRESULT CreateBitmapDecoderFromResource( | ||||||
|  | 			_Out_ ComPtr<IWICBitmapDecoder>& decoder, | ||||||
|  | 			const Resource& resource | ||||||
| 		) override; | 		) override; | ||||||
| 
 | 
 | ||||||
| 		HRESULT CreateTextFormat( | 		HRESULT CreateTextFormat( | ||||||
|  | @ -56,7 +71,6 @@ namespace kiwano | ||||||
| 		HRESULT CreateTextLayout( | 		HRESULT CreateTextLayout( | ||||||
| 			_Out_ ComPtr<IDWriteTextLayout>& text_layout, | 			_Out_ ComPtr<IDWriteTextLayout>& text_layout, | ||||||
| 			_In_ String const& text, | 			_In_ String const& text, | ||||||
| 			_In_ TextStyle const& text_style, |  | ||||||
| 			_In_ ComPtr<IDWriteTextFormat> const& text_format | 			_In_ ComPtr<IDWriteTextFormat> const& text_format | ||||||
| 		) const override; | 		) const override; | ||||||
| 
 | 
 | ||||||
|  | @ -68,8 +82,6 @@ namespace kiwano | ||||||
| 			_In_ ComPtr<ID2D1Bitmap1> const& target | 			_In_ ComPtr<ID2D1Bitmap1> const& target | ||||||
| 		) override; | 		) override; | ||||||
| 
 | 
 | ||||||
| 		ID2D1StrokeStyle* GetStrokeStyle(StrokeStyle stroke) const override; |  | ||||||
| 
 |  | ||||||
| 		void DiscardResources() override; | 		void DiscardResources() override; | ||||||
| 
 | 
 | ||||||
| 	public: | 	public: | ||||||
|  | @ -85,10 +97,6 @@ namespace kiwano | ||||||
| 	protected: | 	protected: | ||||||
| 		unsigned long ref_count_; | 		unsigned long ref_count_; | ||||||
| 		Float32 dpi_; | 		Float32 dpi_; | ||||||
| 
 |  | ||||||
| 		ComPtr<ID2D1StrokeStyle>	d2d_miter_stroke_style_; |  | ||||||
| 		ComPtr<ID2D1StrokeStyle>	d2d_bevel_stroke_style_; |  | ||||||
| 		ComPtr<ID2D1StrokeStyle>	d2d_round_stroke_style_; |  | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -195,16 +203,16 @@ namespace kiwano | ||||||
| 		ComPtr<IWICImagingFactory>	imaging_factory; | 		ComPtr<IWICImagingFactory>	imaging_factory; | ||||||
| 		ComPtr<IDWriteFactory>		dwrite_factory; | 		ComPtr<IDWriteFactory>		dwrite_factory; | ||||||
| 
 | 
 | ||||||
| 		D2D1_FACTORY_OPTIONS options; | 		D2D1_FACTORY_OPTIONS config; | ||||||
| 		ZeroMemory(&options, sizeof(D2D1_FACTORY_OPTIONS)); | 		ZeroMemory(&config, sizeof(D2D1_FACTORY_OPTIONS)); | ||||||
| #ifdef KGE_DEBUG | #if defined(KGE_DEBUG) && defined(KGE_ENABLE_DX_DEBUG) | ||||||
| 		options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; | 		config.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 		hr = D2D1CreateFactory( | 		hr = D2D1CreateFactory( | ||||||
| 			D2D1_FACTORY_TYPE_SINGLE_THREADED, | 			D2D1_FACTORY_TYPE_SINGLE_THREADED, | ||||||
| 			__uuidof(ID2D1Factory1), | 			__uuidof(ID2D1Factory1), | ||||||
| 			&options, | 			&config, | ||||||
| 			reinterpret_cast<void**>(&d2d_factory) | 			reinterpret_cast<void**>(&d2d_factory) | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
|  | @ -316,143 +324,113 @@ namespace kiwano | ||||||
| 			device_context_->SetTarget(target_bitmap_.get()); | 			device_context_->SetTarget(target_bitmap_.get()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	HRESULT D2DDeviceResources::CreateBitmapFromFile(_Out_ ComPtr<ID2D1Bitmap> & bitmap, _In_ String const & file_path) | 	HRESULT D2DDeviceResources::CreateBitmapConverter(_Out_ ComPtr<IWICFormatConverter>& converter, _In_opt_ ComPtr<IWICBitmapSource> source, | ||||||
|  | 		_In_ REFWICPixelFormatGUID format, WICBitmapDitherType dither, _In_opt_ ComPtr<IWICPalette> palette, double alpha_threshold_percent, | ||||||
|  | 		WICBitmapPaletteType palette_translate | ||||||
|  | 	) | ||||||
| 	{ | 	{ | ||||||
| 		if (!imaging_factory_ || !device_context_) | 		if (!imaging_factory_) | ||||||
| 			return E_UNEXPECTED; | 			return E_UNEXPECTED; | ||||||
| 
 | 
 | ||||||
| 		if (!FileUtil::ExistsFile(file_path)) | 		ComPtr<IWICFormatConverter> output; | ||||||
|  | 		HRESULT hr = imaging_factory_->CreateFormatConverter(&output); | ||||||
|  | 
 | ||||||
|  | 		if (SUCCEEDED(hr)) | ||||||
| 		{ | 		{ | ||||||
| 			KGE_WARNING_LOG(L"Image file '%s' not found!", file_path.c_str()); | 			hr = output->Initialize( | ||||||
| 			return E_FAIL; | 				source.get(), | ||||||
|  | 				format, | ||||||
|  | 				dither, | ||||||
|  | 				palette.get(), | ||||||
|  | 				alpha_threshold_percent, | ||||||
|  | 				palette_translate | ||||||
|  | 			); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		ComPtr<IWICBitmapDecoder>		decoder; | 		if (SUCCEEDED(hr)) | ||||||
| 		ComPtr<IWICBitmapFrameDecode>	source; | 		{ | ||||||
| 		ComPtr<IWICStream>				stream; | 			converter = output; | ||||||
| 		ComPtr<IWICFormatConverter>		converter; | 		} | ||||||
| 		ComPtr<ID2D1Bitmap>				bitmap_tmp; | 		return hr; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
|  | 	HRESULT D2DDeviceResources::CreateBitmapFromConverter(_Out_ ComPtr<ID2D1Bitmap>& bitmap, _In_opt_ const D2D1_BITMAP_PROPERTIES* properties, | ||||||
|  | 		_In_ ComPtr<IWICFormatConverter> converter) | ||||||
|  | 	{ | ||||||
|  | 		if (!device_context_) | ||||||
|  | 			return E_UNEXPECTED; | ||||||
|  | 
 | ||||||
|  | 		ComPtr<ID2D1Bitmap> output; | ||||||
|  | 		HRESULT hr = device_context_->CreateBitmapFromWicBitmap( | ||||||
|  | 			converter.get(), | ||||||
|  | 			properties, | ||||||
|  | 			&output | ||||||
|  | 		); | ||||||
|  | 
 | ||||||
|  | 		if (SUCCEEDED(hr)) | ||||||
|  | 		{ | ||||||
|  | 			bitmap = output; | ||||||
|  | 		} | ||||||
|  | 		return hr; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	HRESULT D2DDeviceResources::CreateBitmapDecoderFromFile(_Out_ ComPtr<IWICBitmapDecoder>& decoder, const String& file_path) | ||||||
|  | 	{ | ||||||
|  | 		if (!imaging_factory_) | ||||||
|  | 			return E_UNEXPECTED; | ||||||
|  | 
 | ||||||
|  | 		ComPtr<IWICBitmapDecoder> decoder_output; | ||||||
| 		HRESULT hr = imaging_factory_->CreateDecoderFromFilename( | 		HRESULT hr = imaging_factory_->CreateDecoderFromFilename( | ||||||
| 			file_path.c_str(), | 			file_path.c_str(), | ||||||
| 			nullptr, | 			nullptr, | ||||||
| 			GENERIC_READ, | 			GENERIC_READ, | ||||||
| 			WICDecodeMetadataCacheOnLoad, | 			WICDecodeMetadataCacheOnLoad, | ||||||
| 			&decoder | 			&decoder_output | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr)) | 		if (SUCCEEDED(hr)) | ||||||
| 		{ | 		{ | ||||||
| 			hr = decoder->GetFrame(0, &source); | 			decoder = decoder_output; | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = imaging_factory_->CreateFormatConverter(&converter); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			// 图片格式转换成 32bppPBGRA
 |  | ||||||
| 			hr = converter->Initialize( |  | ||||||
| 				source.get(), |  | ||||||
| 				GUID_WICPixelFormat32bppPBGRA, |  | ||||||
| 				WICBitmapDitherTypeNone, |  | ||||||
| 				nullptr, |  | ||||||
| 				0.f, |  | ||||||
| 				WICBitmapPaletteTypeMedianCut |  | ||||||
| 			); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = device_context_->CreateBitmapFromWicBitmap( |  | ||||||
| 				converter.get(), |  | ||||||
| 				nullptr, |  | ||||||
| 				&bitmap_tmp |  | ||||||
| 			); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			bitmap = bitmap_tmp; |  | ||||||
| 		} | 		} | ||||||
| 		return hr; | 		return hr; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	HRESULT D2DDeviceResources::CreateBitmapFromResource(_Out_ ComPtr<ID2D1Bitmap> & bitmap, _In_ Resource const & res) | 	HRESULT D2DDeviceResources::CreateBitmapDecoderFromResource(_Out_ ComPtr<IWICBitmapDecoder>& decoder, const Resource& resource) | ||||||
| 	{ | 	{ | ||||||
| 		if (!imaging_factory_ || !device_context_) | 		if (!imaging_factory_) | ||||||
| 			return E_UNEXPECTED; | 			return E_UNEXPECTED; | ||||||
| 
 | 
 | ||||||
| 		ComPtr<IWICBitmapDecoder>		decoder; | 		Resource::Data res_data = resource.GetData(); | ||||||
| 		ComPtr<IWICBitmapFrameDecode>	source; |  | ||||||
| 		ComPtr<IWICStream>				stream; |  | ||||||
| 		ComPtr<IWICFormatConverter>		converter; |  | ||||||
| 		ComPtr<ID2D1Bitmap>				bitmap_tmp; |  | ||||||
| 
 |  | ||||||
| 		// 加载资源
 |  | ||||||
| 		Resource::Data res_data = res.GetData(); |  | ||||||
| 		HRESULT hr = res_data ? S_OK : E_FAIL; | 		HRESULT hr = res_data ? S_OK : E_FAIL; | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr)) | 		if (SUCCEEDED(hr)) | ||||||
| 		{ | 		{ | ||||||
|  | 			ComPtr<IWICStream> stream; | ||||||
| 			hr = imaging_factory_->CreateStream(&stream); | 			hr = imaging_factory_->CreateStream(&stream); | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr)) | 			if (SUCCEEDED(hr)) | ||||||
| 		{ | 			{ | ||||||
| 			hr = stream->InitializeFromMemory( | 				hr = stream->InitializeFromMemory( | ||||||
| 				static_cast<WICInProcPointer>(res_data.buffer), | 					static_cast<WICInProcPointer>(res_data.buffer), | ||||||
| 				res_data.size | 					res_data.size | ||||||
| 			); | 				); | ||||||
| 		} | 			} | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr)) | 			if (SUCCEEDED(hr)) | ||||||
| 		{ | 			{ | ||||||
| 			hr = imaging_factory_->CreateDecoderFromStream( | 				ComPtr<IWICBitmapDecoder> decoder_output; | ||||||
| 				stream.get(), | 				hr = imaging_factory_->CreateDecoderFromStream( | ||||||
| 				nullptr, | 					stream.get(), | ||||||
| 				WICDecodeMetadataCacheOnLoad, | 					nullptr, | ||||||
| 				&decoder | 					WICDecodeMetadataCacheOnLoad, | ||||||
| 			); | 					&decoder_output | ||||||
| 		} | 				); | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr)) | 				if (SUCCEEDED(hr)) | ||||||
| 		{ | 				{ | ||||||
| 			hr = decoder->GetFrame(0, &source); | 					decoder = decoder_output; | ||||||
| 		} | 				} | ||||||
| 
 | 			} | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = imaging_factory_->CreateFormatConverter(&converter); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			// 图片格式转换成 32bppPBGRA
 |  | ||||||
| 			hr = converter->Initialize( |  | ||||||
| 				source.get(), |  | ||||||
| 				GUID_WICPixelFormat32bppPBGRA, |  | ||||||
| 				WICBitmapDitherTypeNone, |  | ||||||
| 				nullptr, |  | ||||||
| 				0.f, |  | ||||||
| 				WICBitmapPaletteTypeMedianCut |  | ||||||
| 			); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = device_context_->CreateBitmapFromWicBitmap( |  | ||||||
| 				converter.get(), |  | ||||||
| 				nullptr, |  | ||||||
| 				&bitmap_tmp |  | ||||||
| 			); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			bitmap = bitmap_tmp; |  | ||||||
| 		} | 		} | ||||||
| 		return hr; | 		return hr; | ||||||
| 	} | 	} | ||||||
|  | @ -470,7 +448,7 @@ namespace kiwano | ||||||
| 			font.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, | 			font.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, | ||||||
| 			DWRITE_FONT_STRETCH_NORMAL, | 			DWRITE_FONT_STRETCH_NORMAL, | ||||||
| 			font.size, | 			font.size, | ||||||
| 			L"en-us", | 			L"", | ||||||
| 			&output | 			&output | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
|  | @ -481,95 +459,21 @@ namespace kiwano | ||||||
| 		return hr; | 		return hr; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	HRESULT D2DDeviceResources::CreateTextLayout(_Out_ ComPtr<IDWriteTextLayout> & text_layout, _In_ String const & text, | 	HRESULT D2DDeviceResources::CreateTextLayout(_Out_ ComPtr<IDWriteTextLayout>& text_layout, _In_ String const& text, | ||||||
| 		_In_ TextStyle const & text_style, _In_ ComPtr<IDWriteTextFormat> const& text_format) const | 		_In_ ComPtr<IDWriteTextFormat> const& text_format) const | ||||||
| 	{ | 	{ | ||||||
| 		if (!dwrite_factory_) | 		if (!dwrite_factory_) | ||||||
| 			return E_UNEXPECTED; | 			return E_UNEXPECTED; | ||||||
| 
 | 
 | ||||||
| 		HRESULT hr; |  | ||||||
| 		ComPtr<IDWriteTextLayout> output; | 		ComPtr<IDWriteTextLayout> output; | ||||||
| 		UInt32 length = static_cast<UInt32>(text.length()); | 		HRESULT hr = dwrite_factory_->CreateTextLayout( | ||||||
| 
 | 			text.c_str(), | ||||||
| 		if (text_style.wrap_width > 0) | 			static_cast<UINT32>(text.length()), | ||||||
| 		{ | 			text_format.get(), | ||||||
| 			hr = dwrite_factory_->CreateTextLayout( | 			0, | ||||||
| 				text.c_str(), | 			0, | ||||||
| 				length, | 			&output | ||||||
| 				text_format.get(), | 		); | ||||||
| 				text_style.wrap_width, |  | ||||||
| 				0, |  | ||||||
| 				&output |  | ||||||
| 			); |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			hr = dwrite_factory_->CreateTextLayout( |  | ||||||
| 				text.c_str(), |  | ||||||
| 				length, |  | ||||||
| 				text_format.get(), |  | ||||||
| 				0, |  | ||||||
| 				0, |  | ||||||
| 				&output |  | ||||||
| 			); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			if (text_style.line_spacing == 0.f) |  | ||||||
| 			{ |  | ||||||
| 				hr = output->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0); |  | ||||||
| 			} |  | ||||||
| 			else |  | ||||||
| 			{ |  | ||||||
| 				hr = output->SetLineSpacing( |  | ||||||
| 					DWRITE_LINE_SPACING_METHOD_UNIFORM, |  | ||||||
| 					text_style.line_spacing, |  | ||||||
| 					text_style.line_spacing * 0.8f |  | ||||||
| 				); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = output->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(text_style.alignment)); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			hr = output->SetWordWrapping((text_style.wrap_width > 0) ? DWRITE_WORD_WRAPPING_WRAP : DWRITE_WORD_WRAPPING_NO_WRAP); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			if (text_style.underline) |  | ||||||
| 			{ |  | ||||||
| 				hr = output->SetUnderline(true, { 0, length }); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			if (text_style.strikethrough) |  | ||||||
| 			{ |  | ||||||
| 				output->SetStrikethrough(true, { 0, length }); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (SUCCEEDED(hr)) |  | ||||||
| 		{ |  | ||||||
| 			// Fix the layout width when the text does not wrap
 |  | ||||||
| 			if (!(text_style.wrap_width > 0)) |  | ||||||
| 			{ |  | ||||||
| 				DWRITE_TEXT_METRICS metrics; |  | ||||||
| 				hr = output->GetMetrics(&metrics); |  | ||||||
| 				 |  | ||||||
| 				if (SUCCEEDED(hr)) |  | ||||||
| 				{ |  | ||||||
| 					hr = output->SetMaxWidth(metrics.width); |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		if (SUCCEEDED(hr)) | 		if (SUCCEEDED(hr)) | ||||||
| 		{ | 		{ | ||||||
|  | @ -578,15 +482,4 @@ namespace kiwano | ||||||
| 		return hr; | 		return hr; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ID2D1StrokeStyle* D2DDeviceResources::GetStrokeStyle(StrokeStyle stroke) const |  | ||||||
| 	{ |  | ||||||
| 		switch (stroke) |  | ||||||
| 		{ |  | ||||||
| 		case StrokeStyle::Miter: return d2d_miter_stroke_style_.get(); break; |  | ||||||
| 		case StrokeStyle::Bevel: return d2d_bevel_stroke_style_.get(); break; |  | ||||||
| 		case StrokeStyle::Round: return d2d_round_stroke_style_.get(); break; |  | ||||||
| 		} |  | ||||||
| 		return nullptr; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -189,14 +189,30 @@ namespace kiwano | ||||||
| 	public: | 	public: | ||||||
| 		static HRESULT Create(ID2DDeviceResources** device_resources); | 		static HRESULT Create(ID2DDeviceResources** device_resources); | ||||||
| 
 | 
 | ||||||
| 		virtual HRESULT CreateBitmapFromFile( | 		virtual HRESULT CreateBitmapConverter( | ||||||
| 			_Out_ ComPtr<ID2D1Bitmap>& bitmap, | 			_Out_ ComPtr<IWICFormatConverter>& converter, | ||||||
| 			_In_ String const& file_path | 			_In_opt_ ComPtr<IWICBitmapSource> source, | ||||||
|  | 			_In_ REFWICPixelFormatGUID format, | ||||||
|  | 			WICBitmapDitherType dither, | ||||||
|  | 			_In_opt_ ComPtr<IWICPalette> palette, | ||||||
|  | 			double alpha_threshold_percent, | ||||||
|  | 			WICBitmapPaletteType palette_translate | ||||||
| 		) = 0; | 		) = 0; | ||||||
| 
 | 
 | ||||||
| 		virtual HRESULT CreateBitmapFromResource( | 		virtual HRESULT CreateBitmapFromConverter( | ||||||
| 			_Out_ ComPtr<ID2D1Bitmap>& bitmap, | 			_Out_ ComPtr<ID2D1Bitmap>& bitmap, | ||||||
| 			_In_ Resource const& res | 			_In_opt_ const D2D1_BITMAP_PROPERTIES* properties, | ||||||
|  | 			_In_ ComPtr<IWICFormatConverter> converter | ||||||
|  | 		) = 0; | ||||||
|  | 
 | ||||||
|  | 		virtual HRESULT CreateBitmapDecoderFromFile( | ||||||
|  | 			_Out_ ComPtr<IWICBitmapDecoder>& decoder, | ||||||
|  | 			const String& file_path | ||||||
|  | 		) = 0; | ||||||
|  | 
 | ||||||
|  | 		virtual HRESULT CreateBitmapDecoderFromResource( | ||||||
|  | 			_Out_ ComPtr<IWICBitmapDecoder>& decoder, | ||||||
|  | 			const Resource& resource | ||||||
| 		) = 0; | 		) = 0; | ||||||
| 
 | 
 | ||||||
| 		virtual HRESULT CreateTextFormat( | 		virtual HRESULT CreateTextFormat( | ||||||
|  | @ -207,12 +223,9 @@ namespace kiwano | ||||||
| 		virtual HRESULT CreateTextLayout( | 		virtual HRESULT CreateTextLayout( | ||||||
| 			_Out_ ComPtr<IDWriteTextLayout>& text_layout, | 			_Out_ ComPtr<IDWriteTextLayout>& text_layout, | ||||||
| 			_In_ String const& text, | 			_In_ String const& text, | ||||||
| 			_In_ TextStyle const& text_style, |  | ||||||
| 			_In_ ComPtr<IDWriteTextFormat> const& text_format | 			_In_ ComPtr<IDWriteTextFormat> const& text_format | ||||||
| 		) const = 0; | 		) const = 0; | ||||||
| 
 | 
 | ||||||
| 		virtual ID2D1StrokeStyle* GetStrokeStyle(StrokeStyle stroke) const = 0; |  | ||||||
| 
 |  | ||||||
| 		virtual HRESULT SetD2DDevice( | 		virtual HRESULT SetD2DDevice( | ||||||
| 			_In_ ComPtr<ID2D1Device> const& device | 			_In_ ComPtr<ID2D1Device> const& device | ||||||
| 		) = 0; | 		) = 0; | ||||||
|  | @ -230,6 +243,10 @@ namespace kiwano | ||||||
| 		inline ID2D1DeviceContext*		GetDeviceContext() const		{ KGE_ASSERT(device_context_); return device_context_.get(); } | 		inline ID2D1DeviceContext*		GetDeviceContext() const		{ KGE_ASSERT(device_context_); return device_context_.get(); } | ||||||
| 		inline ID2D1Bitmap1*			GetTargetBitmap() const			{ KGE_ASSERT(target_bitmap_); return target_bitmap_.get(); } | 		inline ID2D1Bitmap1*			GetTargetBitmap() const			{ KGE_ASSERT(target_bitmap_); return target_bitmap_.get(); } | ||||||
| 
 | 
 | ||||||
|  | 		inline ID2D1StrokeStyle*		GetMiterStrokeStyle() const		{ KGE_ASSERT(d2d_miter_stroke_style_); return d2d_miter_stroke_style_.get(); } | ||||||
|  | 		inline ID2D1StrokeStyle*		GetBevelStrokeStyle() const		{ KGE_ASSERT(d2d_bevel_stroke_style_); return d2d_bevel_stroke_style_.get(); } | ||||||
|  | 		inline ID2D1StrokeStyle*		GetRoundStrokeStyle() const		{ KGE_ASSERT(d2d_round_stroke_style_); return d2d_round_stroke_style_.get(); } | ||||||
|  | 
 | ||||||
| 	protected: | 	protected: | ||||||
| 		ComPtr<ID2D1Factory1>		factory_; | 		ComPtr<ID2D1Factory1>		factory_; | ||||||
| 		ComPtr<ID2D1Device>			device_; | 		ComPtr<ID2D1Device>			device_; | ||||||
|  | @ -238,6 +255,10 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 		ComPtr<IWICImagingFactory>	imaging_factory_; | 		ComPtr<IWICImagingFactory>	imaging_factory_; | ||||||
| 		ComPtr<IDWriteFactory>		dwrite_factory_; | 		ComPtr<IDWriteFactory>		dwrite_factory_; | ||||||
|  | 
 | ||||||
|  | 		ComPtr<ID2D1StrokeStyle>	d2d_miter_stroke_style_; | ||||||
|  | 		ComPtr<ID2D1StrokeStyle>	d2d_bevel_stroke_style_; | ||||||
|  | 		ComPtr<ID2D1StrokeStyle>	d2d_round_stroke_style_; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -217,7 +217,7 @@ namespace kiwano | ||||||
| 		// than the API default. It is required for compatibility with Direct2D.
 | 		// than the API default. It is required for compatibility with Direct2D.
 | ||||||
| 		UInt32 creation_flags = D3D10_CREATE_DEVICE_BGRA_SUPPORT; | 		UInt32 creation_flags = D3D10_CREATE_DEVICE_BGRA_SUPPORT; | ||||||
| 
 | 
 | ||||||
| #if defined(KGE_DEBUG) | #if defined(KGE_DEBUG) && defined(KGE_ENABLE_DX_DEBUG) | ||||||
| 		if (DX::SdkLayersAvailable()) | 		if (DX::SdkLayersAvailable()) | ||||||
| 		{ | 		{ | ||||||
| 			creation_flags |= D3D10_CREATE_DEVICE_DEBUG; | 			creation_flags |= D3D10_CREATE_DEVICE_DEBUG; | ||||||
|  |  | ||||||
|  | @ -209,7 +209,7 @@ namespace kiwano | ||||||
| 		// than the API default. It is required for compatibility with Direct2D.
 | 		// than the API default. It is required for compatibility with Direct2D.
 | ||||||
| 		UInt32 creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; | 		UInt32 creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; | ||||||
| 
 | 
 | ||||||
| #if defined(KGE_DEBUG) | #if defined(KGE_DEBUG) && defined(KGE_ENABLE_DX_DEBUG) | ||||||
| 		if (DX::SdkLayersAvailable()) | 		if (DX::SdkLayersAvailable()) | ||||||
| 		{ | 		{ | ||||||
| 			creation_flags |= D3D11_CREATE_DEVICE_DEBUG; | 			creation_flags |= D3D11_CREATE_DEVICE_DEBUG; | ||||||
|  |  | ||||||
|  | @ -112,7 +112,7 @@ namespace kiwano | ||||||
| 			if (evt.type == Event::MouseHover) | 			if (evt.type == Event::MouseHover) | ||||||
| 			{ | 			{ | ||||||
| 				SetStatus(Status::Hover); | 				SetStatus(Status::Hover); | ||||||
| 				Window::GetInstance()->SetMouseCursor(MouseCursor::Hand); | 				Window::GetInstance()->SetCursor(CursorType::Hand); | ||||||
| 
 | 
 | ||||||
| 				if (mouse_over_callback_) | 				if (mouse_over_callback_) | ||||||
| 					mouse_over_callback_(); | 					mouse_over_callback_(); | ||||||
|  | @ -120,7 +120,7 @@ namespace kiwano | ||||||
| 			else if (evt.type == Event::MouseOut) | 			else if (evt.type == Event::MouseOut) | ||||||
| 			{ | 			{ | ||||||
| 				SetStatus(Status::Normal); | 				SetStatus(Status::Normal); | ||||||
| 				Window::GetInstance()->SetMouseCursor(MouseCursor::Arrow); | 				Window::GetInstance()->SetCursor(CursorType::Arrow); | ||||||
| 
 | 
 | ||||||
| 				if (mouse_out_callback_) | 				if (mouse_out_callback_) | ||||||
| 					mouse_out_callback_(); | 					mouse_out_callback_(); | ||||||
|  |  | ||||||
|  | @ -23,6 +23,7 @@ | ||||||
| #include "../2d/Frame.h" | #include "../2d/Frame.h" | ||||||
| #include "../2d/FrameSequence.h" | #include "../2d/FrameSequence.h" | ||||||
| #include "../renderer/GifImage.h" | #include "../renderer/GifImage.h" | ||||||
|  | #include "../renderer/FontCollection.h" | ||||||
| #include <fstream> | #include <fstream> | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
|  | @ -30,7 +31,7 @@ namespace kiwano | ||||||
| 	namespace __resource_cache_01 | 	namespace __resource_cache_01 | ||||||
| 	{ | 	{ | ||||||
| 		bool LoadJsonData(ResourceCache* loader, Json const& json_data); | 		bool LoadJsonData(ResourceCache* loader, Json const& json_data); | ||||||
| 		bool LoadXmlData(ResourceCache* loader, tinyxml2::XMLElement* elem); | 		bool LoadXmlData(ResourceCache* loader, const tinyxml2::XMLElement* elem); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	namespace | 	namespace | ||||||
|  | @ -40,7 +41,7 @@ namespace kiwano | ||||||
| 			{ L"0.1", __resource_cache_01::LoadJsonData }, | 			{ L"0.1", __resource_cache_01::LoadJsonData }, | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		Map<String, Function<bool(ResourceCache*, tinyxml2::XMLElement*)>> load_xml_funcs = { | 		Map<String, Function<bool(ResourceCache*, const tinyxml2::XMLElement*)>> load_xml_funcs = { | ||||||
| 			{ L"latest", __resource_cache_01::LoadXmlData }, | 			{ L"latest", __resource_cache_01::LoadXmlData }, | ||||||
| 			{ L"0.1", __resource_cache_01::LoadXmlData }, | 			{ L"0.1", __resource_cache_01::LoadXmlData }, | ||||||
| 		}; | 		}; | ||||||
|  | @ -138,7 +139,7 @@ namespace kiwano | ||||||
| 		return LoadFromXml(&doc); | 		return LoadFromXml(&doc); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool ResourceCache::LoadFromXml(tinyxml2::XMLDocument* doc) | 	bool ResourceCache::LoadFromXml(const tinyxml2::XMLDocument* doc) | ||||||
| 	{ | 	{ | ||||||
| 		if (doc) | 		if (doc) | ||||||
| 		{ | 		{ | ||||||
|  | @ -201,8 +202,8 @@ namespace kiwano | ||||||
| 		if (files.empty()) | 		if (files.empty()) | ||||||
| 			return 0; | 			return 0; | ||||||
| 
 | 
 | ||||||
| 		Vector<FramePtr> image_arr; | 		Vector<FramePtr> frames; | ||||||
| 		image_arr.reserve(files.size()); | 		frames.reserve(files.size()); | ||||||
| 
 | 
 | ||||||
| 		for (const auto& file : files) | 		for (const auto& file : files) | ||||||
| 		{ | 		{ | ||||||
|  | @ -211,20 +212,20 @@ namespace kiwano | ||||||
| 			{ | 			{ | ||||||
| 				if (ptr->Load(file)) | 				if (ptr->Load(file)) | ||||||
| 				{ | 				{ | ||||||
| 					image_arr.push_back(ptr); | 					frames.push_back(ptr); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (!image_arr.empty()) | 		if (!frames.empty()) | ||||||
| 		{ | 		{ | ||||||
| 			FrameSequencePtr frames = new (std::nothrow) FrameSequence(image_arr); | 			FrameSequencePtr fs = new (std::nothrow) FrameSequence(frames); | ||||||
| 			return AddFrameSequence(id, frames); | 			return AddFrameSequence(id, fs); | ||||||
| 		} | 		} | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	UInt32 ResourceCache::AddFrameSequence(String const & id, String const& file_path, Int32 cols, Int32 rows) | 	UInt32 ResourceCache::AddFrameSequence(String const & id, String const& file_path, Int32 cols, Int32 rows, Float32 padding_x, Float32 padding_y) | ||||||
| 	{ | 	{ | ||||||
| 		if (cols <= 0 || rows <= 0) | 		if (cols <= 0 || rows <= 0) | ||||||
| 			return 0; | 			return 0; | ||||||
|  | @ -235,27 +236,31 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 		Float32 raw_width = raw->GetWidth(); | 		Float32 raw_width = raw->GetWidth(); | ||||||
| 		Float32 raw_height = raw->GetHeight(); | 		Float32 raw_height = raw->GetHeight(); | ||||||
| 		Float32 width = raw_width / cols; | 		Float32 width = (raw_width - (cols - 1) * padding_x) / cols; | ||||||
| 		Float32 height = raw_height / rows; | 		Float32 height = (raw_height - (rows - 1) * padding_y) / rows; | ||||||
| 
 | 
 | ||||||
| 		Vector<FramePtr> image_arr; | 		Vector<FramePtr> frames; | ||||||
| 		image_arr.reserve(rows * cols); | 		frames.reserve(rows * cols); | ||||||
| 
 | 
 | ||||||
|  | 		Float32 dty = 0; | ||||||
| 		for (Int32 i = 0; i < rows; i++) | 		for (Int32 i = 0; i < rows; i++) | ||||||
| 		{ | 		{ | ||||||
|  | 			Float32 dtx = 0; | ||||||
| 			for (Int32 j = 0; j < cols; j++) | 			for (Int32 j = 0; j < cols; j++) | ||||||
| 			{ | 			{ | ||||||
| 				FramePtr ptr = new (std::nothrow) Frame(raw->GetImage()); | 				FramePtr ptr = new (std::nothrow) Frame(raw->GetTexture()); | ||||||
| 				if (ptr) | 				if (ptr) | ||||||
| 				{ | 				{ | ||||||
| 					ptr->SetCropRect(Rect{ j * width, i * height, (j + 1) * width, (i + 1) * height }); | 					ptr->SetCropRect(Rect{ dtx, dty, dtx + width, dty + height }); | ||||||
| 					image_arr.push_back(ptr); | 					frames.push_back(ptr); | ||||||
| 				} | 				} | ||||||
|  | 				dtx += (width + padding_x); | ||||||
| 			} | 			} | ||||||
|  | 			dty += (height + padding_y); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		FrameSequencePtr frames = new (std::nothrow) FrameSequence(image_arr); | 		FrameSequencePtr fs = new (std::nothrow) FrameSequence(frames); | ||||||
| 		return AddFrameSequence(id, frames); | 		return AddFrameSequence(id, fs); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	UInt32 ResourceCache::AddFrameSequence(String const & id, FrameSequencePtr frames) | 	UInt32 ResourceCache::AddFrameSequence(String const & id, FrameSequencePtr frames) | ||||||
|  | @ -278,6 +283,36 @@ namespace kiwano | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	bool ResourceCache::AddGifImage(String const& id, GifImage const& gif) | ||||||
|  | 	{ | ||||||
|  | 		if (gif.IsValid()) | ||||||
|  | 		{ | ||||||
|  | 			gif_cache_.insert(std::make_pair(id, gif)); | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool ResourceCache::AddGifImage(String const& id, String const& file_path) | ||||||
|  | 	{ | ||||||
|  | 		GifImage gif; | ||||||
|  | 		if (gif.Load(file_path)) | ||||||
|  | 		{ | ||||||
|  | 			return AddGifImage(id, gif); | ||||||
|  | 		} | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool ResourceCache::AddFontCollection(String const& id, FontCollection const& collection) | ||||||
|  | 	{ | ||||||
|  | 		if (collection.IsValid()) | ||||||
|  | 		{ | ||||||
|  | 			font_collection_cache_.insert(std::make_pair(id, collection)); | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	FramePtr ResourceCache::GetFrame(String const & id) const | 	FramePtr ResourceCache::GetFrame(String const & id) const | ||||||
| 	{ | 	{ | ||||||
| 		return Get<Frame>(id); | 		return Get<Frame>(id); | ||||||
|  | @ -288,6 +323,22 @@ namespace kiwano | ||||||
| 		return Get<FrameSequence>(id); | 		return Get<FrameSequence>(id); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	GifImage ResourceCache::GetGifImage(String const& id) const | ||||||
|  | 	{ | ||||||
|  | 		auto iter = gif_cache_.find(id); | ||||||
|  | 		if (iter != gif_cache_.end()) | ||||||
|  | 			return iter->second; | ||||||
|  | 		return GifImage(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	FontCollection ResourceCache::GetFontCollection(String const& id) const | ||||||
|  | 	{ | ||||||
|  | 		auto iter = font_collection_cache_.find(id); | ||||||
|  | 		if (iter != font_collection_cache_.end()) | ||||||
|  | 			return iter->second; | ||||||
|  | 		return FontCollection(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	void ResourceCache::Delete(String const & id) | 	void ResourceCache::Delete(String const & id) | ||||||
| 	{ | 	{ | ||||||
| 		cache_.erase(id); | 		cache_.erase(id); | ||||||
|  | @ -309,28 +360,28 @@ namespace kiwano | ||||||
| 			String path; | 			String path; | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		bool LoadImagesFromData(ResourceCache* loader, GlobalData* gdata, const String* id, const String* type, | 		bool LoadTexturesFromData(ResourceCache* loader, GlobalData* gdata, const String* id, const String* type, const String* file) | ||||||
| 			const String* file, const Vector<const WChar*>* files, Int32 rows, Int32 cols) |  | ||||||
| 		{ | 		{ | ||||||
| 			if (!gdata || !id) return false; | 			if (!gdata || !id) return false; | ||||||
| 
 | 
 | ||||||
| 			if (file) | 			if (type && (*type) == L"gif") | ||||||
| 			{ | 			{ | ||||||
| 				if (!(*file).empty()) | 				// GIF image
 | ||||||
| 				{ | 				return loader->AddGifImage(*id, gdata->path + (*file)); | ||||||
| 					if (rows || cols) |  | ||||||
| 					{ |  | ||||||
| 						// Frame slices
 |  | ||||||
| 						return !!loader->AddFrameSequence(*id, gdata->path + (*file), std::max(cols, 1), std::max(rows, 1)); |  | ||||||
| 					} |  | ||||||
| 					else |  | ||||||
| 					{ |  | ||||||
| 						// Simple image
 |  | ||||||
| 						return loader->AddFrame(*id, gdata->path + (*file)); |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | 			if (file && !(*file).empty()) | ||||||
|  | 			{ | ||||||
|  | 				// Simple image
 | ||||||
|  | 				return loader->AddFrame(*id, gdata->path + (*file)); | ||||||
|  | 			} | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		bool LoadTexturesFromData(ResourceCache* loader, GlobalData* gdata, const String* id, const Vector<const WChar*>* files) | ||||||
|  | 		{ | ||||||
|  | 			if (!gdata || !id) return false; | ||||||
|  | 
 | ||||||
| 			// Frames
 | 			// Frames
 | ||||||
| 			if (files) | 			if (files) | ||||||
| 			{ | 			{ | ||||||
|  | @ -350,6 +401,52 @@ namespace kiwano | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		bool LoadTexturesFromData(ResourceCache* loader, GlobalData* gdata, const String* id, const String* file, | ||||||
|  | 			Int32 rows, Int32 cols, Float32 padding_x, Float32 padding_y) | ||||||
|  | 		{ | ||||||
|  | 			if (!gdata || !id) return false; | ||||||
|  | 
 | ||||||
|  | 			if (file) | ||||||
|  | 			{ | ||||||
|  | 				if (!(*file).empty()) | ||||||
|  | 				{ | ||||||
|  | 					if (rows || cols) | ||||||
|  | 					{ | ||||||
|  | 						// Frame slices
 | ||||||
|  | 						return !!loader->AddFrameSequence(*id, gdata->path + (*file), std::max(cols, 1), std::max(rows, 1), padding_x, padding_y); | ||||||
|  | 					} | ||||||
|  | 					else | ||||||
|  | 					{ | ||||||
|  | 						// Simple image
 | ||||||
|  | 						return loader->AddFrame(*id, gdata->path + (*file)); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		bool LoadFontsFromData(ResourceCache* loader, GlobalData* gdata, const String* id, const Vector<String>* files) | ||||||
|  | 		{ | ||||||
|  | 			if (!gdata || !id) return false; | ||||||
|  | 
 | ||||||
|  | 			// Font Collection
 | ||||||
|  | 			if (files) | ||||||
|  | 			{ | ||||||
|  | 				Vector<String> files_copy(*files); | ||||||
|  | 				for (auto& file : files_copy) | ||||||
|  | 				{ | ||||||
|  | 					file = gdata->path + file; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				FontCollection collection; | ||||||
|  | 				if (collection.Load(files_copy)) | ||||||
|  | 				{ | ||||||
|  | 					return loader->AddFontCollection(*id, collection); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		bool LoadJsonData(ResourceCache* loader, Json const& json_data) | 		bool LoadJsonData(ResourceCache* loader, Json const& json_data) | ||||||
| 		{ | 		{ | ||||||
| 			GlobalData global_data; | 			GlobalData global_data; | ||||||
|  | @ -371,6 +468,16 @@ namespace kiwano | ||||||
| 					if (image.count(L"rows")) rows = image[L"rows"].as_int(); | 					if (image.count(L"rows")) rows = image[L"rows"].as_int(); | ||||||
| 					if (image.count(L"cols")) cols = image[L"cols"].as_int(); | 					if (image.count(L"cols")) cols = image[L"cols"].as_int(); | ||||||
| 
 | 
 | ||||||
|  | 					if (rows || cols) | ||||||
|  | 					{ | ||||||
|  | 						Float32 padding_x = 0, padding_y = 0; | ||||||
|  | 						if (image.count(L"padding-x")) padding_x = image[L"padding-x"].get<Float32>(); | ||||||
|  | 						if (image.count(L"padding-y")) padding_y = image[L"padding-y"].get<Float32>(); | ||||||
|  | 
 | ||||||
|  | 						if (!LoadTexturesFromData(loader, &global_data, id, file, rows, cols, padding_x, padding_y)) | ||||||
|  | 							return false; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
| 					if (image.count(L"files")) | 					if (image.count(L"files")) | ||||||
| 					{ | 					{ | ||||||
| 						Vector<const WChar*> files; | 						Vector<const WChar*> files; | ||||||
|  | @ -379,12 +486,33 @@ namespace kiwano | ||||||
| 						{ | 						{ | ||||||
| 							files.push_back(file.as_string().c_str()); | 							files.push_back(file.as_string().c_str()); | ||||||
| 						} | 						} | ||||||
| 						if (!LoadImagesFromData(loader, &global_data, id, type, file, &files, rows, cols)) | 						if(!LoadTexturesFromData(loader, &global_data, id, &files)) | ||||||
| 							return false; | 							return false; | ||||||
| 					} | 					} | ||||||
| 					else | 					else | ||||||
| 					{ | 					{ | ||||||
| 						if (!LoadImagesFromData(loader, &global_data, id, type, file, nullptr, rows, cols)) | 						if(!LoadTexturesFromData(loader, &global_data, id, type, file)) | ||||||
|  | 							return false; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (json_data.count(L"fonts")) | ||||||
|  | 			{ | ||||||
|  | 				for (const auto& font : json_data[L"fonts"]) | ||||||
|  | 				{ | ||||||
|  | 					String id; | ||||||
|  | 
 | ||||||
|  | 					if (font.count(L"id")) id = font[L"id"].as_string(); | ||||||
|  | 					if (font.count(L"files")) | ||||||
|  | 					{ | ||||||
|  | 						Vector<String> files; | ||||||
|  | 						files.reserve(font[L"files"].size()); | ||||||
|  | 						for (const auto& file : font[L"files"]) | ||||||
|  | 						{ | ||||||
|  | 							files.push_back(file.as_string()); | ||||||
|  | 						} | ||||||
|  | 						if (!LoadFontsFromData(loader, &global_data, &id, &files)) | ||||||
| 							return false; | 							return false; | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
|  | @ -392,7 +520,7 @@ namespace kiwano | ||||||
| 			return true; | 			return true; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		bool LoadXmlData(ResourceCache* loader, tinyxml2::XMLElement* elem) | 		bool LoadXmlData(ResourceCache* loader, const tinyxml2::XMLElement* elem) | ||||||
| 		{ | 		{ | ||||||
| 			GlobalData global_data; | 			GlobalData global_data; | ||||||
| 			if (auto path = elem->FirstChildElement(L"path")) | 			if (auto path = elem->FirstChildElement(L"path")) | ||||||
|  | @ -413,6 +541,16 @@ namespace kiwano | ||||||
| 					if (auto attr = image->IntAttribute(L"rows")) rows = attr; | 					if (auto attr = image->IntAttribute(L"rows")) rows = attr; | ||||||
| 					if (auto attr = image->IntAttribute(L"cols")) cols = attr; | 					if (auto attr = image->IntAttribute(L"cols")) cols = attr; | ||||||
| 
 | 
 | ||||||
|  | 					if (rows || cols) | ||||||
|  | 					{ | ||||||
|  | 						Float32 padding_x = 0, padding_y = 0; | ||||||
|  | 						if (auto attr = image->FloatAttribute(L"padding-x")) padding_x = attr; | ||||||
|  | 						if (auto attr = image->FloatAttribute(L"padding-y")) padding_y = attr; | ||||||
|  | 
 | ||||||
|  | 						if (!LoadTexturesFromData(loader, &global_data, &id, &file, rows, cols, padding_x, padding_y)) | ||||||
|  | 							return false; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
| 					if (file.empty() && !image->NoChildren()) | 					if (file.empty() && !image->NoChildren()) | ||||||
| 					{ | 					{ | ||||||
| 						Vector<const WChar*> files_arr; | 						Vector<const WChar*> files_arr; | ||||||
|  | @ -423,16 +561,36 @@ namespace kiwano | ||||||
| 								files_arr.push_back(path); | 								files_arr.push_back(path); | ||||||
| 							} | 							} | ||||||
| 						} | 						} | ||||||
| 						if (!LoadImagesFromData(loader, &global_data, &id, &type, &file, &files_arr, rows, cols)) | 						if (!LoadTexturesFromData(loader, &global_data, &id, &files_arr)) | ||||||
| 							return false; | 							return false; | ||||||
| 					} | 					} | ||||||
| 					else | 					else | ||||||
| 					{ | 					{ | ||||||
| 						if (!LoadImagesFromData(loader, &global_data, &id, &type, &file, nullptr, rows, cols)) | 						if (!LoadTexturesFromData(loader, &global_data, &id, &type, &file)) | ||||||
| 							return false; | 							return false; | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | 
 | ||||||
|  | 			if (auto fonts = elem->FirstChildElement(L"fonts")) | ||||||
|  | 			{ | ||||||
|  | 				for (auto font = fonts->FirstChildElement(); font; font = font->NextSiblingElement()) | ||||||
|  | 				{ | ||||||
|  | 					String id; | ||||||
|  | 					if (auto attr = font->Attribute(L"id")) id.assign(attr); | ||||||
|  | 
 | ||||||
|  | 					Vector<String> files_arr; | ||||||
|  | 					for (auto file = font->FirstChildElement(); file; file = file->NextSiblingElement()) | ||||||
|  | 					{ | ||||||
|  | 						if (auto path = file->Attribute(L"path")) | ||||||
|  | 						{ | ||||||
|  | 							files_arr.push_back(path); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					if (!LoadFontsFromData(loader, &global_data, &id, &files_arr)) | ||||||
|  | 						return false; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 			return true; | 			return true; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -44,7 +44,7 @@ namespace kiwano | ||||||
| 		bool LoadFromXmlFile(String const& file_path); | 		bool LoadFromXmlFile(String const& file_path); | ||||||
| 
 | 
 | ||||||
| 		// 从 XML 文档对象加载资源信息
 | 		// 从 XML 文档对象加载资源信息
 | ||||||
| 		bool LoadFromXml(tinyxml2::XMLDocument* doc); | 		bool LoadFromXml(const tinyxml2::XMLDocument* doc); | ||||||
| 
 | 
 | ||||||
| 		// 添加帧图像
 | 		// 添加帧图像
 | ||||||
| 		bool AddFrame(String const& id, String const& file_path); | 		bool AddFrame(String const& id, String const& file_path); | ||||||
|  | @ -57,7 +57,7 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 		// 添加序列帧
 | 		// 添加序列帧
 | ||||||
| 		// 按行列数裁剪图片
 | 		// 按行列数裁剪图片
 | ||||||
| 		UInt32 AddFrameSequence(String const& id, String const& file_path, Int32 cols, Int32 rows = 1); | 		UInt32 AddFrameSequence(String const& id, String const& file_path, Int32 cols, Int32 rows = 1, Float32 padding_x = 0, Float32 padding_y = 0); | ||||||
| 
 | 
 | ||||||
| 		// 添加序列帧
 | 		// 添加序列帧
 | ||||||
| 		UInt32 AddFrameSequence(String const& id, FrameSequencePtr frames); | 		UInt32 AddFrameSequence(String const& id, FrameSequencePtr frames); | ||||||
|  | @ -65,12 +65,27 @@ namespace kiwano | ||||||
| 		// 添加对象
 | 		// 添加对象
 | ||||||
| 		bool AddObjectBase(String const& id, ObjectBasePtr obj); | 		bool AddObjectBase(String const& id, ObjectBasePtr obj); | ||||||
| 
 | 
 | ||||||
|  | 		// Ìí¼Ó GIF ͼÏñ
 | ||||||
|  | 		bool AddGifImage(String const& id, GifImage const& gif); | ||||||
|  | 
 | ||||||
|  | 		// Ìí¼Ó GIF ͼÏñ
 | ||||||
|  | 		bool AddGifImage(String const& id, String const& file_path); | ||||||
|  | 
 | ||||||
|  | 		// Ìí¼Ó×ÖÌ弯
 | ||||||
|  | 		bool AddFontCollection(String const& id, FontCollection const& collection); | ||||||
|  | 
 | ||||||
| 		// 获取帧图像
 | 		// 获取帧图像
 | ||||||
| 		FramePtr GetFrame(String const& id) const; | 		FramePtr GetFrame(String const& id) const; | ||||||
| 
 | 
 | ||||||
| 		// 获取序列帧
 | 		// 获取序列帧
 | ||||||
| 		FrameSequencePtr GetFrameSequence(String const& id) const; | 		FrameSequencePtr GetFrameSequence(String const& id) const; | ||||||
| 
 | 
 | ||||||
|  | 		// »ñÈ¡ GIF ͼÏñ
 | ||||||
|  | 		GifImage GetGifImage(String const& id) const; | ||||||
|  | 
 | ||||||
|  | 		// »ñÈ¡×ÖÌ弯
 | ||||||
|  | 		FontCollection GetFontCollection(String const& id) const; | ||||||
|  | 
 | ||||||
| 		// 删除指定资源
 | 		// 删除指定资源
 | ||||||
| 		void Delete(String const& id); | 		void Delete(String const& id); | ||||||
| 
 | 
 | ||||||
|  | @ -93,5 +108,8 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| 	protected: | 	protected: | ||||||
| 		UnorderedMap<String, ObjectBasePtr> cache_; | 		UnorderedMap<String, ObjectBasePtr> cache_; | ||||||
|  | 
 | ||||||
|  | 		UnorderedMap<String, GifImage> gif_cache_; | ||||||
|  | 		UnorderedMap<String, FontCollection> font_collection_cache_; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue