From 406ea51b5797c930f83484f458a2690362e0170e Mon Sep 17 00:00:00 2001 From: Haibo Date: Thu, 22 Nov 2018 19:31:44 +0800 Subject: [PATCH] add Events and EventDispatcher --- core/base/ActionManager.cpp | 2 +- core/base/BaseTypes.hpp | 52 +- core/base/Canvas.cpp | 4 +- core/base/{KeyEvent.h => Event.hpp} | 58 +- core/base/EventDispatcher.cpp | 135 ++++ core/base/EventDispatcher.h | 78 ++ core/base/EventListener.cpp | 63 ++ core/base/EventListener.h | 65 ++ core/base/Game.cpp | 318 ++++---- core/base/Game.h | 33 +- core/base/GeometryNode.cpp | 2 +- core/base/Image.cpp | 4 +- core/base/Input.cpp | 140 ++-- core/base/Input.h | 92 ++- core/base/{KeyEvent.cpp => KeyEvent.hpp} | 37 +- core/base/MouseEvent.cpp | 85 -- core/base/MouseEvent.h | 97 --- core/base/MouseEvent.hpp | 51 ++ core/base/Music.cpp | 4 +- core/base/Node.cpp | 93 ++- core/base/Node.h | 29 +- core/base/Scene.cpp | 24 + core/base/Scene.h | 10 +- core/base/Sprite.cpp | 2 +- core/base/TaskManager.cpp | 2 +- core/base/Text.cpp | 2 +- core/base/Transition.cpp | 6 +- core/base/audio.cpp | 168 ++-- core/base/audio.h | 56 +- core/base/base.hpp | 2 + core/base/render.cpp | 951 +++++++++++------------ core/base/render.h | 224 +++--- core/base/window.cpp | 7 +- core/base/window.h | 2 + core/easy2d.h | 30 +- core/ui/Button.cpp | 70 +- core/ui/Button.h | 8 +- project/vs2013/Easy2D.vcxproj | 11 +- project/vs2013/Easy2D.vcxproj.filters | 33 +- project/vs2015/Easy2D.vcxproj | 11 +- project/vs2015/Easy2D.vcxproj.filters | 33 +- project/vs2017/Easy2D.vcxproj | 11 +- project/vs2017/Easy2D.vcxproj.filters | 33 +- 43 files changed, 1734 insertions(+), 1404 deletions(-) rename core/base/{KeyEvent.h => Event.hpp} (69%) create mode 100644 core/base/EventDispatcher.cpp create mode 100644 core/base/EventDispatcher.h create mode 100644 core/base/EventListener.cpp create mode 100644 core/base/EventListener.h rename core/base/{KeyEvent.cpp => KeyEvent.hpp} (73%) delete mode 100644 core/base/MouseEvent.cpp delete mode 100644 core/base/MouseEvent.h create mode 100644 core/base/MouseEvent.hpp diff --git a/core/base/ActionManager.cpp b/core/base/ActionManager.cpp index 5f61ec1d..a7726fe2 100644 --- a/core/base/ActionManager.cpp +++ b/core/base/ActionManager.cpp @@ -44,7 +44,7 @@ namespace easy2d void ActionManager::AddAction(spAction const& action) { if (!action) - logs::Warningln("Node::RunAction failed, action is nullptr"); + logs::Warningln("AddAction failed, action is nullptr"); if (action) { diff --git a/core/base/BaseTypes.hpp b/core/base/BaseTypes.hpp index aad90645..56404b80 100644 --- a/core/base/BaseTypes.hpp +++ b/core/base/BaseTypes.hpp @@ -46,19 +46,34 @@ namespace easy2d Round = 2 /* 圆角 */ }; - // 键盘键值 + // 图层属性 + struct LayerProperties + { + Rect area; + float opacity; + }; + + // 鼠标键值 + enum class MouseButton : int + { + Left = VK_LBUTTON, // 鼠标左键 + Right = VK_RBUTTON, // 鼠标右键 + Middle = VK_MBUTTON // 鼠标中键 + }; + + // 按键键值 enum class KeyCode : int { - Unknown = 0, - Up = VK_UP, - Left = VK_LEFT, - Right = VK_RIGHT, - Down = VK_DOWN, - Enter = VK_RETURN, - Space = VK_SPACE, - Esc = VK_ESCAPE, - Ctrl = VK_CONTROL, - Shift = VK_SHIFT, + Unknown = 0, + Up = VK_UP, + Left = VK_LEFT, + Right = VK_RIGHT, + Down = VK_DOWN, + Enter = VK_RETURN, + Space = VK_SPACE, + Esc = VK_ESCAPE, + Ctrl = VK_CONTROL, + Shift = VK_SHIFT, A = 0x41, B, @@ -122,19 +137,4 @@ namespace easy2d F11, F12, }; - - // 鼠标键值 - enum class MouseCode : int - { - Left = VK_LBUTTON, /* 鼠标左键 */ - Right = VK_RBUTTON, /* 鼠标右键 */ - Middle = VK_MBUTTON /* 鼠标中键 */ - }; - - // 图层属性 - struct LayerProperties - { - Rect area; - float opacity; - }; } diff --git a/core/base/Canvas.cpp b/core/base/Canvas.cpp index e2623649..b1926b09 100644 --- a/core/base/Canvas.cpp +++ b/core/base/Canvas.cpp @@ -32,7 +32,7 @@ namespace easy2d , stroke_width_(1.0f) { ThrowIfFailed( - devices::Graphics::Instance()->CreateBitmapRenderTarget(render_target_) + Graphics::Instance()->CreateBitmapRenderTarget(render_target_) ); auto properties = D2D1::BrushProperties(); @@ -105,7 +105,7 @@ namespace easy2d if (bitmap_cached_) { - devices::Graphics::Instance()->DrawBitmap(bitmap_cached_); + Graphics::Instance()->DrawBitmap(bitmap_cached_); } } diff --git a/core/base/KeyEvent.h b/core/base/Event.hpp similarity index 69% rename from core/base/KeyEvent.h rename to core/base/Event.hpp index c701abf4..ee1fa0b0 100644 --- a/core/base/KeyEvent.h +++ b/core/base/Event.hpp @@ -20,49 +20,37 @@ #pragma once #include "macros.h" -#include "BaseTypes.hpp" namespace easy2d { - // 按键消息 - class KeyEvent + typedef UINT EventType; + + class Event { public: - // 按键消息类型 - enum class Type : int + Event(EventType type) : type(type), has_target(false) {} + + EventType type; + bool has_target; + }; + + class SysEvent + : public Event + { + public: + enum Type { - Down = 0x0100, // 按下 - Up // 抬起 + First = WM_NULL, + + WindowActivate, // 窗口获得焦点 + WindowDeavtivate, // 窗口失去焦点 + WindowClose, // 关闭窗口 + + Last }; - public: - explicit KeyEvent( - UINT message, - WPARAM w_param, - LPARAM l_param - ); + SysEvent(EventType type) : Event(type) {} - // 获取事件类型 - KeyEvent::Type GetType() const; - - // 获取按键键值 - KeyCode GetCode() const; - - // 获取按键次数 - int GetCount() const; - - protected: - UINT message_; - WPARAM w_param_; - LPARAM l_param_; - }; - - - // 按键消息处理接口 - class KeyEventHandler - { - public: - // 处理按键消息 - virtual void Handle(KeyEvent e) = 0; + static bool Check(Event* e) { return e->type > Type::First && e->type < Type::Last; } }; } diff --git a/core/base/EventDispatcher.cpp b/core/base/EventDispatcher.cpp new file mode 100644 index 00000000..17a122d4 --- /dev/null +++ b/core/base/EventDispatcher.cpp @@ -0,0 +1,135 @@ +// Copyright (c) 2016-2018 Easy2D - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "EventDispatcher.h" +#include "logs.h" + +namespace easy2d +{ + void EventDispatcher::DispatchEvent(Event* e) + { + if (listeners_.IsEmpty()) + return; + + spEventListener next; + for (auto listener = listeners_.First(); listener; listener = next) + { + next = listener->NextItem(); + + if (listener->type_ == e->type) + { + listener->callback_(e); + } + } + } + + void EventDispatcher::AddListener(spEventListener const & listener) + { + if (!listener) + logs::Warningln("AddListener failed, action is nullptr"); + + if (listener) + { + listeners_.PushBack(EventListener::ItemType(listener)); + } + } + + void EventDispatcher::AddListener(EventType type, EventCallback callback, String const& name) + { + spEventListener listener = new EventListener(type, callback, name); + if (listener) + { + listeners_.PushBack(EventListener::ItemType(listener)); + } + } + + void EventDispatcher::StartListeners(String const & listener_name) + { + for (auto listener = listeners_.First(); listener; listener = listener->NextItem()) + { + if (listener->GetName() == listener_name) + { + listener->Start(); + } + } + } + + void EventDispatcher::StopListeners(String const & listener_name) + { + for (auto listener = listeners_.First(); listener; listener = listener->NextItem()) + { + if (listener->GetName() == listener_name) + { + listener->Stop(); + } + } + } + + void EventDispatcher::RemoveListeners(String const & listener_name) + { + spEventListener next; + for (auto listener = listeners_.First(); listener; listener = next) + { + next = listener->NextItem(); + + if (listener->GetName() == listener_name) + { + listeners_.Remove(listener); + } + } + } + + void EventDispatcher::StartListeners(EventType type) + { + for (auto listener = listeners_.First(); listener; listener = listener->NextItem()) + { + if (listener->type_ == type) + { + listener->Start(); + } + } + } + + void EventDispatcher::StopListeners(EventType type) + { + for (auto listener = listeners_.First(); listener; listener = listener->NextItem()) + { + if (listener->type_ == type) + { + listener->Stop(); + } + } + } + + void EventDispatcher::RemoveListeners(EventType type) + { + spEventListener next; + for (auto listener = listeners_.First(); listener; listener = next) + { + next = listener->NextItem(); + + if (listener->type_ == type) + { + listeners_.Remove(listener); + } + } + } + +} diff --git a/core/base/EventDispatcher.h b/core/base/EventDispatcher.h new file mode 100644 index 00000000..e8a6c1c7 --- /dev/null +++ b/core/base/EventDispatcher.h @@ -0,0 +1,78 @@ +// 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 "EventListener.h" + +namespace easy2d +{ + class EventDispatcher + { + using Listeners = intrusive::List; + + public: + // 添加监听器 + void AddListener( + spEventListener const& listener + ); + + // 添加监听器 + void AddListener( + EventType type, + EventCallback callback, + String const& name = L"" + ); + + // 启动监听器 + void StartListeners( + String const& listener_name + ); + + // 停止监听器 + void StopListeners( + String const& listener_name + ); + + // 移除监听器 + void RemoveListeners( + String const& listener_name + ); + + // 启动监听器 + void StartListeners( + EventType type + ); + + // 停止监听器 + void StopListeners( + EventType type + ); + + // 移除监听器 + void RemoveListeners( + EventType type + ); + + virtual void DispatchEvent(Event* e); + + protected: + Listeners listeners_; + }; +} diff --git a/core/base/EventListener.cpp b/core/base/EventListener.cpp new file mode 100644 index 00000000..47eab905 --- /dev/null +++ b/core/base/EventListener.cpp @@ -0,0 +1,63 @@ +// 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 "EventListener.h" + +namespace easy2d +{ + EventListener::EventListener(EventType type, EventCallback const & callback, String const & name) + : type_(type) + , callback_(callback) + , name_(name) + , running_(true) + { + } + + EventListener::~EventListener() + { + } + + void EventListener::Start() + { + running_ = true; + } + + void EventListener::Stop() + { + running_ = false; + } + + bool EventListener::IsRunning() const + { + return running_; + } + + String const & EventListener::GetName() const + { + return name_; + } + + void EventListener::SetName(String const & name) + { + name_ = name; + } + +} diff --git a/core/base/EventListener.h b/core/base/EventListener.h new file mode 100644 index 00000000..159636e5 --- /dev/null +++ b/core/base/EventListener.h @@ -0,0 +1,65 @@ +// 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 "base.hpp" +#include "intrusive/List.hpp" +#include "Event.hpp" + +namespace easy2d +{ + typedef std::function EventCallback; + + + class EventDispatcher; + + class EventListener + : public RefCounter + , protected intrusive::ListItem + { + friend class EventDispatcher; + friend class intrusive::List; + + public: + EventListener( + EventType type, + EventCallback const& callback, + String const& name = L"" + ); + + virtual ~EventListener(); + + void Start(); + + void Stop(); + + void SetName(String const& name); + + bool IsRunning() const; + + String const& GetName() const; + + protected: + bool running_; + String name_; + EventType type_; + EventCallback callback_; + }; +} diff --git a/core/base/Game.cpp b/core/base/Game.cpp index 4c1012e4..b51873cc 100644 --- a/core/base/Game.cpp +++ b/core/base/Game.cpp @@ -23,26 +23,24 @@ #include "modules.h" #include "Factory.h" #include "Scene.h" -#include "Transition.h" #include "Debuger.h" +#include "Transition.h" +#include "KeyEvent.hpp" +#include "MouseEvent.hpp" #include "../math/Matrix.hpp" -#include +#include #include + #pragma comment (lib ,"imm32.lib") namespace easy2d { Game::Game() - : initialized_(false) - , window_inactived_(false) + : active_(false) + , debug_(false) , curr_scene_(nullptr) , next_scene_(nullptr) , transition_(nullptr) - , window_(nullptr) - , graphics_(nullptr) - , input_(nullptr) - , audio_(nullptr) - , debug_enabled_(false) , time_scale_(1.f) { ::CoInitialize(nullptr); @@ -61,52 +59,44 @@ namespace easy2d void Game::Init(const Options& options) { - if (initialized_) - return; - - debug_enabled_ = options.debug; - - window_ = Window::Instance(); - graphics_ = devices::Graphics::Instance(); - input_ = devices::Input::Instance(); - audio_ = devices::Audio::Instance(); + debug_ = options.debug; ThrowIfFailed( - Factory::Instance()->Init(debug_enabled_) + Factory::Instance()->Init(debug_) ); ThrowIfFailed( - window_->Init( + Window::Instance()->Init( options.title, options.width, options.height, options.icon, Game::WndProc, - debug_enabled_ + debug_ ) ); - HWND hwnd = window_->GetHandle(); + HWND hwnd = Window::Instance()->GetHandle(); ThrowIfFailed( - graphics_->Init( + Graphics::Instance()->Init( hwnd, options.vsync, - debug_enabled_ + debug_ ) ); ThrowIfFailed( - input_->Init( + Input::Instance()->Init( hwnd, - window_->GetContentScaleX(), - window_->GetContentScaleY(), - debug_enabled_ + Window::Instance()->GetContentScaleX(), + Window::Instance()->GetContentScaleY(), + debug_ ) ); ThrowIfFailed( - audio_->Init(debug_enabled_) + Audio::Instance()->Init(debug_) ); // disable imm @@ -114,7 +104,7 @@ namespace easy2d // show console if debug mode enabled HWND console = ::GetConsoleWindow(); - if (debug_enabled_ && !console) + if (debug_ && !console) { if (::AllocConsole()) { @@ -125,7 +115,7 @@ namespace easy2d freopen_s(&stderrStream, "conout$", "w+t", stderr); } } - else if (!debug_enabled_ && console) + else if (!debug_ && console) { ::ShowWindow(console, SW_HIDE); } @@ -139,54 +129,47 @@ namespace easy2d // use Game instance in message loop ::SetWindowLongW(hwnd, GWLP_USERDATA, PtrToUlong(this)); - - initialized_ = true; } void Game::Run() { - if (!initialized_) - return; + HWND hwnd = Window::Instance()->GetHandle(); - ::ShowWindow(window_->GetHandle(), SW_SHOWNORMAL); - ::UpdateWindow(window_->GetHandle()); - - MSG msg = {}; - while (::GetMessageW(&msg, nullptr, 0, 0)) + if (hwnd) { - ::TranslateMessage(&msg); - ::DispatchMessageW(&msg); + ::ShowWindow(hwnd, SW_SHOWNORMAL); + ::UpdateWindow(hwnd); + + MSG msg = {}; + while (::GetMessageW(&msg, nullptr, 0, 0)) + { + ::TranslateMessage(&msg); + ::DispatchMessageW(&msg); + } } } void Game::Quit() { - if (window_) - ::DestroyWindow(window_->GetHandle()); + Window::Instance()->Destroy(); } - bool Game::EnterScene(spScene const & scene) + void Game::EnterScene(spScene const & scene) { if (!scene) - { logs::Warningln("Game::EnterScene failed, scene is nullptr"); - return false; - } - if (curr_scene_ == scene || - next_scene_ == scene) - return false; + if (curr_scene_ == scene || next_scene_ == scene) + return; next_scene_ = scene; - return true; } - bool Game::EnterScene(spScene const& scene, spTransition const& transition) + void Game::EnterScene(spScene const& scene, spTransition const& transition) { - if (!EnterScene(scene)) - return false; + EnterScene(scene); - if (transition) + if (transition && next_scene_) { if (transition_) { @@ -195,7 +178,6 @@ namespace easy2d transition_ = transition; transition_->Init(curr_scene_, next_scene_); } - return true; } spScene const& Game::GetCurrentScene() @@ -216,7 +198,7 @@ namespace easy2d const auto dt = (now - last) * time_scale_; last = now; - input_->Update(); + Input::Instance()->Update(); if (curr_scene_) curr_scene_->Update(dt); @@ -224,7 +206,7 @@ namespace easy2d if (next_scene_) next_scene_->Update(dt); - if (debug_enabled_) + if (debug_) Debuger::Instance()->Update(dt); if (transition_) @@ -251,12 +233,12 @@ namespace easy2d } } - void Game::Render() + void Game::Render(HWND hwnd) { - auto graphics = devices::Graphics::Instance(); + auto graphics = Graphics::Instance(); ThrowIfFailed( - graphics->BeginDraw(window_->GetHandle()) + graphics->BeginDraw(hwnd) ); if (transition_) @@ -268,7 +250,7 @@ namespace easy2d curr_scene_->Render(); } - if (debug_enabled_) + if (debug_) { graphics->SetTransform(math::Matrix()); graphics->SetOpacity(1.f); @@ -290,36 +272,13 @@ namespace easy2d graphics->EndDraw() ); - if (!window_inactived_) - ::InvalidateRect(window_->GetHandle(), NULL, FALSE); + if (active_) + ::InvalidateRect(hwnd, NULL, FALSE); } - void Game::Dispatch(MouseEvent const & e) + bool Game::HandleMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - if (transition_) - return; - - if (curr_scene_) - curr_scene_->Dispatch(e, false); - } - - void Game::Dispatch(KeyEvent const & e) - { - if (transition_) - return; - - if (curr_scene_) - curr_scene_->Dispatch(e, false); - } - - LRESULT CALLBACK Game::WndProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param) - { - LRESULT result = 0; - bool was_handled = false; - - Game * game = reinterpret_cast( - static_cast(::GetWindowLongW(hwnd, GWLP_USERDATA)) - ); + bool unhandled = false; switch (msg) { @@ -328,96 +287,185 @@ namespace easy2d PAINTSTRUCT ps; ::BeginPaint(hwnd, &ps); - game->Update(); - game->Render(); + Update(); + Render(hwnd); ::EndPaint(hwnd, &ps); } - result = 0; - was_handled = true; break; case WM_LBUTTONUP: case WM_LBUTTONDOWN: - case WM_LBUTTONDBLCLK: - case WM_MBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONDBLCLK: + //case WM_LBUTTONDBLCLK: + //case WM_MBUTTONUP: + //case WM_MBUTTONDOWN: + //case WM_MBUTTONDBLCLK: case WM_RBUTTONUP: case WM_RBUTTONDOWN: - case WM_RBUTTONDBLCLK: + //case WM_RBUTTONDBLCLK: case WM_MOUSEMOVE: case WM_MOUSEWHEEL: { - game->Dispatch(MouseEvent(msg, w_param, l_param)); + float x = GET_X_LPARAM(lparam) * Window::Instance()->GetContentScaleX(); + float y = GET_Y_LPARAM(lparam) * Window::Instance()->GetContentScaleY(); + float wheel_delta = 0.f; + + MouseEvent::Type type; + if (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN) + type = MouseEvent::Down; + else if (msg == WM_LBUTTONUP || msg == WM_RBUTTONUP) + type = MouseEvent::Up; + else if (msg == WM_MOUSEMOVE) + type = MouseEvent::Move; + else + { + type = MouseEvent::Wheel; + wheel_delta = GET_WHEEL_DELTA_WPARAM(wparam) / 120.f; + } + + MouseEvent event(type, x, y, wheel_delta); + + if (wparam & MK_LBUTTON || wparam & MK_RBUTTON) + event.button_down = true; + + Dispatch(&event); } - result = 0; - was_handled = true; break; case WM_KEYDOWN: case WM_KEYUP: { - game->Dispatch(KeyEvent(msg, w_param, l_param)); - } - result = 0; - was_handled = true; - break; - - case WM_SIZE: - { - if (SIZE_MAXHIDE == w_param || SIZE_MINIMIZED == w_param) - game->window_inactived_ = true; - else - { - game->window_inactived_ = false; - ::InvalidateRect(hwnd, nullptr, FALSE); - } - - UINT width = LOWORD(l_param); - UINT height = HIWORD(l_param); - - // 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染 - // 目标的大小。它可能会调用失败,但是这里可以忽略有可能的 - // 错误,因为这个错误将在下一次调用 EndDraw 时产生 - devices::Graphics::Instance()->Resize(width, height); + KeyEvent event(msg, KeyCode(wparam)); + Dispatch(&event); } break; case WM_DISPLAYCHANGE: { + E2D_LOG("The display resolution has changed"); ::InvalidateRect(hwnd, nullptr, FALSE); } - result = 0; - was_handled = true; break; case WM_CLOSE: { - if (game->OnClose()) + E2D_LOG("Received a message to close the window"); + + SysEvent event(SysEvent::WindowClose); + Dispatch(&event); + + if (OnClose()) { ::DestroyWindow(hwnd); } } - result = 0; - was_handled = true; break; case WM_DESTROY: { - game->OnExit(); + E2D_LOG("Window was destroyed"); + + OnExit(); ::PostQuitMessage(0); } - result = 1; - was_handled = true; break; + case WM_SIZE: + { + if (SIZE_MAXHIDE == wparam || SIZE_MINIMIZED == wparam) + { + active_ = false; + + E2D_LOG("Window minimized"); + } + else if (SIZE_RESTORED == wparam) + { + active_ = true; + ::InvalidateRect(hwnd, nullptr, FALSE); + + E2D_LOG("Window restored"); + } + + UINT width = LOWORD(lparam); + UINT height = HIWORD(lparam); + + // 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染 + // 目标的大小。它可能会调用失败,但是这里可以忽略有可能的 + // 错误,因为这个错误将在下一次调用 EndDraw 时产生 + Graphics::Instance()->Resize(width, height); + } + unhandled = true; + break; + + case WM_ACTIVATE: + { + if (WA_INACTIVE == wparam) + { + E2D_LOG("Window deactivated"); + + SysEvent event(SysEvent::WindowDeavtivate); + Dispatch(&event); + } + else + { + E2D_LOG("Window activated"); + + SysEvent event(SysEvent::WindowActivate); + Dispatch(&event); + } + } + unhandled = true; + break; + + case WM_SETTEXT: + { + E2D_LOG("Window title changed"); + } + unhandled = true; + break; + + case WM_SETICON: + { + E2D_LOG("Window icon changed"); + } + unhandled = true; + break; + + default: + unhandled = true; + break; + } + + return !unhandled; + } + + void Game::Dispatch(Event * event) + { + if (transition_) + return; + + if (curr_scene_) + curr_scene_->DispatchEvent(event); + } + + LRESULT CALLBACK Game::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) + { + LRESULT result = 0; + bool was_handled = false; + + Game * game = reinterpret_cast( + static_cast(::GetWindowLongW(hwnd, GWLP_USERDATA)) + ); + + if (game) + { + was_handled = game->HandleMessage(hwnd, msg, wparam, lparam); } if (!was_handled) { - result = ::DefWindowProcW(hwnd, msg, w_param, l_param); + result = ::DefWindowProcW(hwnd, msg, wparam, lparam); } return result; } -} \ No newline at end of file +} diff --git a/core/base/Game.h b/core/base/Game.h index 30db361a..d032a24f 100644 --- a/core/base/Game.h +++ b/core/base/Game.h @@ -25,8 +25,7 @@ #include "render.h" #include "input.h" #include "audio.h" -#include "KeyEvent.h" -#include "MouseEvent.h" +#include "Event.hpp" namespace easy2d { @@ -62,11 +61,10 @@ namespace easy2d virtual ~Game(); - // 退出时 + // 退出游戏 virtual void OnExit() {} - // 窗口关闭时 - // 返回值:返回 false 将阻止窗口关闭 + // 窗口关闭 virtual bool OnClose() { return true; } // 初始化 @@ -81,12 +79,12 @@ namespace easy2d void Quit(); // 切换场景 - bool EnterScene( + void EnterScene( spScene const& scene /* 场景 */ ); // 切换场景 - bool EnterScene( + void EnterScene( spScene const& scene, /* 场景 */ spTransition const& transition /* 场景动画 */ ); @@ -98,32 +96,29 @@ namespace easy2d void SetTimeScale(float scale); private: - void Render(); + void Render(HWND); void Update(); - void Dispatch( - MouseEvent const& e + bool HandleMessage( + HWND hwnd, + UINT msg, + WPARAM wparam, + LPARAM lparam ); void Dispatch( - KeyEvent const& e + Event* event ); static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); private: - bool initialized_; - bool debug_enabled_; - bool window_inactived_; + bool debug_; + bool active_; float time_scale_; spScene curr_scene_; spScene next_scene_; spTransition transition_; - - WindowImpl* window_; - devices::GraphicsDevice* graphics_; - devices::InputDevice* input_; - devices::AudioDevice* audio_; }; } diff --git a/core/base/GeometryNode.cpp b/core/base/GeometryNode.cpp index 54fde7ae..255d7a45 100644 --- a/core/base/GeometryNode.cpp +++ b/core/base/GeometryNode.cpp @@ -70,7 +70,7 @@ namespace easy2d { if (geometry_ && geometry_->geo_) { - auto graphics = devices::Graphics::Instance(); + auto graphics = Graphics::Instance(); graphics->SetTransform(geometry_->GetTransformMatrix() * GetTransformMatrix()); graphics->FillGeometry( diff --git a/core/base/Image.cpp b/core/base/Image.cpp index c134f2a5..e08d7b9c 100644 --- a/core/base/Image.cpp +++ b/core/base/Image.cpp @@ -70,7 +70,7 @@ namespace easy2d bool Image::Load(Resource const& res) { cpBitmap bitmap; - HRESULT hr = devices::Graphics::Instance()->CreateBitmapFromResource(bitmap, res); + HRESULT hr = Graphics::Instance()->CreateBitmapFromResource(bitmap, res); if (FAILED(hr)) { logs::Errorln(hr, "Load Image from resource failed!"); @@ -94,7 +94,7 @@ namespace easy2d String image_file_path = image_file.GetPath(); cpBitmap bitmap; - HRESULT hr = devices::Graphics::Instance()->CreateBitmapFromFile(bitmap, image_file_path); + HRESULT hr = Graphics::Instance()->CreateBitmapFromFile(bitmap, image_file_path); if (FAILED(hr)) { logs::Errorln(hr, "Load Image from file failed!"); diff --git a/core/base/Input.cpp b/core/base/Input.cpp index c5372c2f..d6737900 100644 --- a/core/base/Input.cpp +++ b/core/base/Input.cpp @@ -24,88 +24,92 @@ namespace easy2d { - namespace devices + InputDevice::InputDevice() + : hwnd_(nullptr) + , scale_x_(1.f) + , scale_y_(1.f) { - InputDevice::InputDevice() - : hwnd_(nullptr) - , scale_x_(1.f) - , scale_y_(1.f) - { - ZeroMemory(keys_, sizeof(keys_)); - ZeroMemory(keys_cache_, sizeof(keys_cache_)); - } + ZeroMemory(keys_, sizeof(keys_)); + ZeroMemory(keys_cache_, sizeof(keys_cache_)); + } - InputDevice::~InputDevice() - { - E2D_LOG("Destroying input device"); - } + InputDevice::~InputDevice() + { + E2D_LOG("Destroying input device"); + } - HRESULT InputDevice::Init(HWND hwnd, float scale_x, float scale_y, bool debug) - { - E2D_LOG("Initing input device"); + HRESULT InputDevice::Init(HWND hwnd, float scale_x, float scale_y, bool debug) + { + E2D_LOG("Initing input device"); - hwnd_ = hwnd; - scale_x_ = scale_x; - scale_y_ = scale_y; + hwnd_ = hwnd; + scale_x_ = scale_x; + scale_y_ = scale_y; - return S_OK; - } + return S_OK; + } - void InputDevice::Update() - { - memcpy(keys_cache_, keys_, sizeof(keys_cache_)); - GetKeyboardState(keys_); + void InputDevice::Update() + { + memcpy(keys_cache_, keys_, sizeof(keys_cache_)); + GetKeyboardState(keys_); + } - POINT client_cursor_pos; - GetCursorPos(&client_cursor_pos); - ScreenToClient(hwnd_, &client_cursor_pos); + bool InputDevice::IsDown(KeyCode code) + { + return !!(keys_[static_cast(code)] & 0x80); + } - mouse_pos_ = Point(client_cursor_pos.x * scale_x_, client_cursor_pos.y * scale_y_); - } + bool InputDevice::IsDown(MouseButton btn) + { + return !!(keys_[static_cast(btn)] & 0x80); + } - bool InputDevice::IsDown(KeyCode code) - { - if (keys_[static_cast(code)] & 0x80) - return true; - return false; - } + bool InputDevice::WasPressed(KeyCode code) + { + return !(keys_cache_[static_cast(code)] & 0x80) + && (keys_[static_cast(code)] & 0x80); + } - bool InputDevice::IsDown(MouseCode code) - { - if (keys_[static_cast(code)] & 0x80) - return true; - return false; - } + bool InputDevice::WasPressed(MouseButton btn) + { + return !(keys_cache_[static_cast(btn)] & 0x80) + && (keys_[static_cast(btn)] & 0x80); + } - bool InputDevice::WasPressed(KeyCode code) - { - if (keys_cache_[static_cast(code)] & 0x80 && - !(keys_[static_cast(code)] & 0x80)) - return true; - return false; - } + bool InputDevice::WasReleased(KeyCode code) + { + return (keys_cache_[static_cast(code)] & 0x80) + && !(keys_[static_cast(code)] & 0x80); + } - bool InputDevice::WasPressed(MouseCode code) - { - if (keys_cache_[static_cast(code)] & 0x80 && - !(keys_[static_cast(code)] & 0x80)) - return true; - return false; - } + bool InputDevice::WasReleased(MouseButton btn) + { + return (keys_cache_[static_cast(btn)] & 0x80) + && !(keys_[static_cast(btn)] & 0x80); + } - float InputDevice::GetMouseX() - { - return mouse_pos_.x; - } + float InputDevice::GetMouseX() + { + POINT pos; + ::GetCursorPos(&pos); + ::ScreenToClient(hwnd_, &pos); + return pos.x * scale_x_; + } - float InputDevice::GetMouseY() - { - return mouse_pos_.y; - } + float InputDevice::GetMouseY() + { + POINT pos; + ::GetCursorPos(&pos); + ::ScreenToClient(hwnd_, &pos); + return pos.y * scale_y_; + } - Point InputDevice::GetMousePos() - { - return mouse_pos_; - } + Point InputDevice::GetMousePos() + { + POINT pos; + ::GetCursorPos(&pos); + ::ScreenToClient(hwnd_, &pos); + return Point{ pos.x * scale_x_, pos.y * scale_y_ }; } } \ No newline at end of file diff --git a/core/base/Input.h b/core/base/Input.h index 1d137748..16ccb403 100644 --- a/core/base/Input.h +++ b/core/base/Input.h @@ -24,61 +24,67 @@ namespace easy2d { - namespace devices + class InputDevice + : protected Noncopyable { - class InputDevice - : protected Noncopyable - { - E2D_DECLARE_SINGLETON(InputDevice); + E2D_DECLARE_SINGLETON(InputDevice); - public: - HRESULT Init(HWND hwnd, float scale_x, float scale_y, bool debug); + public: + HRESULT Init(HWND hwnd, float scale_x, float scale_y, bool debug); - // 检测键盘某按键是否正被按下 - bool IsDown( - KeyCode code - ); + // 检测键盘按键是否正被按下 + bool IsDown( + KeyCode code + ); - // 检测鼠标按键是否正被按下 - bool IsDown( - MouseCode code - ); + // 检测鼠标按键是否正被按下 + bool IsDown( + MouseButton btn + ); - // 检测键盘某按键是否点击 - bool WasPressed( - KeyCode code - ); + // 检测键盘按键是否刚被点击 + bool WasPressed( + KeyCode code + ); - // 检测鼠标按键是否点击 - bool WasPressed( - MouseCode code - ); + // 检测鼠标按键是否刚被点击 + bool WasPressed( + MouseButton btn + ); - // 获得鼠标X轴坐标值 - float GetMouseX(); + // 检测键盘按键是否刚抬起 + bool WasReleased( + KeyCode code + ); - // 获得鼠标Y轴坐标值 - float GetMouseY(); + // 检测鼠标按键是否刚抬起 + bool WasReleased( + MouseButton btn + ); - // 获得鼠标坐标值 - Point GetMousePos(); + // 获得鼠标 x 坐标 + float GetMouseX(); - void Update(); + // 获得鼠标 y 坐标 + float GetMouseY(); - protected: - InputDevice(); + // 获得鼠标坐标 + Point GetMousePos(); - ~InputDevice(); + void Update(); - protected: - HWND hwnd_; - float scale_x_; - float scale_y_; - BYTE keys_[256]; - BYTE keys_cache_[256]; - Point mouse_pos_; - }; + protected: + InputDevice(); - E2D_DECLARE_SINGLETON_TYPE(InputDevice, Input); - } + ~InputDevice(); + + protected: + HWND hwnd_; + float scale_x_; + float scale_y_; + BYTE keys_[256]; + BYTE keys_cache_[256]; + }; + + E2D_DECLARE_SINGLETON_TYPE(InputDevice, Input); } diff --git a/core/base/KeyEvent.cpp b/core/base/KeyEvent.hpp similarity index 73% rename from core/base/KeyEvent.cpp rename to core/base/KeyEvent.hpp index b325d395..a73362e3 100644 --- a/core/base/KeyEvent.cpp +++ b/core/base/KeyEvent.hpp @@ -18,29 +18,30 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#include "KeyEvent.h" +#pragma once +#include "Event.hpp" +#include "BaseTypes.hpp" namespace easy2d { - KeyEvent::KeyEvent(UINT message, WPARAM w_param, LPARAM l_param) - : message_(message) - , w_param_(w_param) - , l_param_(l_param) + class KeyEvent + : public Event { - } + public: + enum Type + { + First = WM_KEYFIRST, - KeyCode KeyEvent::GetCode() const - { - return static_cast(w_param_); - } + Down, // 键按下 + Up, // 键抬起 - int KeyEvent::GetCount() const - { - return static_cast((DWORD)l_param_ & 0x0000FFFF); - } + Last // 结束标志 + }; - KeyEvent::Type KeyEvent::GetType() const - { - return Type(message_); - } + KeyEvent(EventType type, KeyCode key) : Event(type), key(key) {} + + static bool Check(Event* e) { return e->type > Type::First && e->type < Type::Last; } + + KeyCode key; + }; } diff --git a/core/base/MouseEvent.cpp b/core/base/MouseEvent.cpp deleted file mode 100644 index 1af5fc3a..00000000 --- a/core/base/MouseEvent.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2016-2018 Easy2D - Nomango -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "MouseEvent.h" -#include "window.h" - -namespace easy2d -{ - MouseEvent::MouseEvent(UINT message, WPARAM w_param, LPARAM l_param) - : message_(message) - , w_param_(w_param) - , l_param_(l_param) - { - } - - float MouseEvent::GetX() const - { - return ((float)(short)LOWORD(l_param_)) * Window::Instance()->GetContentScaleX(); - } - - float MouseEvent::GetY() const - { - return ((float)(short)HIWORD(l_param_)) * Window::Instance()->GetContentScaleY(); - } - - Point MouseEvent::GetPosition() const - { - return Point( - ((float)(short)LOWORD(l_param_)) * Window::Instance()->GetContentScaleX(), - ((float)(short)HIWORD(l_param_)) * Window::Instance()->GetContentScaleY() - ); - } - - bool MouseEvent::IsShiftDown() const - { - return GET_KEYSTATE_WPARAM(w_param_) == MK_SHIFT; - } - - bool MouseEvent::IsCtrlDown() const - { - return GET_KEYSTATE_WPARAM(w_param_) == MK_CONTROL; - } - - float MouseEvent::GetWheelDelta() const - { - return static_cast(GET_WHEEL_DELTA_WPARAM(w_param_)); - } - - bool MouseEvent::IsLButtonDown() const - { - return GET_KEYSTATE_WPARAM(w_param_) == MK_LBUTTON; - } - - bool MouseEvent::IsRButtonDown() const - { - return GET_KEYSTATE_WPARAM(w_param_) == MK_RBUTTON; - } - - bool MouseEvent::IsMButtonDown() const - { - return GET_KEYSTATE_WPARAM(w_param_) == MK_MBUTTON; - } - - MouseEvent::Type MouseEvent::GetType() const - { - return Type(message_); - } -} \ No newline at end of file diff --git a/core/base/MouseEvent.h b/core/base/MouseEvent.h deleted file mode 100644 index ddc11f60..00000000 --- a/core/base/MouseEvent.h +++ /dev/null @@ -1,97 +0,0 @@ -// 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 "macros.h" -#include "BaseTypes.hpp" - -namespace easy2d -{ - // 鼠标消息 - class MouseEvent - { - public: - // 鼠标消息类型 - enum class Type : int - { - Move = 0x0200, // 鼠标移动 - LeftDown, // 鼠标左键按下 - LeftUp, // 鼠标左键抬起 - LeftDoubleClick, // 鼠标左键双击 - RightDown, // 鼠标右键按下 - RightUp, // 鼠标右键抬起 - RightDoubleClick, // 鼠标右键双击 - MiddleDown, // 鼠标中键按下 - MiddleUp, // 鼠标中键抬起 - MiddleDoubleClick, // 鼠标中键双击 - Wheel // 滑动滚轮 - }; - - public: - explicit MouseEvent( - UINT message, - WPARAM w_param, - LPARAM l_param - ); - - // 获取鼠标横坐标 - float GetX() const; - - // 获取鼠标纵坐标 - float GetY() const; - - // 获取鼠标坐标 - Point GetPosition() const; - - // 获取事件类型 - MouseEvent::Type GetType() const; - - float GetWheelDelta() const; - - // 鼠标左键是否按下 - bool IsLButtonDown() const; - - // 鼠标右键是否按下 - bool IsRButtonDown() const; - - // 鼠标中键是否按下 - bool IsMButtonDown() const; - - // Shift 键是否按下 - bool IsShiftDown() const; - - // Ctrl 键是否按下 - bool IsCtrlDown() const; - - protected: - UINT message_; - WPARAM w_param_; - LPARAM l_param_; - }; - - - // 鼠标消息处理接口 - class MouseEventHandler - { - public: - // 处理鼠标消息 - virtual void Handle(MouseEvent e) = 0; - }; -} diff --git a/core/base/MouseEvent.hpp b/core/base/MouseEvent.hpp new file mode 100644 index 00000000..ddb3784a --- /dev/null +++ b/core/base/MouseEvent.hpp @@ -0,0 +1,51 @@ +// 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 "Event.hpp" + +namespace easy2d +{ + class MouseEvent + : public Event + { + public: + enum Type + { + First = WM_MOUSEFIRST, + + Move, // 移动 + Down, // 按下 + Up, // 抬起 + Wheel, // 滚轮滚动 + + Last // 结束标志 + }; + + MouseEvent(EventType type, float x, float y, float wheel_delta) : Event(type), x(x), y(y), wheel_delta(wheel_delta), button_down(false) {} + + static bool Check(Event* e) { return e->type > Type::First && e->type < Type::Last; } + + float x; + float y; + float wheel_delta; + bool button_down; + }; +} diff --git a/core/base/Music.cpp b/core/base/Music.cpp index 8d1de70a..35eaa1ed 100644 --- a/core/base/Music.cpp +++ b/core/base/Music.cpp @@ -87,7 +87,7 @@ namespace easy2d return false; } - hr = devices::Audio::Instance()->CreateVoice(voice_, transcoder.GetWaveFormatEx()); + hr = Audio::Instance()->CreateVoice(voice_, transcoder.GetWaveFormatEx()); if (FAILED(hr)) { if (wave_data_) @@ -119,7 +119,7 @@ namespace easy2d return false; } - hr = devices::Audio::Instance()->CreateVoice(voice_, transcoder.GetWaveFormatEx()); + hr = Audio::Instance()->CreateVoice(voice_, transcoder.GetWaveFormatEx()); if (FAILED(hr)) { if (wave_data_) diff --git a/core/base/Node.cpp b/core/base/Node.cpp index 1a42812a..050f3235 100644 --- a/core/base/Node.cpp +++ b/core/base/Node.cpp @@ -105,7 +105,7 @@ namespace easy2d UpdateTransform(); - auto graphics = devices::Graphics::Instance(); + auto graphics = Graphics::Instance(); if (children_.IsEmpty()) { @@ -146,13 +146,36 @@ namespace easy2d } } + void Node::DispatchEvent(Event * e) + { + if (!visible_) + return; + + this->HandleEvent(e); + + if (!e->has_target) + { + EventDispatcher::DispatchEvent(e); + } + } + + void Node::HandleEvent(Event * e) + { + spNode prev; + for (auto child = children_.Last(); child; child = prev) + { + prev = child->PrevItem(); + child->HandleEvent(e); + } + } + void Node::DrawBorder() { if (visible_) { if (border_) { - devices::Graphics::Instance()->DrawGeometry(border_, border_color_, 1.5f); + Graphics::Instance()->DrawGeometry(border_, border_color_, 1.5f); } for (auto child = children_.First(); child; child = child->NextItem()) @@ -180,6 +203,16 @@ namespace easy2d return final_matrix_; } + spNode Node::GetParent() const + { + return parent_; + } + + spScene Node::GetScene() const + { + return scene_; + } + void Node::UpdateTransform() { if (!dirty_transform_) @@ -241,44 +274,6 @@ namespace easy2d } } - bool Node::Dispatch(const MouseEvent & e, bool handled) - { - if (visible_) - { - spNode prev; - for (auto child = children_.Last(); child; child = prev) - { - prev = child->PrevItem(); - handled = child->Dispatch(e, handled); - } - - auto handler = dynamic_cast(this); - if (handler) - handler->Handle(e); - } - - return handled; - } - - bool Node::Dispatch(const KeyEvent & e, bool handled) - { - if (visible_) - { - spNode prev; - for (auto child = children_.Last(); child; child = prev) - { - prev = child->PrevItem(); - handled = child->Dispatch(e, handled); - } - - auto handler = dynamic_cast(this); - if (handler) - handler->Handle(e); - } - - return handled; - } - void Node::UpdateOpacity() { if (parent_) @@ -291,6 +286,15 @@ namespace easy2d } } + void Node::SetScene(Scene * scene) + { + scene_ = scene; + for (auto child = children_.First(); child; child = child->NextItem()) + { + child->scene_ = scene; + } + } + void Node::SetZOrder(int order) { if (z_order_ == order) @@ -402,6 +406,7 @@ namespace easy2d children_.PushBack(Node::ItemType(child)); child->parent_ = this; + child->SetScene(this->scene_); child->dirty_transform_ = true; child->SetZOrder(z_order); child->UpdateOpacity(); @@ -471,12 +476,12 @@ namespace easy2d logs::Warningln("Node::RemoveChild failed, child is nullptr"); if (children_.IsEmpty()) - { return false; - } if (child) { + child->parent_ = nullptr; + if (child->scene_) child->SetScene(nullptr); children_.Remove(Node::ItemType(child)); return true; } @@ -497,7 +502,9 @@ namespace easy2d next = child->NextItem(); if (child->hash_name_ == hash_code && child->name_ == child_name) - children_.Remove(child); + { + RemoveChild(child); + } } } diff --git a/core/base/Node.h b/core/base/Node.h index c750cb89..30b5adfd 100644 --- a/core/base/Node.h +++ b/core/base/Node.h @@ -22,10 +22,9 @@ #include "base.hpp" #include "time.h" #include "Unit.h" -#include "KeyEvent.h" -#include "MouseEvent.h" -#include "ActionManager.h" #include "TaskManager.h" +#include "ActionManager.h" +#include "EventDispatcher.h" #include "intrusive/List.hpp" namespace easy2d @@ -35,8 +34,9 @@ namespace easy2d // 节点 class Node : public Unit - , public ActionManager , public TaskManager + , public ActionManager + , public EventDispatcher , protected intrusive::ListItem { friend class Game; @@ -59,6 +59,9 @@ namespace easy2d // 渲染节点 virtual void OnRender(); + // 处理事件 + virtual void HandleEvent(Event* e); + // 获取显示状态 bool IsVisible() const { return visible_; } @@ -96,7 +99,10 @@ namespace easy2d virtual math::Matrix const& GetTransformMatrix() override; // 获取父节点 - virtual spNode GetParent() const { return parent_; } + spNode GetParent() const; + + // 获取所在场景 + spScene GetScene() const; // 设置是否显示 void SetVisible( @@ -215,6 +221,8 @@ namespace easy2d // 从父节点移除 void RemoveFromParent(); + virtual void DispatchEvent(Event* e) override; + // 设置默认支点 static void SetDefaultPivot( float pivot_x, @@ -240,15 +248,7 @@ namespace easy2d void UpdateOpacity(); - virtual bool Dispatch( - const MouseEvent& e, - bool handled - ); - - virtual bool Dispatch( - const KeyEvent& e, - bool handled - ); + void SetScene(Scene* scene); protected: bool inited_; @@ -260,6 +260,7 @@ namespace easy2d String name_; size_t hash_name_; Node* parent_; + Scene* scene_; Color border_color_; Children children_; cpGeometry border_; diff --git a/core/base/Scene.cpp b/core/base/Scene.cpp index f1b06003..d10a6610 100644 --- a/core/base/Scene.cpp +++ b/core/base/Scene.cpp @@ -20,14 +20,38 @@ #include "Scene.h" #include "Node.h" +#include "logs.h" namespace easy2d { Scene::Scene() { + AddListener(SysEvent::WindowActivate, std::bind(&Scene::OnActivate, this)); + AddListener(SysEvent::WindowDeavtivate, std::bind(&Scene::OnDeactivate, this)); + + scene_ = this; } Scene::~Scene() { } + + void Scene::OnEnter() + { + E2D_LOG("Scene entered"); + } + + void Scene::OnExit() + { + E2D_LOG("Scene exited"); + } + + void Scene::OnDeactivate() + { + } + + void Scene::OnActivate() + { + } + } diff --git a/core/base/Scene.h b/core/base/Scene.h index e7ebefbe..5172bbfc 100644 --- a/core/base/Scene.h +++ b/core/base/Scene.h @@ -33,9 +33,15 @@ namespace easy2d virtual ~Scene(); // 进入场景 - virtual void OnEnter() {} + virtual void OnEnter(); // 退出场景 - virtual void OnExit() {} + virtual void OnExit(); + + // 窗口获得焦点 + virtual void OnActivate(); + + // 窗口失去焦点 + virtual void OnDeactivate(); }; } diff --git a/core/base/Sprite.cpp b/core/base/Sprite.cpp index 9b7bf272..47fdc7b6 100644 --- a/core/base/Sprite.cpp +++ b/core/base/Sprite.cpp @@ -131,7 +131,7 @@ namespace easy2d { if (image_) { - devices::Graphics::Instance()->DrawImage(image_); + Graphics::Instance()->DrawImage(image_); } } } \ No newline at end of file diff --git a/core/base/TaskManager.cpp b/core/base/TaskManager.cpp index 8bcfab7d..8d99c269 100644 --- a/core/base/TaskManager.cpp +++ b/core/base/TaskManager.cpp @@ -43,7 +43,7 @@ namespace easy2d void TaskManager::AddTask(spTask const& task) { if (!task) - logs::Warningln("Node::AddTask failed, action is nullptr"); + logs::Warningln("AddTask failed, task is nullptr"); if (task) { diff --git a/core/base/Text.cpp b/core/base/Text.cpp index fbf7572a..47199dc0 100644 --- a/core/base/Text.cpp +++ b/core/base/Text.cpp @@ -295,7 +295,7 @@ namespace easy2d { if (text_layout_) { - auto graphics = devices::Graphics::Instance(); + auto graphics = Graphics::Instance(); graphics->SetTextStyle( style_.color, style_.outline, diff --git a/core/base/Transition.cpp b/core/base/Transition.cpp index 5f1e277a..553a75bc 100644 --- a/core/base/Transition.cpp +++ b/core/base/Transition.cpp @@ -66,14 +66,14 @@ namespace easy2d if (in_scene_) { ThrowIfFailed( - devices::Graphics::Instance()->CreateLayer(in_layer_) + Graphics::Instance()->CreateLayer(in_layer_) ); } if (out_scene_) { ThrowIfFailed( - devices::Graphics::Instance()->CreateLayer(out_layer_) + Graphics::Instance()->CreateLayer(out_layer_) ); } @@ -101,7 +101,7 @@ namespace easy2d void Transition::Render() { - auto graphics = devices::Graphics::Instance(); + auto graphics = Graphics::Instance(); if (out_scene_) { diff --git a/core/base/audio.cpp b/core/base/audio.cpp index 6c9ebf97..3c8fffe5 100644 --- a/core/base/audio.cpp +++ b/core/base/audio.cpp @@ -46,7 +46,7 @@ namespace easy2d { Destroy(); - devices::Audio::Instance()->DeleteVoice(this); + Audio::Instance()->DeleteVoice(this); } HRESULT Voice::Play(const BYTE * wave_data, UINT32 data_size, UINT32 loop_count) @@ -155,90 +155,88 @@ namespace easy2d } - namespace devices + //------------------------------------------------------- + // AudioDevice + //------------------------------------------------------- + + AudioDevice::AudioDevice() + : x_audio2_(nullptr) + , mastering_voice_(nullptr) { - //------------------------------------------------------- - // AudioDevice - //------------------------------------------------------- - - AudioDevice::AudioDevice() - : x_audio2_(nullptr) - , mastering_voice_(nullptr) - { - } - - AudioDevice::~AudioDevice() - { - E2D_LOG("Destroying audio device"); - - ClearVoiceCache(); - - if (mastering_voice_) - { - mastering_voice_->DestroyVoice(); - mastering_voice_ = nullptr; - } - - SafeRelease(x_audio2_); - - modules::MediaFoundation().MFShutdown(); - } - - HRESULT AudioDevice::Init(bool debug) - { - E2D_LOG("Initing audio device"); - - HRESULT hr = modules::MediaFoundation().MFStartup(MF_VERSION, MFSTARTUP_FULL); - - if (SUCCEEDED(hr)) - { - hr = modules::XAudio2().XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR); - } - - if (SUCCEEDED(hr)) - { - hr = x_audio2_->CreateMasteringVoice(&mastering_voice_); - } - - return hr; - } - - HRESULT AudioDevice::CreateVoice(Voice& voice, const WAVEFORMATEX* wfx) - { - HRESULT hr; - IXAudio2SourceVoice* source_voice; - - hr = x_audio2_->CreateSourceVoice(&source_voice, wfx, 0, XAUDIO2_DEFAULT_FREQ_RATIO); - if (SUCCEEDED(hr)) - { - voice.SetSourceVoice(source_voice); - voice_cache_.insert(&voice); - } - return hr; - } - - void AudioDevice::DeleteVoice(Voice* voice) - { - voice_cache_.erase(voice); - } - - void AudioDevice::ClearVoiceCache() - { - for (auto voice : voice_cache_) - { - voice->Destroy(); - } - voice_cache_.clear(); - } - - void AudioDevice::Open() - { - x_audio2_->StartEngine(); - } - - void AudioDevice::Close() - { - x_audio2_->StopEngine(); - } } + + AudioDevice::~AudioDevice() + { + E2D_LOG("Destroying audio device"); + + ClearVoiceCache(); + + if (mastering_voice_) + { + mastering_voice_->DestroyVoice(); + mastering_voice_ = nullptr; + } + + SafeRelease(x_audio2_); + + modules::MediaFoundation().MFShutdown(); + } + + HRESULT AudioDevice::Init(bool debug) + { + E2D_LOG("Initing audio device"); + + HRESULT hr = modules::MediaFoundation().MFStartup(MF_VERSION, MFSTARTUP_FULL); + + if (SUCCEEDED(hr)) + { + hr = modules::XAudio2().XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR); + } + + if (SUCCEEDED(hr)) + { + hr = x_audio2_->CreateMasteringVoice(&mastering_voice_); + } + + return hr; + } + + HRESULT AudioDevice::CreateVoice(Voice& voice, const WAVEFORMATEX* wfx) + { + HRESULT hr; + IXAudio2SourceVoice* source_voice; + + hr = x_audio2_->CreateSourceVoice(&source_voice, wfx, 0, XAUDIO2_DEFAULT_FREQ_RATIO); + if (SUCCEEDED(hr)) + { + voice.SetSourceVoice(source_voice); + voice_cache_.insert(&voice); + } + return hr; + } + + void AudioDevice::DeleteVoice(Voice* voice) + { + voice_cache_.erase(voice); + } + + void AudioDevice::ClearVoiceCache() + { + for (auto voice : voice_cache_) + { + voice->Destroy(); + } + voice_cache_.clear(); + } + + void AudioDevice::Open() + { + x_audio2_->StartEngine(); + } + + void AudioDevice::Close() + { + x_audio2_->StopEngine(); + } + } \ No newline at end of file diff --git a/core/base/audio.h b/core/base/audio.h index 729884c3..762534da 100644 --- a/core/base/audio.h +++ b/core/base/audio.h @@ -72,44 +72,42 @@ namespace easy2d IXAudio2SourceVoice* source_voice_; }; - namespace devices + + class AudioDevice + : protected Noncopyable { - class AudioDevice - : protected Noncopyable - { - E2D_DECLARE_SINGLETON(AudioDevice); + E2D_DECLARE_SINGLETON(AudioDevice); - public: - HRESULT Init(bool debug); + public: + HRESULT Init(bool debug); - // 开启设备 - void Open(); + // 开启设备 + void Open(); - // 关闭设备 - void Close(); + // 关闭设备 + void Close(); - HRESULT CreateVoice( - Voice& voice, - const WAVEFORMATEX* wfx - ); + HRESULT CreateVoice( + Voice& voice, + const WAVEFORMATEX* wfx + ); - void DeleteVoice( - Voice* voice - ); + void DeleteVoice( + Voice* voice + ); - void ClearVoiceCache(); + void ClearVoiceCache(); - protected: - AudioDevice(); + protected: + AudioDevice(); - ~AudioDevice(); + ~AudioDevice(); - protected: - IXAudio2* x_audio2_; - IXAudio2MasteringVoice* mastering_voice_; - std::set voice_cache_; - }; + protected: + IXAudio2* x_audio2_; + IXAudio2MasteringVoice* mastering_voice_; + std::set voice_cache_; + }; - E2D_DECLARE_SINGLETON_TYPE(AudioDevice, Audio); - } + E2D_DECLARE_SINGLETON_TYPE(AudioDevice, Audio); } diff --git a/core/base/base.hpp b/core/base/base.hpp index 6675029d..f7136ff7 100644 --- a/core/base/base.hpp +++ b/core/base/base.hpp @@ -24,6 +24,7 @@ #include "ObjectBase.h" #include "intrusive/SmartPointer.hpp" #include "d2dres.hpp" +#include #ifndef E2D_DECLARE_SMART_PTR #define E2D_DECLARE_SMART_PTR(class_name)\ @@ -43,6 +44,7 @@ namespace easy2d E2D_DECLARE_SMART_PTR(Image); E2D_DECLARE_SMART_PTR(Music); E2D_DECLARE_SMART_PTR(Task); + E2D_DECLARE_SMART_PTR(EventListener); E2D_DECLARE_SMART_PTR(Frames); E2D_DECLARE_SMART_PTR(Geometry); diff --git a/core/base/render.cpp b/core/base/render.cpp index 5bdf6818..9641ada0 100644 --- a/core/base/render.cpp +++ b/core/base/render.cpp @@ -28,493 +28,490 @@ namespace easy2d { - namespace devices + GraphicsDevice::GraphicsDevice() + : fps_text_format_(nullptr) + , fps_text_layout_(nullptr) + , clear_color_(D2D1::ColorF(D2D1::ColorF::Black)) + , opacity_(1.f) + , window_occluded_(false) + , vsync_enabled_(true) + , antialias_(true) + , text_antialias_(TextAntialias::ClearType) { - GraphicsDevice::GraphicsDevice() - : fps_text_format_(nullptr) - , fps_text_layout_(nullptr) - , clear_color_(D2D1::ColorF(D2D1::ColorF::Black)) - , opacity_(1.f) - , window_occluded_(false) - , vsync_enabled_(true) - , antialias_(true) - , text_antialias_(TextAntialias::ClearType) + } + + GraphicsDevice::~GraphicsDevice() + { + E2D_LOG("Destroying graphics device"); + + ClearImageCache(); + } + + HRESULT GraphicsDevice::Init(HWND hwnd, bool vsync, bool debug) + { + E2D_LOG("Initing graphics device"); + + HRESULT hr = CreateResources(hwnd); + + if (SUCCEEDED(hr)) { + vsync_enabled_ = vsync; } + return hr; + } - GraphicsDevice::~GraphicsDevice() + HRESULT GraphicsDevice::BeginDraw(HWND hwnd) + { + HRESULT hr = CreateResources(hwnd); + + if (SUCCEEDED(hr)) { - E2D_LOG("Destroying graphics device"); + window_occluded_ = !!(render_target_->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED); - ClearImageCache(); - } - - HRESULT GraphicsDevice::Init(HWND hwnd, bool vsync, bool debug) - { - E2D_LOG("Initing graphics device"); - - HRESULT hr = CreateResources(hwnd); - - if (SUCCEEDED(hr)) - { - vsync_enabled_ = vsync; - } - return hr; - } - - HRESULT GraphicsDevice::BeginDraw(HWND hwnd) - { - HRESULT hr = CreateResources(hwnd); - - if (SUCCEEDED(hr)) - { - window_occluded_ = !!(render_target_->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED); - - if (!window_occluded_) - { - render_target_->BeginDraw(); - render_target_->Clear(clear_color_); - } - } - - return hr; - } - - HRESULT GraphicsDevice::EndDraw() - { - HRESULT hr = S_OK; if (!window_occluded_) { - hr = render_target_->EndDraw(); - - if (hr == D2DERR_RECREATE_TARGET) - { - // 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源 - // 并在下一次调用时重建资源 - DiscardResources(); - hr = S_OK; - } + render_target_->BeginDraw(); + render_target_->Clear(clear_color_); } - return hr; - } - - void GraphicsDevice::ClearImageCache() - { - bitmap_cache_.clear(); - } - - HRESULT GraphicsDevice::CreateLayer(cpLayer& layer) - { - if (!render_target_) - return E_UNEXPECTED; - - layer = nullptr; - return render_target_->CreateLayer(&layer); - } - - HRESULT GraphicsDevice::CreateSolidColorBrush(cpSolidColorBrush & brush) const - { - if (!render_target_) - return E_UNEXPECTED; - - brush = nullptr; - return render_target_->CreateSolidColorBrush( - D2D1::ColorF(D2D1::ColorF::White), - &brush - ); - } - - HRESULT GraphicsDevice::DrawGeometry( - cpGeometry const& geometry, - Color const& stroke_color, - float stroke_width, - StrokeStyle stroke - ) - { - if (!solid_brush_ || - !render_target_) - return E_UNEXPECTED; - - if (window_occluded_) - return S_OK; - - solid_brush_->SetColor(stroke_color); - auto stroke_style = Factory::Instance()->GetStrokeStyle(stroke); - render_target_->DrawGeometry( - geometry.Get(), - solid_brush_.Get(), - stroke_width, - stroke_style.Get() - ); - return S_OK; - } - - HRESULT GraphicsDevice::FillGeometry(cpGeometry const & geometry, const Color & fill_color) - { - if (!solid_brush_ || - !render_target_) - return E_UNEXPECTED; - - if (window_occluded_) - return S_OK; - - solid_brush_->SetColor(fill_color); - render_target_->FillGeometry( - geometry.Get(), - solid_brush_.Get() - ); - return S_OK; - } - - HRESULT GraphicsDevice::DrawImage(spImage const & image) - { - if (!render_target_) - return E_UNEXPECTED; - - if (!image->GetBitmap()) - return S_OK; - - if (window_occluded_) - return S_OK; - - render_target_->DrawBitmap( - image->GetBitmap().Get(), - D2D1::RectF(0.f, 0.f, image->GetWidth(), image->GetHeight()), - opacity_, - D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, - image->GetCropRect() - ); - return S_OK; - } - - HRESULT GraphicsDevice::DrawBitmap( - cpBitmap const& bitmap - ) - { - if (!render_target_) - return E_UNEXPECTED; - - if (window_occluded_) - return S_OK; - - // Do not crop bitmap - auto rect = D2D1::RectF(0.f, 0.f, bitmap->GetSize().width, bitmap->GetSize().height); - render_target_->DrawBitmap( - bitmap.Get(), - rect, - opacity_, - D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, - rect - ); - return S_OK; - } - - HRESULT GraphicsDevice::DrawTextLayout(cpTextLayout const& text_layout) - { - if (!text_renderer_) - return E_UNEXPECTED; - - if (window_occluded_) - return S_OK; - - return text_layout->Draw(nullptr, text_renderer_.Get(), 0, 0); - } - - HRESULT GraphicsDevice::PushClip(const math::Matrix & clip_matrix, const Size & clip_size) - { - if (!render_target_) - return E_UNEXPECTED; - - if (window_occluded_) - return S_OK; - - render_target_->SetTransform(ConvertToD2DMatrix(clip_matrix)); - render_target_->PushAxisAlignedClip( - D2D1::RectF(0, 0, clip_size.width, clip_size.height), - D2D1_ANTIALIAS_MODE_PER_PRIMITIVE - ); - return S_OK; - } - - HRESULT GraphicsDevice::PopClip() - { - if (!render_target_) - return E_UNEXPECTED; - - if (window_occluded_) - return S_OK; - - render_target_->PopAxisAlignedClip(); - return S_OK; - } - - HRESULT GraphicsDevice::PushLayer(cpLayer const& layer, LayerProperties const& properties) - { - if (!render_target_ || - !solid_brush_) - return E_UNEXPECTED; - - if (window_occluded_) - return S_OK; - - render_target_->PushLayer( - D2D1::LayerParameters( - properties.area, - nullptr, - D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, - D2D1::Matrix3x2F::Identity(), - properties.opacity, - solid_brush_.Get(), - D2D1_LAYER_OPTIONS_NONE - ), - layer.Get() - ); - return S_OK; - } - - HRESULT GraphicsDevice::PopLayer() - { - if (!render_target_) - return E_UNEXPECTED; - - if (window_occluded_) - return S_OK; - - render_target_->PopLayer(); - return S_OK; - } - - HRESULT GraphicsDevice::GetSize(Size & size) - { - if (!render_target_) - return E_UNEXPECTED; - - auto rtsize = render_target_->GetSize(); - size.width = rtsize.width; - size.height = rtsize.height; - return S_OK; - } - - HRESULT GraphicsDevice::CreateBitmapFromFile(cpBitmap& bitmap, String const& file_path) - { - if (render_target_ == nullptr) - { - return E_UNEXPECTED; - } - - 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; - } - - cpBitmap bitmap_tmp; - HRESULT hr = Factory::Instance()->CreateBitmapFromFile( - bitmap, - render_target_, - file_path - ); - - if (SUCCEEDED(hr)) - { - bitmap_cache_.insert(std::make_pair(hash_code, bitmap)); - } - - return hr; - } - - HRESULT GraphicsDevice::CreateBitmapFromResource(cpBitmap& bitmap, Resource const& res) - { - if (render_target_ == nullptr) - { - return E_UNEXPECTED; - } - - 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 = Factory::Instance()->CreateBitmapFromResource( - bitmap, - render_target_, - res - ); - - if (SUCCEEDED(hr)) - { - bitmap_cache_.insert(std::make_pair(hash_code, bitmap)); - } - - return hr; - } - - HRESULT GraphicsDevice::CreateBitmapRenderTarget(cpBitmapRenderTarget & brt) - { - if (!render_target_) - return E_UNEXPECTED; - - brt = nullptr; - return render_target_->CreateCompatibleRenderTarget(&brt); - } - - HRESULT GraphicsDevice::Resize(UINT32 width, UINT32 height) - { - if (!render_target_) - return E_UNEXPECTED; - - render_target_->Resize(D2D1::SizeU(width, height)); - return S_OK; - } - - HRESULT GraphicsDevice::SetTransform(const math::Matrix & matrix) - { - if (!render_target_) - return E_UNEXPECTED; - - render_target_->SetTransform(ConvertToD2DMatrix(matrix)); - return S_OK; - } - - HRESULT GraphicsDevice::SetOpacity(float opacity) - { - if (!render_target_) - return E_UNEXPECTED; - - opacity_ = opacity; - solid_brush_->SetOpacity(opacity); - return S_OK; - } - - HRESULT GraphicsDevice::SetTextStyle( - Color const& color, - bool has_outline, - Color const& outline_color, - float outline_width, - StrokeStyle outline_stroke - ) - { - if (!text_renderer_) - return E_UNEXPECTED; - - auto stroke_style = Factory::Instance()->GetStrokeStyle(outline_stroke); - text_renderer_->SetTextStyle( - color, - has_outline, - outline_color, - outline_width, - stroke_style.Get() - ); - return S_OK; - } - - void GraphicsDevice::SetClearColor(const Color& color) - { - clear_color_ = color; - } - - HRESULT GraphicsDevice::SetAntialiasMode(bool enabled) - { - if (!render_target_) - return E_UNEXPECTED; - - render_target_->SetAntialiasMode( - enabled ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED - ); - antialias_ = enabled; - return S_OK; - } - - HRESULT GraphicsDevice::SetTextAntialiasMode(TextAntialias mode) - { - if (!render_target_) - return E_UNEXPECTED; - - text_antialias_ = mode; - D2D1_TEXT_ANTIALIAS_MODE antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; - switch (text_antialias_) - { - case TextAntialias::Default: - antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; - break; - case TextAntialias::ClearType: - antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; - break; - case TextAntialias::GrayScale: - antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; - break; - case TextAntialias::None: - antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED; - break; - default: - break; - } - render_target_->SetTextAntialiasMode(antialias_mode); - return S_OK; - } - - HRESULT GraphicsDevice::CreateResources(HWND hwnd) - { - HRESULT hr = S_OK; - - if (!render_target_) - { - RECT rc; - ::GetClientRect(hwnd, &rc); - - D2D1_SIZE_U size = D2D1::SizeU( - rc.right - rc.left, - rc.bottom - rc.top - ); - - hr = Factory::Instance()->CreateHwndRenderTarget( - render_target_, - D2D1::RenderTargetProperties(), - D2D1::HwndRenderTargetProperties( - hwnd, - size, - vsync_enabled_ ? D2D1_PRESENT_OPTIONS_NONE : D2D1_PRESENT_OPTIONS_IMMEDIATELY - ) - ); - - if (SUCCEEDED(hr)) - { - SetAntialiasMode(antialias_); - SetTextAntialiasMode(text_antialias_); - } - - if (SUCCEEDED(hr)) - { - hr = render_target_->CreateSolidColorBrush( - D2D1::ColorF(D2D1::ColorF::White), - &solid_brush_ - ); - } - - if (SUCCEEDED(hr)) - { - hr = Factory::Instance()->CreateTextRenderer( - text_renderer_, - render_target_, - solid_brush_ - ); - } - } - return hr; - } - - void GraphicsDevice::DiscardResources() - { - // FIXME! 应通知 Game 类销毁所有节点的 device resources - fps_text_format_ = nullptr; - fps_text_layout_ = nullptr; - text_renderer_ = nullptr; - solid_brush_ = nullptr; - render_target_ = nullptr; } + return hr; } + + HRESULT GraphicsDevice::EndDraw() + { + HRESULT hr = S_OK; + if (!window_occluded_) + { + hr = render_target_->EndDraw(); + + if (hr == D2DERR_RECREATE_TARGET) + { + // 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源 + // 并在下一次调用时重建资源 + DiscardResources(); + hr = S_OK; + } + } + return hr; + } + + void GraphicsDevice::ClearImageCache() + { + bitmap_cache_.clear(); + } + + HRESULT GraphicsDevice::CreateLayer(cpLayer& layer) + { + if (!render_target_) + return E_UNEXPECTED; + + layer = nullptr; + return render_target_->CreateLayer(&layer); + } + + HRESULT GraphicsDevice::CreateSolidColorBrush(cpSolidColorBrush & brush) const + { + if (!render_target_) + return E_UNEXPECTED; + + brush = nullptr; + return render_target_->CreateSolidColorBrush( + D2D1::ColorF(D2D1::ColorF::White), + &brush + ); + } + + HRESULT GraphicsDevice::DrawGeometry( + cpGeometry const& geometry, + Color const& stroke_color, + float stroke_width, + StrokeStyle stroke + ) + { + if (!solid_brush_ || + !render_target_) + return E_UNEXPECTED; + + if (window_occluded_) + return S_OK; + + solid_brush_->SetColor(stroke_color); + auto stroke_style = Factory::Instance()->GetStrokeStyle(stroke); + render_target_->DrawGeometry( + geometry.Get(), + solid_brush_.Get(), + stroke_width, + stroke_style.Get() + ); + return S_OK; + } + + HRESULT GraphicsDevice::FillGeometry(cpGeometry const & geometry, const Color & fill_color) + { + if (!solid_brush_ || + !render_target_) + return E_UNEXPECTED; + + if (window_occluded_) + return S_OK; + + solid_brush_->SetColor(fill_color); + render_target_->FillGeometry( + geometry.Get(), + solid_brush_.Get() + ); + return S_OK; + } + + HRESULT GraphicsDevice::DrawImage(spImage const & image) + { + if (!render_target_) + return E_UNEXPECTED; + + if (!image->GetBitmap()) + return S_OK; + + if (window_occluded_) + return S_OK; + + render_target_->DrawBitmap( + image->GetBitmap().Get(), + D2D1::RectF(0.f, 0.f, image->GetWidth(), image->GetHeight()), + opacity_, + D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, + image->GetCropRect() + ); + return S_OK; + } + + HRESULT GraphicsDevice::DrawBitmap( + cpBitmap const& bitmap + ) + { + if (!render_target_) + return E_UNEXPECTED; + + if (window_occluded_) + return S_OK; + + // Do not crop bitmap + auto rect = D2D1::RectF(0.f, 0.f, bitmap->GetSize().width, bitmap->GetSize().height); + render_target_->DrawBitmap( + bitmap.Get(), + rect, + opacity_, + D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, + rect + ); + return S_OK; + } + + HRESULT GraphicsDevice::DrawTextLayout(cpTextLayout const& text_layout) + { + if (!text_renderer_) + return E_UNEXPECTED; + + if (window_occluded_) + return S_OK; + + return text_layout->Draw(nullptr, text_renderer_.Get(), 0, 0); + } + + HRESULT GraphicsDevice::PushClip(const math::Matrix & clip_matrix, const Size & clip_size) + { + if (!render_target_) + return E_UNEXPECTED; + + if (window_occluded_) + return S_OK; + + render_target_->SetTransform(ConvertToD2DMatrix(clip_matrix)); + render_target_->PushAxisAlignedClip( + D2D1::RectF(0, 0, clip_size.width, clip_size.height), + D2D1_ANTIALIAS_MODE_PER_PRIMITIVE + ); + return S_OK; + } + + HRESULT GraphicsDevice::PopClip() + { + if (!render_target_) + return E_UNEXPECTED; + + if (window_occluded_) + return S_OK; + + render_target_->PopAxisAlignedClip(); + return S_OK; + } + + HRESULT GraphicsDevice::PushLayer(cpLayer const& layer, LayerProperties const& properties) + { + if (!render_target_ || + !solid_brush_) + return E_UNEXPECTED; + + if (window_occluded_) + return S_OK; + + render_target_->PushLayer( + D2D1::LayerParameters( + properties.area, + nullptr, + D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, + D2D1::Matrix3x2F::Identity(), + properties.opacity, + solid_brush_.Get(), + D2D1_LAYER_OPTIONS_NONE + ), + layer.Get() + ); + return S_OK; + } + + HRESULT GraphicsDevice::PopLayer() + { + if (!render_target_) + return E_UNEXPECTED; + + if (window_occluded_) + return S_OK; + + render_target_->PopLayer(); + return S_OK; + } + + HRESULT GraphicsDevice::GetSize(Size & size) + { + if (!render_target_) + return E_UNEXPECTED; + + auto rtsize = render_target_->GetSize(); + size.width = rtsize.width; + size.height = rtsize.height; + return S_OK; + } + + HRESULT GraphicsDevice::CreateBitmapFromFile(cpBitmap& bitmap, String const& file_path) + { + if (render_target_ == nullptr) + { + return E_UNEXPECTED; + } + + 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; + } + + cpBitmap bitmap_tmp; + HRESULT hr = Factory::Instance()->CreateBitmapFromFile( + bitmap, + render_target_, + file_path + ); + + if (SUCCEEDED(hr)) + { + bitmap_cache_.insert(std::make_pair(hash_code, bitmap)); + } + + return hr; + } + + HRESULT GraphicsDevice::CreateBitmapFromResource(cpBitmap& bitmap, Resource const& res) + { + if (render_target_ == nullptr) + { + return E_UNEXPECTED; + } + + 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 = Factory::Instance()->CreateBitmapFromResource( + bitmap, + render_target_, + res + ); + + if (SUCCEEDED(hr)) + { + bitmap_cache_.insert(std::make_pair(hash_code, bitmap)); + } + + return hr; + } + + HRESULT GraphicsDevice::CreateBitmapRenderTarget(cpBitmapRenderTarget & brt) + { + if (!render_target_) + return E_UNEXPECTED; + + brt = nullptr; + return render_target_->CreateCompatibleRenderTarget(&brt); + } + + HRESULT GraphicsDevice::Resize(UINT32 width, UINT32 height) + { + if (!render_target_) + return E_UNEXPECTED; + + render_target_->Resize(D2D1::SizeU(width, height)); + return S_OK; + } + + HRESULT GraphicsDevice::SetTransform(const math::Matrix & matrix) + { + if (!render_target_) + return E_UNEXPECTED; + + render_target_->SetTransform(ConvertToD2DMatrix(matrix)); + return S_OK; + } + + HRESULT GraphicsDevice::SetOpacity(float opacity) + { + if (!render_target_) + return E_UNEXPECTED; + + opacity_ = opacity; + solid_brush_->SetOpacity(opacity); + return S_OK; + } + + HRESULT GraphicsDevice::SetTextStyle( + Color const& color, + bool has_outline, + Color const& outline_color, + float outline_width, + StrokeStyle outline_stroke + ) + { + if (!text_renderer_) + return E_UNEXPECTED; + + auto stroke_style = Factory::Instance()->GetStrokeStyle(outline_stroke); + text_renderer_->SetTextStyle( + color, + has_outline, + outline_color, + outline_width, + stroke_style.Get() + ); + return S_OK; + } + + void GraphicsDevice::SetClearColor(const Color& color) + { + clear_color_ = color; + } + + HRESULT GraphicsDevice::SetAntialiasMode(bool enabled) + { + if (!render_target_) + return E_UNEXPECTED; + + render_target_->SetAntialiasMode( + enabled ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED + ); + antialias_ = enabled; + return S_OK; + } + + HRESULT GraphicsDevice::SetTextAntialiasMode(TextAntialias mode) + { + if (!render_target_) + return E_UNEXPECTED; + + text_antialias_ = mode; + D2D1_TEXT_ANTIALIAS_MODE antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; + switch (text_antialias_) + { + case TextAntialias::Default: + antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; + break; + case TextAntialias::ClearType: + antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; + break; + case TextAntialias::GrayScale: + antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; + break; + case TextAntialias::None: + antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED; + break; + default: + break; + } + render_target_->SetTextAntialiasMode(antialias_mode); + return S_OK; + } + + HRESULT GraphicsDevice::CreateResources(HWND hwnd) + { + HRESULT hr = S_OK; + + if (!render_target_) + { + RECT rc; + ::GetClientRect(hwnd, &rc); + + D2D1_SIZE_U size = D2D1::SizeU( + rc.right - rc.left, + rc.bottom - rc.top + ); + + hr = Factory::Instance()->CreateHwndRenderTarget( + render_target_, + D2D1::RenderTargetProperties(), + D2D1::HwndRenderTargetProperties( + hwnd, + size, + vsync_enabled_ ? D2D1_PRESENT_OPTIONS_NONE : D2D1_PRESENT_OPTIONS_IMMEDIATELY + ) + ); + + if (SUCCEEDED(hr)) + { + SetAntialiasMode(antialias_); + SetTextAntialiasMode(text_antialias_); + } + + if (SUCCEEDED(hr)) + { + hr = render_target_->CreateSolidColorBrush( + D2D1::ColorF(D2D1::ColorF::White), + &solid_brush_ + ); + } + + if (SUCCEEDED(hr)) + { + hr = Factory::Instance()->CreateTextRenderer( + text_renderer_, + render_target_, + solid_brush_ + ); + } + } + return hr; + } + + void GraphicsDevice::DiscardResources() + { + // FIXME! 应通知 Game 类销毁所有节点的 device resources + fps_text_format_ = nullptr; + fps_text_layout_ = nullptr; + text_renderer_ = nullptr; + solid_brush_ = nullptr; + render_target_ = nullptr; + } + } diff --git a/core/base/render.h b/core/base/render.h index 85e8f68b..830a8f65 100644 --- a/core/base/render.h +++ b/core/base/render.h @@ -37,150 +37,148 @@ namespace easy2d None // 不启用抗锯齿 }; - namespace devices + + class GraphicsDevice + : protected Noncopyable { - class GraphicsDevice - : protected Noncopyable - { - E2D_DECLARE_SINGLETON(GraphicsDevice); + E2D_DECLARE_SINGLETON(GraphicsDevice); - public: - HRESULT Init(HWND hwnd, bool vsync, bool debug); + public: + HRESULT Init(HWND hwnd, bool vsync, bool debug); - // 开始渲染 - HRESULT BeginDraw(HWND hwnd); + // 开始渲染 + HRESULT BeginDraw(HWND hwnd); - // 结束渲染 - HRESULT EndDraw(); + // 结束渲染 + HRESULT EndDraw(); - // 设置清空屏幕的颜色 - void SetClearColor( - const Color& color - ); + // 设置清空屏幕的颜色 + void SetClearColor( + const Color& color + ); - // 设置抗锯齿模式 - HRESULT SetAntialiasMode( - bool enabled - ); + // 设置抗锯齿模式 + HRESULT SetAntialiasMode( + bool enabled + ); - // 设置文字抗锯齿模式 - HRESULT SetTextAntialiasMode( - TextAntialias mode - ); + // 设置文字抗锯齿模式 + HRESULT SetTextAntialiasMode( + TextAntialias mode + ); - HRESULT CreateResources( - HWND hwnd - ); + HRESULT CreateResources( + HWND hwnd + ); - void DiscardResources(); + void DiscardResources(); - HRESULT CreateLayer( - cpLayer& layer - ); + HRESULT CreateLayer( + cpLayer& layer + ); - HRESULT CreateSolidColorBrush( - cpSolidColorBrush& brush - ) const; + HRESULT CreateSolidColorBrush( + cpSolidColorBrush& brush + ) const; - HRESULT CreateBitmapFromFile( - cpBitmap& bitmap, - String const& file_path - ); + HRESULT CreateBitmapFromFile( + cpBitmap& bitmap, + String const& file_path + ); - HRESULT CreateBitmapFromResource( - cpBitmap& bitmap, - Resource const& res - ); + HRESULT CreateBitmapFromResource( + cpBitmap& bitmap, + Resource const& res + ); - HRESULT CreateBitmapRenderTarget( - cpBitmapRenderTarget& brt - ); + HRESULT CreateBitmapRenderTarget( + cpBitmapRenderTarget& brt + ); - HRESULT SetTransform( - const math::Matrix& matrix - ); + HRESULT SetTransform( + const math::Matrix& matrix + ); - HRESULT SetOpacity( - float opacity - ); + HRESULT SetOpacity( + float opacity + ); - HRESULT SetTextStyle( - const Color& color, - bool has_outline, - const Color& outline_color, - float outline_width, - StrokeStyle outline_stroke - ); + HRESULT SetTextStyle( + const Color& color, + bool has_outline, + const Color& outline_color, + float outline_width, + StrokeStyle outline_stroke + ); - HRESULT DrawGeometry( - cpGeometry const& geometry, - const Color& stroke_color, - float stroke_width, - StrokeStyle stroke = StrokeStyle::Miter - ); + HRESULT DrawGeometry( + cpGeometry const& geometry, + const Color& stroke_color, + float stroke_width, + StrokeStyle stroke = StrokeStyle::Miter + ); - HRESULT FillGeometry( - cpGeometry const& geometry, - const Color& fill_color - ); + HRESULT FillGeometry( + cpGeometry const& geometry, + const Color& fill_color + ); - HRESULT DrawImage( - spImage const& image - ); + HRESULT DrawImage( + spImage const& image + ); - HRESULT DrawBitmap( - cpBitmap const& bitmap - ); + HRESULT DrawBitmap( + cpBitmap const& bitmap + ); - HRESULT DrawTextLayout( - cpTextLayout const& text_layout - ); + HRESULT DrawTextLayout( + cpTextLayout const& text_layout + ); - HRESULT PushClip( - const math::Matrix& clip_matrix, - const Size& clip_size - ); + HRESULT PushClip( + const math::Matrix& clip_matrix, + const Size& clip_size + ); - HRESULT PopClip(); + HRESULT PopClip(); - HRESULT PushLayer( - cpLayer const& layer, - LayerProperties const& properties - ); + HRESULT PushLayer( + cpLayer const& layer, + LayerProperties const& properties + ); - HRESULT PopLayer(); + HRESULT PopLayer(); - HRESULT GetSize( - Size& size - ); + HRESULT GetSize( + Size& size + ); - HRESULT Resize( - UINT32 width, - UINT32 height - ); + HRESULT Resize( + UINT32 width, + UINT32 height + ); - void ClearImageCache(); + void ClearImageCache(); - protected: - GraphicsDevice(); + protected: + GraphicsDevice(); - ~GraphicsDevice(); + ~GraphicsDevice(); - protected: - bool window_occluded_; - bool vsync_enabled_; - bool antialias_; - TextAntialias text_antialias_; - float opacity_; - cpTextRenderer text_renderer_; - cpSolidColorBrush solid_brush_; - cpHwndRenderTarget render_target_; - D2D1_COLOR_F clear_color_; - cpTextFormat fps_text_format_; - cpTextLayout fps_text_layout_; - std::map bitmap_cache_; - }; + protected: + bool window_occluded_; + bool vsync_enabled_; + bool antialias_; + TextAntialias text_antialias_; + float opacity_; + cpTextRenderer text_renderer_; + cpSolidColorBrush solid_brush_; + cpHwndRenderTarget render_target_; + D2D1_COLOR_F clear_color_; + cpTextFormat fps_text_format_; + cpTextLayout fps_text_layout_; + std::map bitmap_cache_; + }; - E2D_DECLARE_SINGLETON_TYPE(GraphicsDevice, Graphics); - } + E2D_DECLARE_SINGLETON_TYPE(GraphicsDevice, Graphics); } diff --git a/core/base/window.cpp b/core/base/window.cpp index f43897d6..15ef7303 100644 --- a/core/base/window.cpp +++ b/core/base/window.cpp @@ -81,7 +81,6 @@ namespace easy2d GetContentScale(&scale_x, &scale_y); - Rect client_rect = LocateWindow(width, height, scale_x, scale_y); handle = ::CreateWindowEx( NULL, @@ -197,6 +196,12 @@ namespace easy2d return scale_y; } + void WindowImpl::Destroy() + { + if (handle) + ::DestroyWindow(handle); + } + namespace { void GetContentScale(float* scale_x, float* scale_y) diff --git a/core/base/window.h b/core/base/window.h index c6b7acf3..8380bef1 100644 --- a/core/base/window.h +++ b/core/base/window.h @@ -66,6 +66,8 @@ namespace easy2d float GetContentScaleY() const; + void Destroy(); + protected: WindowImpl(); diff --git a/core/easy2d.h b/core/easy2d.h index eab186a6..06036d49 100644 --- a/core/easy2d.h +++ b/core/easy2d.h @@ -50,21 +50,13 @@ #include "base/TextStyle.hpp" #include "base/noncopyable.hpp" +#include "base/RefCounter.hpp" #include "base/intrusive/SmartPointer.hpp" #include "base/intrusive/List.hpp" -#include "base/RefCounter.hpp" #include "base/ObjectBase.h" -#include "base/Unit.h" -#include "base/Geometry.h" #include "base/Image.h" #include "base/Frames.h" -#include "base/Node.h" -#include "base/Scene.h" -#include "base/Sprite.h" -#include "base/Text.h" -#include "base/Canvas.h" -#include "base/GeometryNode.h" #include "base/Music.h" #include "base/Task.h" #include "base/Action.hpp" @@ -73,10 +65,24 @@ #include "base/Animation.h" #include "base/Delay.h" #include "base/Transition.h" -#include "base/Debuger.h" +#include "base/TaskManager.h" +#include "base/ActionManager.h" -#include "base/KeyEvent.h" -#include "base/MouseEvent.h" +#include "base/Event.hpp" +#include "base/MouseEvent.hpp" +#include "base/KeyEvent.hpp" +#include "base/EventListener.h" +#include "base/EventDispatcher.h" + +#include "base/Unit.h" +#include "base/Geometry.h" +#include "base/Node.h" +#include "base/Scene.h" +#include "base/Sprite.h" +#include "base/Text.h" +#include "base/Canvas.h" +#include "base/GeometryNode.h" +#include "base/Debuger.h" #include "base/Factory.h" #include "base/Game.h" diff --git a/core/ui/Button.cpp b/core/ui/Button.cpp index 5eb28290..e5c194ba 100644 --- a/core/ui/Button.cpp +++ b/core/ui/Button.cpp @@ -19,7 +19,7 @@ // THE SOFTWARE. #include "Button.h" -#include "../base/input.h" +#include "../base/MouseEvent.hpp" #define SAFE_SET(pointer, func, ...) if (pointer) { pointer->##func(__VA_ARGS__); } @@ -171,53 +171,55 @@ namespace easy2d SAFE_SET(disabled_, SetPivot, pivot_x, pivot_y); } - bool Button::Dispatch(const MouseEvent & e, bool handled) + void Button::HandleEvent(Event* e) { - if (!handled && enabled_ && IsVisible() && normal_) + if (e && MouseEvent::Check(e) && !e->has_target) { - bool contains = normal_->ContainsPoint(e.GetPosition()); - if (e.GetType() == MouseEvent::Type::LeftUp && is_selected_ && contains) + MouseEvent* me = static_cast(e); + if (enabled_ && IsVisible() && normal_) { - if (callback_) + bool contains = normal_->ContainsPoint(Point{ me->x, me->y }); + if (me->type == MouseEvent::Up && is_selected_ && contains) { - callback_(); + if (callback_) + { + callback_(); + } + is_selected_ = false; + SetStatus(Status::Normal); + me->has_target = true; } - is_selected_ = false; - SetStatus(Status::Normal); - return true; - } - else if (e.GetType() == MouseEvent::Type::LeftDown) - { - is_selected_ = contains; - SetStatus(contains ? Status::Selected : Status::Normal); + else if (me->type == MouseEvent::Down) + { + is_selected_ = contains; + SetStatus(contains ? Status::Selected : Status::Normal); - if (contains) - return true; - } - else if (e.GetType() == MouseEvent::Type::LeftUp) - { - is_selected_ = false; - } - else if (e.GetType() == MouseEvent::Type::Move && is_selected_ && contains) - { - SetStatus(Status::Selected); - return true; - } - else - { - if (!e.IsLButtonDown() && is_selected_) + me->has_target = contains; + } + else if (me->type == MouseEvent::Up) { is_selected_ = false; } + else if (me->type == MouseEvent::Move && is_selected_ && contains) + { + SetStatus(Status::Selected); + me->has_target = true; + } + else + { + if (!me->button_down && is_selected_) + { + is_selected_ = false; + } - SetStatus(contains ? Status::Mouseover : Status::Normal); + SetStatus(contains ? Status::Mouseover : Status::Normal); - if (contains) - return true; + me->has_target = contains; + } } } - return Node::Dispatch(e, handled); + Node::HandleEvent(e); } void Button::SetStatus(Status status) diff --git a/core/ui/Button.h b/core/ui/Button.h index 2ffe4c17..9e7b07e6 100644 --- a/core/ui/Button.h +++ b/core/ui/Button.h @@ -102,6 +102,8 @@ namespace easy2d float pivot_y ) override; + virtual void HandleEvent(Event* e) override; + private: // 按钮状态枚举 enum class Status { Normal, Mouseover, Selected }; @@ -114,12 +116,6 @@ namespace easy2d // 刷新按钮显示 virtual void UpdateVisible(); - // 分发鼠标消息 - virtual bool Dispatch( - const MouseEvent& e, - bool handled - ) override; - private: spNode normal_; spNode mouseover_; diff --git a/project/vs2013/Easy2D.vcxproj b/project/vs2013/Easy2D.vcxproj index 894b5170..66b2556c 100644 --- a/project/vs2013/Easy2D.vcxproj +++ b/project/vs2013/Easy2D.vcxproj @@ -32,6 +32,9 @@ + + + @@ -42,11 +45,11 @@ - + - + @@ -96,6 +99,8 @@ + + @@ -103,10 +108,8 @@ - - diff --git a/project/vs2013/Easy2D.vcxproj.filters b/project/vs2013/Easy2D.vcxproj.filters index 9bc3e1bf..313c07e6 100644 --- a/project/vs2013/Easy2D.vcxproj.filters +++ b/project/vs2013/Easy2D.vcxproj.filters @@ -71,12 +71,6 @@ base - - base - - - base - math @@ -197,6 +191,21 @@ base + + base + + + base + + + base + + + base + + + base + @@ -276,12 +285,6 @@ base - - base - - - base - math @@ -348,5 +351,11 @@ base + + base + + + base + \ No newline at end of file diff --git a/project/vs2015/Easy2D.vcxproj b/project/vs2015/Easy2D.vcxproj index 4541122b..a8d319f5 100644 --- a/project/vs2015/Easy2D.vcxproj +++ b/project/vs2015/Easy2D.vcxproj @@ -32,6 +32,9 @@ + + + @@ -42,11 +45,11 @@ - + - + @@ -96,6 +99,8 @@ + + @@ -103,10 +108,8 @@ - - diff --git a/project/vs2015/Easy2D.vcxproj.filters b/project/vs2015/Easy2D.vcxproj.filters index 9bc3e1bf..313c07e6 100644 --- a/project/vs2015/Easy2D.vcxproj.filters +++ b/project/vs2015/Easy2D.vcxproj.filters @@ -71,12 +71,6 @@ base - - base - - - base - math @@ -197,6 +191,21 @@ base + + base + + + base + + + base + + + base + + + base + @@ -276,12 +285,6 @@ base - - base - - - base - math @@ -348,5 +351,11 @@ base + + base + + + base + \ No newline at end of file diff --git a/project/vs2017/Easy2D.vcxproj b/project/vs2017/Easy2D.vcxproj index ae834806..8bfa00c2 100644 --- a/project/vs2017/Easy2D.vcxproj +++ b/project/vs2017/Easy2D.vcxproj @@ -32,6 +32,9 @@ + + + @@ -42,11 +45,11 @@ - + - + @@ -96,6 +99,8 @@ + + @@ -103,10 +108,8 @@ - - diff --git a/project/vs2017/Easy2D.vcxproj.filters b/project/vs2017/Easy2D.vcxproj.filters index 9bc3e1bf..313c07e6 100644 --- a/project/vs2017/Easy2D.vcxproj.filters +++ b/project/vs2017/Easy2D.vcxproj.filters @@ -71,12 +71,6 @@ base - - base - - - base - math @@ -197,6 +191,21 @@ base + + base + + + base + + + base + + + base + + + base + @@ -276,12 +285,6 @@ base - - base - - - base - math @@ -348,5 +351,11 @@ base + + base + + + base + \ No newline at end of file