diff --git a/core/base/Action.h b/core/base/Action.h index efbc925e..671fcaba 100644 --- a/core/base/Action.h +++ b/core/base/Action.h @@ -38,6 +38,8 @@ namespace easy2d friend class Sequence; friend class Spawn; + E2D_DISABLE_COPY(Action); + public: Action(); @@ -92,9 +94,6 @@ namespace easy2d // 获取动作结束状态 virtual bool IsDone() const; - protected: - E2D_DISABLE_COPY(Action); - protected: String name_; bool running_; diff --git a/core/base/ActionCombined.cpp b/core/base/ActionCombined.cpp index 1dc16810..bc2df50c 100644 --- a/core/base/ActionCombined.cpp +++ b/core/base/ActionCombined.cpp @@ -27,7 +27,7 @@ namespace easy2d // Loop //------------------------------------------------------- - Loop::Loop(Action * action, int times /* = -1 */) + Loop::Loop(Action * action, int times) : action_(action) , times_(0) , total_times_(times) diff --git a/core/base/ActionCombined.h b/core/base/ActionCombined.h index 48f4264a..abb87d3e 100644 --- a/core/base/ActionCombined.h +++ b/core/base/ActionCombined.h @@ -27,6 +27,8 @@ namespace easy2d class Loop : public Action { + E2D_DISABLE_COPY(Loop); + public: explicit Loop( Action * action, /* 执行循环的动作 */ @@ -45,8 +47,6 @@ namespace easy2d virtual void Reset() override; protected: - E2D_DISABLE_COPY(Loop); - // 初始化动作 virtual void Initialize() override; @@ -67,6 +67,8 @@ namespace easy2d class Sequence : public Action { + E2D_DISABLE_COPY(Sequence); + public: typedef std::vector Actions; @@ -98,8 +100,6 @@ namespace easy2d virtual void Reset() override; protected: - E2D_DISABLE_COPY(Sequence); - // 初始化动作 virtual void Initialize() override; @@ -119,6 +119,8 @@ namespace easy2d class Spawn : public Action { + E2D_DISABLE_COPY(Spawn); + public: typedef std::vector Actions; @@ -150,8 +152,6 @@ namespace easy2d virtual void Reset() override; protected: - E2D_DISABLE_COPY(Spawn); - // 初始化动作 virtual void Initialize() override; diff --git a/core/base/ActionFiniteTime.h b/core/base/ActionFiniteTime.h index bd88f7ce..30b00596 100644 --- a/core/base/ActionFiniteTime.h +++ b/core/base/ActionFiniteTime.h @@ -27,6 +27,8 @@ namespace easy2d class FiniteTimeAction : public Action { + E2D_DISABLE_COPY(FiniteTimeAction); + public: // 创建特定时长的持续动作 explicit FiniteTimeAction( @@ -37,8 +39,6 @@ namespace easy2d virtual void Reset() override; protected: - E2D_DISABLE_COPY(FiniteTimeAction); - // 初始化动作 virtual void Initialize() override; @@ -58,6 +58,8 @@ namespace easy2d class MoveBy : public FiniteTimeAction { + E2D_DISABLE_COPY(MoveBy); + public: explicit MoveBy( float duration, /* 持续时长 */ @@ -71,8 +73,6 @@ namespace easy2d virtual MoveBy * Reverse() const override; protected: - E2D_DISABLE_COPY(MoveBy); - // 初始化动作 virtual void Initialize() override; @@ -90,6 +90,8 @@ namespace easy2d class MoveTo : public MoveBy { + E2D_DISABLE_COPY(MoveTo); + public: explicit MoveTo( float duration, /* 持续时长 */ @@ -107,8 +109,6 @@ namespace easy2d } protected: - E2D_DISABLE_COPY(MoveTo); - // 初始化动作 virtual void Initialize() override; @@ -121,6 +121,8 @@ namespace easy2d class JumpBy : public FiniteTimeAction { + E2D_DISABLE_COPY(JumpBy); + public: explicit JumpBy( float duration, /* 持续时长 */ @@ -136,8 +138,6 @@ namespace easy2d virtual JumpBy * Reverse() const override; protected: - E2D_DISABLE_COPY(JumpBy); - // 初始化动作 virtual void Initialize() override; @@ -157,6 +157,8 @@ namespace easy2d class JumpTo : public JumpBy { + E2D_DISABLE_COPY(JumpTo); + public: explicit JumpTo( float duration, /* 持续时长 */ @@ -176,8 +178,6 @@ namespace easy2d } protected: - E2D_DISABLE_COPY(JumpTo); - // 初始化动作 virtual void Initialize() override; @@ -190,6 +190,8 @@ namespace easy2d class ScaleBy : public FiniteTimeAction { + E2D_DISABLE_COPY(ScaleBy); + public: explicit ScaleBy( float duration, /* 持续时长 */ @@ -209,8 +211,6 @@ namespace easy2d virtual ScaleBy * Reverse() const override; protected: - E2D_DISABLE_COPY(ScaleBy); - // 初始化动作 virtual void Initialize() override; @@ -229,6 +229,8 @@ namespace easy2d class ScaleTo : public ScaleBy { + E2D_DISABLE_COPY(ScaleTo); + public: explicit ScaleTo( float duration, /* 持续时长 */ @@ -252,8 +254,6 @@ namespace easy2d } protected: - E2D_DISABLE_COPY(ScaleTo); - // 初始化动作 virtual void Initialize() override; @@ -267,6 +267,8 @@ namespace easy2d class OpacityBy : public FiniteTimeAction { + E2D_DISABLE_COPY(OpacityBy); + public: explicit OpacityBy( float duration, /* 持续时长 */ @@ -280,8 +282,6 @@ namespace easy2d virtual OpacityBy * Reverse() const override; protected: - E2D_DISABLE_COPY(OpacityBy); - // 初始化动作 virtual void Initialize() override; @@ -298,6 +298,8 @@ namespace easy2d class OpacityTo : public OpacityBy { + E2D_DISABLE_COPY(OpacityTo); + public: explicit OpacityTo( float duration, /* 持续时长 */ @@ -315,8 +317,6 @@ namespace easy2d } protected: - E2D_DISABLE_COPY(OpacityTo); - // 初始化动作 virtual void Initialize() override; @@ -329,14 +329,13 @@ namespace easy2d class FadeIn : public OpacityTo { + E2D_DISABLE_COPY(FadeIn); + public: // 创建淡入动作 explicit FadeIn( float duration /* 持续时长 */ ); - - protected: - E2D_DISABLE_COPY(FadeIn); }; @@ -344,14 +343,13 @@ namespace easy2d class FadeOut : public OpacityTo { + E2D_DISABLE_COPY(FadeOut); + public: // 创建淡出动作 explicit FadeOut( float duration /* 持续时长 */ ); - - protected: - E2D_DISABLE_COPY(FadeOut); }; @@ -359,6 +357,8 @@ namespace easy2d class RotateBy : public FiniteTimeAction { + E2D_DISABLE_COPY(RotateBy); + public: explicit RotateBy( float duration, /* 持续时长 */ @@ -372,8 +372,6 @@ namespace easy2d virtual RotateBy * Reverse() const override; protected: - E2D_DISABLE_COPY(RotateBy); - // 初始化动作 virtual void Initialize() override; @@ -390,6 +388,8 @@ namespace easy2d class RotateTo : public RotateBy { + E2D_DISABLE_COPY(RotateTo); + public: explicit RotateTo( float duration, /* 持续时长 */ @@ -407,8 +407,6 @@ namespace easy2d } protected: - E2D_DISABLE_COPY(RotateTo); - // 初始化动作 virtual void Initialize() override; @@ -421,6 +419,8 @@ namespace easy2d class Delay : public Action { + E2D_DISABLE_COPY(Delay); + public: explicit Delay( float duration /* 延迟时长(秒) */ @@ -436,8 +436,6 @@ namespace easy2d virtual void Reset() override; protected: - E2D_DISABLE_COPY(Delay); - // 初始化动作 virtual void Initialize() override; diff --git a/core/base/Animation.h b/core/base/Animation.h index 61c4354f..0ad819ac 100644 --- a/core/base/Animation.h +++ b/core/base/Animation.h @@ -28,6 +28,8 @@ namespace easy2d class Animation : public RefCounter { + E2D_DISABLE_COPY(Animation); + public: typedef std::vector Images; @@ -75,9 +77,6 @@ namespace easy2d // 获取帧动画的倒转 Animation * Reverse() const; - protected: - E2D_DISABLE_COPY(Animation); - protected: float interval_; Images frames_; @@ -88,6 +87,8 @@ namespace easy2d class Animate : public Action { + E2D_DISABLE_COPY(Animate); + public: Animate(); @@ -115,8 +116,6 @@ namespace easy2d virtual void Reset() override; protected: - E2D_DISABLE_COPY(Animate); - // 初始化动作 virtual void Initialize() override; diff --git a/core/base/BaseTypes.h b/core/base/BaseTypes.h index 3cb91864..26bacbc9 100644 --- a/core/base/BaseTypes.h +++ b/core/base/BaseTypes.h @@ -23,6 +23,7 @@ #include "../math/vector.hpp" #include "Color.h" #include "Size.h" +#include "Rect.hpp" namespace easy2d { @@ -33,9 +34,9 @@ namespace easy2d // 计算两点间距离: float distance = p1.Distance(p2); // 坐标可以相加减: Point p = Point(10, 10) + Point(20, 20); // p 的坐标是 (30, 30) // - typedef math::Vector2 Point; + using Point = math::Vector2; - typedef std::wstring String; + using String = std::wstring; // 方向 enum class Direction : int @@ -138,4 +139,11 @@ namespace easy2d Right = VK_RBUTTON, /* 鼠标右键 */ Middle = VK_MBUTTON /* 鼠标中键 */ }; + + // 图层属性 + struct LayerProperties + { + Rect area; + float opacity; + }; } diff --git a/core/base/CallFunc.h b/core/base/CallFunc.h index a99ba630..e90c27b4 100644 --- a/core/base/CallFunc.h +++ b/core/base/CallFunc.h @@ -28,6 +28,8 @@ namespace easy2d class CallFunc : public Action { + E2D_DISABLE_COPY(CallFunc); + typedef std::function Callback; public: @@ -42,8 +44,6 @@ namespace easy2d virtual CallFunc *Reverse() const override; protected: - E2D_DISABLE_COPY(CallFunc); - // 初始化动作 virtual void Initialize() override; diff --git a/core/base/Canvas.cpp b/core/base/Canvas.cpp index 23b2e8eb..05825029 100644 --- a/core/base/Canvas.cpp +++ b/core/base/Canvas.cpp @@ -88,7 +88,7 @@ namespace easy2d { SafeRelease(stroke_style_); - stroke_style_ = render::instance.GetStrokeStyle(stroke); + stroke_style_ = devices::Graphics::Instance().GetStrokeStyle(stroke); if (stroke_style_) stroke_style_->AddRef(); diff --git a/core/base/Canvas.h b/core/base/Canvas.h index 0c48f2ae..c6b532e7 100644 --- a/core/base/Canvas.h +++ b/core/base/Canvas.h @@ -28,6 +28,8 @@ namespace easy2d class Canvas : public Node { + E2D_DISABLE_COPY(Canvas); + public: Canvas( float width, @@ -124,12 +126,9 @@ namespace easy2d float radius_y ); - private: - E2D_DISABLE_COPY(Canvas); - private: float stroke_width_; - StrokeStyle stroke_; + StrokeStyle stroke_; ID2D1RenderTarget* render_target_; ID2D1SolidColorBrush* fill_brush_; ID2D1SolidColorBrush* line_brush_; diff --git a/core/base/Game.cpp b/core/base/Game.cpp index 3bc6c535..d6ef244b 100644 --- a/core/base/Game.cpp +++ b/core/base/Game.cpp @@ -34,16 +34,6 @@ namespace easy2d { - namespace - { - Game * instance = nullptr; - } - - Game * Game::GetInstance() - { - return instance; - } - Game::Game() : quit_(true) , curr_scene_(nullptr) @@ -51,12 +41,6 @@ namespace easy2d , transition_(nullptr) , debug_mode_(false) { - if (instance) - { - throw std::runtime_error("同时只能存在一个游戏实例"); - } - instance = this; - ::CoInitialize(nullptr); } @@ -66,25 +50,14 @@ namespace easy2d SafeRelease(curr_scene_); SafeRelease(next_scene_); - Image::ClearCache(); - Player::ClearCache(); - - render::instance.Uninitialize(); - audio::instance.Uninitialize(); - window::instance.Destroy(); - modules::Uninitialize(); - - instance = nullptr; - ::CoUninitialize(); } - void Game::Initialize(const window::Property& property) + void Game::Initialize(const Options& options) { - modules::Initialize(); - window::instance.Initialize(property); - render::instance.Initialize(window::instance.handle); - audio::instance.Initialize(); + Window::Instance().Initialize(options.title, options.width, options.height, options.icon, options.debug); + devices::Graphics::Instance().Initialize(Window::Instance().GetHandle()); + devices::Audio::Instance().Initialize(); // 若开启了调试模式,打开控制台 HWND console = ::GetConsoleWindow(); @@ -117,7 +90,7 @@ namespace easy2d } ::SetWindowLongPtrW( - window::instance.handle, + Window::Instance().GetHandle(), GWLP_USERDATA, PtrToUlong(this) ); @@ -134,8 +107,8 @@ namespace easy2d next_scene_ = nullptr; } - ::ShowWindow(window::instance.handle, SW_SHOWNORMAL); - ::UpdateWindow(window::instance.handle); + ::ShowWindow(Window::Instance().GetHandle(), SW_SHOWNORMAL); + ::UpdateWindow(Window::Instance().GetHandle()); const int64_t min_interval = 5; auto last = time::Now(); @@ -151,10 +124,10 @@ namespace easy2d float dt = (now - last).Seconds(); last = now; - input::instance.Update( - window::instance.handle, - window::instance.xscale, - window::instance.yscale + devices::Input::Instance().Update( + Window::Instance().GetHandle(), + Window::Instance().GetContentScaleX(), + Window::Instance().GetContentScaleY() ); OnUpdate(dt); @@ -277,7 +250,7 @@ namespace easy2d void Game::DrawScene() { - render::instance.BeginDraw(window::instance.handle); + devices::Graphics::Instance().BeginDraw(Window::Instance().GetHandle()); if (transition_) { @@ -292,21 +265,21 @@ namespace easy2d { if (curr_scene_ && curr_scene_->GetRoot()) { - render::instance.SetTransform(math::Matrix()); - render::instance.SetBrushOpacity(1.f); + devices::Graphics::Instance().SetTransform(math::Matrix()); + devices::Graphics::Instance().SetBrushOpacity(1.f); curr_scene_->GetRoot()->DrawBorder(); } if (next_scene_ && next_scene_->GetRoot()) { - render::instance.SetTransform(math::Matrix()); - render::instance.SetBrushOpacity(1.f); + devices::Graphics::Instance().SetTransform(math::Matrix()); + devices::Graphics::Instance().SetBrushOpacity(1.f); next_scene_->GetRoot()->DrawBorder(); } - render::instance.DrawDebugInfo(); + devices::Graphics::Instance().DrawDebugInfo(); } - render::instance.EndDraw(); + devices::Graphics::Instance().EndDraw(); } void Game::SetDebugMode(bool enabled) diff --git a/core/base/Game.h b/core/base/Game.h index b5b72a3f..270654e4 100644 --- a/core/base/Game.h +++ b/core/base/Game.h @@ -27,12 +27,32 @@ namespace easy2d class Scene; class Transition; + struct Options + { + String title; /* 标题 */ + int width; /* 宽度 */ + int height; /* 高度 */ + LPCWSTR icon; /* 图标 */ + bool debug; /* 调试模式 */ + + Options() + : title(L"Easy2D Game") + , width(640) + , height(480) + , icon(nullptr) + , debug(false) + {} + }; + + class Game { + E2D_DISABLE_COPY(Game); + public: Game(); - ~Game(); + virtual ~Game(); // 更新时 virtual void OnUpdate(float dt) {} @@ -46,7 +66,7 @@ namespace easy2d // 初始化 void Initialize( - const window::Property& property /* 窗口属性 */ + const Options& options /* 属性 */ ); // 运行 @@ -80,12 +100,6 @@ namespace easy2d float dt ); - // 获取实例 - static Game * GetInstance(); - - protected: - E2D_DISABLE_COPY(Game); - private: bool debug_mode_; bool quit_; diff --git a/core/base/Image.cpp b/core/base/Image.cpp index b8c3a959..e88d2cd2 100644 --- a/core/base/Image.cpp +++ b/core/base/Image.cpp @@ -25,11 +25,6 @@ namespace easy2d { - namespace - { - std::map bitmap_cache_; - } - Image::Image() : bitmap_(nullptr) , crop_rect_() @@ -73,13 +68,12 @@ namespace easy2d bool Image::Load(Resource& res) { - if (!Image::CacheBitmap(res)) + HRESULT hr = devices::Graphics::Instance().CreateBitmapFromResource(res, &bitmap_); + if (FAILED(hr)) { - E2D_WARNING("Load Image from file failed!"); + logs::Trace(L"Load Image from resource failed!", hr); return false; } - - this->SetBitmap(bitmap_cache_.at(res.GetHashCode())); return true; } @@ -87,16 +81,23 @@ namespace easy2d { E2D_WARNING_IF(file_name.empty(), "Image Load failed! Invalid file name."); - if (file_name.empty()) - return false; - - if (!Image::CacheBitmap(file_name)) + File image_file; + if (!image_file.Open(file_name)) { - E2D_WARNING("Load Image from file failed!"); + E2D_WARNING("Image file not found!"); return false; } - this->SetBitmap(bitmap_cache_.at(std::hash{}(file_name))); + // 用户输入的路径不一定是完整路径,因为用户可能通过 File::AddSearchPath 添加 + // 默认搜索路径,所以需要通过 File::GetPath 获取完整路径 + String image_file_path = image_file.GetPath(); + + HRESULT hr = devices::Graphics::Instance().CreateBitmapFromFile(image_file_path, &bitmap_); + if (FAILED(hr)) + { + logs::Trace(L"Load Image from file failed!", hr); + return false; + } return true; } @@ -186,70 +187,6 @@ namespace easy2d return bitmap_; } - bool Image::CacheBitmap(Resource& res) - { - size_t hash_code = res.GetHashCode(); - if (bitmap_cache_.find(hash_code) != bitmap_cache_.end()) - { - return true; - } - - ID2D1Bitmap* bitmap = nullptr; - HRESULT hr = render::instance.CreateBitmapFromResource(res, &bitmap); - - if (SUCCEEDED(hr)) - { - bitmap_cache_.insert(std::make_pair(hash_code, bitmap)); - } - else - { - logs::Trace(L"CreateBitmapFromFile", hr); - } - - return SUCCEEDED(hr); - } - - bool Image::CacheBitmap(const String & file_name) - { - size_t hash_code = std::hash{}(file_name); - if (bitmap_cache_.find(hash_code) != bitmap_cache_.end()) - return true; - - File image_file; - if (!image_file.Open(file_name)) - return false; - - // 用户输入的路径不一定是完整路径,因为用户可能通过 File::AddSearchPath 添加 - // 默认搜索路径,所以需要通过 File::GetPath 获取完整路径 - String image_file_path = image_file.GetPath(); - - ID2D1Bitmap* bitmap = nullptr; - HRESULT hr = render::instance.CreateBitmapFromFile(file_name, &bitmap); - - if (SUCCEEDED(hr)) - { - bitmap_cache_.insert(std::make_pair(hash_code, bitmap)); - } - else - { - logs::Trace(L"CreateBitmapFromFile", hr); - } - - return SUCCEEDED(hr); - } - - void Image::ClearCache() - { - if (bitmap_cache_.empty()) - return; - - for (const auto& bitmap : bitmap_cache_) - { - bitmap.second->Release(); - } - bitmap_cache_.clear(); - } - void Image::SetBitmap(ID2D1Bitmap * bitmap) { if (bitmap_ == bitmap) diff --git a/core/base/Image.h b/core/base/Image.h index fae528f8..cd902348 100644 --- a/core/base/Image.h +++ b/core/base/Image.h @@ -29,6 +29,8 @@ namespace easy2d class Image : public RefCounter { + E2D_DISABLE_COPY(Image); + public: Image(); @@ -100,22 +102,7 @@ namespace easy2d // 获取 ID2D1Bitmap 对象 ID2D1Bitmap * GetBitmap() const; - // 清空缓存 - static void ClearCache(); - private: - E2D_DISABLE_COPY(Image); - - // 缓存 Bitmap 资源 - static bool CacheBitmap( - const String& file_name - ); - - // 缓存 Bitmap 资源 - static bool CacheBitmap( - Resource& res - ); - // 设置 Bitmap void SetBitmap( ID2D1Bitmap * bitmap diff --git a/core/base/Input.cpp b/core/base/Input.cpp index f8c9c65a..9c850f24 100644 --- a/core/base/Input.cpp +++ b/core/base/Input.cpp @@ -22,10 +22,8 @@ namespace easy2d { - namespace input + namespace devices { - InputDevice instance; - InputDevice::InputDevice() { ZeroMemory(keys_, sizeof(keys_)); @@ -35,7 +33,7 @@ namespace easy2d { } - void InputDevice::Update(HWND hwnd, float xscale, float yscale) + void InputDevice::Update(HWND hwnd, float scale_x, float scale_y) { ::GetKeyboardState(keys_); @@ -43,7 +41,7 @@ namespace easy2d ::GetCursorPos(&client_cursor_pos); ::ScreenToClient(hwnd, &client_cursor_pos); - mouse_pos_ = Point(client_cursor_pos.x * xscale, client_cursor_pos.y * yscale); + mouse_pos_ = Point(client_cursor_pos.x * scale_x, client_cursor_pos.y * scale_y); } bool InputDevice::IsDown(KeyCode code) diff --git a/core/base/Input.h b/core/base/Input.h index 45b65481..08e7e420 100644 --- a/core/base/Input.h +++ b/core/base/Input.h @@ -20,14 +20,18 @@ #pragma once #include "base.h" +#include "Singleton.hpp" namespace easy2d { - namespace input + namespace devices { - // 输入设备 class InputDevice { + E2D_DECLARE_SINGLETON(InputDevice); + + E2D_DISABLE_COPY(InputDevice); + public: InputDevice(); @@ -55,8 +59,8 @@ namespace easy2d // 刷新设备状态 void Update( HWND hwnd, - float xscale, - float yscale + float scale_x, + float scale_y ); protected: @@ -64,6 +68,6 @@ namespace easy2d Point mouse_pos_; }; - extern InputDevice instance; + E2D_DECLARE_SINGLETON_TYPE(InputDevice, Input); } } diff --git a/core/base/MouseEvent.cpp b/core/base/MouseEvent.cpp index 41bf3482..96dbff00 100644 --- a/core/base/MouseEvent.cpp +++ b/core/base/MouseEvent.cpp @@ -32,19 +32,19 @@ namespace easy2d float MouseEvent::GetX() const { - return ((float)(short)LOWORD(l_param_)) * window::instance.xscale; + return ((float)(short)LOWORD(l_param_)) * Window::Instance().GetContentScaleX(); } float MouseEvent::GetY() const { - return ((float)(short)HIWORD(l_param_)) * window::instance.yscale; + return ((float)(short)HIWORD(l_param_)) * Window::Instance().GetContentScaleY(); } Point MouseEvent::GetPosition() const { return Point( - ((float)(short)LOWORD(l_param_)) * window::instance.xscale, - ((float)(short)HIWORD(l_param_)) * window::instance.yscale + ((float)(short)LOWORD(l_param_)) * Window::Instance().GetContentScaleX(), + ((float)(short)HIWORD(l_param_)) * Window::Instance().GetContentScaleY() ); } diff --git a/core/utils/Music.cpp b/core/base/Music.cpp similarity index 62% rename from core/utils/Music.cpp rename to core/base/Music.cpp index 1fd38d87..96ace47a 100644 --- a/core/utils/Music.cpp +++ b/core/base/Music.cpp @@ -19,11 +19,11 @@ // THE SOFTWARE. #include "Music.h" -#include "Transcoder.h" -#include "File.h" -#include "../base/modules.h" -#include "../base/audio.h" -#include "../base/logs.h" +#include "../utils/Transcoder.h" +#include "../utils/File.h" +#include "modules.h" +#include "audio.h" +#include "logs.h" namespace easy2d { @@ -71,7 +71,7 @@ namespace easy2d File music_file; if (!music_file.Open(file_path)) { - E2D_WARNING("Media file not found."); + logs::Trace(L"Media file not found."); return false; } @@ -80,12 +80,14 @@ namespace easy2d String music_file_path = music_file.GetPath(); Transcoder transcoder; - if (!transcoder.LoadMediaFile(music_file_path.c_str(), &wave_data_, &size_)) + HRESULT hr = transcoder.LoadMediaFile(music_file_path.c_str(), &wave_data_, &size_); + if (FAILED(hr)) { + logs::Trace(L"Load media from file failed.", hr); return false; } - HRESULT hr = audio::instance.CreateVoice(&voice_, transcoder.GetWaveFormatEx()); + hr = devices::Audio::Instance().CreateVoice(&voice_, transcoder.GetWaveFormatEx()); if (FAILED(hr)) { if (wave_data_) @@ -109,12 +111,15 @@ namespace easy2d } Transcoder transcoder; - if (!transcoder.LoadMediaResource(res, &wave_data_, &size_)) + HRESULT hr = transcoder.LoadMediaResource(res, &wave_data_, &size_); + + if (FAILED(hr)) { + logs::Trace(L"Load media from resource failed.", hr); return false; } - HRESULT hr = audio::instance.CreateVoice(&voice_, transcoder.GetWaveFormatEx()); + hr = devices::Audio::Instance().CreateVoice(&voice_, transcoder.GetWaveFormatEx()); if (FAILED(hr)) { if (wave_data_) @@ -134,48 +139,26 @@ namespace easy2d { if (!opened_) { - E2D_WARNING("Music must be opened first!"); + logs::Trace(L"Music must be opened first!"); return false; } - if (voice_ == nullptr) - { - E2D_WARNING("IXAudio2SourceVoice Null pointer exception!"); - return false; - } - - XAUDIO2_VOICE_STATE state; - voice_->GetState(&state); - if (state.BuffersQueued) - { + UINT32 buffers_queued = 0; + voice_.GetBuffersQueued(&buffers_queued); + if (buffers_queued) Stop(); - } if (loop_count < 0) - { loop_count = XAUDIO2_LOOP_INFINITE; - } else - { loop_count = std::min(loop_count, XAUDIO2_LOOP_INFINITE - 1); - } - // 提交 wave 样本数据 - XAUDIO2_BUFFER buffer = { 0 }; - buffer.pAudioData = wave_data_; - buffer.Flags = XAUDIO2_END_OF_STREAM; - buffer.AudioBytes = size_; - buffer.LoopCount = loop_count; - - HRESULT hr; - if (FAILED(hr = voice_->SubmitSourceBuffer(&buffer))) + HRESULT hr = voice_.Play(wave_data_, size_, static_cast(loop_count)); + if (FAILED(hr)) { logs::Trace(L"Submitting source buffer error", hr); - return false; } - hr = voice_->Start(0); - playing_ = SUCCEEDED(hr); return playing_; @@ -183,48 +166,25 @@ namespace easy2d void Music::Pause() { - if (voice_) - { - if (SUCCEEDED(voice_->Stop())) - { - playing_ = false; - } - } + if (SUCCEEDED(voice_.Pause())) + playing_ = false; } void Music::Resume() { - if (voice_) - { - if (SUCCEEDED(voice_->Start())) - { - playing_ = true; - } - } + if (SUCCEEDED(voice_.Resume())) + playing_ = true; } void Music::Stop() { - if (voice_) - { - if (SUCCEEDED(voice_->Stop())) - { - voice_->ExitLoop(); - voice_->FlushSourceBuffers(); - playing_ = false; - } - } + if (SUCCEEDED(voice_.Stop())) + playing_ = false; } void Music::Close() { - if (voice_) - { - voice_->Stop(); - voice_->FlushSourceBuffers(); - voice_->DestroyVoice(); - voice_ = nullptr; - } + voice_.Destroy(); if (wave_data_) { @@ -238,11 +198,11 @@ namespace easy2d bool Music::IsPlaying() const { - if (opened_ && voice_) + if (opened_) { - XAUDIO2_VOICE_STATE state; - voice_->GetState(&state); - if (state.BuffersQueued && playing_) + UINT32 buffers_queued = 0; + voice_.GetBuffersQueued(&buffers_queued); + if (buffers_queued && playing_) return true; } return false; @@ -250,27 +210,13 @@ namespace easy2d float Music::GetVolume() const { - if (voice_) - { - float volume = 0.f; - voice_->GetVolume(&volume); - return volume; - } - return 0.f; + float volume = 0.f; + voice_.GetVolume(&volume); + return volume; } bool Music::SetVolume(float volume) { - if (voice_) - { - volume = std::min(std::max(volume, -224.f), 224.f); - return SUCCEEDED(voice_->SetVolume(volume)); - } - return false; - } - - IXAudio2SourceVoice * Music::GetSourceVoice() const - { - return voice_; + return SUCCEEDED(voice_.SetVolume(volume)); } } \ No newline at end of file diff --git a/core/utils/Music.h b/core/base/Music.h similarity index 86% rename from core/utils/Music.h rename to core/base/Music.h index 4839168e..efb4c1cb 100644 --- a/core/utils/Music.h +++ b/core/base/Music.h @@ -19,9 +19,10 @@ // THE SOFTWARE. #pragma once -#include "../base/base.h" -#include "../base/RefCounter.h" -#include "../base/Resource.h" +#include "base.h" +#include "audio.h" +#include "RefCounter.h" +#include "Resource.h" #include namespace easy2d @@ -30,6 +31,8 @@ namespace easy2d class Music : public RefCounter { + E2D_DISABLE_COPY(Music); + public: Music(); @@ -81,17 +84,11 @@ namespace easy2d float volume /* 1 为原始音量, 大于 1 为放大音量, 0 为最小音量 */ ); - // 获取 IXAudio2SourceVoice 对象 - IXAudio2SourceVoice * GetSourceVoice() const; - protected: - E2D_DISABLE_COPY(Music); - - protected: - bool opened_; - bool playing_; - UINT32 size_; - BYTE* wave_data_; - IXAudio2SourceVoice* voice_; + bool opened_; + bool playing_; + UINT32 size_; + BYTE* wave_data_; + Voice voice_; }; } diff --git a/core/base/Node.cpp b/core/base/Node.cpp index 9cf3d965..28ee8856 100644 --- a/core/base/Node.cpp +++ b/core/base/Node.cpp @@ -77,12 +77,12 @@ namespace easy2d if (clip_enabled_) { - render::instance.PushClip(final_matrix_, transform_.size); + devices::Graphics::Instance().PushClip(final_matrix_, transform_.size); } if (children_.empty()) { - render::instance.SetTransform(final_matrix_); + devices::Graphics::Instance().SetTransform(final_matrix_); OnDraw(); } else @@ -114,7 +114,7 @@ namespace easy2d } } - render::instance.SetTransform(final_matrix_); + devices::Graphics::Instance().SetTransform(final_matrix_); OnDraw(); // 访问剩余节点 @@ -124,7 +124,7 @@ namespace easy2d if (clip_enabled_) { - render::instance.PopClip(); + devices::Graphics::Instance().PopClip(); } } @@ -171,7 +171,7 @@ namespace easy2d { if (border_) { - render::instance.DrawGeometry(border_, border_color_, 1.f, 1.5f); + devices::Graphics::Instance().DrawGeometry(border_, border_color_, 1.f, 1.5f); } for (const auto& child : children_) @@ -212,7 +212,7 @@ namespace easy2d SafeRelease(border_); ThrowIfFailed( - render::instance.CreateRectGeometry(final_matrix_, transform_.size, &border_) + devices::Graphics::Instance().CreateRectGeometry(final_matrix_, transform_.size, &border_) ); // 通知子节点进行转换 diff --git a/core/base/Node.h b/core/base/Node.h index 578a5e34..bf18acc7 100644 --- a/core/base/Node.h +++ b/core/base/Node.h @@ -40,6 +40,8 @@ namespace easy2d friend class Game; friend class Scene; + E2D_DISABLE_COPY(Node); + public: typedef std::vector Nodes; typedef std::vector Actions; @@ -418,8 +420,6 @@ namespace easy2d ); private: - E2D_DISABLE_COPY(Node); - // 渲染节点边缘 void DrawBorder(); diff --git a/core/base/Rect.hpp b/core/base/Rect.hpp index ac194c70..ce5cab71 100644 --- a/core/base/Rect.hpp +++ b/core/base/Rect.hpp @@ -19,7 +19,8 @@ // THE SOFTWARE. #pragma once -#include "BaseTypes.h" +#include "../math/vector.hpp" +#include "Size.h" #include namespace easy2d @@ -34,9 +35,11 @@ namespace easy2d // class Rect { + using Point = math::Vector2; + public: - Point origin; // 左上角坐标 - Size size; // 宽度和高度 + Point origin; // 左上角坐标 + Size size; // 宽度和高度 public: Rect() {} diff --git a/core/base/Scene.h b/core/base/Scene.h index d6da1fda..1de206b5 100644 --- a/core/base/Scene.h +++ b/core/base/Scene.h @@ -32,6 +32,8 @@ namespace easy2d class Scene : public RefCounter { + E2D_DISABLE_COPY(Scene); + public: Scene(); @@ -79,9 +81,6 @@ namespace easy2d // 获取转换矩阵 const math::Matrix& GetTransform() const; - private: - E2D_DISABLE_COPY(Scene); - private: Node* root_; math::Matrix transform_; diff --git a/core/base/Singleton.hpp b/core/base/Singleton.hpp new file mode 100644 index 00000000..e74c8bca --- /dev/null +++ b/core/base/Singleton.hpp @@ -0,0 +1,77 @@ +// Copyright (c) 2016-2018 Easy2D - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once +#include + +namespace easy2d +{ + template + class ISingleton + { + public: + static inline T& Instance(); + + static inline void Destroy(); + + private: + ISingleton() {} + + ~ISingleton() {} + + ISingleton(const ISingleton&) = delete; + + ISingleton & operator= (const ISingleton &) = delete; + + static std::unique_ptr instance_; + }; + + template + inline T & easy2d::ISingleton::Instance() + { + if (!instance_) + instance_.reset(new (std::nothrow) T); + return *instance_; + } + + template + inline void easy2d::ISingleton::Destroy() + { + if (instance_) + instance_.reset(); + } + + template + std::unique_ptr easy2d::ISingleton::instance_; +} + +// Class that will implement the singleton mode, +// must use the macro in it's delare file + +#ifndef E2D_DECLARE_SINGLETON +#define E2D_DECLARE_SINGLETON( type ) \ + friend class ::std::unique_ptr< type >; \ + friend struct ::std::default_delete< type >;\ + friend class ::easy2d::ISingleton< type > +#endif + +#ifndef E2D_DECLARE_SINGLETON_TYPE +#define E2D_DECLARE_SINGLETON_TYPE( type, singleton_type ) using singleton_type = ::easy2d::ISingleton< type > +#endif diff --git a/core/base/Sprite.cpp b/core/base/Sprite.cpp index 3ea0bf95..7ddaa0af 100644 --- a/core/base/Sprite.cpp +++ b/core/base/Sprite.cpp @@ -135,7 +135,7 @@ namespace easy2d if (image_ && image_->GetBitmap()) { auto crop_pos = image_->GetCropPos(); - render::instance.DrawImage( + devices::Graphics::Instance().DrawImage( image_, GetDisplayOpacity(), Rect(Point(), GetTransform().size), diff --git a/core/base/Sprite.h b/core/base/Sprite.h index 23a119c6..2c8123ca 100644 --- a/core/base/Sprite.h +++ b/core/base/Sprite.h @@ -28,6 +28,8 @@ namespace easy2d class Sprite : public Node { + E2D_DISABLE_COPY(Sprite); + public: Sprite(); @@ -81,9 +83,6 @@ namespace easy2d // 渲染精灵 virtual void OnDraw() const override; - private: - E2D_DISABLE_COPY(Sprite); - private: Image* image_; }; diff --git a/core/base/Text.cpp b/core/base/Text.cpp index 34a7fd3c..60595071 100644 --- a/core/base/Text.cpp +++ b/core/base/Text.cpp @@ -318,16 +318,16 @@ namespace easy2d // 创建文本区域 D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, GetTransform().size.width, GetTransform().size.height); // 设置画刷颜色和透明度 - render::instance.SetBrushOpacity(GetDisplayOpacity()); + devices::Graphics::Instance().SetBrushOpacity(GetDisplayOpacity()); // 获取文本渲染器 - render::instance.SetTextStyle( + devices::Graphics::Instance().SetTextStyle( style_.color, style_.outline, style_.outline_color, style_.outline_width, style_.outline_stroke ); - render::instance.DrawTextLayout(text_layout_); + devices::Graphics::Instance().DrawTextLayout(text_layout_); } } @@ -344,7 +344,7 @@ namespace easy2d SafeRelease(text_format_); ThrowIfFailed( - render::instance.CreateTextFormat( + devices::Graphics::Instance().CreateTextFormat( &text_format_, font_ ) @@ -399,7 +399,7 @@ namespace easy2d if (style_.wrap) { ThrowIfFailed( - render::instance.CreateTextLayout( + devices::Graphics::Instance().CreateTextLayout( &text_layout_, text_, text_format_, @@ -416,7 +416,7 @@ namespace easy2d { // 为防止文本对齐问题,根据先创建 layout 以获取宽度 ThrowIfFailed( - render::instance.CreateTextLayout( + devices::Graphics::Instance().CreateTextLayout( &text_layout_, text_, text_format_, @@ -433,7 +433,7 @@ namespace easy2d // 重新创建 layout SafeRelease(text_layout_); ThrowIfFailed( - render::instance.CreateTextLayout( + devices::Graphics::Instance().CreateTextLayout( &text_layout_, text_, text_format_, diff --git a/core/base/Text.h b/core/base/Text.h index cb676210..8a8eb1d7 100644 --- a/core/base/Text.h +++ b/core/base/Text.h @@ -28,6 +28,8 @@ namespace easy2d class Text : public Node { + E2D_DISABLE_COPY(Text); + public: // 文本对齐方式 enum class Align @@ -221,8 +223,6 @@ namespace easy2d virtual void OnDraw() const override; private: - E2D_DISABLE_COPY(Text); - // 重新排版文字 void Reset(); diff --git a/core/base/TextRenderer.cpp b/core/base/TextRenderer.cpp index 0c7dd899..a0a9affd 100644 --- a/core/base/TextRenderer.cpp +++ b/core/base/TextRenderer.cpp @@ -73,7 +73,7 @@ namespace easy2d bShowOutline_ = outline; sOutlineColor_ = outline_color; fOutlineWidth = 2 * outline_width; - pCurrStrokeStyle_ = render::instance.GetStrokeStyle(StrokeStyle(outlineJoin)); + pCurrStrokeStyle_ = devices::Graphics::Instance().GetStrokeStyle(StrokeStyle(outlineJoin)); } STDMETHODIMP ITextRenderer::DrawGlyphRun( diff --git a/core/base/Transition.cpp b/core/base/Transition.cpp index efa4dd13..556c5ee7 100644 --- a/core/base/Transition.cpp +++ b/core/base/Transition.cpp @@ -22,6 +22,7 @@ #include "Node.h" #include "Scene.h" #include "window.h" +#include "render.h" #include "../math/Matrix.hpp" namespace easy2d @@ -73,22 +74,19 @@ namespace easy2d if (in_scene_) { ThrowIfFailed( - render::instance.CreateLayer(&in_layer_) + devices::Graphics::Instance().CreateLayer(&in_layer_) ); } if (out_scene_) { ThrowIfFailed( - render::instance.CreateLayer(&out_layer_) + devices::Graphics::Instance().CreateLayer(&out_layer_) ); } - window_size_ = window::instance.GetSize(); - out_layer_prop_ = in_layer_prop_ = render::LayerProperties{ - Rect(Point(), window_size_), - 1.f - }; + window_size_ = Window::Instance().GetSize(); + out_layer_prop_ = in_layer_prop_ = LayerProperties{ Rect(Point(), window_size_),1.f }; } void Transition::Update() @@ -113,30 +111,30 @@ namespace easy2d { if (out_scene_) { - render::instance.PushClip( + devices::Graphics::Instance().PushClip( out_scene_->GetTransform(), window_size_ ); - render::instance.PushLayer(out_layer_, out_layer_prop_); + devices::Graphics::Instance().PushLayer(out_layer_, out_layer_prop_); out_scene_->Draw(); - render::instance.PopLayer(); - render::instance.PopClip(); + devices::Graphics::Instance().PopLayer(); + devices::Graphics::Instance().PopClip(); } if (in_scene_) { - render::instance.PushClip( + devices::Graphics::Instance().PushClip( in_scene_->GetTransform(), window_size_ ); - render::instance.PushLayer(in_layer_, in_layer_prop_); + devices::Graphics::Instance().PushLayer(in_layer_, in_layer_prop_); in_scene_->Draw(); - render::instance.PopLayer(); - render::instance.PopClip(); + devices::Graphics::Instance().PopLayer(); + devices::Graphics::Instance().PopClip(); } } diff --git a/core/base/Transition.h b/core/base/Transition.h index 29c3e237..e1e558b6 100644 --- a/core/base/Transition.h +++ b/core/base/Transition.h @@ -21,7 +21,6 @@ #pragma once #include "base.h" #include "time.h" -#include "render.h" #include "RefCounter.h" namespace easy2d @@ -75,8 +74,8 @@ namespace easy2d Scene* in_scene_; ID2D1Layer* out_layer_; ID2D1Layer* in_layer_; - render::LayerProperties out_layer_prop_; - render::LayerProperties in_layer_prop_; + LayerProperties out_layer_prop_; + LayerProperties in_layer_prop_; }; diff --git a/core/base/audio.cpp b/core/base/audio.cpp index 66b2306c..eacdecbe 100644 --- a/core/base/audio.cpp +++ b/core/base/audio.cpp @@ -27,18 +27,161 @@ namespace easy2d { - namespace audio + //------------------------------------------------------- + // Voice + //------------------------------------------------------- + + Voice::Voice() + : source_voice_(nullptr) { - AudioDevice instance; + } + + Voice::Voice(IXAudio2SourceVoice * source_voice) + : source_voice_(source_voice) + { + } + + Voice::~Voice() + { + Destroy(); + + devices::Audio::Instance().DeleteVoice(this); + } + + HRESULT Voice::Play(const BYTE * wave_data, UINT32 data_size, UINT32 loop_count) + { + if (!source_voice_) + return E_UNEXPECTED; + + XAUDIO2_BUFFER buffer = { 0 }; + buffer.pAudioData = wave_data; + buffer.Flags = XAUDIO2_END_OF_STREAM; + buffer.AudioBytes = data_size; + buffer.LoopCount = loop_count; + + HRESULT hr = source_voice_->SubmitSourceBuffer(&buffer); + if (SUCCEEDED(hr)) + { + hr = source_voice_->Start(); + } + return hr; + } + + HRESULT Voice::Pause() + { + if (!source_voice_) + return E_UNEXPECTED; + + return source_voice_->Stop(); + } + + HRESULT Voice::Resume() + { + if (!source_voice_) + return E_UNEXPECTED; + + return source_voice_->Start(); + } + + HRESULT Voice::Stop() + { + if (!source_voice_) + return E_UNEXPECTED; + + HRESULT hr = source_voice_->Stop(); + if (SUCCEEDED(hr)) + { + hr = source_voice_->ExitLoop(); + } + + if (SUCCEEDED(hr)) + { + hr = source_voice_->FlushSourceBuffers(); + } + return hr; + } + + HRESULT Voice::GetVolume(float * volume) const + { + if (!source_voice_) + return E_UNEXPECTED; + + if (volume == nullptr) + return E_POINTER; + + source_voice_->GetVolume(volume); + return S_OK; + } + + HRESULT Voice::SetVolume(float volume) + { + if (!source_voice_) + return E_UNEXPECTED; + + volume = std::min(std::max(volume, -224.f), 224.f); + return source_voice_->SetVolume(volume); + } + + HRESULT Voice::GetBuffersQueued(UINT32 * queued) const + { + if (!source_voice_) + return E_UNEXPECTED; + + if (queued == nullptr) + return E_POINTER; + + XAUDIO2_VOICE_STATE state; + source_voice_->GetState(&state); + *queued = state.BuffersQueued; + return S_OK; + } + + void Voice::Destroy() + { + if (source_voice_) + { + source_voice_->Stop(); + source_voice_->FlushSourceBuffers(); + source_voice_->DestroyVoice(); + source_voice_ = nullptr; + } + } + + void Voice::SetSourceVoice(IXAudio2SourceVoice * source_voice) + { + Destroy(); + source_voice_ = source_voice; + } + + + namespace devices + { + //------------------------------------------------------- + // AudioDevice + //------------------------------------------------------- AudioDevice::AudioDevice() : x_audio2_(nullptr) , mastering_voice_(nullptr) { + modules::Initialize(); } AudioDevice::~AudioDevice() { + ClearVoiceCache(); + + if (mastering_voice_) + { + mastering_voice_->DestroyVoice(); + mastering_voice_ = nullptr; + } + + SafeRelease(x_audio2_); + + modules::MediaFoundation.MFShutdown(); + + modules::Destroy(); } void AudioDevice::Initialize() @@ -56,22 +199,42 @@ namespace easy2d ); } - void AudioDevice::Uninitialize() + HRESULT AudioDevice::CreateVoice(Voice* voice, WAVEFORMATEX * wfx) { - if (mastering_voice_) + HRESULT hr; + IXAudio2SourceVoice* source_voice; + + if (!voice) + return E_POINTER; + + hr = x_audio2_->CreateSourceVoice(&source_voice, wfx, 0, XAUDIO2_DEFAULT_FREQ_RATIO); + if (SUCCEEDED(hr)) { - mastering_voice_->DestroyVoice(); - mastering_voice_ = nullptr; + voice->SetSourceVoice(source_voice); + voice_cache_.push_back(voice); } - - SafeRelease(x_audio2_); - - modules::MediaFoundation.MFShutdown(); + return hr; } - HRESULT AudioDevice::CreateVoice(IXAudio2SourceVoice ** voice, WAVEFORMATEX * wfx) + void AudioDevice::DeleteVoice(Voice * voice) { - return x_audio2_->CreateSourceVoice(voice, wfx, 0, XAUDIO2_DEFAULT_FREQ_RATIO); + for (auto iter = voice_cache_.begin(); iter != voice_cache_.end(); ++iter) + { + if (*iter == voice) + { + voice_cache_.erase(iter); + break; + } + } + } + + void AudioDevice::ClearVoiceCache() + { + for (auto voice : voice_cache_) + { + voice->Destroy(); + } + voice_cache_.clear(); } void AudioDevice::Open() diff --git a/core/base/audio.h b/core/base/audio.h index 85115d7d..8fcddf41 100644 --- a/core/base/audio.h +++ b/core/base/audio.h @@ -20,41 +20,97 @@ #pragma once #include "macros.h" +#include "Singleton.hpp" #include namespace easy2d { - namespace audio + class Voice + { + E2D_DISABLE_COPY(Voice); + + public: + Voice(); + + Voice( + IXAudio2SourceVoice* source_voice + ); + + ~Voice(); + + HRESULT Play( + const BYTE* wave_data, + UINT32 data_size, + UINT32 loop_count + ); + + HRESULT Pause(); + + HRESULT Resume(); + + HRESULT Stop(); + + HRESULT GetVolume( + float* volume + ) const; + + HRESULT SetVolume( + float volume + ); + + HRESULT GetBuffersQueued( + UINT32* queued + ) const; + + void Destroy(); + + void SetSourceVoice( + IXAudio2SourceVoice* source_voice + ); + + protected: + IXAudio2SourceVoice* source_voice_; + }; + + namespace devices { - // 音频设备 class AudioDevice { + E2D_DECLARE_SINGLETON(AudioDevice); + + E2D_DISABLE_COPY(AudioDevice); + public: - AudioDevice(); - - ~AudioDevice(); - void Initialize(); - void Uninitialize(); - // 开启设备 void Open(); // 关闭设备 void Close(); - // 创建音源 HRESULT CreateVoice( - IXAudio2SourceVoice ** voice, + Voice* voice, WAVEFORMATEX * wfx ); + void DeleteVoice( + Voice* voice + ); + + void ClearVoiceCache(); + + protected: + AudioDevice(); + + ~AudioDevice(); + protected: IXAudio2 * x_audio2_; IXAudio2MasteringVoice* mastering_voice_; + std::list voice_cache_; }; - extern AudioDevice instance; + E2D_DECLARE_SINGLETON_TYPE(AudioDevice, Audio); } } diff --git a/core/base/base.h b/core/base/base.h index 080a73a1..23344fd5 100644 --- a/core/base/base.h +++ b/core/base/base.h @@ -20,7 +20,6 @@ #pragma once #include "BaseTypes.h" -#include "Rect.hpp" #include namespace easy2d diff --git a/core/base/macros.h b/core/base/macros.h index c47269ea..ff5aa84a 100644 --- a/core/base/macros.h +++ b/core/base/macros.h @@ -80,6 +80,7 @@ #include #include #include +#include #if VS_VER >= VS_2015 @@ -89,9 +90,10 @@ #endif -#define E2D_DISABLE_COPY(Class) \ - Class(const Class &) = delete; \ - Class & operator= (const Class &) = delete +#define E2D_DISABLE_COPY(Class) \ + private: \ + Class(const Class &) = delete; \ + Class & operator= (const Class &) = delete #if defined( DEBUG ) || defined( _DEBUG ) diff --git a/core/base/modules.cpp b/core/base/modules.cpp index 530563cb..a27f7f58 100644 --- a/core/base/modules.cpp +++ b/core/base/modules.cpp @@ -26,6 +26,8 @@ namespace easy2d { namespace { + int initialize_count = 0; + inline void SafeFreeLibrary(HMODULE instance) { if (instance) @@ -38,6 +40,10 @@ namespace easy2d void Initialize() { + initialize_count++; + if (initialize_count > 1) + return; + const auto xaudio2_dll_names = { L"xaudio2_9.dll", @@ -86,8 +92,12 @@ namespace easy2d } } - void Uninitialize() + void Destroy() { + initialize_count--; + if (initialize_count > 0) + return; + SafeFreeLibrary(XAudio2.instance); SafeFreeLibrary(MediaFoundation.mfplat); SafeFreeLibrary(MediaFoundation.mfreadwrite); diff --git a/core/base/modules.h b/core/base/modules.h index 2ce3327a..14c2e27a 100644 --- a/core/base/modules.h +++ b/core/base/modules.h @@ -29,6 +29,12 @@ namespace easy2d { namespace modules { + // modules can be initialized multiple times, + // but it needs to be destroyed every time + void Initialize(); + + void Destroy(); + // XAudio2 functions typedef HRESULT(WINAPI *PFN_XAudio2Create)(IXAudio2**, UINT32, XAUDIO2_PROCESSOR); @@ -66,13 +72,5 @@ namespace easy2d }; extern Module_MediaFoundation MediaFoundation; - - // - // Functions - // - - void Initialize(); - - void Uninitialize(); } } diff --git a/core/base/render.cpp b/core/base/render.cpp index 6344daff..6cbb10f4 100644 --- a/core/base/render.cpp +++ b/core/base/render.cpp @@ -21,6 +21,7 @@ #include "render.h" #include "time.h" #include "base.h" +#include "modules.h" #pragma comment(lib, "d2d1.lib") #pragma comment(lib, "dwrite.lib") @@ -28,33 +29,49 @@ namespace easy2d { - namespace render + namespace devices { - GraphicsDevice instance; - GraphicsDevice::GraphicsDevice() : fps_text_format_(nullptr) , fps_text_layout_(nullptr) , clear_color_(D2D1::ColorF(D2D1::ColorF::Black)) { ZeroMemory(&d2d, sizeof(D2DResources)); + + modules::Initialize(); } GraphicsDevice::~GraphicsDevice() { + ClearImageCache(); + SafeRelease(fps_text_format_); SafeRelease(fps_text_layout_); + + SafeRelease(d2d.text_renderer); + SafeRelease(d2d.solid_brush); + SafeRelease(d2d.render_target); + + SafeRelease(d2d.miter_stroke_style); + SafeRelease(d2d.bevel_stroke_style); + SafeRelease(d2d.round_stroke_style); + + SafeRelease(d2d.imaging_factory); + SafeRelease(d2d.write_factory); + SafeRelease(d2d.factory); + + modules::Destroy(); } void GraphicsDevice::Initialize(HWND hwnd) { - if (d2d.Factory) + if (d2d.factory) return; ThrowIfFailed( D2D1CreateFactory( D2D1_FACTORY_TYPE_SINGLE_THREADED, - &d2d.Factory + &d2d.factory ) ); @@ -64,7 +81,7 @@ namespace easy2d nullptr, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, - reinterpret_cast(&d2d.WICImagingFactory) + reinterpret_cast(&d2d.imaging_factory) ) ); @@ -72,7 +89,7 @@ namespace easy2d DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), - reinterpret_cast(&d2d.DWriteFactory) + reinterpret_cast(&d2d.write_factory) ) ); @@ -87,65 +104,50 @@ namespace easy2d ); ThrowIfFailed( - d2d.Factory->CreateStrokeStyle( + d2d.factory->CreateStrokeStyle( stroke_style, nullptr, 0, - &d2d.MiterStrokeStyle + &d2d.miter_stroke_style ) ); stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL; ThrowIfFailed( - d2d.Factory->CreateStrokeStyle( + d2d.factory->CreateStrokeStyle( stroke_style, nullptr, 0, - &d2d.BevelStrokeStyle + &d2d.bevel_stroke_style ) ); stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND; ThrowIfFailed( - d2d.Factory->CreateStrokeStyle( + d2d.factory->CreateStrokeStyle( stroke_style, nullptr, 0, - &d2d.RoundStrokeStyle + &d2d.round_stroke_style ) ); CreateDeviceResources(hwnd); } - void GraphicsDevice::Uninitialize() - { - SafeRelease(d2d.TextRenderer); - SafeRelease(d2d.SolidColorBrush); - SafeRelease(d2d.HwndRenderTarget); - - SafeRelease(d2d.MiterStrokeStyle); - SafeRelease(d2d.BevelStrokeStyle); - SafeRelease(d2d.RoundStrokeStyle); - - SafeRelease(d2d.WICImagingFactory); - SafeRelease(d2d.DWriteFactory); - SafeRelease(d2d.Factory); - } - void GraphicsDevice::BeginDraw(HWND hwnd) { CreateDeviceResources(hwnd); - d2d.HwndRenderTarget->BeginDraw(); - d2d.HwndRenderTarget->Clear(clear_color_); + d2d.render_target->BeginDraw(); + d2d.render_target->Clear(clear_color_); } void GraphicsDevice::EndDraw() { - HRESULT hr = d2d.HwndRenderTarget->EndDraw(); + HRESULT hr = d2d.render_target->EndDraw(); if (hr == D2DERR_RECREATE_TARGET) { @@ -155,36 +157,48 @@ namespace easy2d SafeRelease(fps_text_format_); SafeRelease(fps_text_layout_); - SafeRelease(d2d.TextRenderer); - SafeRelease(d2d.SolidColorBrush); - SafeRelease(d2d.HwndRenderTarget); + SafeRelease(d2d.text_renderer); + SafeRelease(d2d.solid_brush); + SafeRelease(d2d.render_target); } ThrowIfFailed(hr); } + void GraphicsDevice::ClearImageCache() + { + if (bitmap_cache_.empty()) + return; + + for (const auto& bitmap : bitmap_cache_) + { + bitmap.second->Release(); + } + bitmap_cache_.clear(); + } + HRESULT GraphicsDevice::CreateRectGeometry( const math::Matrix& matrix, const Size& size, ID2D1Geometry** geometry ) const { - if (!d2d.Factory) + if (!d2d.factory) return E_UNEXPECTED; HRESULT hr; ID2D1RectangleGeometry * rectangle = nullptr; ID2D1TransformedGeometry * transformed = nullptr; - - hr = d2d.Factory->CreateRectangleGeometry( + + hr = d2d.factory->CreateRectangleGeometry( D2D1::RectF(0, 0, size.width, size.height), &rectangle ); if (SUCCEEDED(hr)) { - hr = d2d.Factory->CreateTransformedGeometry( + hr = d2d.factory->CreateTransformedGeometry( rectangle, matrix, &transformed @@ -202,10 +216,10 @@ namespace easy2d HRESULT GraphicsDevice::CreateTextFormat(IDWriteTextFormat ** text_format, const Font & font) const { - if (!d2d.DWriteFactory) + if (!d2d.write_factory) return E_UNEXPECTED; - return d2d.DWriteFactory->CreateTextFormat( + return d2d.write_factory->CreateTextFormat( font.family.c_str(), nullptr, DWRITE_FONT_WEIGHT(font.weight), @@ -219,11 +233,11 @@ namespace easy2d HRESULT GraphicsDevice::CreateTextLayout(IDWriteTextLayout ** text_layout, const String & text, IDWriteTextFormat * text_format, float wrap_width) const { - if (!d2d.DWriteFactory) + if (!d2d.write_factory) return E_UNEXPECTED; UINT32 length = static_cast(text.length()); - return d2d.DWriteFactory->CreateTextLayout( + return d2d.write_factory->CreateTextLayout( text.c_str(), length, text_format, @@ -235,10 +249,10 @@ namespace easy2d HRESULT GraphicsDevice::CreateLayer(ID2D1Layer ** layer) { - if (!d2d.HwndRenderTarget) + if (!d2d.render_target) return E_UNEXPECTED; - return d2d.HwndRenderTarget->CreateLayer(layer); + return d2d.render_target->CreateLayer(layer); } HRESULT GraphicsDevice::DrawGeometry( @@ -249,15 +263,15 @@ namespace easy2d StrokeStyle stroke ) { - if (!d2d.SolidColorBrush || - !d2d.HwndRenderTarget) + if (!d2d.solid_brush || + !d2d.render_target) return E_UNEXPECTED; - d2d.SolidColorBrush->SetColor(border_color); - d2d.SolidColorBrush->SetOpacity(opacity); - d2d.HwndRenderTarget->DrawGeometry( + d2d.solid_brush->SetColor(border_color); + d2d.solid_brush->SetOpacity(opacity); + d2d.render_target->DrawGeometry( geometry, - d2d.SolidColorBrush, + d2d.solid_brush, stroke_width, GetStrokeStyle(stroke) ); @@ -270,13 +284,13 @@ namespace easy2d switch (stroke) { case StrokeStyle::Miter: - stroke_style = d2d.MiterStrokeStyle; + stroke_style = d2d.miter_stroke_style; break; case StrokeStyle::Bevel: - stroke_style = d2d.BevelStrokeStyle; + stroke_style = d2d.bevel_stroke_style; break; case StrokeStyle::Round: - stroke_style = d2d.RoundStrokeStyle; + stroke_style = d2d.round_stroke_style; break; } return stroke_style; @@ -289,10 +303,10 @@ namespace easy2d const Rect & source_rect ) { - if (!d2d.HwndRenderTarget) + if (!d2d.render_target) return E_UNEXPECTED; - d2d.HwndRenderTarget->DrawBitmap( + d2d.render_target->DrawBitmap( image->GetBitmap(), dest_rect, opacity, @@ -304,19 +318,19 @@ namespace easy2d HRESULT GraphicsDevice::DrawTextLayout(IDWriteTextLayout * text_layout) { - if (!d2d.TextRenderer) + if (!d2d.text_renderer) return E_UNEXPECTED; - return text_layout->Draw(nullptr, d2d.TextRenderer, 0, 0); + return text_layout->Draw(nullptr, d2d.text_renderer, 0, 0); } HRESULT GraphicsDevice::PushClip(const math::Matrix & clip_matrix, const Size & clip_size) { - if (!d2d.HwndRenderTarget) + if (!d2d.render_target) return E_UNEXPECTED; - d2d.HwndRenderTarget->SetTransform(clip_matrix); - d2d.HwndRenderTarget->PushAxisAlignedClip( + d2d.render_target->SetTransform(clip_matrix); + d2d.render_target->PushAxisAlignedClip( D2D1::RectF(0, 0, clip_size.width, clip_size.height), D2D1_ANTIALIAS_MODE_PER_PRIMITIVE ); @@ -325,27 +339,27 @@ namespace easy2d HRESULT GraphicsDevice::PopClip() { - if (!d2d.HwndRenderTarget) + if (!d2d.render_target) return E_UNEXPECTED; - d2d.HwndRenderTarget->PopAxisAlignedClip(); + d2d.render_target->PopAxisAlignedClip(); return S_OK; } HRESULT GraphicsDevice::PushLayer(ID2D1Layer * layer, LayerProperties properties) { - if (!d2d.HwndRenderTarget || - !d2d.SolidColorBrush) + if (!d2d.render_target || + !d2d.solid_brush) return E_UNEXPECTED; - d2d.HwndRenderTarget->PushLayer( + d2d.render_target->PushLayer( D2D1::LayerParameters( properties.area, nullptr, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, D2D1::Matrix3x2F::Identity(), properties.opacity, - d2d.SolidColorBrush, + d2d.solid_brush, D2D1_LAYER_OPTIONS_NONE ), layer @@ -355,17 +369,17 @@ namespace easy2d HRESULT GraphicsDevice::PopLayer() { - if (!d2d.HwndRenderTarget) + if (!d2d.render_target) return E_UNEXPECTED; - d2d.HwndRenderTarget->PopLayer(); + d2d.render_target->PopLayer(); return S_OK; } HRESULT GraphicsDevice::CreateBitmapFromFile(const String & file_path, ID2D1Bitmap ** bitmap) { - if (d2d.WICImagingFactory == nullptr || - d2d.HwndRenderTarget == nullptr) + if (d2d.imaging_factory == nullptr || + d2d.render_target == nullptr) { return E_UNEXPECTED; } @@ -375,13 +389,20 @@ namespace easy2d return E_POINTER; } + size_t hash_code = std::hash{}(file_path); + if (bitmap_cache_.find(hash_code) != bitmap_cache_.end()) + { + *bitmap = bitmap_cache_[hash_code]; + return S_OK; + } + IWICBitmapDecoder* decoder = nullptr; IWICBitmapFrameDecode* source = nullptr; IWICStream* stream = nullptr; IWICFormatConverter* converter = nullptr; // 创建解码器 - HRESULT hr = d2d.WICImagingFactory->CreateDecoderFromFilename( + HRESULT hr = d2d.imaging_factory->CreateDecoderFromFilename( file_path.c_str(), nullptr, GENERIC_READ, @@ -398,7 +419,7 @@ namespace easy2d if (SUCCEEDED(hr)) { // 创建图片格式转换器 - hr = d2d.WICImagingFactory->CreateFormatConverter(&converter); + hr = d2d.imaging_factory->CreateFormatConverter(&converter); } if (SUCCEEDED(hr)) @@ -417,13 +438,18 @@ namespace easy2d if (SUCCEEDED(hr)) { // 从 WIC 位图创建一个 Direct2D 位图 - hr = d2d.HwndRenderTarget->CreateBitmapFromWicBitmap( + hr = d2d.render_target->CreateBitmapFromWicBitmap( converter, nullptr, bitmap ); } + if (SUCCEEDED(hr)) + { + bitmap_cache_.insert(std::make_pair(hash_code, *bitmap)); + } + // 释放相关资源 SafeRelease(decoder); SafeRelease(source); @@ -435,8 +461,8 @@ namespace easy2d HRESULT GraphicsDevice::CreateBitmapFromResource(Resource & res, ID2D1Bitmap ** bitmap) { - if (d2d.WICImagingFactory == nullptr || - d2d.HwndRenderTarget == nullptr) + if (d2d.imaging_factory == nullptr || + d2d.render_target == nullptr) { return E_UNEXPECTED; } @@ -446,6 +472,13 @@ namespace easy2d return E_POINTER; } + size_t hash_code = res.GetHashCode(); + if (bitmap_cache_.find(hash_code) != bitmap_cache_.end()) + { + *bitmap = bitmap_cache_[hash_code]; + return S_OK; + } + HRESULT hr; HINSTANCE hinstance = GetModuleHandle(nullptr); @@ -453,14 +486,14 @@ namespace easy2d IWICBitmapFrameDecode* source = nullptr; IWICStream* stream = nullptr; IWICFormatConverter* converter = nullptr; - + // 加载资源 hr = res.Load() ? S_OK : E_FAIL; if (SUCCEEDED(hr)) { // 创建 WIC 流 - hr = d2d.WICImagingFactory->CreateStream(&stream); + hr = d2d.imaging_factory->CreateStream(&stream); } if (SUCCEEDED(hr)) @@ -475,7 +508,7 @@ namespace easy2d if (SUCCEEDED(hr)) { // 创建流的解码器 - hr = d2d.WICImagingFactory->CreateDecoderFromStream( + hr = d2d.imaging_factory->CreateDecoderFromStream( stream, nullptr, WICDecodeMetadataCacheOnLoad, @@ -492,7 +525,7 @@ namespace easy2d if (SUCCEEDED(hr)) { // 创建图片格式转换器 - hr = d2d.WICImagingFactory->CreateFormatConverter(&converter); + hr = d2d.imaging_factory->CreateFormatConverter(&converter); } if (SUCCEEDED(hr)) @@ -511,13 +544,18 @@ namespace easy2d if (SUCCEEDED(hr)) { // 从 WIC 位图创建一个 Direct2D 位图 - hr = d2d.HwndRenderTarget->CreateBitmapFromWicBitmap( + hr = d2d.render_target->CreateBitmapFromWicBitmap( converter, nullptr, bitmap ); } + if (SUCCEEDED(hr)) + { + bitmap_cache_.insert(std::make_pair(hash_code, *bitmap)); + } + // 释放相关资源 SafeRelease(decoder); SafeRelease(source); @@ -529,28 +567,28 @@ namespace easy2d HRESULT GraphicsDevice::Resize(UINT32 width, UINT32 height) { - if (!d2d.HwndRenderTarget) + if (!d2d.render_target) return E_UNEXPECTED; - d2d.HwndRenderTarget->Resize(D2D1::SizeU(width, height)); + d2d.render_target->Resize(D2D1::SizeU(width, height)); return S_OK; } HRESULT GraphicsDevice::SetTransform(const math::Matrix & matrix) { - if (!d2d.HwndRenderTarget) + if (!d2d.render_target) return E_UNEXPECTED; - d2d.HwndRenderTarget->SetTransform(matrix); + d2d.render_target->SetTransform(matrix); return S_OK; } HRESULT GraphicsDevice::SetBrushOpacity(float opacity) { - if (!d2d.HwndRenderTarget) + if (!d2d.render_target) return E_UNEXPECTED; - d2d.SolidColorBrush->SetOpacity(opacity); + d2d.solid_brush->SetOpacity(opacity); return S_OK; } @@ -562,10 +600,10 @@ namespace easy2d StrokeStyle outline_stroke ) { - if (!d2d.TextRenderer) + if (!d2d.text_renderer) return E_UNEXPECTED; - d2d.TextRenderer->SetTextStyle( + d2d.text_renderer->SetTextStyle( color, has_outline, outline_color, @@ -590,7 +628,7 @@ namespace easy2d if (!fps_text_format_) { ThrowIfFailed( - d2d.DWriteFactory->CreateTextFormat( + d2d.write_factory->CreateTextFormat( L"", nullptr, DWRITE_FONT_WEIGHT_NORMAL, @@ -621,7 +659,7 @@ namespace easy2d SafeRelease(fps_text_layout_); ThrowIfFailed( - d2d.DWriteFactory->CreateTextLayout( + d2d.write_factory->CreateTextLayout( fps_text, static_cast(len), fps_text_format_, @@ -634,9 +672,9 @@ namespace easy2d if (fps_text_layout_) { - d2d.HwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); - d2d.SolidColorBrush->SetOpacity(1.0f); - d2d.TextRenderer->SetTextStyle( + d2d.render_target->SetTransform(D2D1::Matrix3x2F::Identity()); + d2d.solid_brush->SetOpacity(1.0f); + d2d.text_renderer->SetTextStyle( D2D1::ColorF(D2D1::ColorF::White), TRUE, D2D1::ColorF(D2D1::ColorF::Black, 0.4f), @@ -644,13 +682,13 @@ namespace easy2d D2D1_LINE_JOIN_ROUND ); - fps_text_layout_->Draw(nullptr, d2d.TextRenderer, 10, 0); + fps_text_layout_->Draw(nullptr, d2d.text_renderer, 10, 0); } } void GraphicsDevice::CreateDeviceResources(HWND hwnd) { - if (!d2d.HwndRenderTarget) + if (!d2d.render_target) { RECT rc; ::GetClientRect(hwnd, &rc); @@ -663,35 +701,35 @@ namespace easy2d // 创建设备相关资源。这些资源应在 Direct2D 设备消失时重建 // 创建一个 Direct2D 渲染目标 ThrowIfFailed( - d2d.Factory->CreateHwndRenderTarget( + d2d.factory->CreateHwndRenderTarget( D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties( hwnd, size, D2D1_PRESENT_OPTIONS_NONE), - &d2d.HwndRenderTarget + &d2d.render_target ) ); } - if (!d2d.SolidColorBrush) + if (!d2d.solid_brush) { ThrowIfFailed( - d2d.HwndRenderTarget->CreateSolidColorBrush( + d2d.render_target->CreateSolidColorBrush( D2D1::ColorF(D2D1::ColorF::White), - &d2d.SolidColorBrush + &d2d.solid_brush ) ); } - if (!d2d.TextRenderer) + if (!d2d.text_renderer) { ThrowIfFailed( ITextRenderer::Create( - &d2d.TextRenderer, - d2d.Factory, - d2d.HwndRenderTarget, - d2d.SolidColorBrush + &d2d.text_renderer, + d2d.factory, + d2d.render_target, + d2d.solid_brush ) ); } diff --git a/core/base/render.h b/core/base/render.h index 2d446bd0..4ff7d778 100644 --- a/core/base/render.h +++ b/core/base/render.h @@ -20,6 +20,7 @@ #pragma once #include "base.h" +#include "Singleton.hpp" #include "Font.h" #include "Resource.h" #include "Image.h" @@ -28,38 +29,31 @@ namespace easy2d { - namespace render + namespace devices { - typedef struct + struct D2DResources { - ID2D1Factory* Factory; - IWICImagingFactory* WICImagingFactory; - IDWriteFactory* DWriteFactory; - ITextRenderer* TextRenderer; - ID2D1SolidColorBrush* SolidColorBrush; - ID2D1HwndRenderTarget* HwndRenderTarget; - ID2D1StrokeStyle* MiterStrokeStyle; - ID2D1StrokeStyle* BevelStrokeStyle; - ID2D1StrokeStyle* RoundStrokeStyle; - } D2DResources; + ID2D1Factory* factory; + IWICImagingFactory* imaging_factory; + IDWriteFactory* write_factory; + ITextRenderer* text_renderer; + ID2D1SolidColorBrush* solid_brush; + ID2D1HwndRenderTarget* render_target; + ID2D1StrokeStyle* miter_stroke_style; + ID2D1StrokeStyle* bevel_stroke_style; + ID2D1StrokeStyle* round_stroke_style; + }; - typedef struct - { - Rect area; - float opacity; - } LayerProperties; class GraphicsDevice { + E2D_DECLARE_SINGLETON(GraphicsDevice); + + E2D_DISABLE_COPY(GraphicsDevice); + public: - GraphicsDevice(); - - ~GraphicsDevice(); - void Initialize(HWND hwnd); - void Uninitialize(); - // 开始渲染 void BeginDraw(HWND hwnd); @@ -166,13 +160,21 @@ namespace easy2d UINT32 height ); + void ClearImageCache(); + protected: - D2D1_COLOR_F clear_color_; - IDWriteTextFormat* fps_text_format_; - IDWriteTextLayout* fps_text_layout_; - D2DResources d2d; + GraphicsDevice(); + + ~GraphicsDevice(); + + protected: + D2DResources d2d; + D2D1_COLOR_F clear_color_; + IDWriteTextFormat* fps_text_format_; + IDWriteTextLayout* fps_text_layout_; + std::map bitmap_cache_; }; - extern GraphicsDevice instance; + E2D_DECLARE_SINGLETON_TYPE(GraphicsDevice, Graphics); } } diff --git a/core/base/window.cpp b/core/base/window.cpp index 5cf11407..464a4cd2 100644 --- a/core/base/window.cpp +++ b/core/base/window.cpp @@ -33,332 +33,342 @@ namespace easy2d { - namespace window + namespace { - namespace + void GetContentScale(float* scale_x, float* scale_y); + + Rect LocateWindow(int width, int height, float scale_x, float scale_y); + + LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param); + } + + WindowInfo::WindowInfo() + : handle(nullptr) + , scale_x(1.f) + , scale_y(1.f) + { + } + + WindowInfo::~WindowInfo() + { + if (handle) + ::DestroyWindow(handle); + } + + void WindowInfo::Initialize(String title, int width, int height, LPCWSTR icon, bool debug) + { + HINSTANCE hinstance = GetModuleHandle(nullptr); + WNDCLASSEX wcex = { 0 }; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.lpszClassName = REGISTER_CLASS; + wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; + wcex.lpfnWndProc = WndProc; + wcex.hIcon = nullptr; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = sizeof(LONG_PTR); + wcex.hInstance = hinstance; + wcex.hbrBackground = nullptr; + wcex.lpszMenuName = nullptr; + wcex.hCursor = ::LoadCursor(nullptr, IDC_ARROW); + + if (icon) { - void GetContentScale(float* xscale, float* yscale); - - Rect LocateWindow(int width, int height); - - LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param); - } - - WindowInfo instance; - - WindowInfo::WindowInfo() - : handle(nullptr) - , xscale(1.f) - , yscale(1.f) - { - } - - void WindowInfo::Initialize(const Property& property) - { - HINSTANCE hinstance = GetModuleHandle(nullptr); - WNDCLASSEX wcex = { 0 }; - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.lpszClassName = REGISTER_CLASS; - wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; - wcex.lpfnWndProc = WndProc; - wcex.hIcon = nullptr; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = sizeof(LONG_PTR); - wcex.hInstance = hinstance; - wcex.hbrBackground = nullptr; - wcex.lpszMenuName = nullptr; - wcex.hCursor = ::LoadCursor(nullptr, IDC_ARROW); - - if (property.icon) - { - wcex.hIcon = (HICON)::LoadImage( - hinstance, - property.icon, - IMAGE_ICON, - 0, - 0, - LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE - ); - } - - ::RegisterClassEx(&wcex); - - GetContentScale(&xscale, &yscale); - - // 计算窗口大小 - Rect client_rect = LocateWindow(property.width, property.height); - - // 创建窗口 - handle = ::CreateWindowEx( - NULL, - REGISTER_CLASS, - property.title.c_str(), - WINDOW_STYLE, - static_cast(client_rect.origin.x), - static_cast(client_rect.origin.y), - static_cast(client_rect.size.width), - static_cast(client_rect.size.height), - nullptr, - nullptr, + wcex.hIcon = (HICON)::LoadImage( hinstance, - this + icon, + IMAGE_ICON, + 0, + 0, + LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE ); - - if (handle == nullptr) - { - ::UnregisterClass(REGISTER_CLASS, hinstance); - throw std::runtime_error("Create window failed"); - } - - // 禁用输入法 - ::ImmAssociateContext(handle, nullptr); } - void WindowInfo::Destroy() + ::RegisterClassEx(&wcex); + + GetContentScale(&scale_x, &scale_y); + + // 计算窗口大小 + Rect client_rect = LocateWindow(width, height, scale_x, scale_y); + + // 创建窗口 + handle = ::CreateWindowEx( + NULL, + REGISTER_CLASS, + title.c_str(), + WINDOW_STYLE, + static_cast(client_rect.origin.x), + static_cast(client_rect.origin.y), + static_cast(client_rect.size.width), + static_cast(client_rect.size.height), + nullptr, + nullptr, + hinstance, + this + ); + + if (handle == nullptr) { - if (handle) - ::DestroyWindow(handle); + ::UnregisterClass(REGISTER_CLASS, hinstance); + throw std::runtime_error("Create window failed"); } - String WindowInfo::GetTitle() const + // 禁用输入法 + ::ImmAssociateContext(handle, nullptr); + } + + String WindowInfo::GetTitle() const + { + if (handle) { - if (handle) - { - wchar_t title[256]; - GetWindowTextW(handle, title, 256); - return title; - } - return String(); + wchar_t title[256]; + GetWindowTextW(handle, title, 256); + return title; } + return String(); + } - void WindowInfo::SetTitle(const String& title) + void WindowInfo::SetTitle(const String& title) + { + if (handle) + ::SetWindowText(handle, title.c_str()); + } + + Size WindowInfo::GetSize() const + { + if (handle) { - if (handle) - ::SetWindowText(handle, title.c_str()); + RECT rect; + GetClientRect(handle, &rect); + return Size( + static_cast(rect.right - rect.left), + static_cast(rect.bottom - rect.top) + ); } + return Size(); + } - Size WindowInfo::GetSize() const + float WindowInfo::GetWidth() const + { + return GetSize().width; + } + + float WindowInfo::GetHeight() const + { + return GetSize().height; + } + + void WindowInfo::SetSize(int width, int height) + { + if (handle) { - if (handle) - { - RECT rect; - GetClientRect(handle, &rect); - return Size( - static_cast(rect.right - rect.left), - static_cast(rect.bottom - rect.top) - ); - } - return Size(); - } - - float WindowInfo::GetWidth() const - { - return GetSize().width; - } - - float WindowInfo::GetHeight() const - { - return GetSize().height; - } - - void WindowInfo::SetSize(int width, int height) - { - if (handle) - { - Rect rect = LocateWindow(width, height); - ::MoveWindow( - handle, - static_cast(rect.origin.x), - static_cast(rect.origin.y), - static_cast(rect.size.width), - static_cast(rect.size.height), - TRUE - ); - } - } - - void WindowInfo::SetIcon(LPCWSTR icon_resource) - { - if (handle) - { - HINSTANCE hinstance = GetModuleHandle(nullptr); - HICON icon = (HICON)::LoadImage( - hinstance, - icon_resource, - IMAGE_ICON, - 0, - 0, - LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE - ); - - ::SendMessage(handle, WM_SETICON, ICON_BIG, (LPARAM)icon); - ::SendMessage(handle, WM_SETICON, ICON_SMALL, (LPARAM)icon); - } - } - - namespace - { - void GetContentScale(float* xscale, float* yscale) - { - const float DEFAULT_SCREEN_DPI = 96.f; - const HDC dc = GetDC(NULL); - float xdpi = static_cast(GetDeviceCaps(dc, LOGPIXELSX)); - float ydpi = static_cast(GetDeviceCaps(dc, LOGPIXELSY)); - ReleaseDC(NULL, dc); - - if (xscale) - *xscale = xdpi / DEFAULT_SCREEN_DPI; - if (yscale) - *yscale = ydpi / DEFAULT_SCREEN_DPI; - } - - Rect LocateWindow(int width, int height) - { - int max_width = ::GetSystemMetrics(SM_CXSCREEN); - int max_height = ::GetSystemMetrics(SM_CYSCREEN); - RECT rect = - { - 0, - 0, - static_cast(math::Ceil(width * instance.xscale)), - static_cast(math::Ceil(height * instance.yscale)) - }; - - // 计算合适的窗口大小 - ::AdjustWindowRectEx(&rect, WINDOW_STYLE, FALSE, NULL); - width = static_cast(rect.right - rect.left); - height = static_cast(rect.bottom - rect.top); - - // 当输入的窗口大小比分辨率大时,给出警告 - E2D_WARNING_IF(max_width < width || max_height < height, "The window Is larger than screen!"); - width = std::min(width, max_width); - height = std::min(height, max_height); - - return Rect( - static_cast((max_width - width) / 2), - static_cast((max_height - height) / 2), - static_cast(width), - static_cast(height) - ); - } - - LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param) - { - LRESULT result = 0; - bool was_handled = false; - - Game * game = reinterpret_cast( - static_cast(::GetWindowLongPtrW(hwnd, GWLP_USERDATA)) - ); - - switch (msg) - { - - // 处理鼠标消息 - case WM_LBUTTONUP: - case WM_LBUTTONDOWN: - case WM_LBUTTONDBLCLK: - case WM_MBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONDBLCLK: - case WM_RBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONDBLCLK: - case WM_MOUSEMOVE: - case WM_MOUSEWHEEL: - { - if (game->IsTransitioning()) - break; - - auto curr_scene = game->GetCurrentScene(); - if (curr_scene) - { - curr_scene->Dispatch(MouseEvent(msg, w_param, l_param)); - } - } - result = 0; - was_handled = true; - break; - - // 处理按键消息 - case WM_KEYDOWN: - case WM_KEYUP: - { - if (game->IsTransitioning()) - break; - - auto curr_scene = game->GetCurrentScene(); - if (curr_scene) - { - curr_scene->Dispatch(KeyEvent(msg, w_param, l_param)); - } - } - result = 0; - was_handled = true; - break; - - // 处理窗口大小变化消息 - case WM_SIZE: - { - UINT width = LOWORD(l_param); - UINT height = HIWORD(l_param); - - // 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染 - // 目标的大小。它可能会调用失败,但是这里可以忽略有可能的 - // 错误,因为这个错误将在下一次调用 EndDraw 时产生 - render::instance.Resize(width, height); - } - break; - - // 处理分辨率变化消息 - case WM_DISPLAYCHANGE: - { - // 重绘客户区 - ::InvalidateRect(hwnd, nullptr, FALSE); - } - result = 0; - was_handled = true; - break; - - // 重绘窗口 - case WM_PAINT: - { - game->DrawScene(); - ::ValidateRect(hwnd, nullptr); - } - result = 0; - was_handled = true; - break; - - // 窗口关闭消息 - case WM_CLOSE: - { - if (game->OnClose()) - { - game->Quit(); - } - } - result = 0; - was_handled = true; - break; - - // 窗口销毁消息 - case WM_DESTROY: - { - ::PostQuitMessage(0); - } - result = 1; - was_handled = true; - break; - - } - - if (!was_handled) - { - result = ::DefWindowProc(hwnd, msg, w_param, l_param); - } - return result; - } + Rect rect = LocateWindow(width, height, scale_x, scale_y); + ::MoveWindow( + handle, + static_cast(rect.origin.x), + static_cast(rect.origin.y), + static_cast(rect.size.width), + static_cast(rect.size.height), + TRUE + ); } } -} \ No newline at end of file + + void WindowInfo::SetIcon(LPCWSTR icon_resource) + { + if (handle) + { + HINSTANCE hinstance = GetModuleHandle(nullptr); + HICON icon = (HICON)::LoadImage( + hinstance, + icon_resource, + IMAGE_ICON, + 0, + 0, + LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE + ); + + ::SendMessage(handle, WM_SETICON, ICON_BIG, (LPARAM)icon); + ::SendMessage(handle, WM_SETICON, ICON_SMALL, (LPARAM)icon); + } + } + + HWND WindowInfo::GetHandle() const + { + return handle; + } + + float WindowInfo::GetContentScaleX() const + { + return scale_x; + } + + float WindowInfo::GetContentScaleY() const + { + return scale_y; + } + + namespace + { + void GetContentScale(float* scale_x, float* scale_y) + { + const float DEFAULT_SCREEN_DPI = 96.f; + const HDC dc = GetDC(NULL); + float xdpi = static_cast(GetDeviceCaps(dc, LOGPIXELSX)); + float ydpi = static_cast(GetDeviceCaps(dc, LOGPIXELSY)); + ReleaseDC(NULL, dc); + + if (scale_x) + *scale_x = xdpi / DEFAULT_SCREEN_DPI; + if (scale_y) + *scale_y = ydpi / DEFAULT_SCREEN_DPI; + } + + Rect LocateWindow(int width, int height, float scale_x, float scale_y) + { + int max_width = ::GetSystemMetrics(SM_CXSCREEN); + int max_height = ::GetSystemMetrics(SM_CYSCREEN); + RECT rect = + { + 0, + 0, + static_cast(math::Ceil(width * scale_x)), + static_cast(math::Ceil(height * scale_y)) + }; + + // 计算合适的窗口大小 + ::AdjustWindowRectEx(&rect, WINDOW_STYLE, FALSE, NULL); + width = static_cast(rect.right - rect.left); + height = static_cast(rect.bottom - rect.top); + + // 当输入的窗口大小比分辨率大时,给出警告 + E2D_WARNING_IF(max_width < width || max_height < height, "The window Is larger than screen!"); + width = std::min(width, max_width); + height = std::min(height, max_height); + + return Rect( + static_cast((max_width - width) / 2), + static_cast((max_height - height) / 2), + static_cast(width), + static_cast(height) + ); + } + + LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param) + { + LRESULT result = 0; + bool was_handled = false; + + Game * game = reinterpret_cast( + static_cast(::GetWindowLongPtrW(hwnd, GWLP_USERDATA)) + ); + + switch (msg) + { + + // 处理鼠标消息 + case WM_LBUTTONUP: + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_MBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONDBLCLK: + case WM_MOUSEMOVE: + case WM_MOUSEWHEEL: + { + if (game->IsTransitioning()) + break; + + auto curr_scene = game->GetCurrentScene(); + if (curr_scene) + { + curr_scene->Dispatch(MouseEvent(msg, w_param, l_param)); + } + } + result = 0; + was_handled = true; + break; + + // 处理按键消息 + case WM_KEYDOWN: + case WM_KEYUP: + { + if (game->IsTransitioning()) + break; + + auto curr_scene = game->GetCurrentScene(); + if (curr_scene) + { + curr_scene->Dispatch(KeyEvent(msg, w_param, l_param)); + } + } + result = 0; + was_handled = true; + break; + + // 处理窗口大小变化消息 + case WM_SIZE: + { + UINT width = LOWORD(l_param); + UINT height = HIWORD(l_param); + + // 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染 + // 目标的大小。它可能会调用失败,但是这里可以忽略有可能的 + // 错误,因为这个错误将在下一次调用 EndDraw 时产生 + devices::Graphics::Instance().Resize(width, height); + } + break; + + // 处理分辨率变化消息 + case WM_DISPLAYCHANGE: + { + // 重绘客户区 + ::InvalidateRect(hwnd, nullptr, FALSE); + } + result = 0; + was_handled = true; + break; + + // 重绘窗口 + case WM_PAINT: + { + game->DrawScene(); + ::ValidateRect(hwnd, nullptr); + } + result = 0; + was_handled = true; + break; + + // 窗口关闭消息 + case WM_CLOSE: + { + if (game->OnClose()) + { + game->Quit(); + } + } + result = 0; + was_handled = true; + break; + + // 窗口销毁消息 + case WM_DESTROY: + { + ::PostQuitMessage(0); + } + result = 1; + was_handled = true; + break; + + } + + if (!was_handled) + { + result = ::DefWindowProc(hwnd, msg, w_param, l_param); + } + return result; + } + } +} diff --git a/core/base/window.h b/core/base/window.h index ee9dc8f8..299bef20 100644 --- a/core/base/window.h +++ b/core/base/window.h @@ -20,64 +20,64 @@ #pragma once #include "base.h" +#include "Singleton.hpp" namespace easy2d { - namespace window + + + class WindowInfo { - typedef struct Property - { - String title; /* 标题 */ - int width; /* 宽度 */ - int height; /* 高度 */ - LPCWSTR icon; /* 图标 */ + E2D_DECLARE_SINGLETON(WindowInfo); - Property() - : title(L"Easy2D Game") - , width(640) - , height(480) - , icon(nullptr) - {} - } Property; + E2D_DISABLE_COPY(WindowInfo); - class WindowInfo - { - public: - HWND handle; - float xscale; - float yscale; + public: + void Initialize( + String title, + int width, + int height, + LPCWSTR icon, + bool debug + ); - public: - WindowInfo(); + // 获取标题 + String GetTitle() const; - void Initialize( - const Property& property - ); + // 设置标题 + void SetTitle(const String& title); - void Destroy(); + // 获取窗口大小 + Size GetSize() const; - // 获取标题 - String GetTitle() const; + // 获取窗口宽度 + float GetWidth() const; - // 设置标题 - void SetTitle(const String& title); + // 获取窗口高度 + float GetHeight() const; - // 获取窗口大小 - Size GetSize() const; + // 重设窗口大小 + void SetSize(int width, int height); - // 获取窗口宽度 - float GetWidth() const; + // 设置窗口图标 + void SetIcon(LPCWSTR icon_resource); - // 获取窗口高度 - float GetHeight() const; + HWND GetHandle() const; - // 重设窗口大小 - void SetSize(int width, int height); + float GetContentScaleX() const; - // 设置窗口图标 - void SetIcon(LPCWSTR icon_resource); - }; + float GetContentScaleY() const; - extern WindowInfo instance; - } + protected: + WindowInfo(); + + ~WindowInfo(); + + private: + HWND handle; + float scale_x; + float scale_y; + }; + + E2D_DECLARE_SINGLETON_TYPE(WindowInfo, Window); } diff --git a/core/easy2d.h b/core/easy2d.h index d89ebbcb..09cb6870 100644 --- a/core/easy2d.h +++ b/core/easy2d.h @@ -60,6 +60,7 @@ #include "base/CallFunc.h" #include "base/Canvas.h" #include "base/Transition.h" +#include "base/Music.h" #include "base/KeyEvent.h" #include "base/MouseEvent.h" @@ -85,9 +86,8 @@ #include "utils/Path.h" #include "utils/Data.h" #include "utils/File.h" -#include "utils/Transcoder.h" -#include "utils/Music.h" #include "utils/Player.h" +#include "utils/Transcoder.h" // diff --git a/core/math/Matrix.hpp b/core/math/Matrix.hpp index 367d5b64..34bf97af 100644 --- a/core/math/Matrix.hpp +++ b/core/math/Matrix.hpp @@ -112,9 +112,9 @@ namespace easy2d return *this; } - inline Matrix& Scale(float xscale, float yscale, const Vector2& center) + inline Matrix& Scale(float scale_x, float scale_y, const Vector2& center) { - *this = *this * Matrix::Scaling(xscale, yscale, center); + *this = *this * Matrix::Scaling(scale_x, scale_y, center); return *this; } diff --git a/core/math/vector.hpp b/core/math/vector.hpp index 311e8aa5..2e8a0c96 100644 --- a/core/math/vector.hpp +++ b/core/math/vector.hpp @@ -50,6 +50,16 @@ namespace easy2d , y(other.y) {} + inline float Length() const + { + return math::Sqrt(x * x + y * y); + } + + inline float Distance(const Vector2& v) + { + return Vector2(x - v.x, y - v.y).Length(); + } + inline Vector2 operator + (const Vector2 & other) const { return Vector2(x + other.x, y + other.y); @@ -80,13 +90,6 @@ namespace easy2d return (x == other.x) && (y == other.y); } - inline float Length() const { return math::Sqrt(x * x + y * y); } - - inline float Distance(const Vector2& v) - { - return Vector2(x - v.x, y - v.y).Length(); - } - inline operator D2D1_POINT_2F () const { return D2D1_POINT_2F{ x, y }; diff --git a/core/ui/Button.cpp b/core/ui/Button.cpp index 252f49f8..87ae9e7b 100644 --- a/core/ui/Button.cpp +++ b/core/ui/Button.cpp @@ -223,7 +223,7 @@ namespace easy2d if (IsVisible() && !enabled_ && normal_ && - normal_->ContainsPoint(input::instance.GetMousePos())) + normal_->ContainsPoint(devices::Input::Instance().GetMousePos())) { HCURSOR hcursor = ::LoadCursor(nullptr, IDC_NO); if (hcursor) diff --git a/core/ui/Button.h b/core/ui/Button.h index 705d97f6..3efe2f95 100644 --- a/core/ui/Button.h +++ b/core/ui/Button.h @@ -29,6 +29,8 @@ namespace easy2d class Button : public Node { + E2D_DISABLE_COPY(Button); + typedef std::function Callback; public: @@ -101,8 +103,6 @@ namespace easy2d ) override; private: - E2D_DISABLE_COPY(Button); - // 按钮状态枚举 enum class Status { Normal, Mouseover, Selected }; diff --git a/core/ui/Menu.h b/core/ui/Menu.h index 26bba220..c2b4ac5a 100644 --- a/core/ui/Menu.h +++ b/core/ui/Menu.h @@ -30,6 +30,8 @@ namespace easy2d class Menu : public Node { + E2D_DISABLE_COPY(Menu); + public: Menu(); @@ -61,9 +63,6 @@ namespace easy2d // 获取所有按钮 const std::vector& GetAllButtons() const; - private: - E2D_DISABLE_COPY(Menu); - private: bool enabled_; std::vector buttons_; diff --git a/core/utils/Path.cpp b/core/utils/Path.cpp index 1c435442..583b8e88 100644 --- a/core/utils/Path.cpp +++ b/core/utils/Path.cpp @@ -62,7 +62,7 @@ namespace easy2d { // 设置数据的保存路径 String local_app_data_path = Path::GetLocalAppDataPath(); - String title = window::instance.GetTitle(); + String title = Window::Instance().GetTitle(); String folder_name = std::to_wstring(std::hash{}(title)); if (!local_app_data_path.empty()) @@ -90,7 +90,7 @@ namespace easy2d { // 设置临时文件保存路径 wchar_t path[_MAX_PATH]; - String title = window::instance.GetTitle(); + String title = Window::Instance().GetTitle(); String folder_name = std::to_wstring(std::hash{}(title)); if (0 != ::GetTempPath(_MAX_PATH, path)) diff --git a/core/utils/Player.cpp b/core/utils/Player.cpp index f4642c13..ed84d6d7 100644 --- a/core/utils/Player.cpp +++ b/core/utils/Player.cpp @@ -19,15 +19,10 @@ // THE SOFTWARE. #include "Player.h" -#include "Music.h" +#include "../base/Music.h" namespace easy2d { - namespace - { - std::map musics_; - } - Player::Player() : volume_(1.f) { @@ -35,6 +30,7 @@ namespace easy2d Player::~Player() { + ClearCache(); } bool Player::Load(const String & file_path) @@ -51,7 +47,7 @@ namespace easy2d music->SetVolume(volume_); size_t hash_code = std::hash{}(file_path); - musics_.insert(std::make_pair(hash_code, music)); + musics_cache_.insert(std::make_pair(hash_code, music)); return true; } else @@ -69,7 +65,7 @@ namespace easy2d if (Load(file_path)) { - auto music = musics_[std::hash{}(file_path)]; + auto music = musics_cache_[std::hash{}(file_path)]; if (music->Play(loop_count)) { return true; @@ -84,8 +80,8 @@ namespace easy2d return; size_t hash_code = std::hash{}(file_path); - if (musics_.end() != musics_.find(hash_code)) - musics_[hash_code]->Pause(); + if (musics_cache_.end() != musics_cache_.find(hash_code)) + musics_cache_[hash_code]->Pause(); } void Player::Resume(const String & file_path) @@ -94,8 +90,8 @@ namespace easy2d return; size_t hash_code = std::hash{}(file_path); - if (musics_.end() != musics_.find(hash_code)) - musics_[hash_code]->Resume(); + if (musics_cache_.end() != musics_cache_.find(hash_code)) + musics_cache_[hash_code]->Resume(); } void Player::Stop(const String & file_path) @@ -104,8 +100,8 @@ namespace easy2d return; size_t hash_code = std::hash{}(file_path); - if (musics_.end() != musics_.find(hash_code)) - musics_[hash_code]->Stop(); + if (musics_cache_.end() != musics_cache_.find(hash_code)) + musics_cache_[hash_code]->Stop(); } bool Player::IsPlaying(const String & file_path) @@ -114,15 +110,15 @@ namespace easy2d return false; size_t hash_code = std::hash{}(file_path); - if (musics_.end() != musics_.find(hash_code)) - return musics_[hash_code]->IsPlaying(); + if (musics_cache_.end() != musics_cache_.find(hash_code)) + return musics_cache_[hash_code]->IsPlaying(); return false; } bool Player::Load(Resource& res) { size_t hash_code = res.GetHashCode(); - if (musics_.end() != musics_.find(hash_code)) + if (musics_cache_.end() != musics_cache_.find(hash_code)) return true; Music * music = new (std::nothrow) Music(); @@ -132,7 +128,7 @@ namespace easy2d if (music->Load(res)) { music->SetVolume(volume_); - musics_.insert(std::make_pair(hash_code, music)); + musics_cache_.insert(std::make_pair(hash_code, music)); return true; } else @@ -148,7 +144,7 @@ namespace easy2d if (Load(res)) { size_t hash_code = res.GetHashCode(); - auto music = musics_[hash_code]; + auto music = musics_cache_[hash_code]; if (music->Play(loop_count)) { return true; @@ -160,29 +156,29 @@ namespace easy2d void Player::Pause(Resource& res) { size_t hash_code = res.GetHashCode(); - if (musics_.end() != musics_.find(hash_code)) - musics_[hash_code]->Pause(); + if (musics_cache_.end() != musics_cache_.find(hash_code)) + musics_cache_[hash_code]->Pause(); } void Player::Resume(Resource& res) { size_t hash_code = res.GetHashCode(); - if (musics_.end() != musics_.find(hash_code)) - musics_[hash_code]->Resume(); + if (musics_cache_.end() != musics_cache_.find(hash_code)) + musics_cache_[hash_code]->Resume(); } void Player::Stop(Resource& res) { size_t hash_code = res.GetHashCode(); - if (musics_.end() != musics_.find(hash_code)) - musics_[hash_code]->Stop(); + if (musics_cache_.end() != musics_cache_.find(hash_code)) + musics_cache_[hash_code]->Stop(); } bool Player::IsPlaying(Resource& res) { size_t hash_code = res.GetHashCode(); - if (musics_.end() != musics_.find(hash_code)) - return musics_[hash_code]->IsPlaying(); + if (musics_cache_.end() != musics_cache_.find(hash_code)) + return musics_cache_[hash_code]->IsPlaying(); return false; } @@ -194,7 +190,7 @@ namespace easy2d void Player::SetVolume(float volume) { volume_ = std::min(std::max(volume, -224.f), 224.f); - for (const auto& pair : musics_) + for (const auto& pair : musics_cache_) { pair.second->SetVolume(volume_); } @@ -202,7 +198,7 @@ namespace easy2d void Player::PauseAll() { - for (const auto& pair : musics_) + for (const auto& pair : musics_cache_) { pair.second->Pause(); } @@ -210,7 +206,7 @@ namespace easy2d void Player::ResumeAll() { - for (const auto& pair : musics_) + for (const auto& pair : musics_cache_) { pair.second->Resume(); } @@ -218,7 +214,7 @@ namespace easy2d void Player::StopAll() { - for (const auto& pair : musics_) + for (const auto& pair : musics_cache_) { pair.second->Stop(); } @@ -226,13 +222,13 @@ namespace easy2d void Player::ClearCache() { - if (musics_.empty()) + if (musics_cache_.empty()) return; - for (const auto& pair : musics_) + for (const auto& pair : musics_cache_) { pair.second->Release(); } - musics_.clear(); + musics_cache_.clear(); } } \ No newline at end of file diff --git a/core/utils/Player.h b/core/utils/Player.h index 91ecfc5f..54ef2d98 100644 --- a/core/utils/Player.h +++ b/core/utils/Player.h @@ -24,9 +24,13 @@ namespace easy2d { + class Music; + // 音乐播放器 class Player { + E2D_DISABLE_COPY(Player); + public: Player(); @@ -112,12 +116,10 @@ namespace easy2d void StopAll(); // 清除缓存 - static void ClearCache(); - - protected: - E2D_DISABLE_COPY(Player); + void ClearCache(); protected: float volume_; + std::map musics_cache_; }; } diff --git a/core/utils/Transcoder.cpp b/core/utils/Transcoder.cpp index 0e7429f2..56572d84 100644 --- a/core/utils/Transcoder.cpp +++ b/core/utils/Transcoder.cpp @@ -45,7 +45,7 @@ namespace easy2d return wave_format_; } - bool Transcoder::LoadMediaFile(LPCWSTR file_path, BYTE** wave_data, UINT32* wave_data_size) + HRESULT Transcoder::LoadMediaFile(LPCWSTR file_path, BYTE** wave_data, UINT32* wave_data_size) { HRESULT hr = S_OK; @@ -64,10 +64,10 @@ namespace easy2d SafeRelease(reader); - return SUCCEEDED(hr); + return hr; } - bool Transcoder::LoadMediaResource(Resource& res, BYTE** wave_data, UINT32* wave_data_size) + HRESULT Transcoder::LoadMediaResource(Resource& res, BYTE** wave_data, UINT32* wave_data_size) { HRESULT hr = S_OK; @@ -86,7 +86,7 @@ namespace easy2d if (stream == nullptr) { logs::Trace(L"SHCreateMemStream"); - return false; + return E_OUTOFMEMORY; } if (SUCCEEDED(hr)) @@ -112,7 +112,7 @@ namespace easy2d SafeRelease(byte_stream); SafeRelease(reader); - return SUCCEEDED(hr); + return hr; } HRESULT Transcoder::ReadSource(IMFSourceReader* reader, BYTE** wave_data, UINT32* wave_data_size) diff --git a/core/utils/Transcoder.h b/core/utils/Transcoder.h index e167e40c..b68bc560 100644 --- a/core/utils/Transcoder.h +++ b/core/utils/Transcoder.h @@ -38,13 +38,13 @@ namespace easy2d WAVEFORMATEX* GetWaveFormatEx() const; - bool LoadMediaFile( + HRESULT LoadMediaFile( LPCWSTR file_path, BYTE** wave_data, UINT32* wave_data_size ); - bool LoadMediaResource( + HRESULT LoadMediaResource( Resource& res, BYTE** wave_data, UINT32* wave_data_size diff --git a/project/vs2013/Easy2D.vcxproj b/project/vs2013/Easy2D.vcxproj index 28af00e8..b09ada35 100644 --- a/project/vs2013/Easy2D.vcxproj +++ b/project/vs2013/Easy2D.vcxproj @@ -38,12 +38,14 @@ + + @@ -62,7 +64,6 @@ - @@ -83,6 +84,7 @@ + @@ -102,7 +104,6 @@ - diff --git a/project/vs2013/Easy2D.vcxproj.filters b/project/vs2013/Easy2D.vcxproj.filters index 8b5933b3..668bcfe5 100644 --- a/project/vs2013/Easy2D.vcxproj.filters +++ b/project/vs2013/Easy2D.vcxproj.filters @@ -122,9 +122,6 @@ utils - - utils - utils @@ -140,6 +137,12 @@ ui + + base + + + base + @@ -252,9 +255,6 @@ utils - - utils - utils @@ -270,5 +270,8 @@ ui + + base + \ No newline at end of file diff --git a/project/vs2015/Easy2D.vcxproj b/project/vs2015/Easy2D.vcxproj index 2279adf3..b4b79ab0 100644 --- a/project/vs2015/Easy2D.vcxproj +++ b/project/vs2015/Easy2D.vcxproj @@ -38,12 +38,14 @@ + + @@ -62,7 +64,6 @@ - @@ -83,6 +84,7 @@ + @@ -102,7 +104,6 @@ - diff --git a/project/vs2015/Easy2D.vcxproj.filters b/project/vs2015/Easy2D.vcxproj.filters index 8b5933b3..668bcfe5 100644 --- a/project/vs2015/Easy2D.vcxproj.filters +++ b/project/vs2015/Easy2D.vcxproj.filters @@ -122,9 +122,6 @@ utils - - utils - utils @@ -140,6 +137,12 @@ ui + + base + + + base + @@ -252,9 +255,6 @@ utils - - utils - utils @@ -270,5 +270,8 @@ ui + + base + \ No newline at end of file diff --git a/project/vs2017/Easy2D.vcxproj b/project/vs2017/Easy2D.vcxproj index 80dcea56..f22ae099 100644 --- a/project/vs2017/Easy2D.vcxproj +++ b/project/vs2017/Easy2D.vcxproj @@ -38,12 +38,14 @@ + + @@ -62,7 +64,6 @@ - @@ -83,6 +84,7 @@ + @@ -102,7 +104,6 @@ - diff --git a/project/vs2017/Easy2D.vcxproj.filters b/project/vs2017/Easy2D.vcxproj.filters index 8b5933b3..668bcfe5 100644 --- a/project/vs2017/Easy2D.vcxproj.filters +++ b/project/vs2017/Easy2D.vcxproj.filters @@ -122,9 +122,6 @@ utils - - utils - utils @@ -140,6 +137,12 @@ ui + + base + + + base + @@ -252,9 +255,6 @@ utils - - utils - utils @@ -270,5 +270,8 @@ ui + + base + \ No newline at end of file