diff --git a/projects/kiwano.vcxproj b/projects/kiwano.vcxproj index 070d909b..39a9021c 100644 --- a/projects/kiwano.vcxproj +++ b/projects/kiwano.vcxproj @@ -67,6 +67,7 @@ + @@ -127,6 +128,7 @@ + diff --git a/projects/kiwano.vcxproj.filters b/projects/kiwano.vcxproj.filters index e3db99d4..8995881e 100644 --- a/projects/kiwano.vcxproj.filters +++ b/projects/kiwano.vcxproj.filters @@ -303,6 +303,9 @@ renderer + + renderer + @@ -473,5 +476,8 @@ renderer + + renderer + \ No newline at end of file diff --git a/src/kiwano-audio/src/Player.cpp b/src/kiwano-audio/src/Player.cpp index f460a2c5..a7a862bf 100644 --- a/src/kiwano-audio/src/Player.cpp +++ b/src/kiwano-audio/src/Player.cpp @@ -34,13 +34,33 @@ namespace kiwano ClearCache(); } - bool Player::Load(Resource const& res) + size_t Player::Load(String const& file_path) { - size_t hash_code = res.GetHashCode(); + size_t hash_code = file_path.hash(); if (sound_cache_.end() != sound_cache_.find(hash_code)) return true; - SoundPtr sound = new (std::nothrow) Sound(); + SoundPtr sound = new (std::nothrow) Sound; + + if (sound) + { + if (sound->Load(file_path)) + { + sound->SetVolume(volume_); + sound_cache_.insert(std::make_pair(hash_code, sound)); + return true; + } + } + return false; + } + + size_t Player::Load(Resource const& res) + { + size_t hash_code = res.GetId(); + if (sound_cache_.end() != sound_cache_.find(hash_code)) + return true; + + SoundPtr sound = new (std::nothrow) Sound; if (sound) { @@ -54,42 +74,39 @@ namespace kiwano return false; } - void Player::Play(Resource const& res, int loop_count) + void Player::Play(size_t id, int loop_count) { - if (Load(res)) - { - size_t hash_code = res.GetHashCode(); - if (sound_cache_.end() != sound_cache_.find(hash_code)) - sound_cache_[hash_code]->Play(loop_count); - } + auto iter = sound_cache_.find(id); + if (sound_cache_.end() != iter) + iter->second->Play(loop_count); } - void Player::Pause(Resource const& res) + void Player::Pause(size_t id) { - size_t hash_code = res.GetHashCode(); - if (sound_cache_.end() != sound_cache_.find(hash_code)) - sound_cache_[hash_code]->Pause(); + auto iter = sound_cache_.find(id); + if (sound_cache_.end() != iter) + iter->second->Pause(); } - void Player::Resume(Resource const& res) + void Player::Resume(size_t id) { - size_t hash_code = res.GetHashCode(); - if (sound_cache_.end() != sound_cache_.find(hash_code)) - sound_cache_[hash_code]->Resume(); + auto iter = sound_cache_.find(id); + if (sound_cache_.end() != iter) + iter->second->Resume(); } - void Player::Stop(Resource const& res) + void Player::Stop(size_t id) { - size_t hash_code = res.GetHashCode(); - if (sound_cache_.end() != sound_cache_.find(hash_code)) - sound_cache_[hash_code]->Stop(); + auto iter = sound_cache_.find(id); + if (sound_cache_.end() != iter) + iter->second->Stop(); } - bool Player::IsPlaying(Resource const& res) + bool Player::IsPlaying(size_t id) { - size_t hash_code = res.GetHashCode(); - if (sound_cache_.end() != sound_cache_.find(hash_code)) - return sound_cache_[hash_code]->IsPlaying(); + auto iter = sound_cache_.find(id); + if (sound_cache_.end() != iter) + return iter->second->IsPlaying(); return false; } diff --git a/src/kiwano-audio/src/Player.h b/src/kiwano-audio/src/Player.h index cb9da0a0..8ad90766 100644 --- a/src/kiwano-audio/src/Player.h +++ b/src/kiwano-audio/src/Player.h @@ -33,42 +33,45 @@ namespace kiwano class KGE_API Player : protected ObjectBase { - using MusicMap = Map; - public: Player(); ~Player(); - // 加载音乐资源 - bool Load( + // 加载本地音频文件, 返回该资源标识符 + size_t Load( + String const& file_path + ); + + // 加载音乐资源, 返回该资源标识符 + size_t Load( Resource const& res /* 音乐资源 */ ); // 播放音乐 void Play( - Resource const& res, /* 音乐资源 */ + size_t id, /* 标识符 */ int loop_count = 0 /* 播放循环次数 (-1 为循环播放) */ ); // 暂停音乐 void Pause( - Resource const& res /* 音乐资源 */ + size_t id /* 标识符 */ ); // 继续播放音乐 void Resume( - Resource const& res /* 音乐资源 */ + size_t id /* 标识符 */ ); // 停止音乐 void Stop( - Resource const& res /* 音乐资源 */ + size_t id /* 标识符 */ ); // 获取音乐播放状态 bool IsPlaying( - Resource const& res /* 音乐资源 */ + size_t id /* 标识符 */ ); // 获取音量 @@ -92,8 +95,10 @@ namespace kiwano void ClearCache(); protected: - float volume_; - MusicMap sound_cache_; + float volume_; + + using MusicMap = Map; + MusicMap sound_cache_; }; } } diff --git a/src/kiwano-audio/src/Sound.cpp b/src/kiwano-audio/src/Sound.cpp index ddf88d6f..cf2c9c2e 100644 --- a/src/kiwano-audio/src/Sound.cpp +++ b/src/kiwano-audio/src/Sound.cpp @@ -49,6 +49,46 @@ namespace kiwano Close(); } + bool Sound::Load(String const& file_path) + { + if (opened_) + { + Close(); + } + +#if defined(KGE_DEBUG) + if (!FileUtil::ExistsFile(file_path)) + { + KGE_WARNING_LOG(L"Media file '%s' not found", file_path.c_str()); + return false; + } +#endif + + Transcoder transcoder; + HRESULT hr = transcoder.LoadMediaFile(file_path, &wave_data_, &size_); + + if (FAILED(hr)) + { + KGE_ERROR_LOG(L"Load media file failed with HRESULT of %08X", hr); + return false; + } + + hr = Audio::GetInstance()->CreateVoice(&voice_, transcoder.GetWaveFormatEx()); + if (FAILED(hr)) + { + if (wave_data_) + { + delete[] wave_data_; + wave_data_ = nullptr; + } + KGE_ERROR_LOG(L"Create source voice failed with HRESULT of %08X", hr); + return false; + } + + opened_ = true; + return true; + } + bool Sound::Load(Resource const& res) { if (opened_) @@ -56,28 +96,12 @@ namespace kiwano Close(); } - HRESULT hr = S_OK; Transcoder transcoder; - - if (res.IsFileType()) - { -#if defined(KGE_DEBUG) - if (!FileUtil::ExistsFile(res.GetFileName())) - { - KGE_WARNING_LOG(L"Media file '%s' not found", res.GetFileName().c_str()); - return false; - } -#endif - hr = transcoder.LoadMediaFile(res.GetFileName(), &wave_data_, &size_); - } - else - { - hr = transcoder.LoadMediaResource(res, &wave_data_, &size_); - } + HRESULT hr = transcoder.LoadMediaResource(res, &wave_data_, &size_); if (FAILED(hr)) { - KGE_ERROR_LOG(L"Load media file failed with HRESULT of %08X", hr); + KGE_ERROR_LOG(L"Load media resource failed with HRESULT of %08X", hr); return false; } diff --git a/src/kiwano-audio/src/Sound.h b/src/kiwano-audio/src/Sound.h index 9cf9e71f..d39f457f 100644 --- a/src/kiwano-audio/src/Sound.h +++ b/src/kiwano-audio/src/Sound.h @@ -37,12 +37,21 @@ namespace kiwano public: Sound(); + Sound( + String const& file_path /* 本地音频文件 */ + ); + Sound( Resource const& res /* 音乐资源 */ ); virtual ~Sound(); + // 打开本地音频文件 + bool Load( + String const& file_path + ); + // 打开音乐资源 bool Load( Resource const& res /* 音乐资源 */ diff --git a/src/kiwano-audio/src/Transcoder.cpp b/src/kiwano-audio/src/Transcoder.cpp index 7189690c..0e38305e 100644 --- a/src/kiwano-audio/src/Transcoder.cpp +++ b/src/kiwano-audio/src/Transcoder.cpp @@ -83,13 +83,12 @@ namespace kiwano ComPtr byte_stream; ComPtr reader; - LPVOID buffer; - DWORD buffer_size; - if (!res.Load(buffer, buffer_size)) { return E_FAIL; } + Resource::Data data = res.GetData(); + if (!data) { return E_FAIL; } stream = kiwano::modules::Shlwapi::Get().SHCreateMemStream( - static_cast(buffer), - static_cast(buffer_size) + static_cast(data.buffer), + static_cast(data.size) ); if (stream == nullptr) diff --git a/src/kiwano/2d/Frame.cpp b/src/kiwano/2d/Frame.cpp index 9fbd506e..ff99edde 100644 --- a/src/kiwano/2d/Frame.cpp +++ b/src/kiwano/2d/Frame.cpp @@ -27,19 +27,35 @@ namespace kiwano { } + Frame::Frame(String const& file_path) + { + Load(file_path); + } + Frame::Frame(Resource const& res) { Load(res); } Frame::Frame(Image const& image) - : image_(image) { + SetImage(image); + } + + bool Frame::Load(String const& file_path) + { + Image image = ImageCache::GetInstance()->AddOrGetImage(file_path); + if (image.IsValid()) + { + SetImage(image); + return true; + } + return false; } bool Frame::Load(Resource const& res) { - Image image = ImageCache::GetInstance()->AddImage(res); + Image image = ImageCache::GetInstance()->AddOrGetImage(res); if (image.IsValid()) { SetImage(image); diff --git a/src/kiwano/2d/Frame.h b/src/kiwano/2d/Frame.h index 3ee92fb3..9f13d4f0 100644 --- a/src/kiwano/2d/Frame.h +++ b/src/kiwano/2d/Frame.h @@ -30,6 +30,10 @@ namespace kiwano public: Frame(); + explicit Frame( + String const& file_path + ); + explicit Frame( Resource const& res ); @@ -38,6 +42,10 @@ namespace kiwano Image const& image ); + bool Load( + String const& file_path + ); + bool Load( Resource const& res ); @@ -47,6 +55,11 @@ namespace kiwano Rect const& crop_rect /* 裁剪矩形 */ ); + // 设置位图 + void SetImage( + Image const& image + ); + // 获取宽度 float GetWidth() const { return crop_rect_.size.x; } @@ -65,9 +78,6 @@ namespace kiwano // 获取位图 inline Image const& GetImage() const { return image_; } - // 设置位图 - void SetImage(Image const& image); - protected: Image image_; Rect crop_rect_; diff --git a/src/kiwano/2d/GifSprite.cpp b/src/kiwano/2d/GifSprite.cpp index e331fcf8..08c9c471 100644 --- a/src/kiwano/2d/GifSprite.cpp +++ b/src/kiwano/2d/GifSprite.cpp @@ -34,26 +34,37 @@ namespace kiwano { } + GifSprite::GifSprite(String const& file_path) + { + Load(file_path); + } + GifSprite::GifSprite(Resource const& res) : GifSprite() { Load(res); } - GifSprite::GifSprite(GifImagePtr image) + GifSprite::GifSprite(GifImage image) { Load(image); } - bool GifSprite::Load(Resource const& res) + bool GifSprite::Load(String const& file_path) { - GifImagePtr image = ImageCache::GetInstance()->AddGifImage(res); + GifImage image = ImageCache::GetInstance()->AddOrGetGifImage(file_path); return Load(image); } - bool GifSprite::Load(GifImagePtr image) + bool GifSprite::Load(Resource const& res) { - if (image && image_ != image) + GifImage image = ImageCache::GetInstance()->AddOrGetGifImage(res); + return Load(image); + } + + bool GifSprite::Load(GifImage image) + { + if (image.IsValid()) { image_ = image; @@ -62,8 +73,8 @@ namespace kiwano disposal_type_ = DisposalType::None; SetSize( - static_cast(image_->GetWidthInPixels()), - static_cast(image_->GetHeightInPixels()) + static_cast(image_.GetWidthInPixels()), + static_cast(image_.GetHeightInPixels()) ); if (!frame_rt_.IsValid()) @@ -71,7 +82,7 @@ namespace kiwano Renderer::GetInstance()->CreateImageRenderTarget(frame_rt_); } - if (image_->GetFramesCount() > 0) + if (image_.GetFramesCount() > 0) { ComposeNextFrame(); } @@ -94,7 +105,7 @@ namespace kiwano { Actor::Update(dt); - if (image_ && animating_) + if (image_.IsValid() && animating_) { frame_elapsed_ += dt; if (frame_delay_ <= frame_elapsed_) @@ -124,7 +135,7 @@ namespace kiwano OverlayNextFrame(); } while (frame_delay_.IsZero() && !IsLastFrame()); - animating_ = (!EndOfAnimation() && image_->GetFramesCount() > 1); + animating_ = (!EndOfAnimation() && image_.GetFramesCount() > 1); } } @@ -157,7 +168,7 @@ namespace kiwano { Image raw_image; - HRESULT hr = image_->GetRawFrame(next_index_, raw_image, frame_rect_, frame_delay_, disposal_type_); + HRESULT hr = image_.GetRawFrame(next_index_, raw_image, frame_rect_, frame_delay_, disposal_type_); if (SUCCEEDED(hr)) { @@ -174,7 +185,7 @@ namespace kiwano if (next_index_ == 0) { // 重新绘制背景 - frame_rt_.Clear(image_->GetBackgroundColor()); + frame_rt_.Clear(image_.GetBackgroundColor()); loop_count_++; } @@ -192,7 +203,7 @@ namespace kiwano if (SUCCEEDED(hr)) { frame_ = frame_to_render; - next_index_ = (++next_index_) % image_->GetFramesCount(); + next_index_ = (++next_index_) % image_.GetFramesCount(); } } @@ -266,7 +277,7 @@ namespace kiwano frame_rt_.BeginDraw(); frame_rt_.PushClipRect(frame_rect_); - frame_rt_.Clear(image_->GetBackgroundColor()); + frame_rt_.Clear(image_.GetBackgroundColor()); frame_rt_.PopClipRect(); return frame_rt_.EndDraw(); diff --git a/src/kiwano/2d/GifSprite.h b/src/kiwano/2d/GifSprite.h index 4e1f2a41..6fec6a03 100644 --- a/src/kiwano/2d/GifSprite.h +++ b/src/kiwano/2d/GifSprite.h @@ -37,12 +37,20 @@ namespace kiwano GifSprite(); + GifSprite( + String const& file_path + ); + GifSprite( Resource const& res ); GifSprite( - GifImagePtr image + GifImage image + ); + + bool Load( + String const& file_path ); bool Load( @@ -50,7 +58,7 @@ namespace kiwano ); bool Load( - GifImagePtr image + GifImage image ); // 设置 GIF 动画循环次数 @@ -100,7 +108,7 @@ namespace kiwano DisposalType disposal_type_; LoopDoneCallback loop_cb_; DoneCallback done_cb_; - GifImagePtr image_; + GifImage image_; Image frame_; Rect frame_rect_; Image saved_frame_; diff --git a/src/kiwano/2d/Sprite.cpp b/src/kiwano/2d/Sprite.cpp index 64331909..688faf90 100644 --- a/src/kiwano/2d/Sprite.cpp +++ b/src/kiwano/2d/Sprite.cpp @@ -24,18 +24,26 @@ namespace kiwano { Sprite::Sprite() - : frame_(nullptr) { } + Sprite::Sprite(String const& file_path) + { + Load(file_path); + } + + Sprite::Sprite(String const& file_path, Rect const& crop_rect) + { + Load(file_path); + SetCropRect(crop_rect); + } + Sprite::Sprite(Resource const& res) - : frame_(nullptr) { Load(res); } Sprite::Sprite(Resource const& res, const Rect& crop_rect) - : frame_(nullptr) { Load(res); SetCropRect(crop_rect); @@ -51,6 +59,17 @@ namespace kiwano { } + bool Sprite::Load(String const& file_path) + { + FramePtr frame = new (std::nothrow) Frame; + if (frame->Load(file_path)) + { + SetFrame(frame); + return true; + } + return false; + } + bool Sprite::Load(Resource const& res) { FramePtr frame = new (std::nothrow) Frame; diff --git a/src/kiwano/2d/Sprite.h b/src/kiwano/2d/Sprite.h index 8cd03aad..8138f5e2 100644 --- a/src/kiwano/2d/Sprite.h +++ b/src/kiwano/2d/Sprite.h @@ -32,10 +32,19 @@ namespace kiwano Sprite(); explicit Sprite( - Resource const& res + String const& file_path + ); + + Sprite( + String const& file_path, + Rect const& crop_rect /* 裁剪矩形 */ ); explicit Sprite( + Resource const& res + ); + + Sprite( Resource const& res, Rect const& crop_rect /* 裁剪矩形 */ ); @@ -46,6 +55,11 @@ namespace kiwano virtual ~Sprite(); + // 加载图像 + bool Load( + String const& file_path + ); + // 加载图像资源 bool Load( Resource const& res diff --git a/src/kiwano/base/Resource.cpp b/src/kiwano/base/Resource.cpp index b20d87f3..1ea7ee67 100644 --- a/src/kiwano/base/Resource.cpp +++ b/src/kiwano/base/Resource.cpp @@ -21,114 +21,63 @@ #include "Resource.h" #include "../base/Logger.h" +#include namespace kiwano { - Resource::Resource(LPCWSTR file_name) - : type_(Type::File) - , bin_id_(0) - , bin_type_(nullptr) + Resource::Resource() + : id_(0) + , type_(nullptr) { - if (file_name) - file_name_ = new (std::nothrow) String(file_name); - } - Resource::Resource(String const& file_name) - : type_(Type::File) - , bin_id_(0) - , bin_type_(nullptr) - { - if (!file_name.empty()) - file_name_ = new (std::nothrow) String(file_name); } Resource::Resource(UINT id, LPCWSTR type) - : type_(Type::Binary) - , bin_id_(id) - , bin_type_(type) + : id_(id) + , type_(type) { } - Resource::Resource(Resource const & rhs) + Resource::Data Resource::GetData() const { - operator=(rhs); - } - - Resource::~Resource() - { - if (IsFileType() && file_name_) - delete file_name_; - } - - size_t Resource::GetHashCode() const - { - return (type_ == Type::File) ? GetFileName().hash() : static_cast(bin_id_); - } - - Resource & Resource::operator=(Resource const & rhs) - { - if (&rhs != this) + do { - if (IsFileType() && file_name_) + if (data_.buffer && data_.size) { - delete file_name_; - file_name_ = nullptr; + break; } - type_ = rhs.type_; - if (IsFileType()) + HRSRC res_info = FindResourceW(nullptr, MAKEINTRESOURCE(id_), type_); + if (res_info == nullptr) { - if (rhs.file_name_) - { - file_name_ = new (std::nothrow) String(*rhs.file_name_); - } + KGE_ERROR_LOG(L"FindResource failed"); + break; } - else + + HGLOBAL res_data = LoadResource(nullptr, res_info); + if (res_data == nullptr) { - bin_id_ = rhs.bin_id_; - bin_type_ = rhs.bin_type_; + KGE_ERROR_LOG(L"LoadResource failed"); + break; } - } - return *this; - } - bool Resource::Load(LPVOID& buffer, DWORD& buffer_size) const - { - if (type_ != Type::Binary) - { - KGE_ERROR_LOG(L"Only binary resource can be loaded"); - return false; - } + DWORD size = SizeofResource(nullptr, res_info); + if (size == 0) + { + KGE_ERROR_LOG(L"SizeofResource failed"); + break; + } - HGLOBAL res_data; - HRSRC res_info; + LPVOID buffer = LockResource(res_data); + if (buffer == nullptr) + { + KGE_ERROR_LOG(L"LockResource failed"); + break; + } - res_info = FindResourceW(nullptr, MAKEINTRESOURCE(bin_id_), bin_type_); - if (res_info == nullptr) - { - KGE_ERROR_LOG(L"FindResource failed"); - return false; - } + data_.buffer = static_cast(buffer); + data_.size = static_cast(size); + } while (0); - res_data = LoadResource(nullptr, res_info); - if (res_data == nullptr) - { - KGE_ERROR_LOG(L"LoadResource failed"); - return false; - } - - buffer_size = SizeofResource(nullptr, res_info); - if (buffer_size == 0) - { - KGE_ERROR_LOG(L"SizeofResource failed"); - return false; - } - - buffer = LockResource(res_data); - if (buffer == nullptr) - { - KGE_ERROR_LOG(L"LockResource failed"); - return false; - } - return true; + return data_; } } diff --git a/src/kiwano/base/Resource.h b/src/kiwano/base/Resource.h index 80a1129a..32f990d3 100644 --- a/src/kiwano/base/Resource.h +++ b/src/kiwano/base/Resource.h @@ -26,64 +26,43 @@ namespace kiwano { // 资源 // - // 资源可以是文件类型,也可以是保存在 exe 中的二进制资源 + // 资源是保存在 exe 中的二进制数据 // 例如, 一份音频资源的类型为 L"WAVE", 名称标识符为 IDR_WAVE_1, - // 那么可以这样指定该资源: Resource res(IDR_WAVE_1, L"WAVE"); + // 那么可以这样指定该资源: Resource(IDR_WAVE_1, L"WAVE"); // // 了解资源的更多信息: https://docs.microsoft.com/en-us/windows/desktop/menurc/resources // class KGE_API Resource { - enum class Type { File, Binary }; - public: - Resource( - LPCWSTR file_name /* 文件路径 */ - ); + // 二进制数据 + struct Data + { + void* buffer; + UINT32 size; + + inline Data() : buffer(nullptr), size(0) {} + + inline operator bool() const { return buffer && size; } + }; + + Resource(); Resource( - String const& file_name /* 文件路径 */ + UINT id, /* 资源名称 */ + LPCWSTR type /* 资源类型 */ ); - Resource( - UINT id, /* 资源名称 */ - LPCWSTR type /* 资源类型 */ - ); + // 获取二进制数据 + Resource::Data GetData() const; - Resource( - Resource const& rhs - ); + inline UINT GetId() const { return id_; } - virtual ~Resource(); - - bool Load(LPVOID& buffer, DWORD& buffer_size) const; - - size_t GetHashCode() const; - - Resource& operator= (Resource const& rhs); - - inline bool IsFileType() const { return type_ == Type::File; } - - inline String GetFileName() const { return file_name_ ? (*file_name_) : L""; } - - inline UINT GetResourceId() const { return bin_id_; } - - inline LPCWSTR GetResourceType() const { return bin_type_; } + inline LPCWSTR GetType() const { return type_; } private: - Type type_; - union - { - struct - { - String* file_name_; - }; - - struct - { - UINT bin_id_; - LPCWSTR bin_type_; - }; - }; + UINT id_; + LPCWSTR type_; + mutable Resource::Data data_; }; } diff --git a/src/kiwano/renderer/Font.cpp b/src/kiwano/renderer/Font.cpp index 8ab74f91..1c0016c3 100644 --- a/src/kiwano/renderer/Font.cpp +++ b/src/kiwano/renderer/Font.cpp @@ -19,34 +19,9 @@ // THE SOFTWARE. #include "Font.h" -#include "Renderer.h" namespace kiwano { - // - // FontCollection - // - - FontCollection::FontCollection() - { - } - - FontCollection::FontCollection(Resource const& res) - { - Load(res); - } - - bool FontCollection::Load(Resource const& res) - { - Renderer::GetInstance()->CreateFontFromResource(*this, res); - return false; - } - - - // - // Font - // - Font::Font(const String& family, float size, unsigned int weight, bool italic, FontCollection collection) : family(family) , size(size) diff --git a/src/kiwano/renderer/Font.h b/src/kiwano/renderer/Font.h index 43aa6441..f389df68 100644 --- a/src/kiwano/renderer/Font.h +++ b/src/kiwano/renderer/Font.h @@ -19,10 +19,7 @@ // THE SOFTWARE. #pragma once -#include "../core/core.h" -#include "../base/Resource.h" -#include "win32/ComPtr.hpp" -#include +#include "FontCollection.h" namespace kiwano { @@ -40,28 +37,6 @@ namespace kiwano ExtraBlack = 950 }; - - // 字体集 - class FontCollection - { - public: - FontCollection(); - - FontCollection(Resource const& res); - - // 从资源加载字体集 - bool Load(Resource const& res); - - public: - inline ComPtr GetFontCollection() const { return collection_; } - - inline void SetFontCollection(ComPtr collection) { collection_ = collection; } - - protected: - ComPtr collection_; - }; - - // 字体 class Font { diff --git a/src/kiwano/renderer/FontCollection.cpp b/src/kiwano/renderer/FontCollection.cpp new file mode 100644 index 00000000..87661691 --- /dev/null +++ b/src/kiwano/renderer/FontCollection.cpp @@ -0,0 +1,73 @@ +// Copyright (c) 2016-2018 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "FontCollection.h" +#include "Renderer.h" + +namespace kiwano +{ + FontCollection::FontCollection() + { + } + + FontCollection::FontCollection(String const& file) + { + Load(file); + } + + FontCollection::FontCollection(Vector const& files) + { + Load(files); + } + + FontCollection::FontCollection(Resource const& res) + { + Load(res); + } + + FontCollection::FontCollection(Vector const& res_arr) + { + Load(res_arr); + } + + bool FontCollection::Load(String const& file) + { + Renderer::GetInstance()->CreateFontCollection(*this, { file }); + return false; + } + + bool FontCollection::Load(Vector const& files) + { + Renderer::GetInstance()->CreateFontCollection(*this, files); + return false; + } + + bool FontCollection::Load(Resource const& res) + { + Renderer::GetInstance()->CreateFontCollection(*this, { res }); + return false; + } + + bool FontCollection::Load(Vector const& res_arr) + { + Renderer::GetInstance()->CreateFontCollection(*this, res_arr); + return false; + } +} diff --git a/src/kiwano/renderer/FontCollection.h b/src/kiwano/renderer/FontCollection.h new file mode 100644 index 00000000..e4297181 --- /dev/null +++ b/src/kiwano/renderer/FontCollection.h @@ -0,0 +1,62 @@ +// Copyright (c) 2016-2018 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once +#include "../base/Resource.h" +#include "win32/ComPtr.hpp" +#include + +namespace kiwano +{ + // 字体集 + class FontCollection + { + public: + FontCollection(); + + FontCollection(String const& file); + + FontCollection(Vector const& files); + + FontCollection(Resource const& res); + + FontCollection(Vector const& res_arr); + + // 从本地文件加载字体 + bool Load(String const& file); + + // 从多个本地文件加载字体 + bool Load(Vector const& files); + + // 从资源加载字体 + bool Load(Resource const& res); + + // 从多个资源加载字体 + bool Load(Vector const& res_arr); + + public: + inline ComPtr GetFontCollection() const { return collection_; } + + inline void SetFontCollection(ComPtr collection) { collection_ = collection; } + + protected: + ComPtr collection_; + }; +} diff --git a/src/kiwano/renderer/GifImage.cpp b/src/kiwano/renderer/GifImage.cpp index 49c54acd..a057a663 100644 --- a/src/kiwano/renderer/GifImage.cpp +++ b/src/kiwano/renderer/GifImage.cpp @@ -32,12 +32,33 @@ namespace kiwano { } + GifImage::GifImage(String const& file_path) + { + Load(file_path); + } + GifImage::GifImage(Resource const& res) : GifImage() { Load(res); } + bool GifImage::Load(String const& file_path) + { + Renderer::GetInstance()->CreateGifImage(*this, file_path); + + if (IsValid()) + { + if (FAILED(GetGlobalMetadata())) + { + SetDecoder(nullptr); + return false; + } + return true; + } + return false; + } + bool GifImage::Load(Resource const& res) { Renderer::GetInstance()->CreateGifImage(*this, res); diff --git a/src/kiwano/renderer/GifImage.h b/src/kiwano/renderer/GifImage.h index bcd6efff..30538924 100644 --- a/src/kiwano/renderer/GifImage.h +++ b/src/kiwano/renderer/GifImage.h @@ -24,15 +24,17 @@ namespace kiwano { // GIF 图像 - KGE_DECLARE_SMART_PTR(GifImage); class KGE_API GifImage - : public ObjectBase { public: GifImage(); + GifImage(String const& file_path); + GifImage(Resource const& res); + bool Load(String const& file_path); + bool Load(Resource const& res); bool IsValid() const; diff --git a/src/kiwano/renderer/Image.cpp b/src/kiwano/renderer/Image.cpp index 5fbd80ae..ef001ad6 100644 --- a/src/kiwano/renderer/Image.cpp +++ b/src/kiwano/renderer/Image.cpp @@ -28,13 +28,17 @@ namespace kiwano { } + Image::Image(String const& file_path) + { + Load(file_path); + } + Image::Image(Resource const& res) { Load(res); } Image::Image(ComPtr const & bitmap) - : Image() { SetBitmap(bitmap); } @@ -43,6 +47,12 @@ namespace kiwano { } + bool Image::Load(String const& file_path) + { + Renderer::GetInstance()->CreateImage(*this, file_path); + return IsValid(); + } + bool Image::Load(Resource const& res) { Renderer::GetInstance()->CreateImage(*this, res); diff --git a/src/kiwano/renderer/Image.h b/src/kiwano/renderer/Image.h index 2444aaae..ec3aa193 100644 --- a/src/kiwano/renderer/Image.h +++ b/src/kiwano/renderer/Image.h @@ -29,6 +29,10 @@ namespace kiwano public: Image(); + explicit Image( + String const& file_path + ); + explicit Image( Resource const& res ); @@ -39,6 +43,11 @@ namespace kiwano virtual ~Image(); + // 加载本地文件 + bool Load( + String const& file_path + ); + // 加载资源 bool Load( Resource const& res diff --git a/src/kiwano/renderer/ImageCache.cpp b/src/kiwano/renderer/ImageCache.cpp index e950d1bc..3437c6c4 100644 --- a/src/kiwano/renderer/ImageCache.cpp +++ b/src/kiwano/renderer/ImageCache.cpp @@ -24,6 +24,32 @@ namespace kiwano { + template + _Ty CreateOrGetCache(_CacheTy& cache, _PathTy const& path, size_t hash) + { + auto iter = cache.find(hash); + if (iter != cache.end()) + { + return iter->second; + } + + _Ty image; + if (image.Load(path)) + { + cache.insert(std::make_pair(hash, image)); + } + return image; + } + + template + void RemoveCache(_CacheTy& cache, size_t hash) + { + auto iter = cache.find(hash); + if (iter != cache.end()) + { + cache.erase(iter); + } + } ImageCache::ImageCache() { @@ -33,62 +59,44 @@ namespace kiwano { } - Image ImageCache::AddImage(Resource const& res) + Image ImageCache::AddOrGetImage(String const& file_path) { - size_t hash_code = res.GetHashCode(); + return CreateOrGetCache(image_cache_, file_path, file_path.hash()); + } - auto iter = image_cache_.find(hash_code); - if (iter != image_cache_.end()) - { - return iter->second; - } + Image ImageCache::AddOrGetImage(Resource const& res) + { + return CreateOrGetCache(image_cache_, res, res.GetId()); + } - Image image; - if (image.Load(res)) - { - image_cache_.insert(std::make_pair(hash_code, image)); - } - return image; + GifImage ImageCache::AddOrGetGifImage(String const& file_path) + { + return CreateOrGetCache(gif_image_cache_, file_path, file_path.hash()); + } + + GifImage ImageCache::AddOrGetGifImage(Resource const& res) + { + return CreateOrGetCache(gif_image_cache_, res, res.GetId()); + } + + void ImageCache::RemoveImage(String const& file_path) + { + RemoveCache(image_cache_, file_path.hash()); } void ImageCache::RemoveImage(Resource const& res) { - size_t hash_code = res.GetHashCode(); - - auto iter = image_cache_.find(hash_code); - if (iter != image_cache_.end()) - { - image_cache_.erase(iter); - } + RemoveCache(image_cache_, res.GetId()); } - GifImagePtr ImageCache::AddGifImage(Resource const& res) + void ImageCache::RemoveGifImage(String const& file_path) { - size_t hash_code = res.GetHashCode(); - - auto iter = gif_image_cache_.find(hash_code); - if (iter != gif_image_cache_.end()) - { - return iter->second; - } - - GifImagePtr ptr = new GifImage; - if (ptr->Load(res)) - { - gif_image_cache_.insert(std::make_pair(hash_code, ptr)); - } - return ptr; + RemoveCache(gif_image_cache_, file_path.hash()); } void ImageCache::RemoveGifImage(Resource const& res) { - size_t hash_code = res.GetHashCode(); - - auto iter = gif_image_cache_.find(hash_code); - if (iter != gif_image_cache_.end()) - { - gif_image_cache_.erase(iter); - } + RemoveCache(gif_image_cache_, res.GetId()); } void ImageCache::Clear() diff --git a/src/kiwano/renderer/ImageCache.h b/src/kiwano/renderer/ImageCache.h index f6b62162..25076f12 100644 --- a/src/kiwano/renderer/ImageCache.h +++ b/src/kiwano/renderer/ImageCache.h @@ -30,12 +30,14 @@ namespace kiwano KGE_DECLARE_SINGLETON(ImageCache); public: - Image AddImage(Resource const& res); + Image AddOrGetImage(String const& file_path); + Image AddOrGetImage(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); - - GifImagePtr AddGifImage(Resource const& res); - + void RemoveGifImage(String const& file_path); void RemoveGifImage(Resource const& res); void Clear(); @@ -49,7 +51,7 @@ namespace kiwano using ImageMap = UnorderedMap; ImageMap image_cache_; - using GifImageMap = UnorderedMap; + using GifImageMap = UnorderedMap; GifImageMap gif_image_cache_; }; } diff --git a/src/kiwano/renderer/Renderer.cpp b/src/kiwano/renderer/Renderer.cpp index fcba68cc..74bb8f18 100644 --- a/src/kiwano/renderer/Renderer.cpp +++ b/src/kiwano/renderer/Renderer.cpp @@ -232,6 +232,31 @@ 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; @@ -240,19 +265,15 @@ namespace kiwano hr = E_UNEXPECTED; } - ComPtr bitmap; - if (res.IsFileType()) - { - hr = d2d_res_->CreateBitmapFromFile(bitmap, res.GetFileName()); - } - else - { - hr = d2d_res_->CreateBitmapFromResource(bitmap, res); - } - if (SUCCEEDED(hr)) { - image.SetBitmap(bitmap); + ComPtr bitmap; + hr = d2d_res_->CreateBitmapFromResource(bitmap, res); + + if (SUCCEEDED(hr)) + { + image.SetBitmap(bitmap); + } } if (FAILED(hr)) @@ -261,6 +282,43 @@ namespace kiwano } } + void Renderer::CreateGifImage(GifImage& image, String const& file_path) + { + HRESULT hr = S_OK; + if (!d2d_res_) + { + hr = E_UNEXPECTED; + } + + if (!FileUtil::ExistsFile(file_path)) + { + KGE_WARNING_LOG(L"Gif image 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 + ); + + if (SUCCEEDED(hr)) + { + image.SetDecoder(decoder); + } + } + + if (FAILED(hr)) + { + KGE_WARNING_LOG(L"Load GIF image failed with HRESULT of %08X!", hr); + } + } + void Renderer::CreateGifImage(GifImage& image, Resource const& res) { HRESULT hr = S_OK; @@ -269,61 +327,38 @@ namespace kiwano hr = E_UNEXPECTED; } - ComPtr decoder; - if (res.IsFileType()) - { - if (!FileUtil::ExistsFile(res.GetFileName().c_str())) - { - KGE_WARNING_LOG(L"Gif image file '%s' not found!", res.GetFileName().c_str()); - hr = E_FAIL; - } + Resource::Data res_data = res.GetData(); - if (SUCCEEDED(hr)) - { - hr = d2d_res_->GetWICImagingFactory()->CreateDecoderFromFilename( - res.GetFileName().c_str(), - nullptr, - GENERIC_READ, - WICDecodeMetadataCacheOnLoad, - &decoder - ); - } - } - else - { - LPVOID buffer; - DWORD buffer_size; - HRESULT hr = res.Load(buffer, buffer_size) ? S_OK : E_FAIL; + hr = res_data ? S_OK : E_FAIL; + if (SUCCEEDED(hr)) + { ComPtr stream; - - if (SUCCEEDED(hr)) - { - hr = d2d_res_->GetWICImagingFactory()->CreateStream(&stream); - } + hr = d2d_res_->GetWICImagingFactory()->CreateStream(&stream); if (SUCCEEDED(hr)) { hr = stream->InitializeFromMemory( - static_cast(buffer), - buffer_size + static_cast(res_data.buffer), + res_data.size ); } if (SUCCEEDED(hr)) { + ComPtr decoder; hr = d2d_res_->GetWICImagingFactory()->CreateDecoderFromStream( stream.get(), nullptr, WICDecodeMetadataCacheOnLoad, &decoder ); - } - } - if (SUCCEEDED(hr)) - { - image.SetDecoder(decoder); + if (SUCCEEDED(hr)) + { + image.SetDecoder(decoder); + } + } } if (FAILED(hr)) @@ -332,7 +367,7 @@ namespace kiwano } } - void Renderer::CreateFontFromResource(FontCollection& collection, Resource const& res) + void Renderer::CreateFontCollection(FontCollection& collection, Vector const& file_paths) { HRESULT hr = S_OK; if (!d2d_res_) @@ -340,37 +375,78 @@ namespace kiwano hr = E_UNEXPECTED; } - ComPtr font_collection; - if (res.IsFileType()) + if (SUCCEEDED(hr)) { - String file_path = res.GetFileName(); - if (!FileUtil::ExistsFile(file_path.c_str())) + for (const auto& file_path : file_paths) { - KGE_WARNING_LOG(L"Font file '%s' not found!", file_path.c_str()); - hr = E_FAIL; + if (!FileUtil::ExistsFile(file_path)) + { + KGE_WARNING_LOG(L"Font file '%s' not found!", file_path.c_str()); + hr = E_FAIL; + } } - - hr = d2d_res_->GetDWriteFactory()->CreateCustomFontCollection( - font_collection_loader_.get(), - reinterpret_cast(&file_path), - sizeof(file_path), - &font_collection - ); - } - else - { - UINT id = res.GetResourceId(); - hr = d2d_res_->GetDWriteFactory()->CreateCustomFontCollection( - res_font_collection_loader_.get(), - reinterpret_cast(&id), - sizeof(id), - &font_collection - ); } if (SUCCEEDED(hr)) { - collection.SetFontCollection(font_collection); + LPVOID collection_key = nullptr; + UINT32 collection_key_size = 0; + + hr = font_collection_loader_->AddFilePaths(file_paths, &collection_key, &collection_key_size); + + if (SUCCEEDED(hr)) + { + ComPtr font_collection; + hr = d2d_res_->GetDWriteFactory()->CreateCustomFontCollection( + font_collection_loader_.get(), + collection_key, + collection_key_size, + &font_collection + ); + + if (SUCCEEDED(hr)) + { + collection.SetFontCollection(font_collection); + } + } + } + + if (FAILED(hr)) + { + KGE_WARNING_LOG(L"Load font failed with HRESULT of %08X!", hr); + } + } + + void Renderer::CreateFontCollection(FontCollection& collection, Vector const& res_arr) + { + HRESULT hr = S_OK; + if (!d2d_res_) + { + hr = E_UNEXPECTED; + } + + if (SUCCEEDED(hr)) + { + LPVOID collection_key = nullptr; + UINT32 collection_key_size = 0; + + hr = res_font_collection_loader_->AddResources(res_arr, &collection_key, &collection_key_size); + + if (SUCCEEDED(hr)) + { + ComPtr font_collection; + hr = d2d_res_->GetDWriteFactory()->CreateCustomFontCollection( + res_font_collection_loader_.get(), + collection_key, + collection_key_size, + &font_collection + ); + + if (SUCCEEDED(hr)) + { + collection.SetFontCollection(font_collection); + } + } } if (FAILED(hr)) diff --git a/src/kiwano/renderer/Renderer.h b/src/kiwano/renderer/Renderer.h index 1a77f295..a0fc0d39 100644 --- a/src/kiwano/renderer/Renderer.h +++ b/src/kiwano/renderer/Renderer.h @@ -58,19 +58,34 @@ namespace kiwano ); public: + void CreateImage( + Image& image, + String const& file_path + ); + void CreateImage( Image& image, Resource const& res ); + void CreateGifImage( + GifImage& image, + String const& file_path + ); + void CreateGifImage( GifImage& image, Resource const& res ); - void CreateFontFromResource( + void CreateFontCollection( FontCollection& collection, - Resource const& res + Vector const& file_paths + ); + + void CreateFontCollection( + FontCollection& collection, + Vector const& res_arr ); void CreateTextFormat( diff --git a/src/kiwano/renderer/win32/D2DDeviceResources.cpp b/src/kiwano/renderer/win32/D2DDeviceResources.cpp index 2ebc880e..9e5459f5 100644 --- a/src/kiwano/renderer/win32/D2DDeviceResources.cpp +++ b/src/kiwano/renderer/win32/D2DDeviceResources.cpp @@ -392,9 +392,8 @@ namespace kiwano ComPtr bitmap_tmp; // 加载资源 - LPVOID buffer; - DWORD buffer_size; - HRESULT hr = res.Load(buffer, buffer_size) ? S_OK : E_FAIL; + Resource::Data res_data = res.GetData(); + HRESULT hr = res_data ? S_OK : E_FAIL; if (SUCCEEDED(hr)) { @@ -404,8 +403,8 @@ namespace kiwano if (SUCCEEDED(hr)) { hr = stream->InitializeFromMemory( - static_cast(buffer), - buffer_size + static_cast(res_data.buffer), + res_data.size ); } diff --git a/src/kiwano/renderer/win32/FontCollectionLoader.cpp b/src/kiwano/renderer/win32/FontCollectionLoader.cpp index ad97e532..304cd72d 100644 --- a/src/kiwano/renderer/win32/FontCollectionLoader.cpp +++ b/src/kiwano/renderer/win32/FontCollectionLoader.cpp @@ -37,6 +37,12 @@ namespace kiwano { } + STDMETHOD(AddFilePaths)( + Vector const& filePaths, + _Out_ LPVOID* pCollectionKey, + _Out_ UINT32* pCollectionKeySize + ); + // IUnknown methods virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject); virtual ULONG STDMETHODCALLTYPE AddRef(); @@ -52,6 +58,10 @@ namespace kiwano private: ULONG refCount_; + + typedef Vector FileCollection; + Vector filePaths_; + Vector collectionKeys_; }; HRESULT IFontCollectionLoader::Create(_Out_ IFontCollectionLoader** ppCollectionLoader) @@ -77,6 +87,37 @@ namespace kiwano return hr; } + STDMETHODIMP FontCollectionLoader::AddFilePaths( + Vector const& filePaths, + _Out_ LPVOID* pCollectionKey, + _Out_ UINT32* pCollectionKeySize + ) + { + if (!pCollectionKey || !pCollectionKeySize) + { + return E_INVALIDARG; + } + + try + { + UINT32 collectionKey = filePaths_.size(); + collectionKeys_.push_back(collectionKey); + filePaths_.push_back(filePaths); + + *pCollectionKey = reinterpret_cast(&collectionKeys_.back()); + *pCollectionKeySize = sizeof(collectionKey); + } + catch (std::bad_alloc&) + { + return E_OUTOFMEMORY; + } + catch (...) + { + return E_FAIL; + } + return S_OK; + } + HRESULT STDMETHODCALLTYPE FontCollectionLoader::QueryInterface(REFIID iid, void** ppvObject) { if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontCollectionLoader)) @@ -115,7 +156,7 @@ namespace kiwano { HRESULT hr = S_OK; - if (collectionKey == NULL || collectionKeySize != sizeof(String)) + if (collectionKey == NULL || collectionKeySize % sizeof(UINT32) != 0) hr = E_INVALIDARG; if (SUCCEEDED(hr)) @@ -125,10 +166,8 @@ namespace kiwano if (SUCCEEDED(hr)) { - String const* filePath = static_cast(collectionKey); - UINT32 const fileCount = collectionKeySize / sizeof(String); - - hr = pEnumerator->SetFilePaths(filePath, fileCount); + const UINT32 fileIndex = *static_cast(collectionKey); + hr = pEnumerator->SetFilePaths(filePaths_[fileIndex]); } if (SUCCEEDED(hr)) @@ -157,8 +196,7 @@ namespace kiwano ); STDMETHOD(SetFilePaths)( - String const* filePath, - UINT32 const fileCount + Vector const& filePaths ); ~FontFileEnumerator() @@ -234,13 +272,12 @@ namespace kiwano } STDMETHODIMP FontFileEnumerator::SetFilePaths( - String const* filePath, - UINT32 const fileCount + Vector const& filePaths ) { try { - filePaths_.assign(filePath, filePath + fileCount); + filePaths_.assign(filePaths); } catch (std::bad_alloc&) { @@ -332,6 +369,12 @@ namespace kiwano { } + STDMETHOD(AddResources)( + Vector const& resources, + _Out_ LPVOID* pCollectionKey, + _Out_ UINT32* pCollectionKeySize + ); + // IUnknown methods virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject); virtual ULONG STDMETHODCALLTYPE AddRef(); @@ -348,6 +391,10 @@ namespace kiwano private: ULONG refCount_; IDWriteFontFileLoader* pFileLoader_; + + typedef Vector ResourceCollection; + Vector resources_; + Vector collectionKeys_; }; HRESULT IResourceFontCollectionLoader::Create(_Out_ IResourceFontCollectionLoader** ppCollectionLoader, IDWriteFontFileLoader* pFileLoader) @@ -373,6 +420,37 @@ namespace kiwano return hr; } + STDMETHODIMP ResourceFontCollectionLoader::AddResources( + Vector const& resources, + _Out_ LPVOID* pCollectionKey, + _Out_ UINT32* pCollectionKeySize + ) + { + if (!pCollectionKey || !pCollectionKeySize) + { + return E_INVALIDARG; + } + + try + { + UINT32 collectionKey = resources_.size(); + collectionKeys_.push_back(collectionKey); + resources_.push_back(resources); + + *pCollectionKey = reinterpret_cast(&collectionKeys_.back()); + *pCollectionKeySize = sizeof(collectionKey); + } + catch (std::bad_alloc&) + { + return E_OUTOFMEMORY; + } + catch (...) + { + return E_FAIL; + } + return S_OK; + } + HRESULT STDMETHODCALLTYPE ResourceFontCollectionLoader::QueryInterface(REFIID iid, void** ppvObject) { if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontCollectionLoader)) @@ -411,7 +489,7 @@ namespace kiwano { HRESULT hr = S_OK; - if (collectionKey == NULL || collectionKeySize % sizeof(UINT) != 0) + if (collectionKey == NULL || collectionKeySize % sizeof(Resource*) != 0) hr = E_INVALIDARG; if (SUCCEEDED(hr)) @@ -421,10 +499,9 @@ namespace kiwano if (SUCCEEDED(hr)) { - UINT const* resourceID = static_cast(collectionKey); - UINT32 const resourceCount = collectionKeySize / sizeof(UINT); + const UINT32 resourceIndex = *static_cast(collectionKey); - hr = pEnumerator->SetResources(resourceID, resourceCount); + hr = pEnumerator->SetResources(resources_[resourceIndex]); } if (SUCCEEDED(hr)) @@ -527,16 +604,16 @@ namespace kiwano HRESULT hr = S_OK; // Make sure the key is the right size. - if (fontFileReferenceKeySize != sizeof(UINT)) + if (fontFileReferenceKeySize != sizeof(Resource)) hr = E_INVALIDARG; if (SUCCEEDED(hr)) { // Create the pFileStream object. IResourceFontFileStream* pFileStream = NULL; - UINT resourceID = *static_cast(fontFileReferenceKey); + Resource resource = *static_cast(fontFileReferenceKey); - hr = IResourceFontFileStream::Create(&pFileStream, resourceID); + hr = IResourceFontFileStream::Create(&pFileStream, resource); if (SUCCEEDED(hr)) { @@ -566,8 +643,7 @@ namespace kiwano ); STDMETHOD(SetResources)( - UINT const* resourceID, - UINT32 const resourceCount + Vector const& resources ); ~ResourceFontFileEnumerator() @@ -591,7 +667,7 @@ namespace kiwano IDWriteFactory* pFactory_; IDWriteFontFile* currentFile_; IDWriteFontFileLoader* pLoader_; - Vector resourceIDs_; + Vector resources_; size_t nextIndex_; }; @@ -647,13 +723,12 @@ namespace kiwano } STDMETHODIMP ResourceFontFileEnumerator::SetResources( - UINT const* resourceID, - UINT32 const resourceCount + Vector const& resources ) { try { - resourceIDs_.assign(resourceID, resourceID + resourceCount); + resources_.assign(resources); } catch (std::bad_alloc&) { @@ -702,11 +777,11 @@ namespace kiwano *hasCurrentFile = FALSE; DX::SafeRelease(currentFile_); - if (nextIndex_ < resourceIDs_.size()) + if (nextIndex_ < resources_.size()) { hr = pFactory_->CreateCustomFontFileReference( - &resourceIDs_[nextIndex_], - sizeof(UINT), + &resources_[nextIndex_], + sizeof(Resource), pLoader_, ¤tFile_ ); @@ -743,7 +818,7 @@ namespace kiwano ResourceFontFileStream(); STDMETHOD(Initialize)( - const UINT resourceID + Resource const resources ); // IUnknown methods @@ -782,7 +857,7 @@ namespace kiwano DWORD resourceSize_; }; - HRESULT IResourceFontFileStream::Create(_Out_ IResourceFontFileStream** ppStream, const UINT resourceID) + HRESULT IResourceFontFileStream::Create(_Out_ IResourceFontFileStream** ppStream, const Resource resource) { HRESULT hr = S_OK; @@ -798,7 +873,7 @@ namespace kiwano if (SUCCEEDED(hr)) { - hr = pFileStream->Initialize(resourceID); + hr = pFileStream->Initialize(resource); } if (SUCCEEDED(hr)) @@ -818,14 +893,16 @@ namespace kiwano } STDMETHODIMP ResourceFontFileStream::Initialize( - const UINT resourceID + const Resource resource ) { - HRESULT hr = S_OK; + Resource::Data data = resource.GetData(); + HRESULT hr = data ? S_OK : E_FAIL; - if (!Resource{ resourceID, RT_FONT }.Load(resourcePtr_, resourceSize_)) + if (SUCCEEDED(hr)) { - hr = E_FAIL; + resourcePtr_ = data.buffer; + resourceSize_ = data.size; } return hr; } diff --git a/src/kiwano/renderer/win32/FontCollectionLoader.h b/src/kiwano/renderer/win32/FontCollectionLoader.h index 49479d48..c5e01c20 100644 --- a/src/kiwano/renderer/win32/FontCollectionLoader.h +++ b/src/kiwano/renderer/win32/FontCollectionLoader.h @@ -30,6 +30,12 @@ namespace kiwano static HRESULT Create( _Out_ IFontCollectionLoader** ppCollectionLoader ); + + STDMETHOD(AddFilePaths)( + Vector const& filePaths, + _Out_ LPVOID * pCollectionKey, + _Out_ UINT32 * pCollectionKeySize + ) PURE; }; @@ -43,8 +49,7 @@ namespace kiwano ); STDMETHOD(SetFilePaths)( - String const* filePath, - UINT32 const fileCount + Vector const& filePaths ) PURE; }; @@ -57,6 +62,12 @@ namespace kiwano _Out_ IResourceFontCollectionLoader** ppCollectionLoader, IDWriteFontFileLoader * pFileLoader ); + + STDMETHOD(AddResources)( + Vector const& resources, + _Out_ LPVOID * pCollectionKey, + _Out_ UINT32 * pCollectionKeySize + ) PURE; }; @@ -81,8 +92,7 @@ namespace kiwano ); STDMETHOD(SetResources)( - UINT const* resourceID, - UINT32 const resourceCount + Vector const& resources ) PURE; }; @@ -93,7 +103,7 @@ namespace kiwano public: static HRESULT Create( _Out_ IResourceFontFileStream** ppStream, - const UINT resourceID + const Resource resource ); }; } diff --git a/src/kiwano/utils/FileUtil.cpp b/src/kiwano/utils/FileUtil.cpp index 942a7dc7..519346e5 100644 --- a/src/kiwano/utils/FileUtil.cpp +++ b/src/kiwano/utils/FileUtil.cpp @@ -46,12 +46,11 @@ namespace kiwano if (file_handle == INVALID_HANDLE_VALUE) return false; - LPVOID buffer; - DWORD buffer_size; - if (res.Load(buffer, buffer_size)) + Resource::Data data = res.GetData(); + if (data) { DWORD written_bytes = 0; - ::WriteFile(file_handle, buffer, buffer_size, &written_bytes, NULL); + ::WriteFile(file_handle, data.buffer, data.size, &written_bytes, NULL); ::CloseHandle(file_handle); return true; diff --git a/src/kiwano/utils/ResourceCache.cpp b/src/kiwano/utils/ResourceCache.cpp index 1e821f7c..9340e3d1 100644 --- a/src/kiwano/utils/ResourceCache.cpp +++ b/src/kiwano/utils/ResourceCache.cpp @@ -173,12 +173,12 @@ namespace kiwano return false; } - bool ResourceCache::AddFrame(String const& id, Resource const& res) + bool ResourceCache::AddFrame(String const& id, String const& file_path) { FramePtr ptr = new (std::nothrow) Frame; if (ptr) { - if (ptr->Load(res)) + if (ptr->Load(file_path)) { return AddFrame(id, ptr); } @@ -196,43 +196,20 @@ namespace kiwano return false; } - bool ResourceCache::AddGifImage(String const& id, Resource const& res) + size_t ResourceCache::AddFrameSequence(String const& id, Vector const& files) { - GifImagePtr ptr = new (std::nothrow) GifImage; - if (ptr) - { - if (ptr->Load(res)) - { - return AddGifImage(id, ptr); - } - } - return false; - } - - bool ResourceCache::AddGifImage(String const& id, GifImagePtr image) - { - if (image) - { - cache_.insert(std::make_pair(id, image)); - return true; - } - return false; - } - - size_t ResourceCache::AddFrameSequence(String const& id, Vector const& images) - { - if (images.empty()) + if (files.empty()) return 0; Vector image_arr; - image_arr.reserve(images.size()); + image_arr.reserve(files.size()); - for (const auto& image : images) + for (const auto& file : files) { FramePtr ptr = new (std::nothrow) Frame; if (ptr) { - if (ptr->Load(image)) + if (ptr->Load(file)) { image_arr.push_back(ptr); } @@ -247,22 +224,13 @@ namespace kiwano return 0; } - size_t ResourceCache::AddFrameSequence(String const& id, Vector const& images) - { - if (images.empty()) - return 0; - - FrameSequencePtr frames = new (std::nothrow) FrameSequence(images); - return AddFrameSequence(id, frames); - } - - size_t ResourceCache::AddFrameSequence(String const & id, Resource const & image, int cols, int rows) + size_t ResourceCache::AddFrameSequence(String const & id, String const& file_path, int cols, int rows) { if (cols <= 0 || rows <= 0) return 0; FramePtr raw = new (std::nothrow) Frame; - if (!raw || !raw->Load(image)) + if (!raw || !raw->Load(file_path)) return false; float raw_width = raw->GetWidth(); @@ -290,29 +258,6 @@ namespace kiwano return AddFrameSequence(id, frames); } - size_t ResourceCache::AddFrameSequence(String const & id, Resource const & image, Vector const & crop_rects) - { - FramePtr raw = new (std::nothrow) Frame; - if (!raw || !raw->Load(image)) - return 0; - - Vector image_arr; - image_arr.reserve(crop_rects.size()); - - for (const auto& rect : crop_rects) - { - FramePtr ptr = new (std::nothrow) Frame(raw->GetImage()); - if (ptr) - { - ptr->SetCropRect(rect); - image_arr.push_back(ptr); - } - } - - FrameSequencePtr frames = new (std::nothrow) FrameSequence(image_arr); - return AddFrameSequence(id, frames); - } - size_t ResourceCache::AddFrameSequence(String const & id, FrameSequencePtr frames) { if (frames) @@ -338,11 +283,6 @@ namespace kiwano return Get(id); } - GifImagePtr ResourceCache::GetGifImage(String const& id) const - { - return Get(id); - } - FrameSequencePtr ResourceCache::GetFrameSequence(String const & id) const { return Get(id); @@ -376,23 +316,17 @@ namespace kiwano if (file) { - // Gif image - if (type && (*type) == L"gif") - { - return loader->AddGifImage(*id, Resource(gdata->path + (*file))); - } - if (!(*file).empty()) { if (rows || cols) { // Frame slices - return !!loader->AddFrameSequence(*id, Resource(gdata->path + (*file)), std::max(cols, 1), std::max(rows, 1)); + return !!loader->AddFrameSequence(*id, gdata->path + (*file), std::max(cols, 1), std::max(rows, 1)); } else { // Simple image - return loader->AddFrame(*id, Resource(gdata->path + (*file))); + return loader->AddFrame(*id, gdata->path + (*file)); } } } @@ -410,7 +344,8 @@ namespace kiwano frames.push_back(frame); } } - return !!loader->AddFrameSequence(*id, frames); + FrameSequencePtr frame_seq = new FrameSequence(frames); + return !!loader->AddFrameSequence(*id, frame_seq); } return false; } diff --git a/src/kiwano/utils/ResourceCache.h b/src/kiwano/utils/ResourceCache.h index 06f2b6c7..76559d32 100644 --- a/src/kiwano/utils/ResourceCache.h +++ b/src/kiwano/utils/ResourceCache.h @@ -46,31 +46,18 @@ namespace kiwano // 从 XML 文档对象加载资源信息 bool LoadFromXml(tinyxml2::XMLDocument* doc); - // 添加图片 - bool AddFrame(String const& id, Resource const& res); + // 添加帧图像 + bool AddFrame(String const& id, String const& file_path); - // 添加图片 + // 添加帧图像 bool AddFrame(String const& id, FramePtr frame); - // 添加 GIF 图片 - bool AddGifImage(String const& id, Resource const& res); - - // 添加 GIF 图片 - bool AddGifImage(String const& id, GifImagePtr image); - // 添加序列帧 - size_t AddFrameSequence(String const& id, Vector const& frames); - - // 添加序列帧 - size_t AddFrameSequence(String const& id, Vector const& frames); + size_t AddFrameSequence(String const& id, Vector const& files); // 添加序列帧 // 按行列数裁剪图片 - size_t AddFrameSequence(String const& id, Resource const& frame, int cols, int rows = 1); - - // 添加序列帧 - // 按指定裁剪矩形裁剪图片 - size_t AddFrameSequence(String const& id, Resource const& frame, Vector const& crop_rects); + size_t AddFrameSequence(String const& id, String const& file_path, int cols, int rows = 1); // 添加序列帧 size_t AddFrameSequence(String const& id, FrameSequencePtr frames); @@ -78,12 +65,9 @@ namespace kiwano // 添加对象 bool AddObjectBase(String const& id, ObjectBasePtr obj); - // 获取图片资源 + // 获取帧图像 FramePtr GetFrame(String const& id) const; - // 获取 GIF 图片资源 - GifImagePtr GetGifImage(String const& id) const; - // 获取序列帧 FrameSequencePtr GetFrameSequence(String const& id) const;