diff --git a/projects/kiwano.vcxproj b/projects/kiwano.vcxproj index cd2a541d..30e05eaf 100644 --- a/projects/kiwano.vcxproj +++ b/projects/kiwano.vcxproj @@ -12,7 +12,6 @@ - @@ -70,8 +69,9 @@ - - + + + @@ -132,8 +132,8 @@ - - + + diff --git a/projects/kiwano.vcxproj.filters b/projects/kiwano.vcxproj.filters index 11b8653f..de732345 100644 --- a/projects/kiwano.vcxproj.filters +++ b/projects/kiwano.vcxproj.filters @@ -150,9 +150,6 @@ utils - - base - 2d @@ -258,12 +255,6 @@ renderer - - renderer - - - renderer - renderer @@ -306,6 +297,15 @@ 2d + + renderer + + + renderer + + + renderer + @@ -443,12 +443,6 @@ renderer - - renderer - - - renderer - renderer @@ -482,5 +476,11 @@ 2d + + renderer + + + renderer + \ No newline at end of file diff --git a/src/kiwano-audio/src/Sound.cpp b/src/kiwano-audio/src/Sound.cpp index 30d64e84..e9c3e11c 100644 --- a/src/kiwano-audio/src/Sound.cpp +++ b/src/kiwano-audio/src/Sound.cpp @@ -65,8 +65,7 @@ namespace kiwano Close(); } - Transcoder transcoder; - HRESULT hr = transcoder.LoadMediaFile(file_path); + HRESULT hr = transcoder_.LoadMediaFile(file_path); if (FAILED(hr)) { @@ -74,7 +73,7 @@ namespace kiwano return false; } - hr = Audio::GetInstance()->CreateVoice(&voice_, transcoder.GetBuffer().format); + hr = Audio::GetInstance()->CreateVoice(&voice_, transcoder_.GetBuffer().format); if (FAILED(hr)) { Close(); @@ -94,8 +93,7 @@ namespace kiwano Close(); } - Transcoder transcoder; - HRESULT hr = transcoder.LoadMediaResource(res); + HRESULT hr = transcoder_.LoadMediaResource(res); if (FAILED(hr)) { @@ -103,7 +101,7 @@ namespace kiwano return false; } - hr = Audio::GetInstance()->CreateVoice(&voice_, transcoder.GetBuffer().format); + hr = Audio::GetInstance()->CreateVoice(&voice_, transcoder_.GetBuffer().format); if (FAILED(hr)) { Close(); diff --git a/src/kiwano-imgui/src/ImGuiModule.cpp b/src/kiwano-imgui/src/ImGuiModule.cpp index 7a571cdd..f4f1c41b 100644 --- a/src/kiwano-imgui/src/ImGuiModule.cpp +++ b/src/kiwano-imgui/src/ImGuiModule.cpp @@ -247,20 +247,20 @@ namespace kiwano if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) return; - MouseCursor cursor = MouseCursor::Arrow; + CursorType cursor = CursorType::Arrow; switch (ImGui::GetMouseCursor()) { - case ImGuiMouseCursor_Arrow: cursor = MouseCursor::Arrow; break; - case ImGuiMouseCursor_TextInput: cursor = MouseCursor::TextInput; break; - case ImGuiMouseCursor_ResizeAll: cursor = MouseCursor::SizeAll; break; - case ImGuiMouseCursor_ResizeEW: cursor = MouseCursor::SizeWE; break; - case ImGuiMouseCursor_ResizeNS: cursor = MouseCursor::SizeNS; break; - case ImGuiMouseCursor_ResizeNESW: cursor = MouseCursor::SizeNESW; break; - case ImGuiMouseCursor_ResizeNWSE: cursor = MouseCursor::SizeNWSE; break; - case ImGuiMouseCursor_Hand: cursor = MouseCursor::Hand; break; + case ImGuiMouseCursor_Arrow: cursor = CursorType::Arrow; break; + case ImGuiMouseCursor_TextInput: cursor = CursorType::TextInput; break; + case ImGuiMouseCursor_ResizeAll: cursor = CursorType::SizeAll; break; + case ImGuiMouseCursor_ResizeEW: cursor = CursorType::SizeWE; break; + case ImGuiMouseCursor_ResizeNS: cursor = CursorType::SizeNS; break; + case ImGuiMouseCursor_ResizeNESW: cursor = CursorType::SizeNESW; break; + case ImGuiMouseCursor_ResizeNWSE: cursor = CursorType::SizeNWSE; break; + case ImGuiMouseCursor_Hand: cursor = CursorType::Hand; break; } - Window::GetInstance()->SetMouseCursor(cursor); + Window::GetInstance()->SetCursor(cursor); } void ImGuiModule::UpdateGamepads() { diff --git a/src/kiwano/2d/Canvas.cpp b/src/kiwano/2d/Canvas.cpp index 4cf259f2..3a89408d 100644 --- a/src/kiwano/2d/Canvas.cpp +++ b/src/kiwano/2d/Canvas.cpp @@ -31,7 +31,7 @@ namespace kiwano , stroke_color_(Color::White) , stroke_style_(StrokeStyle::Miter) { - Renderer::GetInstance()->CreateImageRenderTarget(rt_); + Renderer::GetInstance()->CreateTextureRenderTarget(rt_); } Canvas::~Canvas() @@ -53,12 +53,12 @@ namespace kiwano { UpdateCache(); - if (image_cached_.IsValid()) + if (texture_cached_.IsValid()) { PrepareRender(rt); - Rect bitmap_rect(0.f, 0.f, image_cached_.GetWidth(), image_cached_.GetHeight()); - rt->DrawImage(image_cached_, bitmap_rect, bitmap_rect); + Rect bitmap_rect(0.f, 0.f, texture_cached_.GetWidth(), texture_cached_.GetHeight()); + rt->DrawTexture(texture_cached_, bitmap_rect, bitmap_rect); } } @@ -245,11 +245,11 @@ namespace kiwano 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; } } @@ -326,17 +326,17 @@ namespace kiwano cache_expired_ = true; } - Image Canvas::ExportToImage() const + Texture Canvas::ExportToTexture() const { UpdateCache(); - return image_cached_; + return texture_cached_; } void Canvas::UpdateCache() const { if (cache_expired_) { - image_cached_ = rt_.GetOutput(); + texture_cached_ = rt_.GetOutput(); cache_expired_ = false; } } diff --git a/src/kiwano/2d/Canvas.h b/src/kiwano/2d/Canvas.h index cf2a6f0d..78d76fcb 100644 --- a/src/kiwano/2d/Canvas.h +++ b/src/kiwano/2d/Canvas.h @@ -95,9 +95,9 @@ namespace kiwano Vec2 const& radius ); - // 画图片 - void DrawImage( - Image const& image, + // 画图 + void DrawTexture( + Texture const& texture, const Rect* src_rect = nullptr, const Rect* dest_rect = nullptr ); @@ -232,7 +232,7 @@ namespace kiwano Float32 GetBrushOpacity() const; // 导出为图片 - Image ExportToImage() const; + Texture ExportToTexture() const; void OnRender(RenderTarget* rt) override; @@ -247,9 +247,9 @@ namespace kiwano TextStyle text_style_; StrokeStyle stroke_style_; GeometrySink geo_sink_; - ImageRenderTarget rt_; + TextureRenderTarget rt_; mutable bool cache_expired_; - mutable Image image_cached_; + mutable Texture texture_cached_; }; } diff --git a/src/kiwano/2d/DebugActor.cpp b/src/kiwano/2d/DebugActor.cpp index 3ba2ea52..565fdc5d 100644 --- a/src/kiwano/2d/DebugActor.cpp +++ b/src/kiwano/2d/DebugActor.cpp @@ -127,7 +127,16 @@ namespace kiwano } 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()); + } } } diff --git a/src/kiwano/2d/Frame.cpp b/src/kiwano/2d/Frame.cpp index 88169c47..8a92765f 100644 --- a/src/kiwano/2d/Frame.cpp +++ b/src/kiwano/2d/Frame.cpp @@ -19,7 +19,7 @@ // THE SOFTWARE. #include "Frame.h" -#include "../renderer/ImageCache.h" +#include "../renderer/TextureCache.h" namespace kiwano { @@ -37,17 +37,17 @@ namespace kiwano Load(res); } - Frame::Frame(Image const& image) + Frame::Frame(Texture const& texture) { - SetImage(image); + SetTexture(texture); } bool Frame::Load(String const& file_path) { - Image image = ImageCache::GetInstance()->AddOrGetImage(file_path); - if (image.IsValid()) + Texture texture = TextureCache::GetInstance()->AddOrGetTexture(file_path); + if (texture.IsValid()) { - SetImage(image); + SetTexture(texture); return true; } return false; @@ -55,10 +55,10 @@ namespace kiwano bool Frame::Load(Resource const& res) { - Image image = ImageCache::GetInstance()->AddOrGetImage(res); - if (image.IsValid()) + Texture texture = TextureCache::GetInstance()->AddOrGetTexture(res); + if (texture.IsValid()) { - SetImage(image); + SetTexture(texture); return true; } return false; @@ -66,9 +66,9 @@ namespace kiwano 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.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); @@ -76,14 +76,14 @@ namespace kiwano } } - void Frame::SetImage(Image const& image) + void Frame::SetTexture(Texture const& texture) { - image_ = image; - if (image_.IsValid()) + texture_ = texture; + if (texture_.IsValid()) { crop_rect_.left_top.x = crop_rect_.left_top.y = 0; - crop_rect_.right_bottom.x = image_.GetWidth(); - crop_rect_.right_bottom.y = image_.GetHeight(); + crop_rect_.right_bottom.x = texture_.GetWidth(); + crop_rect_.right_bottom.y = texture_.GetHeight(); } } } diff --git a/src/kiwano/2d/Frame.h b/src/kiwano/2d/Frame.h index 30295db4..1c58955f 100644 --- a/src/kiwano/2d/Frame.h +++ b/src/kiwano/2d/Frame.h @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "../renderer/Image.h" +#include "../renderer/Texture.h" namespace kiwano { @@ -39,7 +39,7 @@ namespace kiwano ); explicit Frame( - Image const& image + Texture const& texture ); bool Load( @@ -55,31 +55,31 @@ namespace kiwano Rect const& crop_rect /* 裁剪矩形 */ ); - // 设置位图 - void SetImage( - Image const& image + // 设置纹理 + void SetTexture( + 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: - Image image_; + Texture texture_; Rect crop_rect_; }; } diff --git a/src/kiwano/2d/FrameSequence.cpp b/src/kiwano/2d/FrameSequence.cpp index 1546fd0a..728930f6 100644 --- a/src/kiwano/2d/FrameSequence.cpp +++ b/src/kiwano/2d/FrameSequence.cpp @@ -54,8 +54,8 @@ namespace kiwano else { frames_.reserve(frames_.size() + frames.size()); - for (const auto& image : frames) - AddFrame(image); + for (const auto& texture : frames) + AddFrame(texture); } } diff --git a/src/kiwano/2d/GifSprite.cpp b/src/kiwano/2d/GifSprite.cpp index af8b9053..7918f955 100644 --- a/src/kiwano/2d/GifSprite.cpp +++ b/src/kiwano/2d/GifSprite.cpp @@ -20,7 +20,7 @@ #include "GifSprite.h" #include "../base/Logger.h" -#include "../renderer/ImageCache.h" +#include "../renderer/TextureCache.h" #include "../renderer/Renderer.h" namespace kiwano @@ -30,7 +30,6 @@ namespace kiwano , next_index_(0) , total_loop_count_(1) , loop_count_(0) - , disposal_type_(DisposalType::Unknown) { } @@ -45,41 +44,41 @@ namespace kiwano Load(res); } - GifSprite::GifSprite(GifImage image) + GifSprite::GifSprite(GifImage gif) { - Load(image); + Load(gif); } bool GifSprite::Load(String const& file_path) { - GifImage image = ImageCache::GetInstance()->AddOrGetGifImage(file_path); - return Load(image); + GifImage texture = TextureCache::GetInstance()->AddOrGetGifImage(file_path); + return Load(texture); } bool GifSprite::Load(Resource const& res) { - GifImage image = ImageCache::GetInstance()->AddOrGetGifImage(res); - return Load(image); + GifImage texture = TextureCache::GetInstance()->AddOrGetGifImage(res); + 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; loop_count_ = 0; - disposal_type_ = DisposalType::None; + frame_.disposal_type = GifImage::DisposalType::None; - SetSize(Size{ static_cast(image_.GetWidthInPixels()), static_cast(image_.GetHeightInPixels()) }); + SetSize(Size{ static_cast(gif_.GetWidthInPixels()), static_cast(gif_.GetHeightInPixels()) }); if (!frame_rt_.IsValid()) { - Renderer::GetInstance()->CreateImageRenderTarget(frame_rt_); + Renderer::GetInstance()->CreateTextureRenderTarget(frame_rt_); } - if (image_.GetFramesCount() > 0) + if (gif_.GetFramesCount() > 0) { ComposeNextFrame(); } @@ -90,11 +89,11 @@ namespace kiwano void GifSprite::OnRender(RenderTarget* rt) { - if (frame_.IsValid() && rt->CheckVisibility(GetBounds(), GetTransformMatrix())) + if (frame_.raw.IsValid() && rt->CheckVisibility(GetBounds(), GetTransformMatrix())) { PrepareRender(rt); - rt->DrawImage(frame_); + rt->DrawTexture(frame_.raw, &frame_.rect, nullptr); } } @@ -102,24 +101,30 @@ namespace kiwano { Actor::Update(dt); - if (image_.IsValid() && animating_) + if (gif_.IsValid() && animating_) { frame_elapsed_ += dt; - if (frame_delay_ <= frame_elapsed_) + if (frame_.delay <= frame_elapsed_) { - frame_delay_ -= frame_elapsed_; + frame_.delay -= frame_elapsed_; frame_elapsed_ = 0; ComposeNextFrame(); } } } + void GifSprite::SetGifImage(GifImage const& gif) + { + gif_ = gif; + RestartAnimation(); + } + void GifSprite::RestartAnimation() { animating_ = true; next_index_ = 0; loop_count_ = 0; - disposal_type_ = DisposalType::None; + frame_.disposal_type = GifImage::DisposalType::None; } void GifSprite::ComposeNextFrame() @@ -130,27 +135,27 @@ namespace kiwano { DisposeCurrentFrame(); OverlayNextFrame(); - } while (frame_delay_.IsZero() && !IsLastFrame()); + } while (frame_.delay.IsZero() && !IsLastFrame()); - animating_ = (!EndOfAnimation() && image_.GetFramesCount() > 1); + animating_ = (!EndOfAnimation() && gif_.GetFramesCount() > 1); } } void GifSprite::DisposeCurrentFrame() { - switch (disposal_type_) + switch (frame_.disposal_type) { - case DisposalType::Unknown: - case DisposalType::None: + case GifImage::DisposalType::Unknown: + case GifImage::DisposalType::None: break; - case DisposalType::Background: + case GifImage::DisposalType::Background: { ClearCurrentFrameArea(); break; } - case DisposalType::Previous: + case GifImage::DisposalType::Previous: { RestoreSavedFrame(); break; @@ -163,43 +168,30 @@ namespace kiwano void GifSprite::OverlayNextFrame() { - Image raw_image; - - HRESULT hr = image_.GetRawFrame(next_index_, raw_image, frame_rect_, frame_delay_, disposal_type_); + Renderer::GetInstance()->CreateGifImageFrame(frame_, gif_, next_index_); - if (SUCCEEDED(hr)) + if (frame_.disposal_type == GifImage::DisposalType::Previous) { - if (disposal_type_ == DisposalType::Previous) - { - SaveComposedFrame(); - } + SaveComposedFrame(); } - if (SUCCEEDED(hr)) + if (frame_rt_.IsValid()) { frame_rt_.BeginDraw(); if (next_index_ == 0) { - // 重新绘制背景 - frame_rt_.Clear(image_.GetBackgroundColor()); loop_count_++; } - frame_rt_.DrawImage(raw_image, nullptr, &frame_rect_); + frame_rt_.DrawTexture(frame_.raw, nullptr, &frame_.rect); frame_rt_.EndDraw(); - } - if (SUCCEEDED(hr)) - { - Image frame_to_render = frame_rt_.GetOutput(); - - hr = frame_to_render.IsValid() ? S_OK : E_FAIL; - - if (SUCCEEDED(hr)) + Texture frame_to_render = frame_rt_.GetOutput(); + if (frame_to_render.IsValid()) { - frame_ = frame_to_render; - next_index_ = (++next_index_) % image_.GetFramesCount(); + frame_.raw = frame_to_render; + next_index_ = (++next_index_) % gif_.GetFramesCount(); } } @@ -212,13 +204,11 @@ namespace kiwano { done_cb_(); } - - ThrowIfFailed(hr); } 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; @@ -253,7 +243,7 @@ namespace kiwano 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; @@ -270,8 +260,8 @@ namespace kiwano { frame_rt_.BeginDraw(); - frame_rt_.PushClipRect(frame_rect_); - frame_rt_.Clear(image_.GetBackgroundColor()); + frame_rt_.PushClipRect(frame_.rect); + frame_rt_.Clear(); frame_rt_.PopClipRect(); return frame_rt_.EndDraw(); diff --git a/src/kiwano/2d/GifSprite.h b/src/kiwano/2d/GifSprite.h index ee94ed99..f9c3f0bf 100644 --- a/src/kiwano/2d/GifSprite.h +++ b/src/kiwano/2d/GifSprite.h @@ -31,7 +31,6 @@ namespace kiwano : public Actor { public: - using DisposalType = GifImage::DisposalType; using LoopDoneCallback = Function; using DoneCallback = Function; @@ -46,7 +45,7 @@ namespace kiwano ); GifSprite( - GifImage image + GifImage gif ); bool Load( @@ -58,7 +57,7 @@ namespace kiwano ); bool Load( - GifImage image + GifImage gif ); // 设置 GIF 动画循环次数 @@ -70,12 +69,17 @@ namespace kiwano // 设置 GIF 动画结束回调函数 inline void SetDoneCallback(DoneCallback const& cb) { done_cb_ = cb; } + // 设置 GIF 图像 + void SetGifImage(GifImage const& gif); + // 重新播放动画 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; @@ -103,15 +107,12 @@ namespace kiwano Int32 total_loop_count_; Int32 loop_count_; UInt32 next_index_; - Duration frame_delay_; Duration frame_elapsed_; - DisposalType disposal_type_; LoopDoneCallback loop_cb_; DoneCallback done_cb_; - GifImage image_; - Image frame_; - Rect frame_rect_; - Image saved_frame_; - ImageRenderTarget frame_rt_; + GifImage gif_; + GifImage::Frame frame_; + Texture saved_frame_; + TextureRenderTarget frame_rt_; }; } diff --git a/src/kiwano/2d/ShapeActor.h b/src/kiwano/2d/ShapeActor.h index a710e45e..0ead7c30 100644 --- a/src/kiwano/2d/ShapeActor.h +++ b/src/kiwano/2d/ShapeActor.h @@ -21,6 +21,7 @@ #pragma once #include "Actor.h" #include "../renderer/Geometry.h" +#include "../renderer/StrokeStyle.h" namespace kiwano { diff --git a/src/kiwano/2d/Sprite.cpp b/src/kiwano/2d/Sprite.cpp index 38f7e14c..ab331cfe 100644 --- a/src/kiwano/2d/Sprite.cpp +++ b/src/kiwano/2d/Sprite.cpp @@ -108,7 +108,7 @@ namespace kiwano { PrepareRender(rt); - rt->DrawImage(frame_->GetImage(), &frame_->GetCropRect(), nullptr); + rt->DrawTexture(frame_->GetTexture(), &frame_->GetCropRect(), nullptr); } } } diff --git a/src/kiwano/2d/Stage.cpp b/src/kiwano/2d/Stage.cpp index 5bdee64f..76d8c07b 100644 --- a/src/kiwano/2d/Stage.cpp +++ b/src/kiwano/2d/Stage.cpp @@ -38,12 +38,12 @@ namespace kiwano void Stage::OnEnter() { - KGE_LOG(L"Stage entered"); + // KGE_LOG(L"Stage entered"); } void Stage::OnExit() { - KGE_LOG(L"Stage exited"); + // KGE_LOG(L"Stage exited"); } } diff --git a/src/kiwano/2d/Text.cpp b/src/kiwano/2d/Text.cpp index 6354d071..875bfdc2 100644 --- a/src/kiwano/2d/Text.cpp +++ b/src/kiwano/2d/Text.cpp @@ -126,11 +126,11 @@ namespace kiwano 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; } } diff --git a/src/kiwano/2d/Text.h b/src/kiwano/2d/Text.h index 7dd84ef8..286e96e8 100644 --- a/src/kiwano/2d/Text.h +++ b/src/kiwano/2d/Text.h @@ -102,7 +102,7 @@ namespace kiwano // 设置文字斜体(默认值为 false) void SetItalic( - bool val + bool italic ); // 设置文本自动换行的宽度(默认为 0) diff --git a/src/kiwano/2d/TextStyle.hpp b/src/kiwano/2d/TextStyle.hpp index b11c4c61..023ed954 100644 --- a/src/kiwano/2d/TextStyle.hpp +++ b/src/kiwano/2d/TextStyle.hpp @@ -20,6 +20,7 @@ #pragma once #include "include-forwards.h" +#include "../renderer/StrokeStyle.h" namespace kiwano { diff --git a/src/kiwano/2d/action/Action.cpp b/src/kiwano/2d/action/Action.cpp index 47b11755..fd1d5a6c 100644 --- a/src/kiwano/2d/action/Action.cpp +++ b/src/kiwano/2d/action/Action.cpp @@ -51,8 +51,8 @@ namespace kiwano if (status_ == Status::NotStarted) { - Init(target); status_ = delay_.IsZero() ? Status::Started : Status::Delayed; + Init(target); } switch (status_) diff --git a/src/kiwano/2d/action/ActionWalk.cpp b/src/kiwano/2d/action/ActionWalk.cpp index c6153ce5..41f61ffe 100644 --- a/src/kiwano/2d/action/ActionWalk.cpp +++ b/src/kiwano/2d/action/ActionWalk.cpp @@ -62,7 +62,7 @@ namespace kiwano { if (!path_) { - Complete(target); + Done(); return; } diff --git a/src/kiwano/2d/action/Animation.cpp b/src/kiwano/2d/action/Animation.cpp index 12869a4b..5c5dd0f4 100644 --- a/src/kiwano/2d/action/Animation.cpp +++ b/src/kiwano/2d/action/Animation.cpp @@ -52,6 +52,7 @@ namespace kiwano void Animation::Init(ActorPtr target) { + KGE_ASSERT(frame_seq_ && "Animation::Init() failed: FrameSequence is NULL!"); if (!frame_seq_ || frame_seq_->GetFrames().empty()) { Done(); @@ -59,6 +60,8 @@ namespace kiwano } auto sprite_target = dynamic_cast(target.get()); + KGE_ASSERT(sprite_target && "Animation only supports Sprites!"); + if (sprite_target && frame_seq_) { sprite_target->SetFrame(frame_seq_->GetFrames()[0]); @@ -69,13 +72,14 @@ namespace kiwano { auto sprite_target = dynamic_cast(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(math::Floor(size * percent)), size - 1); - const auto& frames = frame_seq_->GetFrames(); - auto size = frames.size(); - auto index = std::min(static_cast(math::Floor(size * percent)), size - 1); - - sprite_target->SetFrame(frames[index]); + sprite_target->SetFrame(frames[index]); + } } ActionPtr Animation::Clone() const diff --git a/src/kiwano/2d/include-forwards.h b/src/kiwano/2d/include-forwards.h index edbbf0ae..bbe73ae7 100644 --- a/src/kiwano/2d/include-forwards.h +++ b/src/kiwano/2d/include-forwards.h @@ -24,7 +24,6 @@ #include "../base/RefCounter.hpp" #include "../base/SmartPtr.hpp" #include "../base/ObjectBase.h" -#include "../base/types.h" #include "../math/math.h" #include "../renderer/Color.h" diff --git a/src/kiwano/base/Window.cpp b/src/kiwano/base/Window.cpp index e62121bb..38b213bb 100644 --- a/src/kiwano/base/Window.cpp +++ b/src/kiwano/base/Window.cpp @@ -20,6 +20,7 @@ #include "Window.h" #include "Logger.h" +#include "../platform/Application.h" #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 @@ -39,6 +40,16 @@ namespace kiwano 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() : handle_(nullptr) , width_(0) @@ -46,7 +57,7 @@ namespace kiwano , device_name_(nullptr) , is_fullscreen_(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); WNDCLASSEX wcex = { 0 }; @@ -84,9 +95,10 @@ namespace kiwano wcex.lpszMenuName = nullptr; 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); @@ -105,22 +117,24 @@ namespace kiwano device_name_ = new WCHAR[len + 1]; lstrcpyW(device_name_, monitor_info_ex.szDevice); + UInt32 width = config.width; + UInt32 height = config.height; Int32 left = -1; Int32 top = -1; - resizable_ = resizable; - is_fullscreen_ = fullscreen; + resizable_ = config.resizable; + is_fullscreen_ = config.fullscreen; if (is_fullscreen_) { top = monitor_info_ex.rcMonitor.top; left = monitor_info_ex.rcMonitor.left; - if (width > monitor_info_ex.rcWork.right - left) - width = monitor_info_ex.rcWork.right - left; + if (width > static_cast(monitor_info_ex.rcWork.right - left)) + width = static_cast(monitor_info_ex.rcWork.right - left); - if (height > monitor_info_ex.rcWork.bottom - top) - height = monitor_info_ex.rcWork.bottom - top; + if (height > static_cast(monitor_info_ex.rcWork.bottom - top)) + height = static_cast(monitor_info_ex.rcWork.bottom - top); } else { @@ -145,7 +159,7 @@ namespace kiwano handle_ = ::CreateWindowExW( is_fullscreen_ ? WS_EX_TOPMOST : 0, KGE_WND_CLASS_NAME, - title.c_str(), + config.title.c_str(), GetWindowStyle(), left, top, @@ -222,7 +236,7 @@ namespace kiwano if (handle_) { HINSTANCE hinstance = GetModuleHandle(nullptr); - HICON icon = (HICON)::LoadImage( + HICON icon = (HICON)::LoadImageW( hinstance, MAKEINTRESOURCE(icon_resource), IMAGE_ICON, @@ -295,7 +309,7 @@ namespace kiwano } } - void Window::SetMouseCursor(MouseCursor cursor) + void Window::SetCursor(CursorType cursor) { mouse_cursor_ = cursor; } @@ -327,14 +341,14 @@ namespace kiwano LPTSTR win32_cursor = IDC_ARROW; switch (mouse_cursor_) { - case MouseCursor::Arrow: win32_cursor = IDC_ARROW; break; - case MouseCursor::TextInput: win32_cursor = IDC_IBEAM; break; - case MouseCursor::SizeAll: win32_cursor = IDC_SIZEALL; break; - case MouseCursor::SizeWE: win32_cursor = IDC_SIZEWE; break; - case MouseCursor::SizeNS: win32_cursor = IDC_SIZENS; break; - case MouseCursor::SizeNESW: win32_cursor = IDC_SIZENESW; break; - case MouseCursor::SizeNWSE: win32_cursor = IDC_SIZENWSE; break; - case MouseCursor::Hand: win32_cursor = IDC_HAND; break; + case CursorType::Arrow: win32_cursor = IDC_ARROW; break; + case CursorType::TextInput: win32_cursor = IDC_IBEAM; break; + case CursorType::SizeAll: win32_cursor = IDC_SIZEALL; break; + case CursorType::SizeWE: win32_cursor = IDC_SIZEWE; break; + case CursorType::SizeNS: win32_cursor = IDC_SIZENS; break; + case CursorType::SizeNESW: win32_cursor = IDC_SIZENESW; break; + case CursorType::SizeNWSE: win32_cursor = IDC_SIZENWSE; break; + case CursorType::Hand: win32_cursor = IDC_HAND; break; } ::SetCursor(::LoadCursorW(nullptr, win32_cursor)); } @@ -417,4 +431,5 @@ namespace kiwano ::ChangeDisplaySettingsExW(device_name, NULL, NULL, 0, NULL); } } + } diff --git a/src/kiwano/base/Window.h b/src/kiwano/base/Window.h index b613b941..15b15ad5 100644 --- a/src/kiwano/base/Window.h +++ b/src/kiwano/base/Window.h @@ -22,10 +22,44 @@ #include "../macros.h" #include "../core/core.h" #include "../math/math.h" -#include "types.h" 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 : public Singleton { @@ -56,19 +90,11 @@ namespace kiwano // 设置全屏模式 void SetFullscreen(bool fullscreen, Int32 width, Int32 height); - // 设置鼠标指针 - void SetMouseCursor(MouseCursor cursor); + // 设置鼠标指针类型 + void SetCursor(CursorType cursor); public: - void Init( - String const& title, - Int32 width, - Int32 height, - UInt32 icon, - bool resizable, - bool fullscreen, - WNDPROC proc - ); + void Init(WindowConfig const& config, WNDPROC proc); void Prepare(); @@ -94,6 +120,6 @@ namespace kiwano Int32 width_; Int32 height_; WCHAR* device_name_; - MouseCursor mouse_cursor_; + CursorType mouse_cursor_; }; } diff --git a/src/kiwano/config.h b/src/kiwano/config.h index c93cd824..a3999050 100644 --- a/src/kiwano/config.h +++ b/src/kiwano/config.h @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// Compile-time options for Kiwano +// Compile-time configurations for Kiwano //----------------------------------------------------------------------------- #pragma once @@ -19,3 +19,6 @@ //---- Define DirectX version. Defaults to using Direct3D11 //#define KGE_USE_DIRECTX10 + +//---- Define to enable DirectX debug layer +//#define KGE_ENABLE_DX_DEBUG diff --git a/src/kiwano/kiwano.h b/src/kiwano/kiwano.h index 8581c7f0..59d9e3cf 100644 --- a/src/kiwano/kiwano.h +++ b/src/kiwano/kiwano.h @@ -61,12 +61,12 @@ #include "renderer/Color.h" #include "renderer/Font.h" -#include "renderer/Image.h" +#include "renderer/Texture.h" #include "renderer/GifImage.h" #include "renderer/TextLayout.h" #include "renderer/Geometry.h" #include "renderer/LayerArea.h" -#include "renderer/ImageCache.h" +#include "renderer/TextureCache.h" #include "renderer/Renderer.h" diff --git a/src/kiwano/platform/Application.cpp b/src/kiwano/platform/Application.cpp index fbb81e70..3b127c28 100644 --- a/src/kiwano/platform/Application.cpp +++ b/src/kiwano/platform/Application.cpp @@ -20,12 +20,10 @@ #include "Application.h" #include "modules.h" -#include "../base/Window.h" #include "../base/Logger.h" #include "../base/input.h" #include "../base/Director.h" -#include "../renderer/ImageCache.h" -#include "../renderer/Renderer.h" +#include "../renderer/TextureCache.h" #include "../utils/ResourceCache.h" #include // GET_X_LPARAM, GET_Y_LPARAM #include // ImmAssociateContext @@ -43,17 +41,19 @@ namespace kiwano Queue 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) - : title(title) - , width(width) - , height(height) - , icon(icon) - , clear_color(clear_color) - , vsync(vsync) - , resizable(resizable) - , fullscreen(fullscreen) - , debug(debug) - {} + Config::Config(String const& title, UInt32 width, UInt32 height, UInt32 icon) + { + window.title = title; + window.width = width; + window.height = height; + window.icon = icon; + } + + Config::Config(WindowConfig const& wnd_config, RenderConfig const& render_config) + { + window = wnd_config; + render = render_config; + } } namespace kiwano @@ -79,20 +79,10 @@ namespace kiwano ::CoUninitialize(); } - void Application::Init(const Options& options) + void Application::Init(const Config& config) { - Window::GetInstance()->Init( - options.title, - options.width, - options.height, - options.icon, - options.resizable, - options.fullscreen, - Application::WndProc - ); - - Renderer::GetInstance()->SetClearColor(options.clear_color); - Renderer::GetInstance()->SetVSyncEnabled(options.vsync); + Window::GetInstance()->Init(config.window, Application::WndProc); + Renderer::GetInstance()->Init(config.render); // Setup all components for (Component* c : components_) @@ -100,7 +90,7 @@ namespace kiwano c->SetupComponent(); } - if (options.debug) + if (config.debug) { Director::GetInstance()->ShowDebugInfo(true); Renderer::GetInstance()->SetCollectingStatus(true); @@ -150,7 +140,7 @@ namespace kiwano // Clear all resources Director::GetInstance()->ClearStages(); ResourceCache::GetInstance()->Clear(); - ImageCache::GetInstance()->Clear(); + TextureCache::GetInstance()->Clear(); if (inited_) { @@ -166,7 +156,7 @@ namespace kiwano // Destroy all instances Director::DestroyInstance(); ResourceCache::DestroyInstance(); - ImageCache::DestroyInstance(); + TextureCache::DestroyInstance(); Input::DestroyInstance(); Renderer::DestroyInstance(); Window::DestroyInstance(); @@ -299,10 +289,11 @@ namespace kiwano LRESULT CALLBACK Application::WndProc(HWND hwnd, UInt32 msg, WPARAM wparam, LPARAM lparam) { - Application * app = reinterpret_cast(static_cast(::GetWindowLongPtrW(hwnd, GWLP_USERDATA))); - - if (!app) + Application* app = reinterpret_cast(static_cast(::GetWindowLongPtrW(hwnd, GWLP_USERDATA))); + if (app == nullptr) + { return ::DefWindowProcW(hwnd, msg, wparam, lparam); + } // Handle Message for (Component* c : app->components_) diff --git a/src/kiwano/platform/Application.h b/src/kiwano/platform/Application.h index 97de5da3..2b24c3dd 100644 --- a/src/kiwano/platform/Application.h +++ b/src/kiwano/platform/Application.h @@ -23,32 +23,27 @@ #include "../base/time.h" #include "../base/Component.h" #include "../base/Event.hpp" -#include "../renderer/Color.h" +#include "../base/Window.h" +#include "../renderer/Renderer.h" namespace kiwano { - struct Options + struct Config { - String title; // 标题 - Int32 width; // 宽度 - Int32 height; // 高度 - UInt32 icon; // 图标资源 ID - Color clear_color; // 清屏颜色 - bool vsync; // 垂直同步 - bool resizable; // 窗口大小可拉伸 - bool fullscreen; // 全屏模式 - bool debug; // 调试模式 + WindowConfig window; // 窗口设置 + RenderConfig render; // 渲染设置 + bool debug; // 调试模式 - Options( + Config( String const& title = L"Kiwano Game", - Int32 width = 640, - Int32 height = 480, - UInt32 icon = 0, - Color clear_color = Color::Black, - bool vsync = true, - bool resizable = false, - bool fullscreen = false, - bool debug = false + UInt32 width = 640, + UInt32 height = 480, + UInt32 icon = 0 + ); + + Config( + WindowConfig const& wnd_config, + RenderConfig const& render_config = RenderConfig() ); }; @@ -64,7 +59,7 @@ namespace kiwano // 初始化 void Init( - Options const& options = Options{} + Config const& config = Config() ); // 初始化成功时 diff --git a/src/kiwano/renderer/Font.cpp b/src/kiwano/renderer/Font.cpp index 24958349..2bb8de63 100644 --- a/src/kiwano/renderer/Font.cpp +++ b/src/kiwano/renderer/Font.cpp @@ -22,7 +22,16 @@ 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) , size(size) , weight(weight) diff --git a/src/kiwano/renderer/Font.h b/src/kiwano/renderer/Font.h index c703c6d0..6d5cbfd8 100644 --- a/src/kiwano/renderer/Font.h +++ b/src/kiwano/renderer/Font.h @@ -49,11 +49,18 @@ namespace kiwano public: Font( - const String& family = L"", + String const& family = L"", Float32 size = 18, UInt32 weight = FontWeight::Normal, - bool italic = false, - FontCollection collection = FontCollection() + bool italic = false + ); + + Font( + FontCollection collection, + String const& family = L"", + Float32 size = 18, + UInt32 weight = FontWeight::Normal, + bool italic = false ); }; } diff --git a/src/kiwano/renderer/FontCollection.cpp b/src/kiwano/renderer/FontCollection.cpp index 87661691..532df86b 100644 --- a/src/kiwano/renderer/FontCollection.cpp +++ b/src/kiwano/renderer/FontCollection.cpp @@ -50,24 +50,30 @@ namespace kiwano bool FontCollection::Load(String const& file) { Renderer::GetInstance()->CreateFontCollection(*this, { file }); - return false; + return IsValid(); } bool FontCollection::Load(Vector const& files) { Renderer::GetInstance()->CreateFontCollection(*this, files); - return false; + return IsValid(); } bool FontCollection::Load(Resource const& res) { Renderer::GetInstance()->CreateFontCollection(*this, { res }); - return false; + return IsValid(); } bool FontCollection::Load(Vector const& res_arr) { Renderer::GetInstance()->CreateFontCollection(*this, res_arr); - return false; + return IsValid(); } + + bool FontCollection::IsValid() const + { + return collection_ != nullptr; + } + } diff --git a/src/kiwano/renderer/FontCollection.h b/src/kiwano/renderer/FontCollection.h index e4297181..6d154587 100644 --- a/src/kiwano/renderer/FontCollection.h +++ b/src/kiwano/renderer/FontCollection.h @@ -51,6 +51,8 @@ namespace kiwano // 从多个资源加载字体 bool Load(Vector const& res_arr); + bool IsValid() const; + public: inline ComPtr GetFontCollection() const { return collection_; } diff --git a/src/kiwano/renderer/GifImage.cpp b/src/kiwano/renderer/GifImage.cpp index bea8a029..9add1fd5 100644 --- a/src/kiwano/renderer/GifImage.cpp +++ b/src/kiwano/renderer/GifImage.cpp @@ -28,7 +28,6 @@ namespace kiwano : frames_count_(0) , width_in_pixels_(0) , height_in_pixels_(0) - , bg_color_{} { } @@ -82,15 +81,6 @@ namespace kiwano HRESULT GifImage::GetGlobalMetadata() { - UInt32 width = 0; - UInt32 height = 0; - - PROPVARIANT prop_val; - ::PropVariantInit(&prop_val); - - ComPtr metadata_reader; - - // 获取帧数量 HRESULT hr = decoder_ ? S_OK : E_FAIL; if (SUCCEEDED(hr)) @@ -100,317 +90,91 @@ namespace kiwano if (SUCCEEDED(hr)) { + ComPtr 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)) { - 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)) { - width = prop_val.uiVal; - } - ::PropVariantClear(&prop_val); - } - } + // 获取宽度 + hr = metadata_reader->GetMetadataByName(L"/logscrdesc/Width", &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(height / pixel_asp_ratio); - } - else - { - width_in_pixels_ = static_cast(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 metadata_reader) - { - UChar bg_index = 0; - WICColor bgcolors[256]; - UInt32 colors_copied = 0; - ComPtr 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 converter; - ComPtr wic_frame; - ComPtr 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 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(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(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(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(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)) { - delay.SetMilliseconds(static_cast(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)) { - 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(height / pixel_asp_ratio); + } + else + { + width_in_pixels_ = static_cast(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); } - else - { - // 获取 DisposalType 失败,可能图片是只有一帧的图片 - disposal_type = DisposalType::Unknown; - } } - - ::PropVariantClear(&prop_val); return hr; } diff --git a/src/kiwano/renderer/GifImage.h b/src/kiwano/renderer/GifImage.h index 1e05bc38..339c63f1 100644 --- a/src/kiwano/renderer/GifImage.h +++ b/src/kiwano/renderer/GifImage.h @@ -19,7 +19,7 @@ // THE SOFTWARE. #pragma once -#include "Image.h" +#include "Texture.h" namespace kiwano { @@ -43,9 +43,7 @@ namespace kiwano inline UInt32 GetHeightInPixels() const { return height_in_pixels_; } - inline UInt32 GetFramesCount() const { return frames_count_; } - - inline Color GetBackgroundColor() const { return bg_color_; } + inline UInt32 GetFramesCount() const { return frames_count_; } public: enum class DisposalType @@ -56,13 +54,15 @@ namespace kiwano Previous }; - HRESULT GetRawFrame( - UInt32 frame_index, - Image& raw_frame, - Rect& frame_rect, - Duration& delay, - DisposalType& disposal_type - ); + struct Frame + { + Duration delay; + Texture raw; + Rect rect; + DisposalType disposal_type; + + Frame() : disposal_type(DisposalType::Unknown) {} + }; inline ComPtr GetDecoder() const { return decoder_; } @@ -71,16 +71,11 @@ namespace kiwano protected: HRESULT GetGlobalMetadata(); - HRESULT GetBackgroundColor( - ComPtr metadata_reader - ); - protected: UInt32 frames_count_; UInt32 width_in_pixels_; UInt32 height_in_pixels_; - Color bg_color_; - ComPtr decoder_; + ComPtr decoder_; }; } diff --git a/src/kiwano/renderer/RenderTarget.cpp b/src/kiwano/renderer/RenderTarget.cpp index b516ea77..6bfe1eed 100644 --- a/src/kiwano/renderer/RenderTarget.cpp +++ b/src/kiwano/renderer/RenderTarget.cpp @@ -30,8 +30,9 @@ namespace kiwano RenderTarget::RenderTarget() : opacity_(1.f) , collecting_status_(false) + , fast_global_transform_(true) , antialias_(true) - , text_antialias_(TextAntialias::GrayScale) + , text_antialias_(TextAntialiasMode::GrayScale) { status_.primitives = 0; } @@ -133,7 +134,7 @@ namespace kiwano geometry.GetGeometry().get(), default_brush_.get(), stroke_width, - device_resources_->GetStrokeStyle(stroke) + GetStrokeStyle(stroke).get() ); IncreasePrimitivesCount(); @@ -179,7 +180,7 @@ namespace kiwano DX::ConvertToPoint2F(point2), default_brush_.get(), stroke_width, - device_resources_->GetStrokeStyle(stroke) + GetStrokeStyle(stroke).get() ); IncreasePrimitivesCount(); @@ -204,7 +205,7 @@ namespace kiwano DX::ConvertToRectF(rect), default_brush_.get(), stroke_width, - device_resources_->GetStrokeStyle(stroke) + GetStrokeStyle(stroke).get() ); IncreasePrimitivesCount(); @@ -253,7 +254,7 @@ namespace kiwano ), default_brush_.get(), stroke_width, - device_resources_->GetStrokeStyle(stroke) + GetStrokeStyle(stroke).get() ); IncreasePrimitivesCount(); @@ -306,7 +307,7 @@ namespace kiwano ), default_brush_.get(), stroke_width, - device_resources_->GetStrokeStyle(stroke) + GetStrokeStyle(stroke).get() ); IncreasePrimitivesCount(); @@ -339,12 +340,12 @@ namespace kiwano 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; if (!render_target_) @@ -352,13 +353,17 @@ namespace kiwano 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( - image.GetBitmap().get(), + texture.GetBitmap().get(), dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr, opacity_, - D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, + mode, src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr ); @@ -384,7 +389,7 @@ namespace kiwano layout.GetTextStyle().outline, DX::ConvertToColorF(layout.GetTextStyle().outline_color), 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 { - return global_matrix_; + return global_transform_; + } + + ComPtr 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) @@ -550,8 +566,16 @@ namespace kiwano if (SUCCEEDED(hr)) { - Matrix3x2 result = matrix * global_matrix_; - render_target_->SetTransform(DX::ConvertToMatrix3x2F(&result)); + if (fast_global_transform_) + { + render_target_->SetTransform(DX::ConvertToMatrix3x2F(&matrix)); + + } + else + { + Matrix3x2 result = matrix * global_transform_; + render_target_->SetTransform(DX::ConvertToMatrix3x2F(&result)); + } } ThrowIfFailed(hr); @@ -559,7 +583,20 @@ namespace kiwano 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) @@ -601,7 +638,7 @@ namespace kiwano ThrowIfFailed(hr); } - void RenderTarget::SetTextAntialiasMode(TextAntialias mode) + void RenderTarget::SetTextAntialiasMode(TextAntialiasMode mode) { HRESULT hr = S_OK; if (!render_target_) @@ -615,16 +652,16 @@ namespace kiwano D2D1_TEXT_ANTIALIAS_MODE antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; switch (text_antialias_) { - case TextAntialias::Default: + case TextAntialiasMode::Default: antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; break; - case TextAntialias::ClearType: + case TextAntialiasMode::ClearType: antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; break; - case TextAntialias::GrayScale: + case TextAntialiasMode::GrayScale: antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; break; - case TextAntialias::None: + case TextAntialiasMode::None: antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED; break; default: @@ -638,9 +675,12 @@ namespace kiwano bool RenderTarget::CheckVisibility(Rect const& bounds, Matrix3x2 const& transform) { - return Rect{ Point{}, reinterpret_cast(render_target_->GetSize()) }.Intersects( - Matrix3x2(transform * global_matrix_).Transform(bounds) - ); + Rect visible_size = { Point{}, reinterpret_cast(render_target_->GetSize()) }; + 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) @@ -658,14 +698,14 @@ namespace kiwano // - // ImageRenderTarget + // TextureRenderTarget // - ImageRenderTarget::ImageRenderTarget() + TextureRenderTarget::TextureRenderTarget() { } - Image ImageRenderTarget::GetOutput() const + Texture TextureRenderTarget::GetOutput() const { HRESULT hr = E_FAIL; @@ -681,13 +721,13 @@ namespace kiwano if (SUCCEEDED(hr)) { - return Image(bitmap); + return Texture(bitmap); } } } ThrowIfFailed(hr); - return Image(); + return Texture(); } } diff --git a/src/kiwano/renderer/RenderTarget.h b/src/kiwano/renderer/RenderTarget.h index f8c63c5e..019ea940 100644 --- a/src/kiwano/renderer/RenderTarget.h +++ b/src/kiwano/renderer/RenderTarget.h @@ -20,7 +20,7 @@ #pragma once #include "../base/time.h" -#include "Image.h" +#include "Texture.h" #include "Geometry.h" #include "TextLayout.h" #include "LayerArea.h" @@ -28,6 +28,16 @@ namespace kiwano { + // 文字抗锯齿模式 + enum class TextAntialiasMode + { + Default, // 系统默认 + ClearType, // ClearType 抗锯齿 + GrayScale, // 灰度抗锯齿 + None // 不启用抗锯齿 + }; + + // 渲染目标 class KGE_API RenderTarget : public noncopyable @@ -103,14 +113,14 @@ namespace kiwano Color const& fill_color ) const; - void DrawImage( - Image const& image, + void DrawTexture( + Texture const& texture, Rect const& src_rect, Rect const& dest_rect ) const; - void DrawImage( - Image const& image, + void DrawTexture( + Texture const& texture, const Rect* src_rect = nullptr, const Rect* dest_rect = nullptr ) const; @@ -154,6 +164,10 @@ namespace kiwano const Matrix3x2& matrix ); + void SetGlobalTransform( + const Matrix3x2* matrix + ); + // 设置抗锯齿模式 void SetAntialiasMode( bool enabled @@ -161,9 +175,10 @@ namespace kiwano // 设置文字抗锯齿模式 void SetTextAntialiasMode( - TextAntialias mode + TextAntialiasMode mode ); + // 检查边界是否在视区内 bool CheckVisibility( Rect const& bounds, Matrix3x2 const& transform @@ -181,11 +196,13 @@ namespace kiwano void IncreasePrimitivesCount() const; - inline Status const& GetStatus() const { return status_; } + inline Status const& GetStatus() const { return status_; } - inline ComPtr GetRenderTarget() const { KGE_ASSERT(render_target_); return render_target_; } + inline ComPtr GetRenderTarget() const { KGE_ASSERT(render_target_); return render_target_; } - inline ComPtr GetTextRenderer() const { KGE_ASSERT(text_renderer_); return text_renderer_; } + inline ComPtr GetTextRenderer() const { KGE_ASSERT(text_renderer_); return text_renderer_; } + + ComPtr GetStrokeStyle(StrokeStyle style) const; public: RenderTarget(); @@ -200,25 +217,26 @@ namespace kiwano protected: Float32 opacity_; bool antialias_; + bool fast_global_transform_; mutable bool collecting_status_; mutable Status status_; - TextAntialias text_antialias_; + TextAntialiasMode text_antialias_; ComPtr text_renderer_; ComPtr render_target_; ComPtr default_brush_; ComPtr current_brush_; ComPtr device_resources_; - Matrix3x2 global_matrix_; + Matrix3x2 global_transform_; }; // 位图渲染目标 - class KGE_API ImageRenderTarget + class KGE_API TextureRenderTarget : public RenderTarget { public: - ImageRenderTarget(); + TextureRenderTarget(); - Image GetOutput() const; + Texture GetOutput() const; }; } diff --git a/src/kiwano/renderer/Renderer.cpp b/src/kiwano/renderer/Renderer.cpp index ccae9a87..699ba874 100644 --- a/src/kiwano/renderer/Renderer.cpp +++ b/src/kiwano/renderer/Renderer.cpp @@ -25,6 +25,12 @@ namespace kiwano { + RenderConfig::RenderConfig(Color clear_color, bool vsync) + : clear_color(clear_color) + , vsync(vsync) + { + } + Renderer::Renderer() : hwnd_(nullptr) , vsync_(true) @@ -37,6 +43,12 @@ namespace kiwano { } + void Renderer::Init(RenderConfig const& config) + { + SetClearColor(config.clear_color); + SetVSyncEnabled(config.vsync); + } + void Renderer::SetupComponent() { KGE_LOG(L"Creating device resources"); @@ -245,57 +257,7 @@ namespace kiwano return hr; } - void Renderer::CreateImage(Image& image, String const& file_path) - { - HRESULT hr = S_OK; - if (!d2d_res_) - { - hr = E_UNEXPECTED; - } - - if (SUCCEEDED(hr)) - { - ComPtr 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 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) + void Renderer::CreateTexture(Texture& texture, String const& file_path) { HRESULT hr = S_OK; if (!d2d_res_) @@ -305,34 +267,58 @@ namespace kiwano 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; } if (SUCCEEDED(hr)) { ComPtr decoder; - hr = d2d_res_->GetWICImagingFactory()->CreateDecoderFromFilename( - file_path.c_str(), - nullptr, - GENERIC_READ, - WICDecodeMetadataCacheOnLoad, - &decoder - ); + hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, file_path); if (SUCCEEDED(hr)) { - image.SetDecoder(decoder); + ComPtr source; + hr = decoder->GetFrame(0, &source); + + if (SUCCEEDED(hr)) + { + ComPtr converter; + hr = d2d_res_->CreateBitmapConverter( + converter, + source, + GUID_WICPixelFormat32bppPBGRA, + WICBitmapDitherTypeNone, + nullptr, + 0.f, + WICBitmapPaletteTypeMedianCut + ); + + if (SUCCEEDED(hr)) + { + ComPtr bitmap; + hr = d2d_res_->CreateBitmapFromConverter( + bitmap, + nullptr, + converter + ); + + if (SUCCEEDED(hr)) + { + texture.SetBitmap(bitmap); + } + } + } } } 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; if (!d2d_res_) @@ -340,43 +326,273 @@ namespace kiwano hr = E_UNEXPECTED; } - Resource::Data res_data = res.GetData(); - - hr = res_data ? S_OK : E_FAIL; - if (SUCCEEDED(hr)) { - ComPtr stream; - hr = d2d_res_->GetWICImagingFactory()->CreateStream(&stream); + ComPtr decoder; + hr = d2d_res_->CreateBitmapDecoderFromResource(decoder, resource); if (SUCCEEDED(hr)) { - hr = stream->InitializeFromMemory( - static_cast(res_data.buffer), - res_data.size - ); - } - - if (SUCCEEDED(hr)) - { - ComPtr decoder; - hr = d2d_res_->GetWICImagingFactory()->CreateDecoderFromStream( - stream.get(), - nullptr, - WICDecodeMetadataCacheOnLoad, - &decoder - ); + ComPtr source; + hr = decoder->GetFrame(0, &source); if (SUCCEEDED(hr)) { - image.SetDecoder(decoder); + ComPtr converter; + hr = d2d_res_->CreateBitmapConverter( + converter, + source, + GUID_WICPixelFormat32bppPBGRA, + WICBitmapDitherTypeNone, + nullptr, + 0.f, + WICBitmapPaletteTypeMedianCut + ); + + if (SUCCEEDED(hr)) + { + ComPtr bitmap; + hr = d2d_res_->CreateBitmapFromConverter( + bitmap, + nullptr, + converter + ); + + if (SUCCEEDED(hr)) + { + texture.SetBitmap(bitmap); + } + } } } } 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 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 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 wic_frame; + HRESULT hr = gif.GetDecoder()->GetFrame(frame_index, &wic_frame); + + if (SUCCEEDED(hr)) + { + ComPtr converter; + d2d_res_->CreateBitmapConverter( + converter, + wic_frame, + GUID_WICPixelFormat32bppPBGRA, + WICBitmapDitherTypeNone, + nullptr, + 0.f, + WICBitmapPaletteTypeCustom + ); + + if (SUCCEEDED(hr)) + { + ComPtr 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 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(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(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(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(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(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); } - 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; if (!d2d_res_) @@ -504,7 +720,6 @@ namespace kiwano hr = d2d_res_->CreateTextLayout( output, text, - style, format.GetTextFormat() ); } @@ -653,7 +868,7 @@ namespace kiwano ThrowIfFailed(hr); } - void Renderer::CreateImageRenderTarget(ImageRenderTarget& render_target) + void Renderer::CreateTextureRenderTarget(TextureRenderTarget& render_target) { HRESULT hr = S_OK; if (!d2d_res_) @@ -732,7 +947,7 @@ namespace kiwano { case ResolutionMode::Fixed: { - SetGlobalTransform(Matrix3x2{}); + SetGlobalTransform(nullptr); break; } diff --git a/src/kiwano/renderer/Renderer.h b/src/kiwano/renderer/Renderer.h index 7e59ff9a..4e14f017 100644 --- a/src/kiwano/renderer/Renderer.h +++ b/src/kiwano/renderer/Renderer.h @@ -39,6 +39,32 @@ namespace kiwano typedef ID3D11DeviceResources ID3DDeviceResources; #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 : public Singleton , public Component @@ -57,25 +83,41 @@ namespace kiwano bool enabled ); + // 设置画面分辨率 + void SetResolution( + Size const& resolution + ); + + // 设置分辨率模式 + void SetResolutionMode( + ResolutionMode mode + ); + public: - void CreateImage( - Image& image, + void CreateTexture( + Texture& texture, String const& file_path ); - void CreateImage( - Image& image, - Resource const& res + void CreateTexture( + Texture& texture, + Resource const& resource ); void CreateGifImage( - GifImage& image, + GifImage& gif, String const& file_path ); void CreateGifImage( - GifImage& image, - Resource const& res + GifImage& gif, + Resource const& resource + ); + + void CreateGifImageFrame( + GifImage::Frame& frame, + GifImage const& gif, + UInt32 frame_index ); void CreateFontCollection( @@ -96,7 +138,6 @@ namespace kiwano void CreateTextLayout( TextLayout& layout, String const& text, - TextStyle const& style, TextFormat const& format ); @@ -127,19 +168,13 @@ namespace kiwano GeometrySink& sink ); - void CreateImageRenderTarget( - ImageRenderTarget& render_target - ); - - void SetResolution( - Size const& resolution - ); - - void SetResolutionMode( - ResolutionMode mode + void CreateTextureRenderTarget( + TextureRenderTarget& render_target ); public: + void Init(RenderConfig const& config); + void SetupComponent() override; void DestroyComponent() override; diff --git a/src/kiwano/base/types.h b/src/kiwano/renderer/StrokeStyle.h similarity index 70% rename from src/kiwano/base/types.h rename to src/kiwano/renderer/StrokeStyle.h index 8bc6aa8b..5afaac8a 100644 --- a/src/kiwano/base/types.h +++ b/src/kiwano/renderer/StrokeStyle.h @@ -23,41 +23,10 @@ namespace kiwano { // 线条样式 - enum class StrokeStyle : Int32 + enum class StrokeStyle { Miter = 0, /* 斜切 */ Bevel = 1, /* 斜角 */ 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, /* 宽高自适应 */ - }; } diff --git a/src/kiwano/renderer/TextLayout.cpp b/src/kiwano/renderer/TextLayout.cpp index c4033479..8a4f2eaa 100644 --- a/src/kiwano/renderer/TextLayout.cpp +++ b/src/kiwano/renderer/TextLayout.cpp @@ -76,9 +76,73 @@ namespace kiwano Renderer::GetInstance()->CreateTextLayout( *this, text, - style, 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() diff --git a/src/kiwano/renderer/Image.cpp b/src/kiwano/renderer/Texture.cpp similarity index 63% rename from src/kiwano/renderer/Image.cpp rename to src/kiwano/renderer/Texture.cpp index 39d9f253..ad53f8d3 100644 --- a/src/kiwano/renderer/Image.cpp +++ b/src/kiwano/renderer/Texture.cpp @@ -18,53 +18,59 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#include "Image.h" +#include "Texture.h" #include "Renderer.h" #include "../base/Logger.h" 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); } - Image::Image(Resource const& res) + Texture::Texture(Resource const& res) + : Texture() { Load(res); } - Image::Image(ComPtr const & bitmap) + Texture::Texture(ComPtr const & bitmap) + : Texture() { 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(); } - bool Image::Load(Resource const& res) + bool Texture::Load(Resource const& res) { - Renderer::GetInstance()->CreateImage(*this, res); + Renderer::GetInstance()->CreateTexture(*this, res); return IsValid(); } - bool Image::IsValid() const + bool Texture::IsValid() const { return bitmap_ != nullptr; } - Float32 Image::GetWidth() const + Float32 Texture::GetWidth() const { if (bitmap_) { @@ -73,7 +79,7 @@ namespace kiwano return 0; } - Float32 Image::GetHeight() const + Float32 Texture::GetHeight() const { if (bitmap_) { @@ -82,7 +88,7 @@ namespace kiwano return 0; } - Size Image::GetSize() const + Size Texture::GetSize() const { if (bitmap_) { @@ -92,7 +98,7 @@ namespace kiwano return Size{}; } - UInt32 Image::GetWidthInPixels() const + UInt32 Texture::GetWidthInPixels() const { if (bitmap_) { @@ -101,7 +107,7 @@ namespace kiwano return 0; } - UInt32 Image::GetHeightInPixels() const + UInt32 Texture::GetHeightInPixels() const { if (bitmap_) { @@ -110,7 +116,7 @@ namespace kiwano return 0; } - math::Vec2T Image::GetSizeInPixels() const + math::Vec2T Texture::GetSizeInPixels() const { if (bitmap_) { @@ -120,7 +126,12 @@ namespace kiwano return math::Vec2T{}; } - 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()) { @@ -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()) { @@ -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_) { @@ -157,14 +182,18 @@ namespace kiwano return D2D1_PIXEL_FORMAT(); } - ComPtr Image::GetBitmap() const + ComPtr Texture::GetBitmap() const { return bitmap_; } - void Image::SetBitmap(ComPtr bitmap) + void Texture::SetBitmap(ComPtr bitmap) { bitmap_ = bitmap; } + void Texture::SetDefaultInterpolationMode(InterpolationMode mode) + { + } + } diff --git a/src/kiwano/renderer/Image.h b/src/kiwano/renderer/Texture.h similarity index 66% rename from src/kiwano/renderer/Image.h rename to src/kiwano/renderer/Texture.h index 86900c60..a2d80211 100644 --- a/src/kiwano/renderer/Image.h +++ b/src/kiwano/renderer/Texture.h @@ -23,25 +23,36 @@ namespace kiwano { - // 图像 - class KGE_API Image + // 插值模式 + // 插值模式指定了位图在缩放和旋转时像素颜色的计算方式 + // Linear (双线性插值): 对周围四个像素进行两次线性插值计算, 在图像放大时可能会模糊(默认) + // Nearest (最邻近插值): 取最邻近的像素点的颜色值 + enum class InterpolationMode + { + Linear, // 双线性插值 + Nearest, // 最邻近插值 + }; + + + // 纹理 + class KGE_API Texture { public: - Image(); + Texture(); - explicit Image( + explicit Texture( String const& file_path ); - explicit Image( + explicit Texture( Resource const& res ); - explicit Image( + explicit Texture( ComPtr const& bitmap ); - virtual ~Image(); + virtual ~Texture(); // 加载本地文件 bool Load( @@ -56,29 +67,38 @@ namespace kiwano // 资源是否有效 bool IsValid() const; - // 获取位图宽度 + // 获取宽度 Float32 GetWidth() const; - // 获取位图高度 + // 获取高度 Float32 GetHeight() const; - // 获取位图大小 + // 获取大小 Size GetSize() const; - // 获取位图像素宽度 + // 获取像素宽度 UInt32 GetWidthInPixels() const; - // 获取位图像素高度 + // 获取像素高度 UInt32 GetHeightInPixels() const; - // 获取位图像素大小 + // 获取像素大小 math::Vec2T 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: // 获取源位图 @@ -92,5 +112,8 @@ namespace kiwano protected: ComPtr bitmap_; + InterpolationMode interpolation_mode_; + + static InterpolationMode default_interpolation_mode_; }; } diff --git a/src/kiwano/renderer/ImageCache.cpp b/src/kiwano/renderer/TextureCache.cpp similarity index 57% rename from src/kiwano/renderer/ImageCache.cpp rename to src/kiwano/renderer/TextureCache.cpp index 7ec0ea39..d4308916 100644 --- a/src/kiwano/renderer/ImageCache.cpp +++ b/src/kiwano/renderer/TextureCache.cpp @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#include "ImageCache.h" +#include "TextureCache.h" #include "Renderer.h" #include "../base/Logger.h" @@ -33,12 +33,12 @@ namespace kiwano return iter->second; } - _Ty image; - if (image.Load(path)) + _Ty texture; + if (texture.Load(path)) { - cache.insert(std::make_pair(hash, image)); + cache.insert(std::make_pair(hash, texture)); } - return image; + return texture; } template @@ -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_cache_, file_path, file_path.hash()); + return CreateOrGetCache(texture_cache_, file_path, file_path.hash()); } - Image ImageCache::AddOrGetImage(Resource const& res) + Texture TextureCache::AddOrGetTexture(Resource const& res) { - return CreateOrGetCache(image_cache_, res, res.GetId()); + return CreateOrGetCache(texture_cache_, res, res.GetId()); } - GifImage ImageCache::AddOrGetGifImage(String const& file_path) + GifImage TextureCache::AddOrGetGifImage(String const& file_path) { - return CreateOrGetCache(gif_image_cache_, file_path, file_path.hash()); + return CreateOrGetCache(gif_texture_cache_, file_path, file_path.hash()); } - GifImage ImageCache::AddOrGetGifImage(Resource const& res) + GifImage TextureCache::AddOrGetGifImage(Resource const& res) { - return CreateOrGetCache(gif_image_cache_, res, res.GetId()); + return CreateOrGetCache(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(); - gif_image_cache_.clear(); + texture_cache_.clear(); + gif_texture_cache_.clear(); } } diff --git a/src/kiwano/renderer/ImageCache.h b/src/kiwano/renderer/TextureCache.h similarity index 75% rename from src/kiwano/renderer/ImageCache.h rename to src/kiwano/renderer/TextureCache.h index e4a07abe..352f9ca4 100644 --- a/src/kiwano/renderer/ImageCache.h +++ b/src/kiwano/renderer/TextureCache.h @@ -19,39 +19,39 @@ // THE SOFTWARE. #pragma once -#include "Image.h" +#include "Texture.h" #include "GifImage.h" namespace kiwano { - class KGE_API ImageCache - : public Singleton + class KGE_API TextureCache + : public Singleton { - KGE_DECLARE_SINGLETON(ImageCache); + KGE_DECLARE_SINGLETON(TextureCache); public: - Image AddOrGetImage(String const& file_path); - Image AddOrGetImage(Resource const& res); + Texture AddOrGetTexture(String const& file_path); + Texture AddOrGetTexture(Resource const& res); GifImage AddOrGetGifImage(String const& file_path); GifImage AddOrGetGifImage(Resource const& res); - void RemoveImage(String const& file_path); - void RemoveImage(Resource const& res); + void RemoveTexture(String const& file_path); + void RemoveTexture(Resource const& res); void RemoveGifImage(String const& file_path); void RemoveGifImage(Resource const& res); void Clear(); protected: - ImageCache(); + TextureCache(); - virtual ~ImageCache(); + virtual ~TextureCache(); protected: - using ImageMap = UnorderedMap; - ImageMap image_cache_; + using TextureMap = UnorderedMap; + TextureMap texture_cache_; using GifImageMap = UnorderedMap; - GifImageMap gif_image_cache_; + GifImageMap gif_texture_cache_; }; } diff --git a/src/kiwano/renderer/win32/D2DDeviceResources.cpp b/src/kiwano/renderer/win32/D2DDeviceResources.cpp index a4cf4834..8a90e67e 100644 --- a/src/kiwano/renderer/win32/D2DDeviceResources.cpp +++ b/src/kiwano/renderer/win32/D2DDeviceResources.cpp @@ -20,7 +20,6 @@ #include "D2DDeviceResources.h" #include "../../base/Logger.h" -#include "../../utils/FileUtil.h" #pragma comment(lib, "d2d1.lib") #pragma comment(lib, "dwrite.lib") @@ -38,14 +37,30 @@ namespace kiwano HRESULT CreateDeviceIndependentResources(); public: - HRESULT CreateBitmapFromFile( - _Out_ ComPtr& bitmap, - _In_ String const& file_path + HRESULT CreateBitmapConverter( + _Out_ ComPtr& converter, + _In_opt_ ComPtr source, + _In_ REFWICPixelFormatGUID format, + WICBitmapDitherType dither, + _In_opt_ ComPtr palette, + double alpha_threshold_percent, + WICBitmapPaletteType palette_translate ) override; - HRESULT CreateBitmapFromResource( + HRESULT CreateBitmapFromConverter( _Out_ ComPtr& bitmap, - _In_ Resource const& res + _In_opt_ const D2D1_BITMAP_PROPERTIES* properties, + _In_ ComPtr converter + ) override; + + HRESULT CreateBitmapDecoderFromFile( + _Out_ ComPtr& decoder, + const String& file_path + ) override; + + HRESULT CreateBitmapDecoderFromResource( + _Out_ ComPtr& decoder, + const Resource& resource ) override; HRESULT CreateTextFormat( @@ -56,7 +71,6 @@ namespace kiwano HRESULT CreateTextLayout( _Out_ ComPtr& text_layout, _In_ String const& text, - _In_ TextStyle const& text_style, _In_ ComPtr const& text_format ) const override; @@ -68,8 +82,6 @@ namespace kiwano _In_ ComPtr const& target ) override; - ID2D1StrokeStyle* GetStrokeStyle(StrokeStyle stroke) const override; - void DiscardResources() override; public: @@ -85,10 +97,6 @@ namespace kiwano protected: unsigned long ref_count_; Float32 dpi_; - - ComPtr d2d_miter_stroke_style_; - ComPtr d2d_bevel_stroke_style_; - ComPtr d2d_round_stroke_style_; }; @@ -195,16 +203,16 @@ namespace kiwano ComPtr imaging_factory; ComPtr dwrite_factory; - D2D1_FACTORY_OPTIONS options; - ZeroMemory(&options, sizeof(D2D1_FACTORY_OPTIONS)); -#ifdef KGE_DEBUG - options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; + D2D1_FACTORY_OPTIONS config; + ZeroMemory(&config, sizeof(D2D1_FACTORY_OPTIONS)); +#if defined(KGE_DEBUG) && defined(KGE_ENABLE_DX_DEBUG) + config.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; #endif hr = D2D1CreateFactory( D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory1), - &options, + &config, reinterpret_cast(&d2d_factory) ); @@ -316,143 +324,113 @@ namespace kiwano device_context_->SetTarget(target_bitmap_.get()); } - HRESULT D2DDeviceResources::CreateBitmapFromFile(_Out_ ComPtr & bitmap, _In_ String const & file_path) + HRESULT D2DDeviceResources::CreateBitmapConverter(_Out_ ComPtr& converter, _In_opt_ ComPtr source, + _In_ REFWICPixelFormatGUID format, WICBitmapDitherType dither, _In_opt_ ComPtr palette, double alpha_threshold_percent, + WICBitmapPaletteType palette_translate + ) { - if (!imaging_factory_ || !device_context_) + if (!imaging_factory_) return E_UNEXPECTED; - if (!FileUtil::ExistsFile(file_path)) + ComPtr output; + HRESULT hr = imaging_factory_->CreateFormatConverter(&output); + + if (SUCCEEDED(hr)) { - KGE_WARNING_LOG(L"Image file '%s' not found!", file_path.c_str()); - return E_FAIL; + hr = output->Initialize( + source.get(), + format, + dither, + palette.get(), + alpha_threshold_percent, + palette_translate + ); } - ComPtr decoder; - ComPtr source; - ComPtr stream; - ComPtr converter; - ComPtr bitmap_tmp; + if (SUCCEEDED(hr)) + { + converter = output; + } + return hr; + } + HRESULT D2DDeviceResources::CreateBitmapFromConverter(_Out_ ComPtr& bitmap, _In_opt_ const D2D1_BITMAP_PROPERTIES* properties, + _In_ ComPtr converter) + { + if (!device_context_) + return E_UNEXPECTED; + + ComPtr output; + HRESULT hr = device_context_->CreateBitmapFromWicBitmap( + converter.get(), + properties, + &output + ); + + if (SUCCEEDED(hr)) + { + bitmap = output; + } + return hr; + } + + HRESULT D2DDeviceResources::CreateBitmapDecoderFromFile(_Out_ ComPtr& decoder, const String& file_path) + { + if (!imaging_factory_) + return E_UNEXPECTED; + + ComPtr decoder_output; HRESULT hr = imaging_factory_->CreateDecoderFromFilename( file_path.c_str(), nullptr, GENERIC_READ, WICDecodeMetadataCacheOnLoad, - &decoder + &decoder_output ); if (SUCCEEDED(hr)) { - hr = decoder->GetFrame(0, &source); - } - - 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; + decoder = decoder_output; } return hr; } - HRESULT D2DDeviceResources::CreateBitmapFromResource(_Out_ ComPtr & bitmap, _In_ Resource const & res) + HRESULT D2DDeviceResources::CreateBitmapDecoderFromResource(_Out_ ComPtr& decoder, const Resource& resource) { - if (!imaging_factory_ || !device_context_) + if (!imaging_factory_) return E_UNEXPECTED; - ComPtr decoder; - ComPtr source; - ComPtr stream; - ComPtr converter; - ComPtr bitmap_tmp; - - // 加载资源 - Resource::Data res_data = res.GetData(); + Resource::Data res_data = resource.GetData(); HRESULT hr = res_data ? S_OK : E_FAIL; if (SUCCEEDED(hr)) { + ComPtr stream; hr = imaging_factory_->CreateStream(&stream); - } - if (SUCCEEDED(hr)) - { - hr = stream->InitializeFromMemory( - static_cast(res_data.buffer), - res_data.size - ); - } + if (SUCCEEDED(hr)) + { + hr = stream->InitializeFromMemory( + static_cast(res_data.buffer), + res_data.size + ); + } - if (SUCCEEDED(hr)) - { - hr = imaging_factory_->CreateDecoderFromStream( - stream.get(), - nullptr, - WICDecodeMetadataCacheOnLoad, - &decoder - ); - } + if (SUCCEEDED(hr)) + { + ComPtr decoder_output; + hr = imaging_factory_->CreateDecoderFromStream( + stream.get(), + nullptr, + WICDecodeMetadataCacheOnLoad, + &decoder_output + ); - if (SUCCEEDED(hr)) - { - hr = decoder->GetFrame(0, &source); - } - - 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; + if (SUCCEEDED(hr)) + { + decoder = decoder_output; + } + } } return hr; } @@ -470,7 +448,7 @@ namespace kiwano font.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, font.size, - L"en-us", + L"", &output ); @@ -481,95 +459,21 @@ namespace kiwano return hr; } - HRESULT D2DDeviceResources::CreateTextLayout(_Out_ ComPtr & text_layout, _In_ String const & text, - _In_ TextStyle const & text_style, _In_ ComPtr const& text_format) const + HRESULT D2DDeviceResources::CreateTextLayout(_Out_ ComPtr& text_layout, _In_ String const& text, + _In_ ComPtr const& text_format) const { if (!dwrite_factory_) return E_UNEXPECTED; - HRESULT hr; ComPtr output; - UInt32 length = static_cast(text.length()); - - if (text_style.wrap_width > 0) - { - hr = dwrite_factory_->CreateTextLayout( - text.c_str(), - length, - 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); - } - } - } + HRESULT hr = dwrite_factory_->CreateTextLayout( + text.c_str(), + static_cast(text.length()), + text_format.get(), + 0, + 0, + &output + ); if (SUCCEEDED(hr)) { @@ -578,15 +482,4 @@ namespace kiwano 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; - } - } diff --git a/src/kiwano/renderer/win32/D2DDeviceResources.h b/src/kiwano/renderer/win32/D2DDeviceResources.h index c3c73a24..5c117a29 100644 --- a/src/kiwano/renderer/win32/D2DDeviceResources.h +++ b/src/kiwano/renderer/win32/D2DDeviceResources.h @@ -189,14 +189,30 @@ namespace kiwano public: static HRESULT Create(ID2DDeviceResources** device_resources); - virtual HRESULT CreateBitmapFromFile( - _Out_ ComPtr& bitmap, - _In_ String const& file_path + virtual HRESULT CreateBitmapConverter( + _Out_ ComPtr& converter, + _In_opt_ ComPtr source, + _In_ REFWICPixelFormatGUID format, + WICBitmapDitherType dither, + _In_opt_ ComPtr palette, + double alpha_threshold_percent, + WICBitmapPaletteType palette_translate ) = 0; - virtual HRESULT CreateBitmapFromResource( + virtual HRESULT CreateBitmapFromConverter( _Out_ ComPtr& bitmap, - _In_ Resource const& res + _In_opt_ const D2D1_BITMAP_PROPERTIES* properties, + _In_ ComPtr converter + ) = 0; + + virtual HRESULT CreateBitmapDecoderFromFile( + _Out_ ComPtr& decoder, + const String& file_path + ) = 0; + + virtual HRESULT CreateBitmapDecoderFromResource( + _Out_ ComPtr& decoder, + const Resource& resource ) = 0; virtual HRESULT CreateTextFormat( @@ -207,12 +223,9 @@ namespace kiwano virtual HRESULT CreateTextLayout( _Out_ ComPtr& text_layout, _In_ String const& text, - _In_ TextStyle const& text_style, _In_ ComPtr const& text_format ) const = 0; - virtual ID2D1StrokeStyle* GetStrokeStyle(StrokeStyle stroke) const = 0; - virtual HRESULT SetD2DDevice( _In_ ComPtr const& device ) = 0; @@ -230,6 +243,10 @@ namespace kiwano 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 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: ComPtr factory_; ComPtr device_; @@ -238,6 +255,10 @@ namespace kiwano ComPtr imaging_factory_; ComPtr dwrite_factory_; + + ComPtr d2d_miter_stroke_style_; + ComPtr d2d_bevel_stroke_style_; + ComPtr d2d_round_stroke_style_; }; } diff --git a/src/kiwano/renderer/win32/D3D10DeviceResources.cpp b/src/kiwano/renderer/win32/D3D10DeviceResources.cpp index 9278893c..59e4dfbe 100644 --- a/src/kiwano/renderer/win32/D3D10DeviceResources.cpp +++ b/src/kiwano/renderer/win32/D3D10DeviceResources.cpp @@ -217,7 +217,7 @@ namespace kiwano // than the API default. It is required for compatibility with Direct2D. UInt32 creation_flags = D3D10_CREATE_DEVICE_BGRA_SUPPORT; -#if defined(KGE_DEBUG) +#if defined(KGE_DEBUG) && defined(KGE_ENABLE_DX_DEBUG) if (DX::SdkLayersAvailable()) { creation_flags |= D3D10_CREATE_DEVICE_DEBUG; diff --git a/src/kiwano/renderer/win32/D3D11DeviceResources.cpp b/src/kiwano/renderer/win32/D3D11DeviceResources.cpp index 801ce3bb..11e64378 100644 --- a/src/kiwano/renderer/win32/D3D11DeviceResources.cpp +++ b/src/kiwano/renderer/win32/D3D11DeviceResources.cpp @@ -209,7 +209,7 @@ namespace kiwano // than the API default. It is required for compatibility with Direct2D. UInt32 creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; -#if defined(KGE_DEBUG) +#if defined(KGE_DEBUG) && defined(KGE_ENABLE_DX_DEBUG) if (DX::SdkLayersAvailable()) { creation_flags |= D3D11_CREATE_DEVICE_DEBUG; diff --git a/src/kiwano/ui/Button.cpp b/src/kiwano/ui/Button.cpp index 9108b090..b91b67c4 100644 --- a/src/kiwano/ui/Button.cpp +++ b/src/kiwano/ui/Button.cpp @@ -112,7 +112,7 @@ namespace kiwano if (evt.type == Event::MouseHover) { SetStatus(Status::Hover); - Window::GetInstance()->SetMouseCursor(MouseCursor::Hand); + Window::GetInstance()->SetCursor(CursorType::Hand); if (mouse_over_callback_) mouse_over_callback_(); @@ -120,7 +120,7 @@ namespace kiwano else if (evt.type == Event::MouseOut) { SetStatus(Status::Normal); - Window::GetInstance()->SetMouseCursor(MouseCursor::Arrow); + Window::GetInstance()->SetCursor(CursorType::Arrow); if (mouse_out_callback_) mouse_out_callback_(); diff --git a/src/kiwano/utils/ResourceCache.cpp b/src/kiwano/utils/ResourceCache.cpp index 43dd40ff..7a8b8a67 100644 --- a/src/kiwano/utils/ResourceCache.cpp +++ b/src/kiwano/utils/ResourceCache.cpp @@ -23,6 +23,7 @@ #include "../2d/Frame.h" #include "../2d/FrameSequence.h" #include "../renderer/GifImage.h" +#include "../renderer/FontCollection.h" #include namespace kiwano @@ -30,7 +31,7 @@ namespace kiwano namespace __resource_cache_01 { bool LoadJsonData(ResourceCache* loader, Json const& json_data); - bool LoadXmlData(ResourceCache* loader, tinyxml2::XMLElement* elem); + bool LoadXmlData(ResourceCache* loader, const tinyxml2::XMLElement* elem); } namespace @@ -40,7 +41,7 @@ namespace kiwano { L"0.1", __resource_cache_01::LoadJsonData }, }; - Map> load_xml_funcs = { + Map> load_xml_funcs = { { L"latest", __resource_cache_01::LoadXmlData }, { L"0.1", __resource_cache_01::LoadXmlData }, }; @@ -138,7 +139,7 @@ namespace kiwano return LoadFromXml(&doc); } - bool ResourceCache::LoadFromXml(tinyxml2::XMLDocument* doc) + bool ResourceCache::LoadFromXml(const tinyxml2::XMLDocument* doc) { if (doc) { @@ -201,8 +202,8 @@ namespace kiwano if (files.empty()) return 0; - Vector image_arr; - image_arr.reserve(files.size()); + Vector frames; + frames.reserve(files.size()); for (const auto& file : files) { @@ -211,20 +212,20 @@ namespace kiwano { 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); - return AddFrameSequence(id, frames); + FrameSequencePtr fs = new (std::nothrow) FrameSequence(frames); + return AddFrameSequence(id, fs); } 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) return 0; @@ -235,27 +236,31 @@ namespace kiwano Float32 raw_width = raw->GetWidth(); Float32 raw_height = raw->GetHeight(); - Float32 width = raw_width / cols; - Float32 height = raw_height / rows; + Float32 width = (raw_width - (cols - 1) * padding_x) / cols; + Float32 height = (raw_height - (rows - 1) * padding_y) / rows; - Vector image_arr; - image_arr.reserve(rows * cols); + Vector frames; + frames.reserve(rows * cols); + Float32 dty = 0; for (Int32 i = 0; i < rows; i++) { + Float32 dtx = 0; 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) { - ptr->SetCropRect(Rect{ j * width, i * height, (j + 1) * width, (i + 1) * height }); - image_arr.push_back(ptr); + ptr->SetCropRect(Rect{ dtx, dty, dtx + width, dty + height }); + frames.push_back(ptr); } + dtx += (width + padding_x); } + dty += (height + padding_y); } - FrameSequencePtr frames = new (std::nothrow) FrameSequence(image_arr); - return AddFrameSequence(id, frames); + FrameSequencePtr fs = new (std::nothrow) FrameSequence(frames); + return AddFrameSequence(id, fs); } UInt32 ResourceCache::AddFrameSequence(String const & id, FrameSequencePtr frames) @@ -278,6 +283,36 @@ namespace kiwano 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 { return Get(id); @@ -288,6 +323,22 @@ namespace kiwano return Get(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) { cache_.erase(id); @@ -309,28 +360,28 @@ namespace kiwano String path; }; - bool LoadImagesFromData(ResourceCache* loader, GlobalData* gdata, const String* id, const String* type, - const String* file, const Vector* files, Int32 rows, Int32 cols) + bool LoadTexturesFromData(ResourceCache* loader, GlobalData* gdata, const String* id, const String* type, const String* file) { if (!gdata || !id) return false; - if (file) + if (type && (*type) == L"gif") { - if (!(*file).empty()) - { - 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)); - } - } + // GIF image + return loader->AddGifImage(*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* files) + { + if (!gdata || !id) return false; + // Frames if (files) { @@ -350,6 +401,52 @@ namespace kiwano 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* files) + { + if (!gdata || !id) return false; + + // Font Collection + if (files) + { + Vector 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) { GlobalData global_data; @@ -371,6 +468,16 @@ namespace kiwano if (image.count(L"rows")) rows = image[L"rows"].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(); + if (image.count(L"padding-y")) padding_y = image[L"padding-y"].get(); + + if (!LoadTexturesFromData(loader, &global_data, id, file, rows, cols, padding_x, padding_y)) + return false; + } + if (image.count(L"files")) { Vector files; @@ -379,12 +486,33 @@ namespace kiwano { 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; } 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 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; } } @@ -392,7 +520,7 @@ namespace kiwano return true; } - bool LoadXmlData(ResourceCache* loader, tinyxml2::XMLElement* elem) + bool LoadXmlData(ResourceCache* loader, const tinyxml2::XMLElement* elem) { GlobalData global_data; 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"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()) { Vector files_arr; @@ -423,16 +561,36 @@ namespace kiwano 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; } else { - if (!LoadImagesFromData(loader, &global_data, &id, &type, &file, nullptr, rows, cols)) + if (!LoadTexturesFromData(loader, &global_data, &id, &type, &file)) 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 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; } } diff --git a/src/kiwano/utils/ResourceCache.h b/src/kiwano/utils/ResourceCache.h index 8a87c072..1a6252c7 100644 --- a/src/kiwano/utils/ResourceCache.h +++ b/src/kiwano/utils/ResourceCache.h @@ -44,7 +44,7 @@ namespace kiwano bool LoadFromXmlFile(String const& file_path); // 从 XML 文档对象加载资源信息 - bool LoadFromXml(tinyxml2::XMLDocument* doc); + bool LoadFromXml(const tinyxml2::XMLDocument* doc); // 添加帧图像 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); @@ -65,12 +65,27 @@ namespace kiwano // 添加对象 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; // 获取序列帧 FrameSequencePtr GetFrameSequence(String const& id) const; + // 获取 GIF 图像 + GifImage GetGifImage(String const& id) const; + + // 获取字体集 + FontCollection GetFontCollection(String const& id) const; + // 删除指定资源 void Delete(String const& id); @@ -93,5 +108,8 @@ namespace kiwano protected: UnorderedMap cache_; + + UnorderedMap gif_cache_; + UnorderedMap font_collection_cache_; }; }