From bf25bd1d41e953deacdce6f58e4e3f0bd64b4583 Mon Sep 17 00:00:00 2001 From: Haibo Date: Wed, 21 Nov 2018 19:24:18 +0800 Subject: [PATCH] add TimeScale refactoring refactoring --- core/base/Canvas.cpp | 2 +- core/base/Canvas.h | 2 +- core/base/Debuger.cpp | 2 +- core/base/Debuger.h | 2 +- core/base/Factory.cpp | 168 +++++++++++---------- core/base/Factory.h | 15 +- core/base/Game.cpp | 137 ++++++++++------- core/base/Game.h | 19 ++- core/base/GeometryNode.cpp | 10 +- core/base/GeometryNode.h | 5 +- core/base/Input.cpp | 10 +- core/base/Input.h | 3 +- core/base/Node.cpp | 219 +++++++++++++++------------- core/base/Node.h | 65 +++++---- core/base/Sprite.cpp | 2 +- core/base/Sprite.h | 2 +- core/base/Text.cpp | 2 +- core/base/Text.h | 2 +- core/base/Transition.cpp | 4 +- core/base/audio.cpp | 28 ++-- core/base/audio.h | 3 +- core/base/render.cpp | 291 ++++++++++++++++++++----------------- core/base/render.h | 51 +++---- core/base/window.cpp | 18 +-- core/base/window.h | 3 +- core/ui/Button.cpp | 25 ---- core/ui/Button.h | 3 - 27 files changed, 561 insertions(+), 532 deletions(-) diff --git a/core/base/Canvas.cpp b/core/base/Canvas.cpp index 72d6c1e1..e2623649 100644 --- a/core/base/Canvas.cpp +++ b/core/base/Canvas.cpp @@ -96,7 +96,7 @@ namespace easy2d cache_expired_ = true; } - void Canvas::OnDraw() + void Canvas::OnRender() { if (cache_expired_) { diff --git a/core/base/Canvas.h b/core/base/Canvas.h index ed6b4f7e..e8997ee1 100644 --- a/core/base/Canvas.h +++ b/core/base/Canvas.h @@ -218,7 +218,7 @@ namespace easy2d // 导出为图片 spImage ExportToImage() const; - virtual void OnDraw() override; + virtual void OnRender() override; protected: cpBitmap const& GetBitmap() const; diff --git a/core/base/Debuger.cpp b/core/base/Debuger.cpp index e32bd37c..79b06a17 100644 --- a/core/base/Debuger.cpp +++ b/core/base/Debuger.cpp @@ -68,7 +68,7 @@ namespace easy2d texts_.clear(); } - void DebugerNode::OnUpdate(Duration const & dt) + void DebugerNode::Update(Duration const & dt) { try { diff --git a/core/base/Debuger.h b/core/base/Debuger.h index 13cc967e..c585251f 100644 --- a/core/base/Debuger.h +++ b/core/base/Debuger.h @@ -39,7 +39,7 @@ namespace easy2d void ClearDebugText(); - void OnUpdate(Duration const& dt) override; + void Update(Duration const& dt) override; protected: spText debug_text_; diff --git a/core/base/Factory.cpp b/core/base/Factory.cpp index 2f4dc35a..cc8c0100 100644 --- a/core/base/Factory.cpp +++ b/core/base/Factory.cpp @@ -26,7 +26,6 @@ namespace easy2d { FactoryImpl::FactoryImpl() - : initialized_(false) { } @@ -35,91 +34,90 @@ namespace easy2d E2D_LOG("Destroying device independent resources"); } - void FactoryImpl::Init(bool debug) + HRESULT FactoryImpl::Init(bool debug) { - if (initialized_) - return; - E2D_LOG("Creating device independent resources"); D2D1_FACTORY_OPTIONS fact_options; fact_options.debugLevel = debug ? D2D1_DEBUG_LEVEL_INFORMATION : D2D1_DEBUG_LEVEL_NONE; - ThrowIfFailed( - modules::DirectX().D2D1CreateFactory( - D2D1_FACTORY_TYPE_SINGLE_THREADED, - __uuidof(ID2D1Factory), - &fact_options, - reinterpret_cast(&factory) - ) + HRESULT hr = modules::DirectX().D2D1CreateFactory( + D2D1_FACTORY_TYPE_SINGLE_THREADED, + __uuidof(ID2D1Factory), + &fact_options, + reinterpret_cast(&factory_) ); - ThrowIfFailed( + if (SUCCEEDED(hr)) + { CoCreateInstance( CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, __uuidof(IWICImagingFactory), - reinterpret_cast(&imaging_factory) - ) - ); + reinterpret_cast(&imaging_factory_) + ); + } - ThrowIfFailed( + if (SUCCEEDED(hr)) + { modules::DirectX().DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), - reinterpret_cast(&write_factory) - ) - ); + reinterpret_cast(&write_factory_) + ); + } - auto stroke_style = D2D1::StrokeStyleProperties( - D2D1_CAP_STYLE_FLAT, - D2D1_CAP_STYLE_FLAT, - D2D1_CAP_STYLE_FLAT, - D2D1_LINE_JOIN_MITER, - 2.0f, - D2D1_DASH_STYLE_SOLID, - 0.0f - ); + if (SUCCEEDED(hr)) + { + auto stroke_style = D2D1::StrokeStyleProperties( + D2D1_CAP_STYLE_FLAT, + D2D1_CAP_STYLE_FLAT, + D2D1_CAP_STYLE_FLAT, + D2D1_LINE_JOIN_MITER, + 2.0f, + D2D1_DASH_STYLE_SOLID, + 0.0f + ); - ThrowIfFailed( - factory->CreateStrokeStyle( + hr = factory_->CreateStrokeStyle( stroke_style, nullptr, 0, - &miter_stroke_style - ) - ); + &miter_stroke_style_ + ); - stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL; - ThrowIfFailed( - factory->CreateStrokeStyle( - stroke_style, - nullptr, - 0, - &bevel_stroke_style - ) - ); + if (SUCCEEDED(hr)) + { + stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL; + hr = factory_->CreateStrokeStyle( + stroke_style, + nullptr, + 0, + &bevel_stroke_style_ + ); + } - stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND; - ThrowIfFailed( - factory->CreateStrokeStyle( - stroke_style, - nullptr, - 0, - &round_stroke_style - ) - ); - - initialized_ = true; + if (SUCCEEDED(hr)) + { + stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND; + hr = factory_->CreateStrokeStyle( + stroke_style, + nullptr, + 0, + &round_stroke_style_ + ); + } + } + return hr; } HRESULT FactoryImpl::CreateHwndRenderTarget(cpHwndRenderTarget & hwnd_render_target, D2D1_RENDER_TARGET_PROPERTIES const & properties, D2D1_HWND_RENDER_TARGET_PROPERTIES const & hwnd_rt_properties) const { - if (!factory) + if (!factory_) return E_UNEXPECTED; cpHwndRenderTarget hwnd_render_target_tmp; - HRESULT hr = factory->CreateHwndRenderTarget( + HRESULT hr = factory_->CreateHwndRenderTarget( properties, hwnd_rt_properties, &hwnd_render_target_tmp @@ -136,13 +134,13 @@ namespace easy2d cpSolidColorBrush const& brush ) { - if (!factory) + if (!factory_) return E_UNEXPECTED; cpTextRenderer text_renderer_tmp; HRESULT hr = ITextRenderer::Create( &text_renderer_tmp, - factory.Get(), + factory_.Get(), render_target.Get(), brush.Get() ); @@ -154,7 +152,7 @@ namespace easy2d HRESULT FactoryImpl::CreateBitmapFromFile(cpBitmap & bitmap, cpRenderTarget const & rt, String const & file_path) { - if (imaging_factory == nullptr) + if (imaging_factory_ == nullptr) { return E_UNEXPECTED; } @@ -167,7 +165,7 @@ namespace easy2d SmartPointer converter; SmartPointer bitmap_tmp; - HRESULT hr = imaging_factory->CreateDecoderFromFilename( + HRESULT hr = imaging_factory_->CreateDecoderFromFilename( file_path.c_str(), nullptr, GENERIC_READ, @@ -182,7 +180,7 @@ namespace easy2d if (SUCCEEDED(hr)) { - hr = imaging_factory->CreateFormatConverter(&converter); + hr = imaging_factory_->CreateFormatConverter(&converter); } if (SUCCEEDED(hr)) @@ -215,7 +213,7 @@ namespace easy2d HRESULT FactoryImpl::CreateBitmapFromResource(cpBitmap & bitmap, cpRenderTarget const & rt, Resource const & res) { - if (imaging_factory == nullptr) + if (imaging_factory_ == nullptr) { return E_UNEXPECTED; } @@ -234,7 +232,7 @@ namespace easy2d if (SUCCEEDED(hr)) { - hr = imaging_factory->CreateStream(&stream); + hr = imaging_factory_->CreateStream(&stream); } if (SUCCEEDED(hr)) @@ -247,7 +245,7 @@ namespace easy2d if (SUCCEEDED(hr)) { - hr = imaging_factory->CreateDecoderFromStream( + hr = imaging_factory_->CreateDecoderFromStream( stream.Get(), nullptr, WICDecodeMetadataCacheOnLoad, @@ -262,7 +260,7 @@ namespace easy2d if (SUCCEEDED(hr)) { - hr = imaging_factory->CreateFormatConverter(&converter); + hr = imaging_factory_->CreateFormatConverter(&converter); } if (SUCCEEDED(hr)) @@ -297,11 +295,11 @@ namespace easy2d HRESULT FactoryImpl::CreateRectangleGeometry(cpRectangleGeometry & geo, Rect const& rect) const { - if (!factory) + if (!factory_) return E_UNEXPECTED; cpRectangleGeometry rectangle; - HRESULT hr = factory->CreateRectangleGeometry( + HRESULT hr = factory_->CreateRectangleGeometry( rect, &rectangle ); @@ -313,11 +311,11 @@ namespace easy2d HRESULT FactoryImpl::CreateRoundedRectangleGeometry(cpRoundedRectangleGeometry & geo, Rect const & rect, float radius_x, float radius_y) const { - if (!factory) + if (!factory_) return E_UNEXPECTED; cpRoundedRectangleGeometry rounded_rect; - HRESULT hr = factory->CreateRoundedRectangleGeometry( + HRESULT hr = factory_->CreateRoundedRectangleGeometry( D2D1::RoundedRect( rect, radius_x, @@ -333,11 +331,11 @@ namespace easy2d HRESULT FactoryImpl::CreateEllipseGeometry(cpEllipseGeometry & geo, Point const & center, float radius_x, float radius_y) const { - if (!factory) + if (!factory_) return E_UNEXPECTED; cpEllipseGeometry ellipse; - HRESULT hr = factory->CreateEllipseGeometry( + HRESULT hr = factory_->CreateEllipseGeometry( D2D1::Ellipse( center, radius_x, @@ -357,11 +355,11 @@ namespace easy2d cpGeometry const& geo ) const { - if (!factory) + if (!factory_) return E_UNEXPECTED; cpTransformedGeometry transformed_tmp; - HRESULT hr = factory->CreateTransformedGeometry( + HRESULT hr = factory_->CreateTransformedGeometry( geo.Get(), ConvertToD2DMatrix(matrix), &transformed_tmp @@ -376,19 +374,19 @@ namespace easy2d HRESULT FactoryImpl::CreatePathGeometry(cpPathGeometry & geometry) const { - if (!factory) + if (!factory_) return E_UNEXPECTED; - return factory->CreatePathGeometry(&geometry); + return factory_->CreatePathGeometry(&geometry); } HRESULT FactoryImpl::CreateTextFormat(cpTextFormat & text_format, Font const & font, TextStyle const & text_style) const { - if (!write_factory) + if (!write_factory_) return E_UNEXPECTED; cpTextFormat text_format_tmp; - HRESULT hr = write_factory->CreateTextFormat( + HRESULT hr = write_factory_->CreateTextFormat( font.family.c_str(), nullptr, DWRITE_FONT_WEIGHT(font.weight), @@ -422,7 +420,7 @@ namespace easy2d HRESULT FactoryImpl::CreateTextLayout(cpTextLayout & text_layout, Size& layout_size, String const & text, cpTextFormat const& text_format, TextStyle const & text_style) const { - if (!write_factory) + if (!write_factory_) return E_UNEXPECTED; text_layout = nullptr; @@ -433,7 +431,7 @@ namespace easy2d if (text_style.wrap) { - hr = write_factory->CreateTextLayout( + hr = write_factory_->CreateTextLayout( text.c_str(), length, text_format.Get(), @@ -444,7 +442,7 @@ namespace easy2d } else { - hr = write_factory->CreateTextLayout( + hr = write_factory_->CreateTextLayout( text.c_str(), length, text_format.Get(), @@ -459,7 +457,7 @@ namespace easy2d if (SUCCEEDED(hr)) { text_layout_tmp = nullptr; - hr = write_factory->CreateTextLayout( + hr = write_factory_->CreateTextLayout( text.c_str(), length, text_format.Get(), @@ -503,16 +501,16 @@ namespace easy2d switch (stroke) { case StrokeStyle::Miter: - return miter_stroke_style; + return miter_stroke_style_; break; case StrokeStyle::Bevel: - return bevel_stroke_style; + return bevel_stroke_style_; break; case StrokeStyle::Round: - return round_stroke_style; + return round_stroke_style_; break; } - return miter_stroke_style; + return miter_stroke_style_; } } diff --git a/core/base/Factory.h b/core/base/Factory.h index 32d47689..d84eed04 100644 --- a/core/base/Factory.h +++ b/core/base/Factory.h @@ -35,7 +35,7 @@ namespace easy2d E2D_DECLARE_SINGLETON(FactoryImpl); public: - void Init(bool debug); + HRESULT Init(bool debug); HRESULT CreateHwndRenderTarget( cpHwndRenderTarget& hwnd_render_target, @@ -114,13 +114,12 @@ namespace easy2d ~FactoryImpl(); protected: - bool initialized_; - cpFactory factory; - cpImagingFactory imaging_factory; - cpWriteFactory write_factory; - cpStrokeStyle miter_stroke_style; - cpStrokeStyle bevel_stroke_style; - cpStrokeStyle round_stroke_style; + cpFactory factory_; + cpImagingFactory imaging_factory_; + cpWriteFactory write_factory_; + cpStrokeStyle miter_stroke_style_; + cpStrokeStyle bevel_stroke_style_; + cpStrokeStyle round_stroke_style_; }; E2D_DECLARE_SINGLETON_TYPE(FactoryImpl, Factory); diff --git a/core/base/Game.cpp b/core/base/Game.cpp index 87b58dee..4c1012e4 100644 --- a/core/base/Game.cpp +++ b/core/base/Game.cpp @@ -20,8 +20,6 @@ #include "Game.h" #include "logs.h" -#include "input.h" -#include "audio.h" #include "modules.h" #include "Factory.h" #include "Scene.h" @@ -35,13 +33,17 @@ namespace easy2d { Game::Game() - : curr_scene_(nullptr) + : initialized_(false) + , window_inactived_(false) + , curr_scene_(nullptr) , next_scene_(nullptr) , transition_(nullptr) + , window_(nullptr) + , graphics_(nullptr) + , input_(nullptr) + , audio_(nullptr) , debug_enabled_(false) - , initialized_(false) - , hwnd_(nullptr) - , window_inactived_(false) + , time_scale_(1.f) { ::CoInitialize(nullptr); } @@ -64,72 +66,90 @@ namespace easy2d debug_enabled_ = options.debug; - Window::Instance()->Init( - options.title, - options.width, - options.height, - options.icon, - Game::WndProc, - debug_enabled_ + window_ = Window::Instance(); + graphics_ = devices::Graphics::Instance(); + input_ = devices::Input::Instance(); + audio_ = devices::Audio::Instance(); + + ThrowIfFailed( + Factory::Instance()->Init(debug_enabled_) ); - const auto window = Window::Instance(); - hwnd_ = window->GetHandle(); + ThrowIfFailed( + window_->Init( + options.title, + options.width, + options.height, + options.icon, + Game::WndProc, + debug_enabled_ + ) + ); - ::SetWindowLongW(hwnd_, GWLP_USERDATA, PtrToUlong(this)); + HWND hwnd = window_->GetHandle(); - Factory::Instance()->Init(debug_enabled_); - devices::Graphics::Instance()->Init(hwnd_, options.graphics_options, debug_enabled_); - devices::Input::Instance()->Init(hwnd_, window->GetContentScaleX(), window->GetContentScaleY(), debug_enabled_); - devices::Audio::Instance()->Init(debug_enabled_); + ThrowIfFailed( + graphics_->Init( + hwnd, + options.vsync, + debug_enabled_ + ) + ); + + ThrowIfFailed( + input_->Init( + hwnd, + window_->GetContentScaleX(), + window_->GetContentScaleY(), + debug_enabled_ + ) + ); + + ThrowIfFailed( + audio_->Init(debug_enabled_) + ); // disable imm - ::ImmAssociateContext(hwnd_, nullptr); + ::ImmAssociateContext(hwnd, nullptr); + // show console if debug mode enabled HWND console = ::GetConsoleWindow(); - if (debug_enabled_) + if (debug_enabled_ && !console) { - if (console == nullptr) + if (::AllocConsole()) { - if (::AllocConsole()) - { - console = ::GetConsoleWindow(); - FILE * stdoutStream, *stdinStream, *stderrStream; - freopen_s(&stdoutStream, "conout$", "w+t", stdout); - freopen_s(&stdinStream, "conin$", "r+t", stdin); - freopen_s(&stderrStream, "conout$", "w+t", stderr); - } + console = ::GetConsoleWindow(); + FILE * stdoutStream, *stdinStream, *stderrStream; + freopen_s(&stdoutStream, "conout$", "w+t", stdout); + freopen_s(&stdinStream, "conin$", "r+t", stdin); + freopen_s(&stderrStream, "conout$", "w+t", stderr); } } - else + else if (!debug_enabled_ && console) { - if (console) - { - ::ShowWindow(console, SW_HIDE); - } + ::ShowWindow(console, SW_HIDE); } + // disable the close button of console if (console) { - // disable the close button of console HMENU hmenu = ::GetSystemMenu(console, FALSE); ::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND); } + // use Game instance in message loop + ::SetWindowLongW(hwnd, GWLP_USERDATA, PtrToUlong(this)); + initialized_ = true; } void Game::Run() { - if (next_scene_) - { - next_scene_->OnEnter(); - curr_scene_ = next_scene_; - next_scene_ = nullptr; - } + if (!initialized_) + return; - ::ShowWindow(hwnd_, SW_SHOWNORMAL); - ::UpdateWindow(hwnd_); + ::ShowWindow(window_->GetHandle(), SW_SHOWNORMAL); + ::UpdateWindow(window_->GetHandle()); MSG msg = {}; while (::GetMessageW(&msg, nullptr, 0, 0)) @@ -141,7 +161,8 @@ namespace easy2d void Game::Quit() { - ::DestroyWindow(hwnd_); + if (window_) + ::DestroyWindow(window_->GetHandle()); } bool Game::EnterScene(spScene const & scene) @@ -182,15 +203,20 @@ namespace easy2d return curr_scene_; } + void Game::SetTimeScale(float scale) + { + time_scale_ = scale; + } + void Game::Update() { static auto last = time::Now(); const auto now = time::Now(); - const auto dt = now - last; + const auto dt = (now - last) * time_scale_; last = now; - devices::Input::Instance()->Update(); + input_->Update(); if (curr_scene_) curr_scene_->Update(dt); @@ -228,7 +254,10 @@ namespace easy2d void Game::Render() { auto graphics = devices::Graphics::Instance(); - graphics->BeginDraw(hwnd_); + + ThrowIfFailed( + graphics->BeginDraw(window_->GetHandle()) + ); if (transition_) { @@ -236,7 +265,7 @@ namespace easy2d } else if (curr_scene_) { - curr_scene_->Visit(); + curr_scene_->Render(); } if (debug_enabled_) @@ -254,13 +283,15 @@ namespace easy2d next_scene_->DrawBorder(); } - Debuger::Instance()->Visit(); + Debuger::Instance()->Render(); } - graphics->EndDraw(); + ThrowIfFailed( + graphics->EndDraw() + ); if (!window_inactived_) - ::InvalidateRect(hwnd_, NULL, FALSE); + ::InvalidateRect(window_->GetHandle(), NULL, FALSE); } void Game::Dispatch(MouseEvent const & e) diff --git a/core/base/Game.h b/core/base/Game.h index 00bd95c3..30db361a 100644 --- a/core/base/Game.h +++ b/core/base/Game.h @@ -20,9 +20,11 @@ #pragma once #include "base.hpp" -#include "window.h" #include "time.h" +#include "window.h" #include "render.h" +#include "input.h" +#include "audio.h" #include "KeyEvent.h" #include "MouseEvent.h" @@ -34,17 +36,16 @@ namespace easy2d int width; // 宽度 int height; // 高度 LPCWSTR icon; // 图标 + bool vsync; // 垂直同步 bool debug; // 调试模式 - GraphicsOptions graphics_options; // 图形渲染选项 - Options() : title(L"Easy2D Game") , width(640) , height(480) , icon(nullptr) + , vsync(true) , debug(false) - , graphics_options() {} }; @@ -93,6 +94,9 @@ namespace easy2d // 获取当前场景 spScene const& GetCurrentScene(); + // 设置变速 + void SetTimeScale(float scale); + private: void Render(); @@ -112,9 +116,14 @@ namespace easy2d bool initialized_; bool debug_enabled_; bool window_inactived_; - HWND hwnd_; + 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 0d9ba623..54fde7ae 100644 --- a/core/base/GeometryNode.cpp +++ b/core/base/GeometryNode.cpp @@ -66,7 +66,7 @@ namespace easy2d outline_join_ = outline_join; } - void GeometryNode::OnDraw() + void GeometryNode::OnRender() { if (geometry_ && geometry_->geo_) { @@ -87,12 +87,4 @@ namespace easy2d } } - void GeometryNode::DrawBorder() - { - if (visible_) - { - DrawChildrenBorder(); - } - } - } diff --git a/core/base/GeometryNode.h b/core/base/GeometryNode.h index 130f5720..f584d7ad 100644 --- a/core/base/GeometryNode.h +++ b/core/base/GeometryNode.h @@ -77,10 +77,7 @@ namespace easy2d // 获取线条相交样式 StrokeStyle SetOutlineJoinStyle() const { return outline_join_; } - virtual void OnDraw() override; - - protected: - virtual void DrawBorder() override; + virtual void OnRender() override; protected: Color fill_color_; diff --git a/core/base/Input.cpp b/core/base/Input.cpp index 915b9911..c5372c2f 100644 --- a/core/base/Input.cpp +++ b/core/base/Input.cpp @@ -27,8 +27,7 @@ namespace easy2d namespace devices { InputDevice::InputDevice() - : initialized_(false) - , hwnd_(nullptr) + : hwnd_(nullptr) , scale_x_(1.f) , scale_y_(1.f) { @@ -41,18 +40,15 @@ namespace easy2d E2D_LOG("Destroying input device"); } - void InputDevice::Init(HWND hwnd, float scale_x, float scale_y, bool debug) + HRESULT InputDevice::Init(HWND hwnd, float scale_x, float scale_y, bool debug) { - if (initialized_) - return; - E2D_LOG("Initing input device"); hwnd_ = hwnd; scale_x_ = scale_x; scale_y_ = scale_y; - initialized_ = true; + return S_OK; } void InputDevice::Update() diff --git a/core/base/Input.h b/core/base/Input.h index 9833f63d..1d137748 100644 --- a/core/base/Input.h +++ b/core/base/Input.h @@ -32,7 +32,7 @@ namespace easy2d E2D_DECLARE_SINGLETON(InputDevice); public: - void Init(HWND hwnd, float scale_x, float scale_y, bool debug); + HRESULT Init(HWND hwnd, float scale_x, float scale_y, bool debug); // 检测键盘某按键是否正被按下 bool IsDown( @@ -71,7 +71,6 @@ namespace easy2d ~InputDevice(); protected: - bool initialized_; HWND hwnd_; float scale_x_; float scale_y_; diff --git a/core/base/Node.cpp b/core/base/Node.cpp index 3da4fc48..1a42812a 100644 --- a/core/base/Node.cpp +++ b/core/base/Node.cpp @@ -32,6 +32,7 @@ namespace easy2d { float default_pivot_x = 0.f; float default_pivot_y = 0.f; + bool border_enabled = false; } void Node::SetDefaultPivot(float pivot_x, float pivot_y) @@ -40,12 +41,23 @@ namespace easy2d default_pivot_y = pivot_y; } + void easy2d::Node::EnableBorder() + { + border_enabled = true; + } + + void easy2d::Node::DisableBorder() + { + border_enabled = false; + } + Node::Node() - : visible_(true) + : inited_(false) + , visible_(true) + , dirty_sort_(false) , parent_(nullptr) , hash_name_(0) - , dirty_sort_(false) - , order_(0) + , z_order_(0) , opacity_(1.f) , display_opacity_(1.f) , children_() @@ -57,11 +69,36 @@ namespace easy2d { } - Node::~Node() + void Node::Init() { + inited_ = true; } - void Node::Visit() + void Node::OnRender() + { + // normal node renders nothing + } + + void Node::Update(Duration const & dt) + { + if (!inited_) + { + Init(); + } + + UpdateActions(this, dt); + UpdateTasks(dt); + + if (!children_.IsEmpty()) + { + for (auto child = children_.First(); child; child = child->NextItem()) + { + child->Update(dt); + } + } + } + + void Node::Render() { if (!visible_) return; @@ -74,26 +111,21 @@ namespace easy2d { graphics->SetTransform(final_matrix_); graphics->SetOpacity(display_opacity_); - OnDraw(); + + OnRender(); } else { - if (dirty_sort_) - { - children_.Sort( - [](spNode const& n1, spNode const& n2) { return n1->GetOrder() < n2->GetOrder(); } - ); - - dirty_sort_ = false; - } + SortChildren(); + // render children those are less than 0 in Z-Order spNode child = children_.First(); for (spNode next; child; child = next) { next = child->NextItem(); - if (child->GetOrder() < 0) + if (child->GetZOrder() < 0) { - child->Visit(); + child->Render(); } else { @@ -103,49 +135,13 @@ namespace easy2d graphics->SetTransform(final_matrix_); graphics->SetOpacity(display_opacity_); - OnDraw(); + + OnRender(); for (spNode next; child; child = next) { next = child->NextItem(); - child->Visit(); - } - } - } - - void Node::Update(Duration const& dt) - { - if (children_.IsEmpty()) - { - OnUpdate(dt); - UpdateActions(this, dt); - UpdateTasks(dt); - } - else - { - // 访问 Order 小于零的节点 - spNode child = children_.First(); - for (spNode next; child; child = next) - { - if (child->GetOrder() < 0) - { - next = child->NextItem(); - child->Update(dt); - } - else - { - break; - } - } - - OnUpdate(dt); - UpdateActions(this, dt); - UpdateTasks(dt); - - for (spNode next; child; child = next) - { - next = child->NextItem(); - child->Update(dt); + child->Render(); } } } @@ -159,15 +155,22 @@ namespace easy2d devices::Graphics::Instance()->DrawGeometry(border_, border_color_, 1.5f); } - DrawChildrenBorder(); + for (auto child = children_.First(); child; child = child->NextItem()) + { + child->DrawBorder(); + } } } - void Node::DrawChildrenBorder() + void Node::SortChildren() { - for (auto child = children_.First(); child; child = child->NextItem()) + if (dirty_sort_) { - child->DrawBorder(); + children_.Sort( + [](spNode const& n1, spNode const& n2) { return n1->GetZOrder() < n2->GetZOrder(); } + ); + + dirty_sort_ = false; } } @@ -200,12 +203,17 @@ namespace easy2d final_matrix_ = final_matrix_ * parent_->initial_matrix_; } - UpdateBorder(); - + // update children's transform for (auto child = children_.First(); child; child = child->NextItem()) { child->dirty_transform_ = true; } + + // update border + if (border_enabled) + { + UpdateBorder(); + } } void Node::UpdateBorder() @@ -213,22 +221,24 @@ namespace easy2d cpRectangleGeometry rect; cpTransformedGeometry transformed; - ThrowIfFailed( - Factory::Instance()->CreateRectangleGeometry( - rect, - Rect(Point{}, size_) - ) + HRESULT hr = Factory::Instance()->CreateRectangleGeometry( + rect, + Rect(Point{}, size_) ); - ThrowIfFailed( - Factory::Instance()->CreateTransformedGeometry( + if (SUCCEEDED(hr)) + { + hr = Factory::Instance()->CreateTransformedGeometry( transformed, final_matrix_, rect - ) - ); + ); + } - border_ = transformed; + if (SUCCEEDED(hr)) + { + border_ = transformed; + } } bool Node::Dispatch(const MouseEvent & e, bool handled) @@ -281,12 +291,12 @@ namespace easy2d } } - void Node::SetOrder(int order) + void Node::SetZOrder(int order) { - if (order_ == order) + if (z_order_ == order) return; - order_ = order; + z_order_ = order; if (parent_) { parent_->dirty_sort_ = true; @@ -358,7 +368,21 @@ namespace easy2d border_color_ = color; } - void Node::AddChild(spNode const& child, int order) + void Node::SetVisible(bool val) + { + visible_ = val; + } + + void Node::SetName(String const& name) + { + if (name_ != name) + { + name_ = name; + hash_name_ = std::hash{}(name); + } + } + + void Node::AddChild(spNode const& child, int z_order) { if (!child) logs::Warningln("Node::AddChild failed, child is nullptr"); @@ -366,28 +390,31 @@ namespace easy2d if (child) { #ifdef E2D_DEBUG + if (child->parent_) logs::Errorln("The node to be added already has a parent"); + for (Node* parent = parent_; parent; parent = parent->parent_) if (parent == child) logs::Errorln("A node cannot be its own parent"); + #endif // E2D_DEBUG children_.PushBack(Node::ItemType(child)); child->parent_ = this; child->dirty_transform_ = true; - child->SetOrder(order); + child->SetZOrder(z_order); child->UpdateOpacity(); dirty_sort_ = true; } } - void Node::AddChild(const Nodes& nodes, int order) + void Node::AddChild(const Nodes& nodes, int z_order) { for (const auto& node : nodes) { - this->AddChild(node, order); + this->AddChild(node, z_order); } } @@ -486,30 +513,22 @@ namespace easy2d UpdateTransform(); - BOOL ret = 0; + cpRectangleGeometry border; + ThrowIfFailed( - border_->FillContainsPoint( - point, - D2D1::Matrix3x2F::Identity(), - &ret + Factory::Instance()->CreateRectangleGeometry( + border, + Rect(Point{}, size_) ) ); + + BOOL ret = 0; + // no matter it failed or not + border->FillContainsPoint( + point, + ConvertToD2DMatrix(final_matrix_), + &ret + ); return !!ret; } - - void Node::SetVisible(bool val) - { - visible_ = val; - } - - void Node::SetName(String const& name) - { - if (name_ != name) - { - // 保存节点名 - name_ = name; - // 保存节点 Hash 名 - hash_name_ = std::hash{}(name); - } - } -} \ No newline at end of file +} diff --git a/core/base/Node.h b/core/base/Node.h index a48a3122..c750cb89 100644 --- a/core/base/Node.h +++ b/core/base/Node.h @@ -50,13 +50,14 @@ namespace easy2d public: Node(); - virtual ~Node(); - - // 渲染节点 - virtual void OnDraw() {} + // 初始化节点 + virtual void Init(); // 更新节点 - virtual void OnUpdate(Duration const& dt) {} + virtual void Update(Duration const& dt); + + // 渲染节点 + virtual void OnRender(); // 获取显示状态 bool IsVisible() const { return visible_; } @@ -67,8 +68,8 @@ namespace easy2d // 获取名称的 Hash 值 size_t GetHashName() const { return hash_name_; } - // 获取绘图顺序 - int GetOrder() const { return order_; } + // 获取 Z 轴顺序 + int GetZOrder() const { return z_order_; } // 获取宽度 virtual float GetWidth() const { return size_.width * transform_.scale.x; } @@ -157,9 +158,9 @@ namespace easy2d float opacity ); - // 设置绘图顺序 + // 设置 Z 轴顺序 // 默认为 0 - void SetOrder( + void SetZOrder( int order ); @@ -176,13 +177,13 @@ namespace easy2d // 添加子节点 void AddChild( spNode const& child, - int order = 0 /* 渲染顺序 */ + int z_order = 0 /* Z 轴顺序 */ ); // 添加多个子节点 void AddChild( const Nodes& nodes, /* 节点数组 */ - int order = 0 /* 渲染顺序 */ + int z_order = 0 /* Z 轴顺序 */ ); // 获取所有名称相同的子节点 @@ -220,8 +221,24 @@ namespace easy2d float pivot_y ); + // 启用边框自动生成 + static void EnableBorder(); + + // 禁用边框自动生成 + static void DisableBorder(); + protected: - virtual void Visit(); + void Render(); + + void DrawBorder(); + + void SortChildren(); + + void UpdateBorder(); + + void UpdateTransform(); + + void UpdateOpacity(); virtual bool Dispatch( const MouseEvent& e, @@ -234,26 +251,14 @@ namespace easy2d ); protected: - virtual void Update(Duration const& dt); - - virtual void DrawBorder(); - - void DrawChildrenBorder(); - - void UpdateBorder(); - - void UpdateTransform(); - - void UpdateOpacity(); - - protected: - String name_; - size_t hash_name_; - float display_opacity_; - float opacity_; - int order_; + bool inited_; bool visible_; bool dirty_sort_; + int z_order_; + float opacity_; + float display_opacity_; + String name_; + size_t hash_name_; Node* parent_; Color border_color_; Children children_; diff --git a/core/base/Sprite.cpp b/core/base/Sprite.cpp index 0b5e797b..9b7bf272 100644 --- a/core/base/Sprite.cpp +++ b/core/base/Sprite.cpp @@ -127,7 +127,7 @@ namespace easy2d return image_; } - void Sprite::OnDraw() + void Sprite::OnRender() { if (image_) { diff --git a/core/base/Sprite.h b/core/base/Sprite.h index a50e19cd..fd13eb62 100644 --- a/core/base/Sprite.h +++ b/core/base/Sprite.h @@ -79,7 +79,7 @@ namespace easy2d spImage const& GetImage() const; // 渲染精灵 - virtual void OnDraw() override; + virtual void OnRender() override; protected: spImage image_; diff --git a/core/base/Text.cpp b/core/base/Text.cpp index 71e1dc73..fbf7572a 100644 --- a/core/base/Text.cpp +++ b/core/base/Text.cpp @@ -291,7 +291,7 @@ namespace easy2d style_.outline_stroke = outline_stroke; } - void Text::OnDraw() + void Text::OnRender() { if (text_layout_) { diff --git a/core/base/Text.h b/core/base/Text.h index 0b7d1762..275571c4 100644 --- a/core/base/Text.h +++ b/core/base/Text.h @@ -199,7 +199,7 @@ namespace easy2d TextStyle const& style ); - virtual void OnDraw() override; + virtual void OnRender() override; protected: void UpdateLayout(); diff --git a/core/base/Transition.cpp b/core/base/Transition.cpp index 874a15a1..5f1e277a 100644 --- a/core/base/Transition.cpp +++ b/core/base/Transition.cpp @@ -111,7 +111,7 @@ namespace easy2d ); graphics->PushLayer(out_layer_, out_layer_prop_); - out_scene_->Visit(); + out_scene_->Render(); graphics->PopLayer(); graphics->PopClip(); @@ -125,7 +125,7 @@ namespace easy2d ); graphics->PushLayer(in_layer_, in_layer_prop_); - in_scene_->Visit(); + in_scene_->Render(); graphics->PopLayer(); graphics->PopClip(); diff --git a/core/base/audio.cpp b/core/base/audio.cpp index 7a88c569..6c9ebf97 100644 --- a/core/base/audio.cpp +++ b/core/base/audio.cpp @@ -164,7 +164,6 @@ namespace easy2d AudioDevice::AudioDevice() : x_audio2_(nullptr) , mastering_voice_(nullptr) - , initialized_(false) { } @@ -185,26 +184,23 @@ namespace easy2d modules::MediaFoundation().MFShutdown(); } - void AudioDevice::Init(bool debug) + HRESULT AudioDevice::Init(bool debug) { - if (initialized_) - return; - E2D_LOG("Initing audio device"); - ThrowIfFailed( - modules::MediaFoundation().MFStartup(MF_VERSION, MFSTARTUP_FULL) - ); + HRESULT hr = modules::MediaFoundation().MFStartup(MF_VERSION, MFSTARTUP_FULL); - ThrowIfFailed( - modules::XAudio2().XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR) - ); + if (SUCCEEDED(hr)) + { + hr = modules::XAudio2().XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR); + } - ThrowIfFailed( - x_audio2_->CreateMasteringVoice(&mastering_voice_) - ); - - initialized_ = true; + if (SUCCEEDED(hr)) + { + hr = x_audio2_->CreateMasteringVoice(&mastering_voice_); + } + + return hr; } HRESULT AudioDevice::CreateVoice(Voice& voice, const WAVEFORMATEX* wfx) diff --git a/core/base/audio.h b/core/base/audio.h index a89939b5..729884c3 100644 --- a/core/base/audio.h +++ b/core/base/audio.h @@ -80,7 +80,7 @@ namespace easy2d E2D_DECLARE_SINGLETON(AudioDevice); public: - void Init(bool debug); + HRESULT Init(bool debug); // 开启设备 void Open(); @@ -105,7 +105,6 @@ namespace easy2d ~AudioDevice(); protected: - bool initialized_; IXAudio2* x_audio2_; IXAudio2MasteringVoice* mastering_voice_; std::set voice_cache_; diff --git a/core/base/render.cpp b/core/base/render.cpp index e0f93cd2..5bdf6818 100644 --- a/core/base/render.cpp +++ b/core/base/render.cpp @@ -36,8 +36,9 @@ namespace easy2d , clear_color_(D2D1::ColorF(D2D1::ColorF::Black)) , opacity_(1.f) , window_occluded_(false) - , initialized_(false) - , options_() + , vsync_enabled_(true) + , antialias_(true) + , text_antialias_(TextAntialias::ClearType) { } @@ -48,54 +49,53 @@ namespace easy2d ClearImageCache(); } - void GraphicsDevice::Init(HWND hwnd, GraphicsOptions options, bool debug) + HRESULT GraphicsDevice::Init(HWND hwnd, bool vsync, bool debug) { - if (initialized_) - return; - E2D_LOG("Initing graphics device"); - options_ = options; + HRESULT hr = CreateResources(hwnd); - CreateDeviceResources(hwnd); - - initialized_ = true; - } - - void GraphicsDevice::BeginDraw(HWND hwnd) - { - CreateDeviceResources(hwnd); - - window_occluded_ = !!(render_target->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED); - - if (!window_occluded_) + if (SUCCEEDED(hr)) { - render_target->BeginDraw(); - render_target->Clear(clear_color_); + vsync_enabled_ = vsync; } + return hr; } - void GraphicsDevice::EndDraw() + 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_) { - HRESULT hr = render_target->EndDraw(); + hr = render_target_->EndDraw(); if (hr == D2DERR_RECREATE_TARGET) { // 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源 // 并在下一次调用时重建资源 + DiscardResources(); hr = S_OK; - - fps_text_format_ = nullptr; - fps_text_layout_ = nullptr; - text_renderer = nullptr; - solid_brush = nullptr; - render_target = nullptr; } - - ThrowIfFailed(hr); } + return hr; } void GraphicsDevice::ClearImageCache() @@ -105,20 +105,20 @@ namespace easy2d HRESULT GraphicsDevice::CreateLayer(cpLayer& layer) { - if (!render_target) + if (!render_target_) return E_UNEXPECTED; layer = nullptr; - return render_target->CreateLayer(&layer); + return render_target_->CreateLayer(&layer); } HRESULT GraphicsDevice::CreateSolidColorBrush(cpSolidColorBrush & brush) const { - if (!render_target) + if (!render_target_) return E_UNEXPECTED; brush = nullptr; - return render_target->CreateSolidColorBrush( + return render_target_->CreateSolidColorBrush( D2D1::ColorF(D2D1::ColorF::White), &brush ); @@ -131,18 +131,18 @@ namespace easy2d StrokeStyle stroke ) { - if (!solid_brush || - !render_target) + if (!solid_brush_ || + !render_target_) return E_UNEXPECTED; if (window_occluded_) return S_OK; - solid_brush->SetColor(stroke_color); + solid_brush_->SetColor(stroke_color); auto stroke_style = Factory::Instance()->GetStrokeStyle(stroke); - render_target->DrawGeometry( + render_target_->DrawGeometry( geometry.Get(), - solid_brush.Get(), + solid_brush_.Get(), stroke_width, stroke_style.Get() ); @@ -151,24 +151,24 @@ namespace easy2d HRESULT GraphicsDevice::FillGeometry(cpGeometry const & geometry, const Color & fill_color) { - if (!solid_brush || - !render_target) + if (!solid_brush_ || + !render_target_) return E_UNEXPECTED; if (window_occluded_) return S_OK; - solid_brush->SetColor(fill_color); - render_target->FillGeometry( + solid_brush_->SetColor(fill_color); + render_target_->FillGeometry( geometry.Get(), - solid_brush.Get() + solid_brush_.Get() ); return S_OK; } HRESULT GraphicsDevice::DrawImage(spImage const & image) { - if (!render_target) + if (!render_target_) return E_UNEXPECTED; if (!image->GetBitmap()) @@ -177,7 +177,7 @@ namespace easy2d if (window_occluded_) return S_OK; - render_target->DrawBitmap( + render_target_->DrawBitmap( image->GetBitmap().Get(), D2D1::RectF(0.f, 0.f, image->GetWidth(), image->GetHeight()), opacity_, @@ -191,7 +191,7 @@ namespace easy2d cpBitmap const& bitmap ) { - if (!render_target) + if (!render_target_) return E_UNEXPECTED; if (window_occluded_) @@ -199,7 +199,7 @@ namespace easy2d // Do not crop bitmap auto rect = D2D1::RectF(0.f, 0.f, bitmap->GetSize().width, bitmap->GetSize().height); - render_target->DrawBitmap( + render_target_->DrawBitmap( bitmap.Get(), rect, opacity_, @@ -211,25 +211,25 @@ namespace easy2d HRESULT GraphicsDevice::DrawTextLayout(cpTextLayout const& text_layout) { - if (!text_renderer) + if (!text_renderer_) return E_UNEXPECTED; if (window_occluded_) return S_OK; - return text_layout->Draw(nullptr, text_renderer.Get(), 0, 0); + 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) + if (!render_target_) return E_UNEXPECTED; if (window_occluded_) return S_OK; - render_target->SetTransform(ConvertToD2DMatrix(clip_matrix)); - render_target->PushAxisAlignedClip( + render_target_->SetTransform(ConvertToD2DMatrix(clip_matrix)); + render_target_->PushAxisAlignedClip( D2D1::RectF(0, 0, clip_size.width, clip_size.height), D2D1_ANTIALIAS_MODE_PER_PRIMITIVE ); @@ -238,33 +238,33 @@ namespace easy2d HRESULT GraphicsDevice::PopClip() { - if (!render_target) + if (!render_target_) return E_UNEXPECTED; if (window_occluded_) return S_OK; - render_target->PopAxisAlignedClip(); + render_target_->PopAxisAlignedClip(); return S_OK; } HRESULT GraphicsDevice::PushLayer(cpLayer const& layer, LayerProperties const& properties) { - if (!render_target || - !solid_brush) + if (!render_target_ || + !solid_brush_) return E_UNEXPECTED; if (window_occluded_) return S_OK; - render_target->PushLayer( + render_target_->PushLayer( D2D1::LayerParameters( properties.area, nullptr, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, D2D1::Matrix3x2F::Identity(), properties.opacity, - solid_brush.Get(), + solid_brush_.Get(), D2D1_LAYER_OPTIONS_NONE ), layer.Get() @@ -274,22 +274,22 @@ namespace easy2d HRESULT GraphicsDevice::PopLayer() { - if (!render_target) + if (!render_target_) return E_UNEXPECTED; if (window_occluded_) return S_OK; - render_target->PopLayer(); + render_target_->PopLayer(); return S_OK; } HRESULT GraphicsDevice::GetSize(Size & size) { - if (!render_target) + if (!render_target_) return E_UNEXPECTED; - auto rtsize = render_target->GetSize(); + auto rtsize = render_target_->GetSize(); size.width = rtsize.width; size.height = rtsize.height; return S_OK; @@ -297,7 +297,7 @@ namespace easy2d HRESULT GraphicsDevice::CreateBitmapFromFile(cpBitmap& bitmap, String const& file_path) { - if (render_target == nullptr) + if (render_target_ == nullptr) { return E_UNEXPECTED; } @@ -312,7 +312,7 @@ namespace easy2d cpBitmap bitmap_tmp; HRESULT hr = Factory::Instance()->CreateBitmapFromFile( bitmap, - render_target, + render_target_, file_path ); @@ -326,7 +326,7 @@ namespace easy2d HRESULT GraphicsDevice::CreateBitmapFromResource(cpBitmap& bitmap, Resource const& res) { - if (render_target == nullptr) + if (render_target_ == nullptr) { return E_UNEXPECTED; } @@ -340,7 +340,7 @@ namespace easy2d HRESULT hr = Factory::Instance()->CreateBitmapFromResource( bitmap, - render_target, + render_target_, res ); @@ -354,38 +354,38 @@ namespace easy2d HRESULT GraphicsDevice::CreateBitmapRenderTarget(cpBitmapRenderTarget & brt) { - if (!render_target) + if (!render_target_) return E_UNEXPECTED; brt = nullptr; - return render_target->CreateCompatibleRenderTarget(&brt); + return render_target_->CreateCompatibleRenderTarget(&brt); } HRESULT GraphicsDevice::Resize(UINT32 width, UINT32 height) { - if (!render_target) + if (!render_target_) return E_UNEXPECTED; - render_target->Resize(D2D1::SizeU(width, height)); + render_target_->Resize(D2D1::SizeU(width, height)); return S_OK; } HRESULT GraphicsDevice::SetTransform(const math::Matrix & matrix) { - if (!render_target) + if (!render_target_) return E_UNEXPECTED; - render_target->SetTransform(ConvertToD2DMatrix(matrix)); + render_target_->SetTransform(ConvertToD2DMatrix(matrix)); return S_OK; } HRESULT GraphicsDevice::SetOpacity(float opacity) { - if (!render_target) + if (!render_target_) return E_UNEXPECTED; opacity_ = opacity; - solid_brush->SetOpacity(opacity); + solid_brush_->SetOpacity(opacity); return S_OK; } @@ -397,11 +397,11 @@ namespace easy2d StrokeStyle outline_stroke ) { - if (!text_renderer) + if (!text_renderer_) return E_UNEXPECTED; auto stroke_style = Factory::Instance()->GetStrokeStyle(outline_stroke); - text_renderer->SetTextStyle( + text_renderer_->SetTextStyle( color, has_outline, outline_color, @@ -411,14 +411,56 @@ namespace easy2d return S_OK; } - void GraphicsDevice::SetBackgroundColor(const Color& color) + void GraphicsDevice::SetClearColor(const Color& color) { clear_color_ = color; } - void GraphicsDevice::CreateDeviceResources(HWND hwnd) + HRESULT GraphicsDevice::SetAntialiasMode(bool enabled) { - if (!render_target) + 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); @@ -428,65 +470,50 @@ namespace easy2d rc.bottom - rc.top ); - // 创建设备相关资源。这些资源应在 Direct2D 设备消失时重建 - // 创建一个 Direct2D 渲染目标 - ThrowIfFailed( - Factory::Instance()->CreateHwndRenderTarget( - render_target, - D2D1::RenderTargetProperties(), - D2D1::HwndRenderTargetProperties( - hwnd, - size, - options_.vsync ? D2D1_PRESENT_OPTIONS_NONE : D2D1_PRESENT_OPTIONS_IMMEDIATELY - ) + hr = Factory::Instance()->CreateHwndRenderTarget( + render_target_, + D2D1::RenderTargetProperties(), + D2D1::HwndRenderTargetProperties( + hwnd, + size, + vsync_enabled_ ? D2D1_PRESENT_OPTIONS_NONE : D2D1_PRESENT_OPTIONS_IMMEDIATELY ) ); - render_target->SetAntialiasMode( - options_.antialias ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED - ); - - D2D1_TEXT_ANTIALIAS_MODE mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; - switch (options_.text_antialias) + if (SUCCEEDED(hr)) { - case TextAntialias::Default: - mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; - break; - case TextAntialias::ClearType: - mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; - break; - case TextAntialias::GrayScale: - mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; - break; - case TextAntialias::None: - mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED; - break; - default: - break; + SetAntialiasMode(antialias_); + SetTextAntialiasMode(text_antialias_); } - render_target->SetTextAntialiasMode(mode); - } - - if (!solid_brush) - { - ThrowIfFailed( - render_target->CreateSolidColorBrush( + + if (SUCCEEDED(hr)) + { + hr = render_target_->CreateSolidColorBrush( D2D1::ColorF(D2D1::ColorF::White), - &solid_brush - ) - ); - } + &solid_brush_ + ); + } - if (!text_renderer) - { - ThrowIfFailed( - Factory::Instance()->CreateTextRenderer( - text_renderer, - render_target, - 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 06422947..85e8f68b 100644 --- a/core/base/render.h +++ b/core/base/render.h @@ -37,20 +37,6 @@ namespace easy2d None // 不启用抗锯齿 }; - // 图形渲染选项 - struct GraphicsOptions - { - bool vsync; // 垂直同步 - bool antialias; // 抗锯齿 - TextAntialias text_antialias; // 文字抗锯齿模式 - - GraphicsOptions() - : vsync(true) - , antialias(true) - , text_antialias(TextAntialias::ClearType) - {} - }; - namespace devices { class GraphicsDevice @@ -59,20 +45,34 @@ namespace easy2d E2D_DECLARE_SINGLETON(GraphicsDevice); public: - void Init(HWND hwnd, GraphicsOptions options, bool debug); + HRESULT Init(HWND hwnd, bool vsync, bool debug); // 开始渲染 - void BeginDraw(HWND hwnd); + HRESULT BeginDraw(HWND hwnd); // 结束渲染 - void EndDraw(); + HRESULT EndDraw(); - // 设置背景色 - void SetBackgroundColor( + // 设置清空屏幕的颜色 + void SetClearColor( const Color& color ); - void CreateDeviceResources(HWND hwnd); + // 设置抗锯齿模式 + HRESULT SetAntialiasMode( + bool enabled + ); + + // 设置文字抗锯齿模式 + HRESULT SetTextAntialiasMode( + TextAntialias mode + ); + + HRESULT CreateResources( + HWND hwnd + ); + + void DiscardResources(); HRESULT CreateLayer( cpLayer& layer @@ -167,13 +167,14 @@ namespace easy2d ~GraphicsDevice(); protected: - bool initialized_; bool window_occluded_; + bool vsync_enabled_; + bool antialias_; + TextAntialias text_antialias_; float opacity_; - GraphicsOptions options_; - cpTextRenderer text_renderer; - cpSolidColorBrush solid_brush; - cpHwndRenderTarget render_target; + cpTextRenderer text_renderer_; + cpSolidColorBrush solid_brush_; + cpHwndRenderTarget render_target_; D2D1_COLOR_F clear_color_; cpTextFormat fps_text_format_; cpTextLayout fps_text_layout_; diff --git a/core/base/window.cpp b/core/base/window.cpp index 2e760420..f43897d6 100644 --- a/core/base/window.cpp +++ b/core/base/window.cpp @@ -39,7 +39,6 @@ namespace easy2d : handle(nullptr) , scale_x(1.f) , scale_y(1.f) - , initialized_(false) { } @@ -48,11 +47,8 @@ namespace easy2d E2D_LOG("Destroying window"); } - void WindowImpl::Init(String title, int width, int height, LPCWSTR icon, WNDPROC proc, bool debug) + HRESULT WindowImpl::Init(String title, int width, int height, LPCWSTR icon, WNDPROC proc, bool debug) { - if (initialized_) - return; - E2D_LOG("Creating window"); HINSTANCE hinstance = GetModuleHandle(nullptr); @@ -85,10 +81,8 @@ namespace easy2d GetContentScale(&scale_x, &scale_y); - // 计算窗口大小 - Rect client_rect = LocateWindow(width, height, scale_x, scale_y); - // 创建窗口 + Rect client_rect = LocateWindow(width, height, scale_x, scale_y); handle = ::CreateWindowEx( NULL, REGISTER_CLASS, @@ -107,13 +101,9 @@ namespace easy2d if (handle == nullptr) { ::UnregisterClass(REGISTER_CLASS, hinstance); - - const char* err = "Create window failed!"; - logs::Errorln(HRESULT_FROM_WIN32(GetLastError()), err); - throw std::runtime_error(err); + return HRESULT_FROM_WIN32(GetLastError()); } - - initialized_ = true; + return S_OK; } String WindowImpl::GetTitle() const diff --git a/core/base/window.h b/core/base/window.h index 38440114..c6b7acf3 100644 --- a/core/base/window.h +++ b/core/base/window.h @@ -30,7 +30,7 @@ namespace easy2d E2D_DECLARE_SINGLETON(WindowImpl); public: - void Init( + HRESULT Init( String title, int width, int height, @@ -72,7 +72,6 @@ namespace easy2d ~WindowImpl(); private: - bool initialized_; HWND handle; float scale_x; float scale_y; diff --git a/core/ui/Button.cpp b/core/ui/Button.cpp index 80356d3c..5eb28290 100644 --- a/core/ui/Button.cpp +++ b/core/ui/Button.cpp @@ -220,31 +220,6 @@ namespace easy2d return Node::Dispatch(e, handled); } - void Button::Visit() - { - Node::Visit(); - - if (IsVisible() && - !enabled_ && - normal_ && - normal_->ContainsPoint(devices::Input::Instance()->GetMousePos())) - { - HCURSOR hcursor = ::LoadCursor(nullptr, IDC_NO); - if (hcursor) - { - ::SetCursor(hcursor); - } - } - else if (status_ == Status::Mouseover || status_ == Status::Selected) - { - HCURSOR hcursor = ::LoadCursor(nullptr, IDC_HAND); - if (hcursor) - { - ::SetCursor(hcursor); - } - } - } - void Button::SetStatus(Status status) { if (status_ != status) diff --git a/core/ui/Button.h b/core/ui/Button.h index bef26ae1..2ffe4c17 100644 --- a/core/ui/Button.h +++ b/core/ui/Button.h @@ -120,9 +120,6 @@ namespace easy2d bool handled ) override; - // 遍历节点 - virtual void Visit() override; - private: spNode normal_; spNode mouseover_;