From 074af87127925ee425f6c10ba4b0c1392188d447 Mon Sep 17 00:00:00 2001 From: Nomango <569629550@qq.com> Date: Sun, 10 Mar 2019 13:44:02 +0800 Subject: [PATCH] d3d11 support --- project/Box2DSample/main.cpp | 2 +- project/Easy2D/Easy2D.vcxproj | 16 +- project/Easy2D/Easy2D.vcxproj.filters | 51 +- project/HelloWorld/main.cpp | 8 +- project/Samples/Demo1.h | 2 + project/Samples/Demo2.h | 2 + project/Samples/Demo3.h | 9 +- project/Samples/main.cpp | 2 +- src/core/Application.cpp | 109 ++-- src/core/Application.h | 21 +- src/core/Canvas.cpp | 88 ++- src/core/Canvas.h | 27 +- src/core/DebugNode.cpp | 32 +- src/core/DebugNode.h | 10 +- src/core/Factory.h | 125 ----- src/core/Geometry.cpp | 71 ++- src/core/Geometry.h | 6 +- src/core/GeometryNode.cpp | 8 +- src/core/GeometryNode.h | 2 +- src/core/Image.cpp | 14 +- src/core/Image.h | 8 +- src/core/Input.cpp | 4 +- src/core/Input.h | 2 +- src/core/Node.cpp | 33 +- src/core/Node.h | 19 +- src/core/Scene.h | 2 +- src/core/Sprite.cpp | 2 +- src/core/Sprite.h | 2 +- src/core/Text.cpp | 60 +- src/core/Text.h | 20 +- src/core/Transform.hpp | 4 +- src/core/Transition.cpp | 22 +- src/core/Transition.h | 4 +- src/core/audio.cpp | 6 +- src/core/audio.h | 2 +- src/core/d2dhelper.hpp | 101 ---- src/core/helper.hpp | 4 +- src/core/include-forwards.h | 2 +- src/core/logs.h | 5 +- src/core/modules.cpp | 11 + src/core/modules.h | 3 + src/core/render.cpp | 519 ++++++------------ src/core/render.h | 186 +++---- src/core/window.cpp | 8 +- src/core/window.h | 3 +- .../Factory.cpp => dx/D2DDeviceResources.cpp} | 378 ++++++------- src/dx/D2DDeviceResources.h | 117 ++++ src/dx/D3D11DeviceResources.cpp | 387 +++++++++++++ src/dx/D3D11DeviceResources.h | 82 +++ src/dx/DeviceResources.h | 27 + src/{core => dx}/TextRenderer.cpp | 145 +++-- src/{core => dx}/TextRenderer.h | 9 +- src/dx/helper.hpp | 90 +++ src/easy2d.h | 3 +- src/math/Matrix.cpp | 152 ----- src/math/{Matrix.h => Matrix.hpp} | 137 +++-- src/math/Rect.hpp | 2 +- src/math/scalar.hpp | 1 - src/math/vector.hpp | 7 +- src/utils/Transcoder.cpp | 18 +- 60 files changed, 1741 insertions(+), 1451 deletions(-) delete mode 100644 src/core/Factory.h delete mode 100644 src/core/d2dhelper.hpp rename src/{core/Factory.cpp => dx/D2DDeviceResources.cpp} (53%) create mode 100644 src/dx/D2DDeviceResources.h create mode 100644 src/dx/D3D11DeviceResources.cpp create mode 100644 src/dx/D3D11DeviceResources.h create mode 100644 src/dx/DeviceResources.h rename src/{core => dx}/TextRenderer.cpp (77%) rename src/{core => dx}/TextRenderer.h (88%) create mode 100644 src/dx/helper.hpp delete mode 100644 src/math/Matrix.cpp rename src/math/{Matrix.h => Matrix.hpp} (57%) diff --git a/project/Box2DSample/main.cpp b/project/Box2DSample/main.cpp index 6f8f51cc..d51a78e1 100644 --- a/project/Box2DSample/main.cpp +++ b/project/Box2DSample/main.cpp @@ -216,7 +216,7 @@ int main() } catch (std::exception& e) { - ::MessageBoxA(nullptr, e.what(), "An exception has occurred!", MB_ICONERROR | MB_TASKMODAL); + ::MessageBoxA(nullptr, e.what(), "An exception has occurred!", MB_ICONERROR | MB_OK); } return 0; } diff --git a/project/Easy2D/Easy2D.vcxproj b/project/Easy2D/Easy2D.vcxproj index 442d4eea..a5a99d20 100644 --- a/project/Easy2D/Easy2D.vcxproj +++ b/project/Easy2D/Easy2D.vcxproj @@ -13,12 +13,10 @@ - - @@ -47,16 +45,20 @@ - + + + + + - + @@ -83,7 +85,6 @@ - @@ -102,11 +103,12 @@ - - + + + diff --git a/project/Easy2D/Easy2D.vcxproj.filters b/project/Easy2D/Easy2D.vcxproj.filters index b46a74cb..4ca70313 100644 --- a/project/Easy2D/Easy2D.vcxproj.filters +++ b/project/Easy2D/Easy2D.vcxproj.filters @@ -13,6 +13,9 @@ {07b6d541-4a1b-472a-aae0-daf9d082fe84} + + {a9793a75-3212-4e31-a443-b23f18a1e136} + @@ -64,9 +67,6 @@ core - - core - core @@ -154,9 +154,6 @@ math - - core - core @@ -169,9 +166,6 @@ core - - core - core @@ -208,9 +202,6 @@ core - - math - core @@ -220,6 +211,24 @@ core + + math + + + dx + + + dx + + + dx + + + dx + + + dx + @@ -264,9 +273,6 @@ core - - core - core @@ -327,9 +333,6 @@ core - - core - core @@ -351,11 +354,17 @@ core - - math - core + + dx + + + dx + + + dx + \ No newline at end of file diff --git a/project/HelloWorld/main.cpp b/project/HelloWorld/main.cpp index ed22128b..998c131c 100644 --- a/project/HelloWorld/main.cpp +++ b/project/HelloWorld/main.cpp @@ -13,9 +13,11 @@ public: { // 创建文字节点 easy2d::TextPtr text = new easy2d::Text(L"Hello Easy2D!"); - // 修改节点位置 + // 设置节点大小为文字布局大小 + text->SetSize(text->GetLayoutSize()); + // 修改节点位置, 使节点在屏幕上居中 text->SetPosition(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2); - // 修改节点锚点, 使节点在屏幕上居中 + // 修改节点锚点, 使文字中心对齐屏幕中心 text->SetAnchor(0.5, 0.5); // 添加到场景中 this->AddChild(text); @@ -46,7 +48,7 @@ int main() } catch (std::exception& e) { - ::MessageBoxA(nullptr, e.what(), "An exception has occurred!", MB_ICONERROR | MB_TASKMODAL); + ::MessageBoxA(nullptr, e.what(), "An exception has occurred!", MB_ICONERROR | MB_OK); } return 0; } diff --git a/project/Samples/Demo1.h b/project/Samples/Demo1.h index 1d49fc76..d9ee5c82 100644 --- a/project/Samples/Demo1.h +++ b/project/Samples/Demo1.h @@ -16,6 +16,8 @@ public: { // 创建文本 TextPtr text = new Text(L"Hello Easy2D!"); + // 设置节点大小为文字布局大小 + text->SetSize(text->GetLayoutSize()); // 让文本显示在屏幕中央 text->SetPosition(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2); text->SetAnchor(0.5, 0.5); diff --git a/project/Samples/Demo2.h b/project/Samples/Demo2.h index 97b49211..25471345 100644 --- a/project/Samples/Demo2.h +++ b/project/Samples/Demo2.h @@ -80,6 +80,8 @@ public: // 创建说明文字 TextPtr text = new Text(L"按上下左右键移动\n按鼠标左键旋转\n点击鼠标右键隐藏"); + // 设置节点大小为文字布局大小 + text->SetSize(text->GetLayoutSize()); // 设置文字位置 text->SetAnchor(0.5f, 0.5f); text->SetPosition(WINDOW_WIDTH / 2, WINDOW_HEIGHT - 50); diff --git a/project/Samples/Demo3.h b/project/Samples/Demo3.h index d5f3b6ea..0b798212 100644 --- a/project/Samples/Demo3.h +++ b/project/Samples/Demo3.h @@ -33,18 +33,15 @@ public: // 创建说明文字 TextPtr intro_text = new Text(L"按上下键调整音量\n按空格键暂停或继续"); - intro_text->SetAnchor(0.5f, 0.5f); - intro_text->SetPosition(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2 - 50); + intro_text->SetPosition(WINDOW_WIDTH / 2 - 80, WINDOW_HEIGHT / 2 - 50); // 创建音量文字 volume_text = new Text(L"当前音量:"); - volume_text->SetAnchor(0.5f, 0.5f); - volume_text->SetPosition(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2 + 30); + volume_text->SetPosition(WINDOW_WIDTH / 2 - 80, WINDOW_HEIGHT / 2 + 30); // 创建状态文字 state_text = new Text(L"当前状态:"); - state_text->SetAnchor(0.5f, 0.5f); - state_text->SetPosition(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2 + 60); + state_text->SetPosition(WINDOW_WIDTH / 2 - 80, WINDOW_HEIGHT / 2 + 60); // 添加到场景 this->AddChild(intro_text); diff --git a/project/Samples/main.cpp b/project/Samples/main.cpp index 39a7e608..1fcbbbb9 100644 --- a/project/Samples/main.cpp +++ b/project/Samples/main.cpp @@ -76,7 +76,7 @@ int main() } catch (std::exception& e) { - ::MessageBoxA(nullptr, e.what(), "An exception has occurred!", MB_ICONERROR | MB_TASKMODAL); + ::MessageBoxA(nullptr, e.what(), "An exception has occurred!", MB_ICONERROR | MB_OK); } return 0; } diff --git a/src/core/Application.cpp b/src/core/Application.cpp index b22d2742..21987cb1 100644 --- a/src/core/Application.cpp +++ b/src/core/Application.cpp @@ -21,7 +21,7 @@ #include "Application.h" #include "logs.h" #include "modules.h" -#include "Factory.h" +#include "render.h" #include "Event.hpp" #include "Scene.h" #include "DebugNode.h" @@ -37,7 +37,6 @@ namespace easy2d Application::Application(String const& app_name) : end_(true) , inited_(false) - , debug_(false) , curr_scene_(nullptr) , next_scene_(nullptr) , transition_(nullptr) @@ -56,44 +55,6 @@ namespace easy2d void Application::Init(const Options& options) { - debug_ = options.debug; - - // show console if debug mode enabled - if (debug_ && !::GetConsoleWindow()) - { - if (!::AllocConsole()) - { - E2D_WARNING_LOG(L"AllocConsole failed"); - } - else - { - HWND console = ::GetConsoleWindow(); - FILE * dummy; - freopen_s(&dummy, "CONOUT$", "w+t", stdout); - freopen_s(&dummy, "CONIN$", "r+t", stdin); - freopen_s(&dummy, "CONOUT$", "w+t", stderr); - (void)dummy; - - std::cout.clear(); - std::wcout.clear(); - std::cin.clear(); - std::wcin.clear(); - std::cerr.clear(); - std::wcerr.clear(); - - // disable the close button of console - if (console) - { - HMENU hmenu = ::GetSystemMenu(console, FALSE); - ::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND); - } - } - } - - ThrowIfFailed( - Factory::Instance().Init(debug_) - ); - ThrowIfFailed( Window::Instance().Init( options.title, @@ -101,30 +62,26 @@ namespace easy2d options.height, options.icon, options.fullscreen, - Application::WndProc, - debug_ + Application::WndProc ) ); HWND hwnd = Window::Instance().GetHandle(); ThrowIfFailed( - RenderSystem::Instance().Init( - hwnd, - options.vsync, - debug_ - ) + Renderer::Instance().Init(hwnd) ); + Renderer::Instance().SetClearColor(options.clear_color); + ThrowIfFailed( Input::Instance().Init( - hwnd, - debug_ + hwnd ) ); ThrowIfFailed( - Audio::Instance().Init(debug_) + Audio::Instance().Init() ); OnStart(); @@ -173,9 +130,8 @@ namespace easy2d curr_scene_.Reset(); Audio::Instance().Destroy(); - RenderSystem::Instance().Destroy(); + Renderer::Instance().Destroy(); Window::Instance().Destroy(); - Factory::Instance().Destroy(); } } @@ -251,16 +207,14 @@ namespace easy2d if (next_scene_) next_scene_->Update(dt); - if (debug_) + if (DebugNode::IsShown()) DebugNode::Instance().Update(dt); } void Application::Render(HWND hwnd) { - auto& rt = RenderSystem::Instance(); - ThrowIfFailed( - rt.BeginDraw(hwnd) + Renderer::Instance().BeginDraw() ); if (transition_) @@ -272,16 +226,50 @@ namespace easy2d curr_scene_->Render(); } - if (debug_) + if (DebugNode::IsShown()) DebugNode::Instance().Render(); ThrowIfFailed( - rt.EndDraw() + Renderer::Instance().EndDraw() ); ::InvalidateRect(hwnd, NULL, FALSE); } + void Application::AllocConsole() + { + if (!::GetConsoleWindow()) + { + if (!::AllocConsole()) + { + E2D_WARNING_LOG(L"AllocConsole failed"); + } + else + { + HWND console = ::GetConsoleWindow(); + FILE * dummy; + freopen_s(&dummy, "CONOUT$", "w+t", stdout); + freopen_s(&dummy, "CONIN$", "r+t", stdin); + freopen_s(&dummy, "CONOUT$", "w+t", stderr); + (void)dummy; + + std::cout.clear(); + std::wcout.clear(); + std::cin.clear(); + std::wcin.clear(); + std::cerr.clear(); + std::wcerr.clear(); + + // disable the close button of console + if (console) + { + HMENU hmenu = ::GetSystemMenu(console, FALSE); + ::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND); + } + } + } + } + LRESULT CALLBACK Application::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { Application * app = reinterpret_cast( @@ -363,10 +351,7 @@ namespace easy2d UINT width = LOWORD(lparam); UINT height = HIWORD(lparam); - // 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染 - // 目标的大小。它可能会调用失败,但是这里可以忽略有可能的 - // 错误,因为这个错误将在下一次调用 EndDraw 时产生 - RenderSystem::Instance().Resize(width, height); + Renderer::Instance().GetDeviceResources()->SetLogicalSize(Size{ (float)width, (float)height }); if (SIZE_MAXHIDE == wparam || SIZE_MINIMIZED == wparam) { diff --git a/src/core/Application.h b/src/core/Application.h index 9ee1e04a..1567a309 100644 --- a/src/core/Application.h +++ b/src/core/Application.h @@ -22,7 +22,6 @@ #include "include-forwards.h" #include "time.h" #include "window.h" -#include "render.h" #include "input.h" #include "audio.h" @@ -30,22 +29,22 @@ namespace easy2d { struct Options { - String title; // 标题 - int width; // 宽度 - int height; // 高度 - LPCWSTR icon; // 图标 - bool vsync; // 垂直同步 - bool fullscreen; // 全屏模式 - bool debug; // 调试模式 + String title; // 标题 + int width; // 宽度 + int height; // 高度 + LPCWSTR icon; // 图标 + Color clear_color; // 清屏颜色 + bool vsync; // 垂直同步 + bool fullscreen; // 全屏模式 Options() : title(L"Easy2D Game") , width(640) , height(480) , icon(nullptr) + , clear_color(Color::Black) , vsync(true) , fullscreen(false) - , debug(false) {} }; @@ -105,6 +104,9 @@ namespace easy2d float scale_factor ); + // 分配控制台 + static void AllocConsole(); + private: void Render(HWND); @@ -115,7 +117,6 @@ namespace easy2d private: bool end_; bool inited_; - bool debug_; float time_scale_; String app_name_; ScenePtr curr_scene_; diff --git a/src/core/Canvas.cpp b/src/core/Canvas.cpp index 1bfc4573..4ef31229 100644 --- a/src/core/Canvas.cpp +++ b/src/core/Canvas.cpp @@ -23,7 +23,7 @@ #include "logs.h" #include "Image.h" #include "Geometry.h" -#include "Factory.h" +#include "render.h" namespace easy2d { @@ -31,37 +31,30 @@ namespace easy2d : cache_expired_(false) , stroke_width_(1.0f) { + auto ctx = Renderer::Instance().GetDeviceResources()->GetD2DDeviceContext(); + ThrowIfFailed( - RenderSystem::Instance().CreateBitmapRenderTarget(render_target_) + ctx->CreateCompatibleRenderTarget(&render_target_) ); - auto properties = D2D1::BrushProperties(); ThrowIfFailed( render_target_->CreateSolidColorBrush( D2D1::ColorF(0, 0, 0, 0), - properties, + D2D1::BrushProperties(), &fill_brush_) ); ThrowIfFailed( render_target_->CreateSolidColorBrush( D2D1::ColorF(Color::White), - properties, + D2D1::BrushProperties(), &stroke_brush_) ); ThrowIfFailed( - render_target_->CreateSolidColorBrush( - D2D1::ColorF(Color::White), - properties, - &text_brush_) - ); - - ThrowIfFailed( - Factory::Instance().CreateTextRenderer( - text_renderer_, - render_target_, - text_brush_ + ITextRenderer::Create( + &text_renderer_, + render_target_.Get() ) ); @@ -105,18 +98,18 @@ namespace easy2d if (bitmap_cached_) { - RenderSystem::Instance().DrawBitmap(bitmap_cached_); + Renderer::Instance().DrawBitmap(bitmap_cached_); } } void Canvas::SetStrokeColor(Color const& color) { - stroke_brush_->SetColor(ToD2dColorF(color)); + stroke_brush_->SetColor(DX::ConvertToColorF(color)); } void Canvas::SetFillColor(Color const& color) { - fill_brush_->SetColor(ToD2dColorF(color)); + fill_brush_->SetColor(DX::ConvertToColorF(color)); } void Canvas::SetStrokeWidth(float width) @@ -126,7 +119,7 @@ namespace easy2d void Canvas::SetOutlineJoinStyle(StrokeStyle outline_join) { - outline_join_style_ = Factory::Instance().GetStrokeStyle(outline_join); + outline_join_style_ = Renderer::Instance().GetDeviceResources()->GetStrokeStyle(outline_join); } void Canvas::SetTextStyle(Font const& font, TextStyle const & text_style) @@ -135,12 +128,15 @@ namespace easy2d text_style_ = text_style; text_renderer_->SetTextStyle( - ToD2dColorF(text_style_.color), + DX::ConvertToColorF(text_style_.color), text_style_.outline, - ToD2dColorF(text_style_.outline_color), + DX::ConvertToColorF(text_style_.outline_color), text_style_.outline_width, - Factory::Instance().GetStrokeStyle(text_style_.outline_stroke).Get() + Renderer::Instance().GetDeviceResources()->GetStrokeStyle(text_style_.outline_stroke) ); + + // clear text format + text_format_ = nullptr; } Color Canvas::GetStrokeColor() const @@ -162,7 +158,7 @@ namespace easy2d void Canvas::SetBrushTransform(Matrix const & transform) { - render_target_->SetTransform(transform); + render_target_->SetTransform(DX::ConvertToMatrix3x2F(transform)); } void Canvas::DrawLine(const Point & begin, const Point & end) @@ -258,7 +254,7 @@ namespace easy2d D2D1::RectF(0, 0, image->GetWidth(), image->GetHeight()), opacity, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, - ToD2dRectF(image->GetCropRect()) + DX::ConvertToRectF(image->GetCropRect()) ); cache_expired_ = true; } @@ -269,23 +265,25 @@ namespace easy2d if (text.empty()) return; - D2DTextFormatPtr text_format; - ThrowIfFailed( - Factory::Instance().CreateTextFormat( - text_format, - text_font_, - text_style_ - ) - ); + if (!text_format_) + { + ThrowIfFailed( + Renderer::Instance().GetDeviceResources()->CreateTextFormat( + text_format_, + text_font_, + text_style_ + ) + ); + } - D2DTextLayoutPtr text_layout; + ComPtr text_layout; Size layout_size; ThrowIfFailed( - Factory::Instance().CreateTextLayout( + Renderer::Instance().GetDeviceResources()->CreateTextLayout( text_layout, layout_size, text, - text_format, + text_format_, text_style_ ) ); @@ -390,14 +388,14 @@ namespace easy2d current_geometry_ = nullptr; ThrowIfFailed( - Factory::Instance().CreatePathGeometry(current_geometry_) + Renderer::Instance().GetDeviceResources()->GetD2DFactory()->CreatePathGeometry(¤t_geometry_) ); ThrowIfFailed( current_geometry_->Open(¤t_sink_) ); - current_sink_->BeginFigure(ToD2dPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED); + current_sink_->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED); } void Canvas::EndPath(bool closed) @@ -415,7 +413,7 @@ namespace easy2d void Canvas::AddLine(Point const & point) { if (current_sink_) - current_sink_->AddLine(ToD2dPoint2F(point)); + current_sink_->AddLine(DX::ConvertToPoint2F(point)); } void Canvas::AddLines(Array const& points) @@ -435,9 +433,9 @@ namespace easy2d { current_sink_->AddBezier( D2D1::BezierSegment( - ToD2dPoint2F(point1), - ToD2dPoint2F(point2), - ToD2dPoint2F(point3) + DX::ConvertToPoint2F(point1), + DX::ConvertToPoint2F(point2), + DX::ConvertToPoint2F(point3) ) ); } @@ -449,8 +447,8 @@ namespace easy2d { current_sink_->AddArc( D2D1::ArcSegment( - ToD2dPoint2F(point), - ToD2dSizeF(radius), + DX::ConvertToPoint2F(point), + DX::ConvertToSizeF(radius), rotation, clockwise ? D2D1_SWEEP_DIRECTION_CLOCKWISE : D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE, is_small ? D2D1_ARC_SIZE_SMALL : D2D1_ARC_SIZE_LARGE @@ -492,7 +490,7 @@ namespace easy2d return image; } - D2DBitmapPtr const& easy2d::Canvas::GetBitmap() const + ComPtr const& easy2d::Canvas::GetBitmap() const { if (cache_expired_) { diff --git a/src/core/Canvas.h b/src/core/Canvas.h index 8ada5b0e..4cb2dbc1 100644 --- a/src/core/Canvas.h +++ b/src/core/Canvas.h @@ -22,7 +22,7 @@ #include "Node.h" #include "Font.hpp" #include "TextStyle.hpp" -#include "TextRenderer.h" +#include "../DX/TextRenderer.h" #undef DrawText @@ -30,7 +30,7 @@ namespace easy2d { // 画布 class E2D_API Canvas - : public Node + : public VisualNode { public: Canvas(); @@ -221,22 +221,23 @@ namespace easy2d void OnRender() override; protected: - D2DBitmapPtr const& GetBitmap() const; + ComPtr const& GetBitmap() const; protected: float stroke_width_; Font text_font_; TextStyle text_style_; - D2DPathGeometryPtr current_geometry_; - D2DGeometrySinkPtr current_sink_; - D2DStrokeStylePtr outline_join_style_; - D2DSolidColorBrushPtr fill_brush_; - D2DSolidColorBrushPtr stroke_brush_; - D2DSolidColorBrushPtr text_brush_; - D2DTextRendererPtr text_renderer_; - D2DBitmapRenderTargetPtr render_target_; - mutable bool cache_expired_; - mutable D2DBitmapPtr bitmap_cached_; + ComPtr current_geometry_; + ComPtr current_sink_; + ComPtr outline_join_style_; + ComPtr fill_brush_; + ComPtr stroke_brush_; + ComPtr text_format_; + ComPtr text_renderer_; + ComPtr render_target_; + + mutable bool cache_expired_; + mutable ComPtr bitmap_cached_; }; } \ No newline at end of file diff --git a/src/core/DebugNode.cpp b/src/core/DebugNode.cpp index 31a54911..ab214ac9 100644 --- a/src/core/DebugNode.cpp +++ b/src/core/DebugNode.cpp @@ -28,6 +28,11 @@ namespace easy2d { + namespace + { + bool show = false; + } + DebugNode::DebugNode() { debug_text_ = new Text(); @@ -67,16 +72,14 @@ namespace easy2d void DebugNode::OnRender() { - auto& rt = RenderSystem::Instance(); + Renderer::Instance().GetSolidColorBrush()->SetColor(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.5f)); - rt.GetSolidBrush()->SetColor(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.5f)); - - rt.GetRenderTarget()->FillRoundedRectangle( + Renderer::Instance().GetDeviceResources()->GetD2DDeviceContext()->FillRoundedRectangle( D2D1::RoundedRect( D2D1_RECT_F{ 10, 10, 200, 120 }, 6.f, 6.f), - rt.GetSolidBrush().Get() + Renderer::Instance().GetSolidColorBrush() ); } @@ -105,9 +108,9 @@ namespace easy2d ss << "Objects: " << Object::__GetTracingObjects().size() << std::endl; #endif - ss << "Render: " << RenderSystem::Instance().GetStatus().duration.Milliseconds() << "ms" << std::endl; + ss << "Render: " << Renderer::Instance().GetStatus().duration.Milliseconds() << "ms" << std::endl; - ss << "Primitives / sec: " << RenderSystem::Instance().GetStatus().primitives * frame_time_.size() << std::endl; + ss << "Primitives / sec: " << Renderer::Instance().GetStatus().primitives * frame_time_.size() << std::endl; PROCESS_MEMORY_COUNTERS_EX pmc; GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc)); @@ -119,4 +122,19 @@ namespace easy2d debug_text_->SetText(ss.str()); } + void DebugNode::Show() + { + show = true; + } + + void DebugNode::Hide() + { + show = false; + } + + bool DebugNode::IsShown() + { + return show; + } + } diff --git a/src/core/DebugNode.h b/src/core/DebugNode.h index 0cdd04e4..f6c926c6 100644 --- a/src/core/DebugNode.h +++ b/src/core/DebugNode.h @@ -26,7 +26,7 @@ namespace easy2d { class E2D_API DebugNode - : public Node + : public VisualNode , public Singleton { E2D_DECLARE_SINGLETON(DebugNode); @@ -36,6 +36,12 @@ namespace easy2d virtual ~DebugNode(); + // 显示调试信息 + void Show(); + + // 隐藏调试信息 + void Hide(); + void AddDebugText(String const& text); void ClearDebugText(); @@ -44,6 +50,8 @@ namespace easy2d void OnUpdate(Duration dt) override; + static bool IsShown(); + protected: TextPtr debug_text_; Array frame_time_; diff --git a/src/core/Factory.h b/src/core/Factory.h deleted file mode 100644 index 9c47f483..00000000 --- a/src/core/Factory.h +++ /dev/null @@ -1,125 +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 "include-forwards.h" -#include "Singleton.hpp" -#include "Font.hpp" -#include "Resource.h" -#include "TextRenderer.h" -#include "TextStyle.hpp" - -namespace easy2d -{ - class E2D_API Factory - : public Singleton - { - E2D_DECLARE_SINGLETON(Factory); - - public: - HRESULT Init(bool debug); - - void Destroy(); - - HRESULT CreateHwndRenderTarget( - _Out_ D2DHwndRenderTargetPtr& hwnd_render_target, - D2D1_RENDER_TARGET_PROPERTIES const& properties, - D2D1_HWND_RENDER_TARGET_PROPERTIES const& hwnd_rt_properties - ) const; - - HRESULT CreateTextRenderer( - _Out_ D2DTextRendererPtr& text_renderer, - D2DRenderTargetPtr const& render_target, - D2DSolidColorBrushPtr const& brush - ); - - HRESULT CreateBitmapFromFile( - _Out_ D2DBitmapPtr& bitmap, - D2DRenderTargetPtr const& rt, - String const& file_path - ); - - HRESULT CreateBitmapFromResource( - _Out_ D2DBitmapPtr& bitmap, - D2DRenderTargetPtr const& rt, - Resource const& res - ); - - HRESULT CreateRectangleGeometry( - _Out_ D2DRectangleGeometryPtr& geo, - Rect const& rect - ) const; - - HRESULT CreateRoundedRectangleGeometry( - _Out_ D2DRoundedRectangleGeometryPtr& geo, - Rect const& rect, - float radius_x, - float radius_y - ) const; - - HRESULT CreateEllipseGeometry( - _Out_ D2DEllipseGeometryPtr& geo, - Point const& center, - float radius_x, - float radius_y - ) const; - - HRESULT CreateTransformedGeometry( - _Out_ D2DTransformedGeometryPtr& transformed, - Matrix const& matrix, - D2DGeometryPtr const& geo - ) const; - - HRESULT CreatePathGeometry( - _Out_ D2DPathGeometryPtr& geometry - ) const; - - HRESULT CreateTextFormat( - _Out_ D2DTextFormatPtr& text_format, - Font const& font, - TextStyle const& text_style - ) const; - - HRESULT CreateTextLayout( - _Out_ D2DTextLayoutPtr& text_layout, - _Out_ Size& layout_size, - String const& text, - D2DTextFormatPtr const& text_format, - TextStyle const& text_style - ) const; - - D2DStrokeStylePtr const& GetStrokeStyle( - StrokeStyle stroke - ) const; - - protected: - Factory(); - - ~Factory(); - - protected: - D2DFactoryPtr factory_; - D2DImagingFactoryPtr imaging_factory_; - D2DWriteFactoryPtr write_factory_; - D2DStrokeStylePtr miter_stroke_style_; - D2DStrokeStylePtr bevel_stroke_style_; - D2DStrokeStylePtr round_stroke_style_; - }; -} diff --git a/src/core/Geometry.cpp b/src/core/Geometry.cpp index 5e6dd997..46c0fdf9 100644 --- a/src/core/Geometry.cpp +++ b/src/core/Geometry.cpp @@ -19,7 +19,6 @@ // THE SOFTWARE. #include "Geometry.h" -#include "Factory.h" #include "render.h" #include "logs.h" @@ -99,7 +98,7 @@ namespace easy2d BOOL ret = 0; // no matter it failed or not geo_->FillContainsPoint( - ToD2dPoint2F(point), + DX::ConvertToPoint2F(point), D2D1::Matrix3x2F::Identity(), &ret ); @@ -126,10 +125,10 @@ namespace easy2d void LineGeometry::SetLine(Point const & begin, Point const & end) { - D2DPathGeometryPtr path_geo; - D2DGeometrySinkPtr path_sink; + ComPtr path_geo; + ComPtr path_sink; - HRESULT hr = Factory::Instance().CreatePathGeometry(path_geo); + HRESULT hr = Renderer::Instance().GetDeviceResources()->GetD2DFactory()->CreatePathGeometry(&path_geo); if (SUCCEEDED(hr)) { @@ -138,8 +137,8 @@ namespace easy2d if (SUCCEEDED(hr)) { - path_sink->BeginFigure(ToD2dPoint2F(begin), D2D1_FIGURE_BEGIN_FILLED); - path_sink->AddLine(ToD2dPoint2F(end)); + path_sink->BeginFigure(DX::ConvertToPoint2F(begin), D2D1_FIGURE_BEGIN_FILLED); + path_sink->AddLine(DX::ConvertToPoint2F(end)); path_sink->EndFigure(D2D1_FIGURE_END_OPEN); hr = path_sink->Close(); } @@ -185,8 +184,10 @@ namespace easy2d void RectangleGeometry::SetRect(Rect const & rect) { - D2DRectangleGeometryPtr geo; - if (SUCCEEDED(Factory::Instance().CreateRectangleGeometry(geo, rect))) + ComPtr geo; + auto factory = Renderer::Instance().GetDeviceResources()->GetD2DFactory(); + + if (SUCCEEDED(factory->CreateRectangleGeometry(DX::ConvertToRectF(rect), &geo))) { geo_ = geo; rect_ = rect; @@ -224,8 +225,15 @@ namespace easy2d void CircleGeometry::SetCircle(Point const & center, float radius) { - D2DEllipseGeometryPtr geo; - if (SUCCEEDED(Factory::Instance().CreateEllipseGeometry(geo, center, radius, radius))) + ComPtr geo; + auto factory = Renderer::Instance().GetDeviceResources()->GetD2DFactory(); + + if (SUCCEEDED(factory->CreateEllipseGeometry( + D2D1::Ellipse( + DX::ConvertToPoint2F(center), + radius, + radius), + &geo))) { geo_ = geo; center_ = center; @@ -265,8 +273,15 @@ namespace easy2d void EllipseGeometry::SetEllipse(Point const & center, float radius_x, float radius_y) { - D2DEllipseGeometryPtr geo; - if (SUCCEEDED(Factory::Instance().CreateEllipseGeometry(geo, center, radius_x, radius_y))) + ComPtr geo; + auto factory = Renderer::Instance().GetDeviceResources()->GetD2DFactory(); + + if (SUCCEEDED(factory->CreateEllipseGeometry( + D2D1::Ellipse( + DX::ConvertToPoint2F(center), + radius_x, + radius_y), + &geo))) { geo_ = geo; radius_x_ = radius_x; @@ -291,15 +306,17 @@ namespace easy2d { current_geometry_ = nullptr; + auto factory = Renderer::Instance().GetDeviceResources()->GetD2DFactory(); + ThrowIfFailed( - Factory::Instance().CreatePathGeometry(current_geometry_) + factory->CreatePathGeometry(¤t_geometry_) ); ThrowIfFailed( current_geometry_->Open(¤t_sink_) ); - current_sink_->BeginFigure(ToD2dPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED); + current_sink_->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED); } void PathGeometry::EndPath(bool closed) @@ -321,7 +338,7 @@ namespace easy2d void PathGeometry::AddLine(Point const & point) { if (current_sink_) - current_sink_->AddLine(ToD2dPoint2F(point)); + current_sink_->AddLine(DX::ConvertToPoint2F(point)); } void PathGeometry::AddLines(Array const& points) @@ -341,9 +358,9 @@ namespace easy2d { current_sink_->AddBezier( D2D1::BezierSegment( - ToD2dPoint2F(point1), - ToD2dPoint2F(point2), - ToD2dPoint2F(point3) + DX::ConvertToPoint2F(point1), + DX::ConvertToPoint2F(point2), + DX::ConvertToPoint2F(point3) ) ); } @@ -355,8 +372,8 @@ namespace easy2d { current_sink_->AddArc( D2D1::ArcSegment( - ToD2dPoint2F(point), - ToD2dSizeF(radius), + DX::ConvertToPoint2F(point), + DX::ConvertToSizeF(radius), rotation, clockwise ? D2D1_SWEEP_DIRECTION_CLOCKWISE : D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE, is_small ? D2D1_ARC_SIZE_SMALL : D2D1_ARC_SIZE_LARGE @@ -404,8 +421,16 @@ namespace easy2d void RoundedRectGeometry::SetRoundedRect(Rect const & rect, float radius_x, float radius_y) { - D2DRoundedRectangleGeometryPtr geo; - if (SUCCEEDED(Factory::Instance().CreateRoundedRectangleGeometry(geo, rect, radius_x, radius_y))) + ComPtr geo; + auto factory = Renderer::Instance().GetDeviceResources()->GetD2DFactory(); + + if (SUCCEEDED(factory->CreateRoundedRectangleGeometry( + D2D1::RoundedRect( + DX::ConvertToRectF(rect), + radius_x, + radius_y + ), + &geo))) { geo_ = geo; rect_ = rect; diff --git a/src/core/Geometry.h b/src/core/Geometry.h index 917113d9..aed3637f 100644 --- a/src/core/Geometry.h +++ b/src/core/Geometry.h @@ -57,7 +57,7 @@ namespace easy2d float ComputeArea(); protected: - D2DGeometryPtr geo_; + ComPtr geo_; }; @@ -254,8 +254,8 @@ namespace easy2d void ClearPath(); protected: - D2DPathGeometryPtr current_geometry_; - D2DGeometrySinkPtr current_sink_; + ComPtr current_geometry_; + ComPtr current_sink_; }; diff --git a/src/core/GeometryNode.cpp b/src/core/GeometryNode.cpp index 54cbcc69..3a3ca899 100644 --- a/src/core/GeometryNode.cpp +++ b/src/core/GeometryNode.cpp @@ -70,14 +70,12 @@ namespace easy2d { if (geometry_ && geometry_->geo_) { - auto& rt = RenderSystem::Instance(); - - rt.FillGeometry( - geometry_->geo_, + Renderer::Instance().FillGeometry( + geometry_->geo_.Get(), fill_color_ ); - rt.DrawGeometry( + Renderer::Instance().DrawGeometry( geometry_->geo_, stroke_color_, stroke_width_, diff --git a/src/core/GeometryNode.h b/src/core/GeometryNode.h index 00a1b9f1..6296a20b 100644 --- a/src/core/GeometryNode.h +++ b/src/core/GeometryNode.h @@ -26,7 +26,7 @@ namespace easy2d { // 几何图形 class E2D_API GeometryNode - : public Node + : public VisualNode { public: GeometryNode(); diff --git a/src/core/Image.cpp b/src/core/Image.cpp index e4041442..87cb14e4 100644 --- a/src/core/Image.cpp +++ b/src/core/Image.cpp @@ -19,8 +19,8 @@ // THE SOFTWARE. #include "Image.h" -#include "render.h" #include "logs.h" +#include "render.h" #include "../utils/File.h" #include "../utils/string.h" @@ -45,7 +45,7 @@ namespace easy2d this->Crop(crop_rect); } - Image::Image(D2DBitmapPtr const & bitmap) + Image::Image(ComPtr const & bitmap) : Image() { SetBitmap(bitmap); @@ -58,7 +58,7 @@ namespace easy2d bool Image::Load(Resource const& res) { HRESULT hr = S_OK; - D2DBitmapPtr bitmap; + ComPtr bitmap; if (res.IsFileType()) { @@ -67,11 +67,11 @@ namespace easy2d E2D_WARNING_LOG(L"Image file '%s' not found!", res.GetFileName().c_str()); return false; } - hr = RenderSystem::Instance().CreateBitmapFromFile(bitmap, res.GetFileName()); + hr = Renderer::Instance().GetDeviceResources()->CreateBitmapFromFile(bitmap, res.GetFileName()); } else { - hr = RenderSystem::Instance().CreateBitmapFromResource(bitmap, res); + hr = Renderer::Instance().GetDeviceResources()->CreateBitmapFromResource(bitmap, res); } if (FAILED(hr)) @@ -164,12 +164,12 @@ namespace easy2d return crop_rect_; } - D2DBitmapPtr const& Image::GetBitmap() const + ComPtr const& Image::GetBitmap() const { return bitmap_; } - void Image::SetBitmap(D2DBitmapPtr const & bitmap) + void Image::SetBitmap(ComPtr const & bitmap) { if (bitmap) { diff --git a/src/core/Image.h b/src/core/Image.h index ed525586..a335a77a 100644 --- a/src/core/Image.h +++ b/src/core/Image.h @@ -41,7 +41,7 @@ namespace easy2d ); explicit Image( - D2DBitmapPtr const& bitmap + ComPtr const& bitmap ); virtual ~Image(); @@ -89,15 +89,15 @@ namespace easy2d // 获取裁剪矩形 Rect const& GetCropRect() const; - D2DBitmapPtr const& GetBitmap() const; + ComPtr const& GetBitmap() const; protected: void SetBitmap( - D2DBitmapPtr const& bitmap + ComPtr const& bitmap ); protected: Rect crop_rect_; - D2DBitmapPtr bitmap_; + ComPtr bitmap_; }; } diff --git a/src/core/Input.cpp b/src/core/Input.cpp index e1d2b4ca..10d15285 100644 --- a/src/core/Input.cpp +++ b/src/core/Input.cpp @@ -37,10 +37,8 @@ namespace easy2d { } - HRESULT Input::Init(HWND hwnd, bool debug) + HRESULT Input::Init(HWND hwnd) { - E2D_NOT_USED(debug); - hwnd_ = hwnd; return S_OK; diff --git a/src/core/Input.h b/src/core/Input.h index 97ff6ace..dff99897 100644 --- a/src/core/Input.h +++ b/src/core/Input.h @@ -55,7 +55,7 @@ namespace easy2d // 获得鼠标坐标 Point GetMousePos(); - HRESULT Init(HWND hwnd, bool debug); + HRESULT Init(HWND hwnd); void Update(); diff --git a/src/core/Node.cpp b/src/core/Node.cpp index 32e0ac25..1799e613 100644 --- a/src/core/Node.cpp +++ b/src/core/Node.cpp @@ -20,7 +20,6 @@ #include "Node.h" #include "Action.h" -#include "Factory.h" #include "Scene.h" #include "Task.h" #include "render.h" @@ -42,7 +41,7 @@ namespace easy2d Node::Node() : visible_(true) - , pause_(false) + , update_pausing_(false) , hover_(false) , pressed_(false) , responsible_(false) @@ -59,7 +58,7 @@ namespace easy2d void Node::Update(Duration dt) { - if (pause_) + if (update_pausing_) return; UpdateActions(this, dt); @@ -88,13 +87,9 @@ namespace easy2d UpdateTransform(); - auto& rt = RenderSystem::Instance(); - if (children_.IsEmpty()) { - rt.SetTransform(transform_matrix_); - rt.SetOpacity(display_opacity_); - + PrepareRender(); OnRender(); } else @@ -110,9 +105,7 @@ namespace easy2d child = child->NextItem().Get(); } - rt.SetTransform(transform_matrix_); - rt.SetOpacity(display_opacity_); - + PrepareRender(); OnRender(); while (child) @@ -184,16 +177,6 @@ namespace easy2d EventDispatcher::Dispatch(evt); } - void Node::PauseUpdating() - { - pause_ = true; - } - - void Node::ResumeUpdating() - { - pause_ = false; - } - Matrix const & Node::GetTransformMatrix() const { UpdateTransform(); @@ -607,4 +590,12 @@ namespace easy2d Point local = GetTransformInverseMatrix().Transform(point); return GetBounds().ContainsPoint(local); } + + + void VisualNode::PrepareRender() + { + Renderer::Instance().SetTransform(transform_matrix_); + Renderer::Instance().SetOpacity(display_opacity_); + } + } diff --git a/src/core/Node.h b/src/core/Node.h index b38b9901..6c6f6dce 100644 --- a/src/core/Node.h +++ b/src/core/Node.h @@ -344,13 +344,13 @@ namespace easy2d void RemoveFromParent(); // 暂停节点更新 - void PauseUpdating(); + inline void PauseUpdating() { update_pausing_ = true; } // 继续节点更新 - void ResumeUpdating(); + inline void ResumeUpdating() { update_pausing_ = false; } // 节点更新是否暂停 - inline bool IsUpdatePausing() const { return pause_; } + inline bool IsUpdatePausing() const { return update_pausing_; } // 设置更新时的回调函数 inline void SetCallbackOnUpdate(UpdateCallback const& cb) { cb_update_ = cb; } @@ -365,6 +365,8 @@ namespace easy2d ); protected: + virtual void PrepareRender() {} + void Update(Duration dt); void Render(); @@ -380,7 +382,7 @@ namespace easy2d bool hover_; bool pressed_; bool responsible_; - bool pause_; + bool update_pausing_; int z_order_; float opacity_; float display_opacity_; @@ -398,4 +400,13 @@ namespace easy2d mutable Matrix transform_matrix_; mutable Matrix transform_matrix_inverse_; }; + + + class E2D_API VisualNode + : public Node + { + public: + virtual void PrepareRender() override; + }; + } diff --git a/src/core/Scene.h b/src/core/Scene.h index 3e40a66d..11e24dc1 100644 --- a/src/core/Scene.h +++ b/src/core/Scene.h @@ -25,7 +25,7 @@ namespace easy2d { // 场景 class E2D_API Scene - : public Node + : public VisualNode { public: Scene(); diff --git a/src/core/Sprite.cpp b/src/core/Sprite.cpp index 5ac2e9d3..c0539b9c 100644 --- a/src/core/Sprite.cpp +++ b/src/core/Sprite.cpp @@ -99,7 +99,7 @@ namespace easy2d { if (image_) { - RenderSystem::Instance().DrawImage(image_, GetBounds()); + Renderer::Instance().DrawImage(image_, GetBounds()); } } } \ No newline at end of file diff --git a/src/core/Sprite.h b/src/core/Sprite.h index ed03aea6..9e2ac4db 100644 --- a/src/core/Sprite.h +++ b/src/core/Sprite.h @@ -26,7 +26,7 @@ namespace easy2d { // 精灵 class E2D_API Sprite - : public Node + : public VisualNode { public: Sprite(); diff --git a/src/core/Text.cpp b/src/core/Text.cpp index 9039ade5..84054bef 100644 --- a/src/core/Text.cpp +++ b/src/core/Text.cpp @@ -19,9 +19,7 @@ // THE SOFTWARE. #include "Text.h" -#include "Factory.h" #include "render.h" -#include "include-forwards.h" #include "logs.h" namespace easy2d @@ -45,6 +43,7 @@ namespace easy2d Text::Text() : font_(text_default_font) , style_(text_default_style) + , layout_dirty_(false) { } @@ -67,8 +66,8 @@ namespace easy2d : font_(font) , style_(style) , text_(text) + , layout_dirty_(true) { - UpdateLayout(); } Text::~Text() @@ -127,6 +126,7 @@ namespace easy2d int Text::GetLineCount() { + UpdateLayout(); if (text_layout_) { DWRITE_TEXT_METRICS metrics; @@ -138,6 +138,12 @@ namespace easy2d return 0; } + Size const& Text::GetLayoutSize() const + { + UpdateLayout(); + return layout_size_; + } + bool Text::IsItalic() const { return font_.italic; @@ -161,19 +167,19 @@ namespace easy2d void Text::SetText(String const& text) { text_ = text; - UpdateLayout(); + layout_dirty_ = true; } void Text::SetStyle(const TextStyle& style) { style_ = style; - UpdateLayout(); + layout_dirty_ = true; } void Text::SetFont(const Font & font) { font_ = font; - UpdateLayout(); + layout_dirty_ = true; } void Text::SetFontFamily(String const& family) @@ -181,7 +187,7 @@ namespace easy2d if (font_.family != family) { font_.family = family; - UpdateLayout(); + layout_dirty_ = true; } } @@ -190,7 +196,7 @@ namespace easy2d if (font_.size != size) { font_.size = size; - UpdateLayout(); + layout_dirty_ = true; } } @@ -199,7 +205,7 @@ namespace easy2d if (font_.weight != weight) { font_.weight = weight; - UpdateLayout(); + layout_dirty_ = true; } } @@ -213,7 +219,7 @@ namespace easy2d if (font_.italic != val) { font_.italic = val; - UpdateLayout(); + layout_dirty_ = true; } } @@ -222,7 +228,7 @@ namespace easy2d if (style_.wrap != wrap) { style_.wrap = wrap; - UpdateLayout(); + layout_dirty_ = true; } } @@ -231,7 +237,7 @@ namespace easy2d if (style_.wrap_width != wrap_width) { style_.wrap_width = std::max(wrap_width, 0.f); - UpdateLayout(); + layout_dirty_ = true; } } @@ -240,7 +246,7 @@ namespace easy2d if (style_.line_spacing != line_spacing) { style_.line_spacing = line_spacing; - UpdateLayout(); + layout_dirty_ = true; } } @@ -249,7 +255,7 @@ namespace easy2d if (style_.alignment != align) { style_.alignment = align; - UpdateLayout(); + layout_dirty_ = true; } } @@ -258,7 +264,7 @@ namespace easy2d if (style_.underline != underline) { style_.underline = underline; - UpdateLayout(); + layout_dirty_ = true; } } @@ -267,7 +273,7 @@ namespace easy2d if (style_.strikethrough != strikethrough) { style_.strikethrough = strikethrough; - UpdateLayout(); + layout_dirty_ = true; } } @@ -293,22 +299,27 @@ namespace easy2d void Text::OnRender() { + UpdateLayout(); + if (text_layout_) { - auto& rt = RenderSystem::Instance(); - rt.SetTextStyle( + Renderer::Instance().SetTextStyle( style_.color, style_.outline, style_.outline_color, style_.outline_width, style_.outline_stroke ); - rt.DrawTextLayout(text_layout_); + Renderer::Instance().DrawTextLayout(text_layout_); } } - void Text::UpdateLayout() + void Text::UpdateLayout() const { + if (!layout_dirty_) + return; + + layout_dirty_ = false; text_format_ = nullptr; text_layout_ = nullptr; @@ -316,24 +327,21 @@ namespace easy2d return; ThrowIfFailed( - Factory::Instance().CreateTextFormat( + Renderer::Instance().GetDeviceResources()->CreateTextFormat( text_format_, font_, style_ ) ); - Size layout_size; ThrowIfFailed( - Factory::Instance().CreateTextLayout( + Renderer::Instance().GetDeviceResources()->CreateTextLayout( text_layout_, - layout_size, + layout_size_, text_, text_format_, style_ ) ); - - this->SetSize(layout_size); } } diff --git a/src/core/Text.h b/src/core/Text.h index d33c0bf1..1459d174 100644 --- a/src/core/Text.h +++ b/src/core/Text.h @@ -27,7 +27,7 @@ namespace easy2d { // 文本 class E2D_API Text - : public Node + : public VisualNode { public: Text(); @@ -87,6 +87,9 @@ namespace easy2d // 获取文本显示行数 int GetLineCount(); + // 获取文字布局大小 + Size const& GetLayoutSize() const; + // 是否是斜体 bool IsItalic() const; @@ -202,13 +205,16 @@ namespace easy2d void OnRender() override; protected: - void UpdateLayout(); + void UpdateLayout() const; protected: - String text_; - Font font_; - TextStyle style_; - D2DTextFormatPtr text_format_; - D2DTextLayoutPtr text_layout_; + String text_; + Font font_; + TextStyle style_; + + mutable bool layout_dirty_; + mutable Size layout_size_; + mutable ComPtr text_format_; + mutable ComPtr text_layout_; }; } \ No newline at end of file diff --git a/src/core/Transform.hpp b/src/core/Transform.hpp index 8c2cbefe..5da5816a 100644 --- a/src/core/Transform.hpp +++ b/src/core/Transform.hpp @@ -19,11 +19,11 @@ // THE SOFTWARE. #pragma once -#include "helper.hpp" +#include "../math/Matrix.hpp" namespace easy2d { - class E2D_API Transform + class Transform { public: float rotation; // 旋转 diff --git a/src/core/Transition.cpp b/src/core/Transition.cpp index 447c8917..e33b7acf 100644 --- a/src/core/Transition.cpp +++ b/src/core/Transition.cpp @@ -66,14 +66,14 @@ namespace easy2d if (in_scene_) { ThrowIfFailed( - RenderSystem::Instance().CreateLayer(in_layer_) + Renderer::Instance().CreateLayer(in_layer_) ); } if (out_scene_) { ThrowIfFailed( - RenderSystem::Instance().CreateLayer(out_layer_) + Renderer::Instance().CreateLayer(out_layer_) ); } @@ -101,34 +101,34 @@ namespace easy2d void Transition::Render() { - auto& rt = RenderSystem::Instance(); + auto& renderer = Renderer::Instance(); if (out_scene_) { - rt.PushClip( + renderer.PushClip( out_scene_->GetTransformMatrix(), window_size_ ); - rt.PushLayer(out_layer_, out_layer_prop_); + renderer.PushLayer(out_layer_, out_layer_prop_); out_scene_->Render(); - rt.PopLayer(); - rt.PopClip(); + renderer.PopLayer(); + renderer.PopClip(); } if (in_scene_) { - rt.PushClip( + renderer.PushClip( in_scene_->GetTransformMatrix(), window_size_ ); - rt.PushLayer(in_layer_, in_layer_prop_); + renderer.PushLayer(in_layer_, in_layer_prop_); in_scene_->Render(); - rt.PopLayer(); - rt.PopClip(); + renderer.PopLayer(); + renderer.PopClip(); } } diff --git a/src/core/Transition.h b/src/core/Transition.h index 6e9143bb..e21f34a8 100644 --- a/src/core/Transition.h +++ b/src/core/Transition.h @@ -63,8 +63,8 @@ namespace easy2d Size window_size_; ScenePtr out_scene_; ScenePtr in_scene_; - D2DLayerPtr out_layer_; - D2DLayerPtr in_layer_; + ComPtr out_layer_; + ComPtr in_layer_; LayerProperties out_layer_prop_; LayerProperties in_layer_prop_; }; diff --git a/src/core/audio.cpp b/src/core/audio.cpp index cdbd92da..7ec893af 100644 --- a/src/core/audio.cpp +++ b/src/core/audio.cpp @@ -169,10 +169,8 @@ namespace easy2d { } - HRESULT Audio::Init(bool debug) + HRESULT Audio::Init() { - E2D_NOT_USED(debug); - E2D_LOG(L"Initing audio resources"); HRESULT hr = modules::MediaFoundation::Get().MFStartup(MF_VERSION, MFSTARTUP_FULL); @@ -202,7 +200,7 @@ namespace easy2d mastering_voice_ = nullptr; } - SafeRelease(x_audio2_); + DX::SafeRelease(x_audio2_); modules::MediaFoundation::Get().MFShutdown(); } diff --git a/src/core/audio.h b/src/core/audio.h index bd7660e9..355dfa09 100644 --- a/src/core/audio.h +++ b/src/core/audio.h @@ -82,7 +82,7 @@ namespace easy2d using VoiceMap = UnorderedSet; public: - HRESULT Init(bool debug); + HRESULT Init(); void Destroy(); diff --git a/src/core/d2dhelper.hpp b/src/core/d2dhelper.hpp deleted file mode 100644 index a8798e07..00000000 --- a/src/core/d2dhelper.hpp +++ /dev/null @@ -1,101 +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 "IntrusivePtr.hpp" -#include "../math/vector.hpp" -#include "../math/Rect.hpp" -#include "Color.h" -#include -#include - -#ifndef E2D_DECLARE_D2D_SMART_PTR -#define E2D_DECLARE_D2D_SMART_PTR(class_name, sp_name)\ - using sp_name = ::easy2d::IntrusivePtr< class_name > -#endif - - -namespace easy2d -{ - // "D2DPtr" is a shorthand for "COM Pointer" - - E2D_DECLARE_D2D_SMART_PTR(ID2D1Factory, D2DFactoryPtr); - E2D_DECLARE_D2D_SMART_PTR(IWICImagingFactory, D2DImagingFactoryPtr); - E2D_DECLARE_D2D_SMART_PTR(IDWriteFactory, D2DWriteFactoryPtr); - E2D_DECLARE_D2D_SMART_PTR(ID2D1SolidColorBrush, D2DSolidColorBrushPtr); - E2D_DECLARE_D2D_SMART_PTR(ID2D1RenderTarget, D2DRenderTargetPtr); - E2D_DECLARE_D2D_SMART_PTR(ID2D1HwndRenderTarget, D2DHwndRenderTargetPtr); - E2D_DECLARE_D2D_SMART_PTR(ID2D1BitmapRenderTarget, D2DBitmapRenderTargetPtr); - E2D_DECLARE_D2D_SMART_PTR(ID2D1StrokeStyle, D2DStrokeStylePtr); - - E2D_DECLARE_D2D_SMART_PTR(ID2D1Geometry, D2DGeometryPtr); - E2D_DECLARE_D2D_SMART_PTR(ID2D1RectangleGeometry, D2DRectangleGeometryPtr); - E2D_DECLARE_D2D_SMART_PTR(ID2D1RoundedRectangleGeometry, D2DRoundedRectangleGeometryPtr); - E2D_DECLARE_D2D_SMART_PTR(ID2D1EllipseGeometry, D2DEllipseGeometryPtr); - E2D_DECLARE_D2D_SMART_PTR(ID2D1GeometryGroup, D2DGeometryGroupPtr); - E2D_DECLARE_D2D_SMART_PTR(ID2D1PathGeometry, D2DPathGeometryPtr); - E2D_DECLARE_D2D_SMART_PTR(ID2D1TransformedGeometry, D2DTransformedGeometryPtr); - E2D_DECLARE_D2D_SMART_PTR(ID2D1GeometrySink, D2DGeometrySinkPtr); - - E2D_DECLARE_D2D_SMART_PTR(ID2D1Layer, D2DLayerPtr); - E2D_DECLARE_D2D_SMART_PTR(ID2D1Bitmap, D2DBitmapPtr); - E2D_DECLARE_D2D_SMART_PTR(IDWriteTextFormat, D2DTextFormatPtr); - E2D_DECLARE_D2D_SMART_PTR(IDWriteTextLayout, D2DTextLayoutPtr); - - inline void IntrusivePtrAddRef(IUnknown* ptr) - { - if (ptr) { ptr->AddRef(); } - } - - inline void IntrusivePtrRelease(IUnknown* ptr) - { - if (ptr) { ptr->Release(); } - } - - template - inline void SafeRelease(T*& ptr) - { - if (ptr != nullptr) - { - ptr->Release(); - ptr = nullptr; - } - } - - inline D2D1_POINT_2F const& ToD2dPoint2F(math::Vec2 const& point) - { - return reinterpret_cast(point); - } - - inline D2D1_SIZE_F const& ToD2dSizeF(math::Vec2 const& size) - { - return reinterpret_cast(size); - } - - inline D2D1_RECT_F ToD2dRectF(math::Rect const& rect) - { - return D2D1_RECT_F{ rect.origin.x, rect.origin.y, rect.origin.x + rect.size.x, rect.origin.y + rect.size.y }; - } - - inline D2D1_COLOR_F const& ToD2dColorF(Color const& color) - { - return reinterpret_cast(color); - } -} diff --git a/src/core/helper.hpp b/src/core/helper.hpp index 5343148d..db90dd91 100644 --- a/src/core/helper.hpp +++ b/src/core/helper.hpp @@ -25,7 +25,7 @@ #include "closure.hpp" #include "../math/vector.hpp" #include "../math/Rect.hpp" -#include "../math/Matrix.h" +#include "../math/Matrix.hpp" #include #include #include @@ -72,8 +72,6 @@ namespace easy2d namespace easy2d { - // "Ptr" is a shorthand for "Smart Pointer" - E2D_DECLARE_SMART_PTR(Object); E2D_DECLARE_SMART_PTR(Image); E2D_DECLARE_SMART_PTR(Music); diff --git a/src/core/include-forwards.h b/src/core/include-forwards.h index fe09f445..b790d13b 100644 --- a/src/core/include-forwards.h +++ b/src/core/include-forwards.h @@ -23,7 +23,7 @@ #include "Color.h" #include "Object.h" #include "helper.hpp" -#include "d2dhelper.hpp" +#include "../DX/helper.hpp" namespace easy2d { diff --git a/src/core/logs.h b/src/core/logs.h index a5dc2cb0..744c8bb9 100644 --- a/src/core/logs.h +++ b/src/core/logs.h @@ -97,7 +97,10 @@ namespace easy2d if (FAILED(hr)) { E2D_ERROR_LOG(L"Fatal error with HRESULT of %08X", hr); - throw std::runtime_error("Fatal error"); + + static char buffer[1024 + 1]; + sprintf_s(buffer, "Fatal error with HRESULT of %08X", hr); + throw std::runtime_error(buffer); } } } diff --git a/src/core/modules.cpp b/src/core/modules.cpp index 8c7d2cbb..5bc4e84c 100644 --- a/src/core/modules.cpp +++ b/src/core/modules.cpp @@ -65,6 +65,17 @@ namespace easy2d { E2D_LOG(L"load dwrite.dll failed"); } + + d3d11 = LoadLibraryW(L"d3d11.dll"); + if (d3d11) + { + D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE) + GetProcAddress(d3d11, "D3D11CreateDevice"); + } + else + { + E2D_LOG(L"load d3d11.dll failed"); + } } XAudio2::XAudio2() diff --git a/src/core/modules.h b/src/core/modules.h index fc350d59..998eee76 100644 --- a/src/core/modules.h +++ b/src/core/modules.h @@ -26,6 +26,7 @@ #include #include #include +#include namespace easy2d { @@ -57,6 +58,7 @@ namespace easy2d { DirectX(); + HMODULE d3d11; HMODULE d2d; HMODULE dwrite; @@ -73,6 +75,7 @@ namespace easy2d PFN_D2D1CreateFactory D2D1CreateFactory; PFN_DWriteCreateFactory DWriteCreateFactory; + PFN_D3D11_CREATE_DEVICE D3D11CreateDevice; }; diff --git a/src/core/render.cpp b/src/core/render.cpp index fbd5c2fe..f4454024 100644 --- a/src/core/render.cpp +++ b/src/core/render.cpp @@ -20,220 +20,233 @@ #include "render.h" #include "logs.h" -#include "Factory.h" +#include "render.h" #include "Image.h" #include "Transform.hpp" namespace easy2d { - RenderSystem::RenderSystem() - : fps_text_format_(nullptr) - , fps_text_layout_(nullptr) + Renderer::Renderer() + : antialias_(true) + , text_antialias_(TextAntialias::ClearType) , clear_color_(D2D1::ColorF(D2D1::ColorF::Black)) , opacity_(1.f) - , debug_(false) - , window_occluded_(false) - , vsync_enabled_(true) - , antialias_(true) - , text_antialias_(TextAntialias::ClearType) + { + status_.primitives = 0; + } + + Renderer::~Renderer() { } - RenderSystem::~RenderSystem() + HRESULT Renderer::Init(HWND hwnd) { + HRESULT hr = S_OK; + + E2D_LOG(L"Creating device resources"); + + { + device_resources_ = nullptr; + hr = DeviceResources::Create( + &device_resources_, + hwnd + ); + } + + if (SUCCEEDED(hr)) + { + factory_ = device_resources_->GetD2DFactory(); + device_context_ = device_resources_->GetD2DDeviceContext(); + } + + if (SUCCEEDED(hr)) + { + drawing_state_block_ = nullptr; + hr = factory_->CreateDrawingStateBlock( + &drawing_state_block_ + ); + } + + if (SUCCEEDED(hr)) + { + hr = CreateDeviceResources(); + } + return hr; } - HRESULT RenderSystem::Init(HWND hwnd, bool vsync, bool debug) + void Renderer::Destroy() { - E2D_LOG(L"Initing graphics resources"); - - vsync_enabled_ = vsync; - debug_ = debug; - - return CreateResources(hwnd); - } - - void RenderSystem::Destroy() - { - E2D_LOG(L"Destroying graphics resources"); - - ClearImageCache(); + E2D_LOG(L"Destroying device resources"); + device_resources_.Reset(); + factory_.Reset(); + device_context_.Reset(); + drawing_state_block_.Reset(); text_renderer_.Reset(); - solid_brush_.Reset(); - render_target_.Reset(); - fps_text_format_.Reset(); - fps_text_layout_.Reset(); + solid_color_brush_.Reset(); } - HRESULT RenderSystem::BeginDraw(HWND hwnd) + HRESULT Renderer::CreateDeviceResources() { - HRESULT hr = CreateResources(hwnd); + HRESULT hr = S_OK; - if (debug_) + hr = device_context_->CreateSolidColorBrush( + D2D1::ColorF(D2D1::ColorF::White), + &solid_color_brush_ + ); + + if (SUCCEEDED(hr)) + { + hr = ITextRenderer::Create( + &text_renderer_, + device_context_.Get() + ); + } + + if (SUCCEEDED(hr)) + { + SetAntialiasMode(antialias_); + SetTextAntialiasMode(text_antialias_); + } + return hr; + } + + HRESULT Renderer::HandleDeviceLost() + { + HRESULT hr = device_resources_->HandleDeviceLost(); + + if (SUCCEEDED(hr)) + { + hr = CreateDeviceResources(); + } + return hr; + } + + HRESULT Renderer::BeginDraw() + { + if (!device_context_) + return E_UNEXPECTED; + + // if (debug_) { status_.start = time::Now(); status_.primitives = 0; } - if (SUCCEEDED(hr)) - { - window_occluded_ = !!(render_target_->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED); + device_context_->SaveDrawingState(drawing_state_block_.Get()); - if (!window_occluded_) - { - render_target_->BeginDraw(); - render_target_->Clear(clear_color_); - } - } - return hr; + device_context_->BeginDraw(); + device_context_->Clear(clear_color_); + return S_OK; } - HRESULT RenderSystem::EndDraw() + HRESULT Renderer::EndDraw() { - HRESULT hr = S_OK; - - if (!window_occluded_) - { - hr = render_target_->EndDraw(); + if (!device_context_) + return E_UNEXPECTED; - if (hr == D2DERR_RECREATE_TARGET) - { - // 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源 - // 并在下一次调用时重建资源 - DiscardResources(); - hr = S_OK; - } + HRESULT hr = device_context_->EndDraw(); + + device_context_->RestoreDrawingState(drawing_state_block_.Get()); + + if (SUCCEEDED(hr)) + { + // The first argument instructs DXGI to block until VSync. + hr = device_resources_->GetDXGISwapChain()->Present(1, 0); } - if (debug_) + if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) + { + // 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源 + hr = HandleDeviceLost(); + } + + // if (debug_) { status_.duration = time::Now() - status_.start; } return hr; } - void RenderSystem::ClearImageCache() + HRESULT Renderer::CreateLayer(ComPtr& layer) { - bitmap_cache_.clear(); - } - - D2DHwndRenderTargetPtr const & RenderSystem::GetRenderTarget() const - { - return render_target_; - } - - D2DSolidColorBrushPtr const & RenderSystem::GetSolidBrush() const - { - return solid_brush_; - } - - HRESULT RenderSystem::CreateLayer(D2DLayerPtr& layer) - { - if (!render_target_) + if (!device_context_) return E_UNEXPECTED; layer = nullptr; - return render_target_->CreateLayer(&layer); + return device_context_->CreateLayer(&layer); } - HRESULT RenderSystem::CreateSolidColorBrush(D2DSolidColorBrushPtr & brush) const - { - if (!render_target_) - return E_UNEXPECTED; - - brush = nullptr; - return render_target_->CreateSolidColorBrush( - D2D1::ColorF(D2D1::ColorF::White), - &brush - ); - } - - HRESULT RenderSystem::DrawGeometry( - D2DGeometryPtr const& geometry, + HRESULT Renderer::DrawGeometry( + ComPtr const& geometry, Color const& stroke_color, float stroke_width, StrokeStyle stroke ) { - if (!solid_brush_ || - !render_target_) + if (!solid_color_brush_ || !device_context_) return E_UNEXPECTED; - if (window_occluded_) - return S_OK; + solid_color_brush_->SetColor(DX::ConvertToColorF(stroke_color)); - solid_brush_->SetColor(ToD2dColorF(stroke_color)); - auto stroke_style = Factory::Instance().GetStrokeStyle(stroke); - render_target_->DrawGeometry( + device_context_->DrawGeometry( geometry.Get(), - solid_brush_.Get(), + solid_color_brush_.Get(), stroke_width, - stroke_style.Get() + device_resources_->GetStrokeStyle(stroke) ); - if (debug_) + // if (debug_) ++status_.primitives; return S_OK; } - HRESULT RenderSystem::FillGeometry(D2DGeometryPtr const & geometry, const Color & fill_color) + HRESULT Renderer::FillGeometry(ComPtr const & geometry, Color const& fill_color) { - if (!solid_brush_ || - !render_target_) + if (!solid_color_brush_ || !device_context_) return E_UNEXPECTED; - if (window_occluded_) - return S_OK; - - solid_brush_->SetColor(ToD2dColorF(fill_color)); - render_target_->FillGeometry( + solid_color_brush_->SetColor(DX::ConvertToColorF(fill_color)); + device_context_->FillGeometry( geometry.Get(), - solid_brush_.Get() + solid_color_brush_.Get() ); - if (debug_) - ++status_.primitives; return S_OK; } - HRESULT RenderSystem::DrawImage(ImagePtr const & image, Rect const& dest_rect) + HRESULT Renderer::DrawImage(ImagePtr const & image, Rect const& dest_rect) { - if (!render_target_) + if (!device_context_) return E_UNEXPECTED; if (!image->GetBitmap()) return S_OK; - if (window_occluded_) - return S_OK; - - render_target_->DrawBitmap( + device_context_->DrawBitmap( image->GetBitmap().Get(), - ToD2dRectF(dest_rect), + DX::ConvertToRectF(dest_rect), opacity_, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, - ToD2dRectF(image->GetCropRect()) + DX::ConvertToRectF(image->GetCropRect()) ); - if (debug_) + // if (debug_) ++status_.primitives; return S_OK; } - HRESULT RenderSystem::DrawBitmap( - D2DBitmapPtr const& bitmap - ) + HRESULT Renderer::DrawBitmap(ComPtr const & bitmap) { - if (!render_target_) + if (!device_context_) return E_UNEXPECTED; - if (window_occluded_) + if (!bitmap) return S_OK; // Do not crop bitmap - auto rect = D2D1::RectF(0.f, 0.f, bitmap->GetSize().width, bitmap->GetSize().height); - render_target_->DrawBitmap( + D2D_RECT_F rect = D2D1::RectF(0.f, 0.f, bitmap->GetSize().width, bitmap->GetSize().height); + device_context_->DrawBitmap( bitmap.Get(), rect, opacity_, @@ -241,69 +254,56 @@ namespace easy2d rect ); - if (debug_) - ++status_.primitives; + // if (debug_) + ++status_.primitives; return S_OK; } - HRESULT RenderSystem::DrawTextLayout(D2DTextLayoutPtr const& text_layout) + HRESULT Renderer::DrawTextLayout(ComPtr const& text_layout) { if (!text_renderer_) return E_UNEXPECTED; - if (window_occluded_) - return S_OK; - - if (debug_) + // if (debug_) ++status_.primitives; return text_layout->Draw(nullptr, text_renderer_.Get(), 0, 0); } - HRESULT RenderSystem::PushClip(const Matrix & clip_matrix, const Size & clip_size) + HRESULT Renderer::PushClip(const Matrix & clip_matrix, const Size & clip_size) { - if (!render_target_) + if (!device_context_) return E_UNEXPECTED; - if (window_occluded_) - return S_OK; - - render_target_->SetTransform(clip_matrix); - render_target_->PushAxisAlignedClip( + device_context_->SetTransform(DX::ConvertToMatrix3x2F(clip_matrix)); + device_context_->PushAxisAlignedClip( D2D1::RectF(0, 0, clip_size.x, clip_size.y), D2D1_ANTIALIAS_MODE_PER_PRIMITIVE ); return S_OK; } - HRESULT RenderSystem::PopClip() + HRESULT Renderer::PopClip() { - if (!render_target_) + if (!device_context_) return E_UNEXPECTED; - if (window_occluded_) - return S_OK; - - render_target_->PopAxisAlignedClip(); + device_context_->PopAxisAlignedClip(); return S_OK; } - HRESULT RenderSystem::PushLayer(D2DLayerPtr const& layer, LayerProperties const& properties) + HRESULT Renderer::PushLayer(ComPtr const& layer, LayerProperties const& properties) { - if (!render_target_ || - !solid_brush_) + if (!device_context_ || !solid_color_brush_) return E_UNEXPECTED; - if (window_occluded_) - return S_OK; - - render_target_->PushLayer( + device_context_->PushLayer( D2D1::LayerParameters( - ToD2dRectF(properties.area), + DX::ConvertToRectF(properties.area), nullptr, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, D2D1::Matrix3x2F::Identity(), properties.opacity, - solid_brush_.Get(), + solid_color_brush_.Get(), D2D1_LAYER_OPTIONS_NONE ), layer.Get() @@ -311,124 +311,39 @@ namespace easy2d return S_OK; } - HRESULT RenderSystem::PopLayer() + HRESULT Renderer::PopLayer() { - if (!render_target_) + if (!device_context_) return E_UNEXPECTED; - if (window_occluded_) - return S_OK; - - render_target_->PopLayer(); + device_context_->PopLayer(); return S_OK; } - HRESULT RenderSystem::GetSize(Size & size) + void Renderer::SetClearColor(const Color & color) { - if (!render_target_) + clear_color_ = DX::ConvertToColorF(color); + } + + HRESULT Renderer::SetTransform(const Matrix & matrix) + { + if (!device_context_) return E_UNEXPECTED; - auto rtsize = render_target_->GetSize(); - size.x = rtsize.width; - size.y = rtsize.height; + device_context_->SetTransform(DX::ConvertToMatrix3x2F(matrix)); return S_OK; } - HRESULT RenderSystem::CreateBitmapFromFile(D2DBitmapPtr& bitmap, String const& file_path) + void Renderer::SetOpacity(float opacity) { - if (render_target_ == nullptr) + if (opacity_ != opacity) { - return E_UNEXPECTED; + opacity_ = opacity; + solid_color_brush_->SetOpacity(opacity); } - - 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; - } - - D2DBitmapPtr 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 RenderSystem::CreateBitmapFromResource(D2DBitmapPtr& 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 RenderSystem::CreateBitmapRenderTarget(D2DBitmapRenderTargetPtr & brt) - { - if (!render_target_) - return E_UNEXPECTED; - - brt = nullptr; - return render_target_->CreateCompatibleRenderTarget(&brt); - } - - HRESULT RenderSystem::Resize(UINT32 width, UINT32 height) - { - if (!render_target_) - return E_UNEXPECTED; - - render_target_->Resize(D2D1::SizeU(width, height)); - return S_OK; - } - - HRESULT RenderSystem::SetTransform(const Matrix & matrix) - { - if (!render_target_) - return E_UNEXPECTED; - - render_target_->SetTransform(matrix); - return S_OK; - } - - HRESULT RenderSystem::SetOpacity(float opacity) - { - if (!render_target_) - return E_UNEXPECTED; - - opacity_ = opacity; - solid_brush_->SetOpacity(opacity); - return S_OK; - } - - HRESULT RenderSystem::SetTextStyle( + HRESULT Renderer::SetTextStyle( Color const& color, bool has_outline, Color const& outline_color, @@ -436,40 +351,34 @@ namespace easy2d StrokeStyle outline_stroke ) { - if (!text_renderer_) + if (!text_renderer_ || !device_resources_) return E_UNEXPECTED; - auto stroke_style = Factory::Instance().GetStrokeStyle(outline_stroke); text_renderer_->SetTextStyle( - ToD2dColorF(color), + DX::ConvertToColorF(color), has_outline, - ToD2dColorF(outline_color), + DX::ConvertToColorF(outline_color), outline_width, - stroke_style.Get() + device_resources_->GetStrokeStyle(outline_stroke) ); return S_OK; } - void RenderSystem::SetClearColor(const Color& color) + HRESULT Renderer::SetAntialiasMode(bool enabled) { - clear_color_ = ToD2dColorF(color); - } - - HRESULT RenderSystem::SetAntialiasMode(bool enabled) - { - if (!render_target_) + if (!device_context_) return E_UNEXPECTED; - render_target_->SetAntialiasMode( + device_context_->SetAntialiasMode( enabled ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED ); antialias_ = enabled; return S_OK; } - HRESULT RenderSystem::SetTextAntialiasMode(TextAntialias mode) + HRESULT Renderer::SetTextAntialiasMode(TextAntialias mode) { - if (!render_target_) + if (!device_context_) return E_UNEXPECTED; text_antialias_ = mode; @@ -491,78 +400,8 @@ namespace easy2d default: break; } - render_target_->SetTextAntialiasMode(antialias_mode); + device_context_->SetTextAntialiasMode(antialias_mode); return S_OK; } - RenderSystem::Status const & RenderSystem::GetStatus() const - { - return status_; - } - - HRESULT RenderSystem::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_RENDER_TARGET_TYPE_DEFAULT, - D2D1::PixelFormat(), - 96.f, - 96.f - ), - 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 RenderSystem::DiscardResources() - { - // FIXME! 应通知 Application 类销毁所有节点的 device resources - fps_text_format_ = nullptr; - fps_text_layout_ = nullptr; - text_renderer_ = nullptr; - solid_brush_ = nullptr; - render_target_ = nullptr; - } - } diff --git a/src/core/render.h b/src/core/render.h index a939d319..79135d98 100644 --- a/src/core/render.h +++ b/src/core/render.h @@ -20,45 +20,80 @@ #pragma once #include "include-forwards.h" -#include "time.h" #include "Font.hpp" #include "Resource.h" -#include "TextRenderer.h" #include "TextStyle.hpp" #include "Singleton.hpp" -#include "../math/Matrix.h" -#include +#include "../DX/helper.hpp" +#include "../DX/DeviceResources.h" +#include "../DX/TextRenderer.h" +#include "time.h" +#include +#include namespace easy2d { - class E2D_API RenderSystem - : public Singleton + struct RenderStatus { - E2D_DECLARE_SINGLETON(RenderSystem); + TimePoint start; + Duration duration; + int primitives; + }; - struct Status - { - TimePoint start; - Duration duration; - int primitives; - }; - - using BitmapMap = UnorderedMap; + class E2D_API Renderer + : public Singleton + { + E2D_DECLARE_SINGLETON(Renderer); public: - HRESULT Init(HWND hwnd, bool vsync, bool debug); + HRESULT Init(HWND hwnd); void Destroy(); - // 开始渲染 - HRESULT BeginDraw(HWND hwnd); + inline RenderStatus const& GetStatus() const { return status_; } + + inline DeviceResources* GetDeviceResources() const { return device_resources_.Get(); } + + inline ITextRenderer* GetTextRenderer() const { return text_renderer_.Get(); } + + inline ID2D1SolidColorBrush* GetSolidColorBrush() const { return solid_color_brush_.Get(); } + + HRESULT BeginDraw(); - // 结束渲染 HRESULT EndDraw(); - // 设置清空屏幕的颜色 + HRESULT CreateLayer( + ComPtr& layer + ); + + HRESULT DrawGeometry( + ComPtr const& geometry, + const Color& stroke_color, + float stroke_width, + StrokeStyle stroke = StrokeStyle::Miter + ); + + HRESULT FillGeometry( + ComPtr const& geometry, + Color const& fill_color + ); + + HRESULT DrawImage( + ImagePtr const& image, + Rect const& dest_rect + ); + + HRESULT DrawBitmap( + ComPtr const& bitmap + ); + + HRESULT DrawTextLayout( + ComPtr const& text_layout + ); + + // 设置清屏颜色 void SetClearColor( - const Color& color + Color const& clear_color ); // 设置抗锯齿模式 @@ -71,44 +106,15 @@ namespace easy2d TextAntialias mode ); - Status const& GetStatus() const; - - HRESULT CreateResources( - HWND hwnd - ); - - void DiscardResources(); - - HRESULT CreateLayer( - D2DLayerPtr& layer - ); - - HRESULT CreateSolidColorBrush( - D2DSolidColorBrushPtr& brush - ) const; - - HRESULT CreateBitmapFromFile( - D2DBitmapPtr& bitmap, - String const& file_path - ); - - HRESULT CreateBitmapFromResource( - D2DBitmapPtr& bitmap, - Resource const& res - ); - - HRESULT CreateBitmapRenderTarget( - D2DBitmapRenderTargetPtr& brt + // 设置画笔透明度 + void SetOpacity( + float opacity ); HRESULT SetTransform( const Matrix& matrix ); - HRESULT SetOpacity( - float opacity - ); - HRESULT SetTextStyle( const Color& color, bool has_outline, @@ -117,31 +123,6 @@ namespace easy2d StrokeStyle outline_stroke ); - HRESULT DrawGeometry( - D2DGeometryPtr const& geometry, - const Color& stroke_color, - float stroke_width, - StrokeStyle stroke = StrokeStyle::Miter - ); - - HRESULT FillGeometry( - D2DGeometryPtr const& geometry, - const Color& fill_color - ); - - HRESULT DrawImage( - ImagePtr const& image, - Rect const& dest_rect - ); - - HRESULT DrawBitmap( - D2DBitmapPtr const& bitmap - ); - - HRESULT DrawTextLayout( - D2DTextLayoutPtr const& text_layout - ); - HRESULT PushClip( const Matrix& clip_matrix, const Size& clip_size @@ -150,46 +131,35 @@ namespace easy2d HRESULT PopClip(); HRESULT PushLayer( - D2DLayerPtr const& layer, + ComPtr const& layer, LayerProperties const& properties ); HRESULT PopLayer(); - HRESULT GetSize( - Size& size - ); + private: + Renderer(); - HRESULT Resize( - UINT32 width, - UINT32 height - ); + ~Renderer(); - void ClearImageCache(); + HRESULT CreateDeviceResources(); - D2DHwndRenderTargetPtr const& GetRenderTarget() const; + HRESULT HandleDeviceLost(); - D2DSolidColorBrushPtr const& GetSolidBrush() const; + private: + float opacity_; + bool antialias_; + unsigned long ref_count_; - protected: - RenderSystem(); + TextAntialias text_antialias_; + D2D1_COLOR_F clear_color_; + RenderStatus status_; - ~RenderSystem(); - - protected: - bool debug_; - bool window_occluded_; - bool vsync_enabled_; - bool antialias_; - float opacity_; - D2D1_COLOR_F clear_color_; - TextAntialias text_antialias_; - Status status_; - D2DTextRendererPtr text_renderer_; - D2DSolidColorBrushPtr solid_brush_; - D2DHwndRenderTargetPtr render_target_; - D2DTextFormatPtr fps_text_format_; - D2DTextLayoutPtr fps_text_layout_; - BitmapMap bitmap_cache_; + ComPtr device_resources_; + ComPtr factory_; + ComPtr device_context_; + ComPtr drawing_state_block_; + ComPtr text_renderer_; + ComPtr solid_color_brush_; }; } diff --git a/src/core/window.cpp b/src/core/window.cpp index a6d48ee6..87615912 100644 --- a/src/core/window.cpp +++ b/src/core/window.cpp @@ -53,12 +53,8 @@ namespace easy2d { } - HRESULT Window::Init(String title, int width, int height, LPCWSTR icon, bool fullscreen, WNDPROC proc, bool debug) + HRESULT Window::Init(String title, int width, int height, LPCWSTR icon, bool fullscreen, WNDPROC proc) { - E2D_NOT_USED(debug); - - E2D_LOG(L"Creating window"); - HINSTANCE hinst = GetModuleHandleW(nullptr); WNDCLASSEX wcex = { 0 }; wcex.cbSize = sizeof(WNDCLASSEX); @@ -160,8 +156,6 @@ namespace easy2d void Window::Destroy() { - E2D_LOG(L"Destroying window"); - if (is_fullscreen_) RestoreResolution(device_name_); diff --git a/src/core/window.h b/src/core/window.h index 33c7a076..a868879d 100644 --- a/src/core/window.h +++ b/src/core/window.h @@ -60,8 +60,7 @@ namespace easy2d int height, LPCWSTR icon, bool fullscreen, - WNDPROC proc, - bool debug + WNDPROC proc ); void Destroy(); diff --git a/src/core/Factory.cpp b/src/dx/D2DDeviceResources.cpp similarity index 53% rename from src/core/Factory.cpp rename to src/dx/D2DDeviceResources.cpp index 848b2288..78bfd705 100644 --- a/src/core/Factory.cpp +++ b/src/dx/D2DDeviceResources.cpp @@ -18,57 +18,134 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#include "Factory.h" -#include "logs.h" -#include "modules.h" -#include "Transform.hpp" +#include "DeviceResources.h" +#include "../core/Image.h" +#include "../core/modules.h" +#include "../core/logs.h" namespace easy2d { - Factory::Factory() + + D2DDeviceResources::D2DDeviceResources() + : ref_count_(0) + , dpi_(96.f) { + CreateDeviceIndependentResources(); } - Factory::~Factory() + D2DDeviceResources::~D2DDeviceResources() { + DiscardResources(); } - HRESULT Factory::Init(bool debug) + STDMETHODIMP_(unsigned long) D2DDeviceResources::AddRef() { - E2D_LOG(L"Creating device-independent resources"); + return InterlockedIncrement(&ref_count_); + } + + STDMETHODIMP_(unsigned long) D2DDeviceResources::Release() + { + unsigned long newCount = InterlockedDecrement(&ref_count_); + + if (newCount == 0) + { + delete this; + return 0; + } + + return newCount; + } + + STDMETHODIMP D2DDeviceResources::QueryInterface( + IID const& riid, + void** object) + { + if (__uuidof(IUnknown) == riid) + { + *object = this; + } + else + { + *object = nullptr; + return E_FAIL; + } + + AddRef(); + + return S_OK; + } + + void D2DDeviceResources::DiscardResources() + { + ClearImageCache(); + + d2d_factory_.Reset(); + d2d_device_.Reset(); + d2d_device_context_.Reset(); + d2d_target_bitmap_.Reset(); + + imaging_factory_.Reset(); + dwrite_factory_.Reset(); + + d2d_miter_stroke_style_.Reset(); + d2d_bevel_stroke_style_.Reset(); + d2d_round_stroke_style_.Reset(); + } + + HRESULT D2DDeviceResources::CreateDeviceIndependentResources() + { + HRESULT hr = S_OK; + + ComPtr d2d_factory; + ComPtr imaging_factory; + ComPtr dwrite_factory; D2D1_FACTORY_OPTIONS options; - options.debugLevel = debug ? D2D1_DEBUG_LEVEL_INFORMATION : D2D1_DEBUG_LEVEL_NONE; - HRESULT hr = modules::DirectX::Get().D2D1CreateFactory( + ZeroMemory(&options, sizeof(D2D1_FACTORY_OPTIONS)); +#ifdef E2D_DEBUG + options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; +#endif + + hr = modules::DirectX::Get().D2D1CreateFactory( D2D1_FACTORY_TYPE_SINGLE_THREADED, - __uuidof(ID2D1Factory), + __uuidof(ID2D1Factory1), &options, - reinterpret_cast(&factory_) + reinterpret_cast(&d2d_factory) ); if (SUCCEEDED(hr)) { + d2d_factory_ = d2d_factory; + CoCreateInstance( CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, __uuidof(IWICImagingFactory), - reinterpret_cast(&imaging_factory_) + reinterpret_cast(&imaging_factory) ); } if (SUCCEEDED(hr)) { + imaging_factory_ = imaging_factory; + modules::DirectX::Get().DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), - reinterpret_cast(&write_factory_) + reinterpret_cast(&dwrite_factory) ); } if (SUCCEEDED(hr)) { - auto stroke_style = D2D1::StrokeStyleProperties( + dwrite_factory_ = dwrite_factory; + + ComPtr d2d_miter_stroke_style; + ComPtr d2d_bevel_stroke_style; + ComPtr d2d_round_stroke_style; + + D2D1_STROKE_STYLE_PROPERTIES stroke_style = D2D1::StrokeStyleProperties( D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT, @@ -78,101 +155,89 @@ namespace easy2d 0.0f ); - hr = factory_->CreateStrokeStyle( + hr = d2d_factory_->CreateStrokeStyle( stroke_style, nullptr, 0, - &miter_stroke_style_ + &d2d_miter_stroke_style ); if (SUCCEEDED(hr)) { stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL; - hr = factory_->CreateStrokeStyle( + hr = d2d_factory_->CreateStrokeStyle( stroke_style, nullptr, 0, - &bevel_stroke_style_ + &d2d_bevel_stroke_style ); } if (SUCCEEDED(hr)) { stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND; - hr = factory_->CreateStrokeStyle( + hr = d2d_factory_->CreateStrokeStyle( stroke_style, nullptr, 0, - &round_stroke_style_ + &d2d_round_stroke_style ); } + + if (SUCCEEDED(hr)) + { + d2d_miter_stroke_style_ = d2d_miter_stroke_style; + d2d_bevel_stroke_style_ = d2d_bevel_stroke_style; + d2d_round_stroke_style_ = d2d_round_stroke_style; + } } + return hr; } - void Factory::Destroy() + HRESULT D2DDeviceResources::SetD2DDevice(ComPtr const& device) { - E2D_LOG(L"Destroying device-independent resources"); + ComPtr d2d_device_ctx; - factory_.Reset(); - imaging_factory_.Reset(); - write_factory_.Reset(); - miter_stroke_style_.Reset(); - bevel_stroke_style_.Reset(); - round_stroke_style_.Reset(); - } - - HRESULT Factory::CreateHwndRenderTarget(D2DHwndRenderTargetPtr & hwnd_render_target, D2D1_RENDER_TARGET_PROPERTIES const & properties, D2D1_HWND_RENDER_TARGET_PROPERTIES const & hwnd_rt_properties) const - { - if (!factory_) - return E_UNEXPECTED; - - D2DHwndRenderTargetPtr hwnd_render_target_tmp; - HRESULT hr = factory_->CreateHwndRenderTarget( - properties, - hwnd_rt_properties, - &hwnd_render_target_tmp + HRESULT hr = device->CreateDeviceContext( + D2D1_DEVICE_CONTEXT_OPTIONS_NONE, + &d2d_device_ctx ); if (SUCCEEDED(hr)) - hwnd_render_target = hwnd_render_target_tmp; - return hr; - } - - HRESULT Factory::CreateTextRenderer( - D2DTextRendererPtr& text_renderer, - D2DRenderTargetPtr const& render_target, - D2DSolidColorBrushPtr const& brush - ) - { - if (!factory_) - return E_UNEXPECTED; - - D2DTextRendererPtr text_renderer_tmp; - HRESULT hr = ITextRenderer::Create( - &text_renderer_tmp, - factory_.Get(), - render_target.Get(), - brush.Get() - ); - - if (SUCCEEDED(hr)) - text_renderer = text_renderer_tmp; - return hr; - } - - HRESULT Factory::CreateBitmapFromFile(D2DBitmapPtr & bitmap, D2DRenderTargetPtr const & rt, String const & file_path) - { - if (imaging_factory_ == nullptr) { - return E_UNEXPECTED; + d2d_device_ = device; + d2d_device_context_ = d2d_device_ctx; + d2d_device_context_->SetDpi(dpi_, dpi_); } - IntrusivePtr decoder; - IntrusivePtr source; - IntrusivePtr stream; - IntrusivePtr converter; - IntrusivePtr bitmap_tmp; + return hr; + } + + void D2DDeviceResources::SetTargetBitmap(ComPtr const& target) + { + d2d_target_bitmap_ = target; + if (d2d_device_context_) + d2d_device_context_->SetTarget(d2d_target_bitmap_.Get()); + } + + HRESULT D2DDeviceResources::CreateBitmapFromFile(ComPtr & bitmap, String const & file_path) + { + if (!imaging_factory_ || !d2d_device_context_) + 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; + } + + ComPtr decoder; + ComPtr source; + ComPtr stream; + ComPtr converter; + ComPtr bitmap_tmp; HRESULT hr = imaging_factory_->CreateDecoderFromFilename( file_path.c_str(), @@ -207,7 +272,7 @@ namespace easy2d if (SUCCEEDED(hr)) { - hr = rt->CreateBitmapFromWicBitmap( + hr = d2d_device_context_->CreateBitmapFromWicBitmap( converter.Get(), nullptr, &bitmap_tmp @@ -215,24 +280,32 @@ namespace easy2d } if (SUCCEEDED(hr)) + { bitmap = bitmap_tmp; + bitmap_cache_.insert(std::make_pair(hash_code, bitmap)); + } return hr; } - HRESULT Factory::CreateBitmapFromResource(D2DBitmapPtr & bitmap, D2DRenderTargetPtr const & rt, Resource const & res) + HRESULT D2DDeviceResources::CreateBitmapFromResource(ComPtr & bitmap, Resource const & res) { - if (imaging_factory_ == nullptr) - { + if (!imaging_factory_ || !d2d_device_context_) 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; } - IntrusivePtr decoder; - IntrusivePtr source; - IntrusivePtr stream; - IntrusivePtr converter; - IntrusivePtr bitmap_tmp; - + ComPtr decoder; + ComPtr source; + ComPtr stream; + ComPtr converter; + ComPtr bitmap_tmp; + // 加载资源 LPVOID buffer; DWORD buffer_size; @@ -286,7 +359,7 @@ namespace easy2d if (SUCCEEDED(hr)) { - hr = rt->CreateBitmapFromWicBitmap( + hr = d2d_device_context_->CreateBitmapFromWicBitmap( converter.Get(), nullptr, &bitmap_tmp @@ -296,105 +369,19 @@ namespace easy2d if (SUCCEEDED(hr)) { bitmap = bitmap_tmp; + bitmap_cache_.insert(std::make_pair(hash_code, bitmap)); } return hr; } - HRESULT Factory::CreateRectangleGeometry(D2DRectangleGeometryPtr & geo, Rect const& rect) const + HRESULT D2DDeviceResources::CreateTextFormat(ComPtr & text_format, Font const & font, TextStyle const & text_style) const { - if (!factory_) + if (!dwrite_factory_) return E_UNEXPECTED; - D2DRectangleGeometryPtr rectangle; - HRESULT hr = factory_->CreateRectangleGeometry( - ToD2dRectF(rect), - &rectangle - ); - - if (SUCCEEDED(hr)) - geo = rectangle; - return hr; - } - - HRESULT Factory::CreateRoundedRectangleGeometry(D2DRoundedRectangleGeometryPtr & geo, Rect const & rect, float radius_x, float radius_y) const - { - if (!factory_) - return E_UNEXPECTED; - - D2DRoundedRectangleGeometryPtr rounded_rect; - HRESULT hr = factory_->CreateRoundedRectangleGeometry( - D2D1::RoundedRect( - ToD2dRectF(rect), - radius_x, - radius_y - ), - &rounded_rect - ); - - if (SUCCEEDED(hr)) - geo = rounded_rect; - return hr; - } - - HRESULT Factory::CreateEllipseGeometry(D2DEllipseGeometryPtr & geo, Point const & center, float radius_x, float radius_y) const - { - if (!factory_) - return E_UNEXPECTED; - - D2DEllipseGeometryPtr ellipse; - HRESULT hr = factory_->CreateEllipseGeometry( - D2D1::Ellipse( - ToD2dPoint2F(center), - radius_x, - radius_y - ), - &ellipse - ); - - if (SUCCEEDED(hr)) - geo = ellipse; - return hr; - } - - HRESULT Factory::CreateTransformedGeometry( - D2DTransformedGeometryPtr& transformed, - Matrix const& matrix, - D2DGeometryPtr const& geo - ) const - { - if (!factory_) - return E_UNEXPECTED; - - D2DTransformedGeometryPtr transformed_tmp; - HRESULT hr = factory_->CreateTransformedGeometry( - geo.Get(), - matrix, - &transformed_tmp - ); - - if (SUCCEEDED(hr)) - { - transformed = transformed_tmp; - } - return hr; - } - - HRESULT Factory::CreatePathGeometry(D2DPathGeometryPtr & geometry) const - { - if (!factory_) - return E_UNEXPECTED; - - return factory_->CreatePathGeometry(&geometry); - } - - HRESULT Factory::CreateTextFormat(D2DTextFormatPtr & text_format, Font const & font, TextStyle const & text_style) const - { - if (!write_factory_) - return E_UNEXPECTED; - - D2DTextFormatPtr text_format_tmp; - HRESULT hr = write_factory_->CreateTextFormat( + ComPtr text_format_tmp; + HRESULT hr = dwrite_factory_->CreateTextFormat( font.family.c_str(), nullptr, DWRITE_FONT_WEIGHT(font.weight), @@ -426,20 +413,20 @@ namespace easy2d return hr; } - HRESULT Factory::CreateTextLayout(D2DTextLayoutPtr & text_layout, Size& layout_size, String const & text, D2DTextFormatPtr const& text_format, TextStyle const & text_style) const + HRESULT D2DDeviceResources::CreateTextLayout(ComPtr & text_layout, Size& layout_size, String const & text, ComPtr const& text_format, TextStyle const & text_style) const { - if (!write_factory_) + if (!dwrite_factory_) return E_UNEXPECTED; text_layout = nullptr; HRESULT hr; - D2DTextLayoutPtr text_layout_tmp; + ComPtr text_layout_tmp; UINT32 length = static_cast(text.length()); if (text_style.wrap) { - hr = write_factory_->CreateTextLayout( + hr = dwrite_factory_->CreateTextLayout( text.c_str(), length, text_format.Get(), @@ -450,7 +437,7 @@ namespace easy2d } else { - hr = write_factory_->CreateTextLayout( + hr = dwrite_factory_->CreateTextLayout( text.c_str(), length, text_format.Get(), @@ -468,7 +455,7 @@ namespace easy2d if (SUCCEEDED(hr)) { text_layout_tmp = nullptr; - hr = write_factory_->CreateTextLayout( + hr = dwrite_factory_->CreateTextLayout( text.c_str(), length, text_format.Get(), @@ -507,21 +494,20 @@ namespace easy2d return hr; } - D2DStrokeStylePtr const& Factory::GetStrokeStyle(StrokeStyle stroke) const + void D2DDeviceResources::ClearImageCache() + { + bitmap_cache_.clear(); + } + + ID2D1StrokeStyle* D2DDeviceResources::GetStrokeStyle(StrokeStyle stroke) const { switch (stroke) { - case StrokeStyle::Miter: - return miter_stroke_style_; - break; - case StrokeStyle::Bevel: - return bevel_stroke_style_; - break; - case StrokeStyle::Round: - return round_stroke_style_; - break; + case StrokeStyle::Miter: return d2d_miter_stroke_style_.Get(); break; + case StrokeStyle::Bevel: return d2d_bevel_stroke_style_.Get(); break; + case StrokeStyle::Round: return d2d_round_stroke_style_.Get(); break; } - return miter_stroke_style_; + return nullptr; } -} +} \ No newline at end of file diff --git a/src/dx/D2DDeviceResources.h b/src/dx/D2DDeviceResources.h new file mode 100644 index 00000000..e9555828 --- /dev/null +++ b/src/dx/D2DDeviceResources.h @@ -0,0 +1,117 @@ +// 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 "helper.hpp" +#include "../core/Resource.h" +#include "../core/Font.hpp" +#include "../core/TextStyle.hpp" +#include +#include + +namespace easy2d +{ + class E2D_API D2DDeviceResources + : public IUnknown + { + public: + HRESULT CreateBitmapFromFile( + _Out_ ComPtr& bitmap, + _In_ String const& file_path + ); + + HRESULT CreateBitmapFromResource( + _Out_ ComPtr& bitmap, + _In_ Resource const& res + ); + + HRESULT CreateTextFormat( + _Out_ ComPtr& text_format, + _In_ Font const& font, + _In_ TextStyle const& text_style + ) const; + + HRESULT CreateTextLayout( + _Out_ ComPtr& text_layout, + _Out_ Size& layout_size, + _In_ String const& text, + _In_ ComPtr const& text_format, + _In_ TextStyle const& text_style + ) const; + + void ClearImageCache(); + + void DiscardResources(); + + HRESULT SetD2DDevice( + _In_ ComPtr const& device + ); + + void SetTargetBitmap( + _In_ ComPtr const& target + ); + + inline ID2D1Factory1* GetD2DFactory() const { return d2d_factory_.Get(); } + inline IWICImagingFactory* GetWICImagingFactory() const { return imaging_factory_.Get(); } + inline IDWriteFactory* GetDWriteFactory() const { return dwrite_factory_.Get(); } + inline ID2D1Device* GetD2DDevice() const { return d2d_device_.Get(); } + inline ID2D1DeviceContext* GetD2DDeviceContext() const { return d2d_device_context_.Get(); } + inline ID2D1Bitmap1* GetD2DTargetBitmap() const { return d2d_target_bitmap_.Get(); } + + ID2D1StrokeStyle* GetStrokeStyle(StrokeStyle stroke) const; + + public: + unsigned long STDMETHODCALLTYPE AddRef(); + + unsigned long STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE QueryInterface( + IID const& riid, + void** ppvObject + ); + + protected: + D2DDeviceResources(); + + virtual ~D2DDeviceResources(); + + HRESULT CreateDeviceIndependentResources(); + + private: + unsigned long ref_count_; + float dpi_; + + using BitmapMap = UnorderedMap>; + BitmapMap bitmap_cache_; + + ComPtr d2d_factory_; + ComPtr d2d_device_; + ComPtr d2d_device_context_; + ComPtr d2d_target_bitmap_; + + ComPtr imaging_factory_; + ComPtr dwrite_factory_; + + ComPtr d2d_miter_stroke_style_; + ComPtr d2d_bevel_stroke_style_; + ComPtr d2d_round_stroke_style_; + }; + +} diff --git a/src/dx/D3D11DeviceResources.cpp b/src/dx/D3D11DeviceResources.cpp new file mode 100644 index 00000000..eff5f86b --- /dev/null +++ b/src/dx/D3D11DeviceResources.cpp @@ -0,0 +1,387 @@ +// 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 "DeviceResources.h" +#include "../core/Image.h" +#include "../core/modules.h" +#include "../core/logs.h" + +namespace easy2d +{ +#if defined(_DEBUG) + namespace DX + { + inline bool SdkLayersAvailable() + { + HRESULT hr = modules::DirectX::Get().D3D11CreateDevice( + nullptr, + D3D_DRIVER_TYPE_NULL, // There is no need to create a real hardware device. + 0, + D3D11_CREATE_DEVICE_DEBUG, // Check for the SDK layers. + nullptr, // Any feature level will do. + 0, + D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Runtime apps. + nullptr, // No need to keep the D3D device reference. + nullptr, // No need to know the feature level. + nullptr // No need to keep the D3D device context reference. + ); + + return SUCCEEDED(hr); + } + } +#endif + + D3D11DeviceResources::D3D11DeviceResources() + : hwnd_(nullptr) + , d3d_feature_level_(D3D_FEATURE_LEVEL_9_1) + { + dpi_ = 96.f; // dpi_ = (float)GetDpiForWindow(hwnd); + } + + D3D11DeviceResources::~D3D11DeviceResources() + { + DiscardResources(); + } + + HRESULT D3D11DeviceResources::Create(D3D11DeviceResources** device_resources, HWND hwnd) + { + HRESULT hr = E_FAIL; + + if (device_resources) + { + D3D11DeviceResources* res = new (std::nothrow) D3D11DeviceResources; + if (res) + { + hr = res->CreateDeviceIndependentResources(); + + if (SUCCEEDED(hr)) + { + RECT rc; + GetClientRect(hwnd, &rc); + + res->hwnd_ = hwnd; + res->logical_size_.x = float(rc.right - rc.left); + res->logical_size_.y = float(rc.bottom - rc.top); + + hr = res->CreateDeviceResources(); + } + + if (SUCCEEDED(hr)) + { + hr = res->CreateWindowSizeDependentResources(); + } + + if (SUCCEEDED(hr)) + { + res->AddRef(); + + DX::SafeRelease(*device_resources); + (*device_resources) = res; + } + else + { + delete res; + res = nullptr; + } + } + } + return hr; + } + + void D3D11DeviceResources::DiscardResources() + { + d3d_device_.Reset(); + d3d_device_context_.Reset(); + dxgi_swap_chain_.Reset(); + dxgi_factory_.Reset(); + + hwnd_ = nullptr; + } + + HRESULT D3D11DeviceResources::CreateDeviceResources() + { + HRESULT hr = S_OK; + + D3D_FEATURE_LEVEL feature_levels[] = + { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1 + }; + + ComPtr device; + ComPtr context; + + // This flag adds support for surfaces with a different color channel ordering + // than the API default. It is required for compatibility with Direct2D. + UINT creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + +#if defined(E2D_DEBUG) + if (DX::SdkLayersAvailable()) + { + creation_flags |= D3D11_CREATE_DEVICE_DEBUG; + } +#endif + + hr = modules::DirectX::Get().D3D11CreateDevice( + nullptr, // Specify nullptr to use the default adapter. + D3D_DRIVER_TYPE_HARDWARE, + 0, // Should be 0 unless the driver is D3D_DRIVER_TYPE_SOFTWARE. + creation_flags, // Set debug and Direct2D compatibility flags. + feature_levels, // List of feature levels this app can support. + ARRAYSIZE(feature_levels), // Size of the list above. + D3D11_SDK_VERSION, + &device, // Returns the Direct3D device created. + &d3d_feature_level_, // Returns feature level of device created. + &context // Returns the device immediate context. + ); + + if (FAILED(hr)) + { + // If the initialization fails, fall back to the WARP device. + // For more information on WARP, see: + // http://go.microsoft.com/fwlink/?LinkId=286690 + hr = modules::DirectX::Get().D3D11CreateDevice( + nullptr, + D3D_DRIVER_TYPE_WARP, // Create a WARP device instead of a hardware device. + 0, + creation_flags, + feature_levels, + ARRAYSIZE(feature_levels), + D3D11_SDK_VERSION, + &device, + &d3d_feature_level_, + &context + ); + } + + if (SUCCEEDED(hr)) + { + d3d_device_ = device; + d3d_device_context_ = context; + + ComPtr dxgi_adapter; + ComPtr dxgi_device; + ComPtr dxgi_factory; + ComPtr d2d_device; + + if (SUCCEEDED(hr)) + { + hr = d3d_device_->QueryInterface(IID_PPV_ARGS(&dxgi_device)); + } + + if (SUCCEEDED(hr)) + { + hr = dxgi_device->GetAdapter(&dxgi_adapter); + } + + if (SUCCEEDED(hr)) + { + hr = dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory)); + } + + if (SUCCEEDED(hr)) + { + dxgi_factory_ = dxgi_factory; + } + + // Create the Direct2D device object and a corresponding context. + if (SUCCEEDED(hr)) + { + hr = GetD2DFactory()->CreateDevice(dxgi_device.Get(), &d2d_device); + } + + if (SUCCEEDED(hr)) + { + hr = SetD2DDevice(d2d_device); + } + } + + return hr; + } + + HRESULT D3D11DeviceResources::CreateWindowSizeDependentResources() + { + HRESULT hr = S_OK; + + // Clear the previous window size specific context. + ID3D11RenderTargetView* null_views[] = { nullptr }; + SetTargetBitmap(nullptr); + d3d_device_context_->OMSetRenderTargets(ARRAYSIZE(null_views), null_views, nullptr); + d3d_device_context_->Flush(); + + // Calculate the necessary render target size in pixels. + output_size_.x = DX::ConvertDipsToPixels(logical_size_.x, dpi_); + output_size_.y = DX::ConvertDipsToPixels(logical_size_.y, dpi_); + + // Prevent zero size DirectX content from being created. + output_size_.x = std::max(output_size_.x, 1.f); + output_size_.y = std::max(output_size_.y, 1.f); + + if (dxgi_swap_chain_) + { + // If the swap chain already exists, resize it. + hr = dxgi_swap_chain_->ResizeBuffers( + 2, // Double-buffered swap chain. + ::lround(output_size_.x), + ::lround(output_size_.y), + DXGI_FORMAT_B8G8R8A8_UNORM, + 0); + } + else + { + // Setup swap chain + DXGI_SWAP_CHAIN_DESC swap_chain_desc = { 0 }; + + swap_chain_desc.BufferCount = 2; + swap_chain_desc.BufferDesc.Width = ::lround(output_size_.x); + swap_chain_desc.BufferDesc.Height = ::lround(output_size_.y); + swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + swap_chain_desc.BufferDesc.RefreshRate.Numerator = 60; + swap_chain_desc.BufferDesc.RefreshRate.Denominator = 1; + swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swap_chain_desc.OutputWindow = hwnd_; + swap_chain_desc.SampleDesc.Count = 1; + swap_chain_desc.SampleDesc.Quality = 0; + swap_chain_desc.Windowed = TRUE; + swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + + ComPtr dxgi_device; + if (SUCCEEDED(hr)) + { + hr = d3d_device_->QueryInterface(&dxgi_device); + } + + ComPtr dxgi_adapter; + if (SUCCEEDED(hr)) + { + hr = dxgi_device->GetAdapter(&dxgi_adapter); + } + + ComPtr dxgi_factory; + if (SUCCEEDED(hr)) + { + hr = dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory)); + } + + if (SUCCEEDED(hr)) + { + hr = dxgi_factory->CreateSwapChain( + d3d_device_.Get(), + &swap_chain_desc, + &dxgi_swap_chain_); + } + } + + if (SUCCEEDED(hr)) + { + // Set the 3D rendering viewport to target the entire window. + CD3D11_VIEWPORT screen_viewport( + 0.0f, + 0.0f, + output_size_.x, + output_size_.y); + + d3d_device_context_->RSSetViewports(1, &screen_viewport); + } + + // Create a Direct2D target bitmap associated with the + // swap chain back buffer and set it as the current target. + if (SUCCEEDED(hr)) + { + D2D1_BITMAP_PROPERTIES1 bitmap_props = + D2D1::BitmapProperties1( + D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), + dpi_, + dpi_); + + ComPtr dxgi_back_buffer; + hr = dxgi_swap_chain_->GetBuffer(0, IID_PPV_ARGS(&dxgi_back_buffer)); + + ComPtr target; + if (SUCCEEDED(hr)) + { + hr = GetD2DDeviceContext()->CreateBitmapFromDxgiSurface( + dxgi_back_buffer.Get(), + &bitmap_props, + &target); + } + + if (SUCCEEDED(hr)) + { + SetTargetBitmap(target); + } + } + + return hr; + } + + HRESULT D3D11DeviceResources::HandleDeviceLost() + { + dxgi_swap_chain_ = nullptr; + + HRESULT hr = CreateDeviceResources(); + + if (SUCCEEDED(hr)) + { + hr = CreateWindowSizeDependentResources(); + } + return hr; + } + + void D3D11DeviceResources::SetLogicalSize(Size logical_size) + { + if (logical_size_ != logical_size) + { + logical_size_ = logical_size; + + ThrowIfFailed( + CreateWindowSizeDependentResources() + ); + } + } + + void D3D11DeviceResources::SetDpi(float dpi) + { + if (dpi != dpi_) + { + dpi_ = dpi; + + RECT rc; + GetClientRect(hwnd_, &rc); + + logical_size_.x = float(rc.right - rc.left); + logical_size_.y = float(rc.bottom - rc.top); + + GetD2DDeviceContext()->SetDpi(dpi_, dpi_); + + ThrowIfFailed( + CreateWindowSizeDependentResources() + ); + } + } + +} diff --git a/src/dx/D3D11DeviceResources.h b/src/dx/D3D11DeviceResources.h new file mode 100644 index 00000000..329b575c --- /dev/null +++ b/src/dx/D3D11DeviceResources.h @@ -0,0 +1,82 @@ +// 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 "helper.hpp" +#include "D2DDeviceResources.h" +#include + +namespace easy2d +{ + class E2D_API D3D11DeviceResources + : public D2DDeviceResources + { + public: + static HRESULT Create( + D3D11DeviceResources** device_resources, + HWND hwnd + ); + + HRESULT HandleDeviceLost(); + + void SetLogicalSize( + Size logical_size + ); + + void SetDpi( + float dpi + ); + + void DiscardResources(); + + inline ID3D11Device* GetD3DDevice() const { return d3d_device_.Get(); } + inline ID3D11DeviceContext* GetD3DDeviceContext() const { return d3d_device_context_.Get(); } + inline IDXGIFactory* GetDXGIFactory() const { return dxgi_factory_.Get(); } + inline IDXGISwapChain* GetDXGISwapChain() const { return dxgi_swap_chain_.Get(); } + + inline D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const { return d3d_feature_level_; } + inline Size const& GetLogicalSize() const { return logical_size_; } + inline Size const& GetOutputSize() const { return output_size_; } + inline float GetDpi() const { return dpi_; } + + protected: + D3D11DeviceResources(); + + virtual ~D3D11DeviceResources(); + + protected: + HRESULT CreateDeviceResources(); + + HRESULT CreateWindowSizeDependentResources(); + + private: + HWND hwnd_; + float dpi_; + Size logical_size_; + Size output_size_; + D3D_FEATURE_LEVEL d3d_feature_level_; + + ComPtr d3d_device_; + ComPtr d3d_device_context_; + ComPtr dxgi_swap_chain_; + ComPtr dxgi_factory_; + }; + +} diff --git a/src/dx/DeviceResources.h b/src/dx/DeviceResources.h new file mode 100644 index 00000000..fc502d68 --- /dev/null +++ b/src/dx/DeviceResources.h @@ -0,0 +1,27 @@ +// 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 "D3D11DeviceResources.h" + +namespace easy2d +{ + using DeviceResources = D3D11DeviceResources; +} diff --git a/src/core/TextRenderer.cpp b/src/dx/TextRenderer.cpp similarity index 77% rename from src/core/TextRenderer.cpp rename to src/dx/TextRenderer.cpp index 028bb4b7..71c9017b 100644 --- a/src/core/TextRenderer.cpp +++ b/src/dx/TextRenderer.cpp @@ -24,17 +24,17 @@ namespace easy2d { - class TextRendererImpl + class TextRenderer : public ITextRenderer { public: - TextRendererImpl( - ID2D1Factory* pD2DFactory, - ID2D1RenderTarget* pRT, - ID2D1SolidColorBrush* pBrush + TextRenderer( + ID2D1RenderTarget* pRT ); - ~TextRendererImpl(); + ~TextRenderer(); + + STDMETHOD(CreateDeviceResources)(); STDMETHOD_(void, SetTextStyle)( CONST D2D1_COLOR_F &fillColor, @@ -109,7 +109,7 @@ namespace easy2d D2D1_COLOR_F sOutlineColor_; FLOAT fOutlineWidth; BOOL bShowOutline_; - ID2D1Factory* pD2DFactory_; + ID2D1Factory* pFactory_; ID2D1RenderTarget* pRT_; ID2D1SolidColorBrush* pBrush_; ID2D1StrokeStyle* pCurrStrokeStyle_; @@ -117,43 +117,72 @@ namespace easy2d HRESULT ITextRenderer::Create( ITextRenderer** ppTextRenderer, - ID2D1Factory* pD2DFactory, - ID2D1RenderTarget* pRT, - ID2D1SolidColorBrush* pBrush) + ID2D1RenderTarget* pRT) { - *ppTextRenderer = new (std::nothrow) TextRendererImpl(pD2DFactory, pRT, pBrush); - if (*ppTextRenderer) + HRESULT hr = E_FAIL; + + if (ppTextRenderer) { - (*ppTextRenderer)->AddRef(); - return S_OK; + TextRenderer* pTextRenderer = new (std::nothrow) TextRenderer(pRT); + if (pTextRenderer) + { + hr = pTextRenderer->CreateDeviceResources(); + + if (SUCCEEDED(hr)) + { + pTextRenderer->AddRef(); + + DX::SafeRelease(*ppTextRenderer); + (*ppTextRenderer) = pTextRenderer; + return S_OK; + } + else + { + delete pTextRenderer; + pTextRenderer = NULL; + } + } } - return E_FAIL; + return hr; } - TextRendererImpl::TextRendererImpl(ID2D1Factory* pD2DFactory, ID2D1RenderTarget* pRT, ID2D1SolidColorBrush* pBrush) + TextRenderer::TextRenderer(ID2D1RenderTarget* pRT) : cRefCount_(0) - , pD2DFactory_(pD2DFactory) + , pFactory_(NULL) , pRT_(pRT) - , pBrush_(pBrush) + , pBrush_(NULL) , sFillColor_() , sOutlineColor_() , fOutlineWidth(1) , bShowOutline_(TRUE) - , pCurrStrokeStyle_(nullptr) + , pCurrStrokeStyle_(NULL) { - pD2DFactory->AddRef(); - pRT->AddRef(); - pBrush->AddRef(); + pRT_->AddRef(); + pRT_->GetFactory(&pFactory_); } - TextRendererImpl::~TextRendererImpl() + TextRenderer::~TextRenderer() { - SafeRelease(pD2DFactory_); - SafeRelease(pRT_); - SafeRelease(pBrush_); + DX::SafeRelease(pFactory_); + DX::SafeRelease(pRT_); + DX::SafeRelease(pBrush_); } - STDMETHODIMP_(void) TextRendererImpl::SetTextStyle( + STDMETHODIMP TextRenderer::CreateDeviceResources() + { + HRESULT hr = S_OK; + + DX::SafeRelease(pBrush_); + + hr = pRT_->CreateSolidColorBrush( + D2D1::ColorF(D2D1::ColorF::White), + &pBrush_ + ); + + return hr; + } + + STDMETHODIMP_(void) TextRenderer::SetTextStyle( CONST D2D1_COLOR_F &fillColor, BOOL outline, CONST D2D1_COLOR_F &outlineColor, @@ -167,7 +196,7 @@ namespace easy2d pCurrStrokeStyle_ = outlineJoin; } - STDMETHODIMP TextRendererImpl::DrawGlyphRun( + STDMETHODIMP TextRenderer::DrawGlyphRun( __maybenull void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, @@ -183,12 +212,12 @@ namespace easy2d HRESULT hr = S_OK; - ID2D1PathGeometry* pPathGeometry = nullptr; - hr = pD2DFactory_->CreatePathGeometry( + ID2D1PathGeometry* pPathGeometry = NULL; + hr = pFactory_->CreatePathGeometry( &pPathGeometry ); - ID2D1GeometrySink* pSink = nullptr; + ID2D1GeometrySink* pSink = NULL; if (SUCCEEDED(hr)) { hr = pPathGeometry->Open( @@ -221,10 +250,10 @@ namespace easy2d baselineOriginX, baselineOriginY ); - ID2D1TransformedGeometry* pTransformedGeometry = nullptr; + ID2D1TransformedGeometry* pTransformedGeometry = NULL; if (SUCCEEDED(hr)) { - hr = pD2DFactory_->CreateTransformedGeometry( + hr = pFactory_->CreateTransformedGeometry( pPathGeometry, &matrix, &pTransformedGeometry @@ -253,14 +282,14 @@ namespace easy2d ); } - SafeRelease(pPathGeometry); - SafeRelease(pSink); - SafeRelease(pTransformedGeometry); + DX::SafeRelease(pPathGeometry); + DX::SafeRelease(pSink); + DX::SafeRelease(pTransformedGeometry); return hr; } - STDMETHODIMP TextRendererImpl::DrawUnderline( + STDMETHODIMP TextRenderer::DrawUnderline( __maybenull void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, @@ -279,8 +308,8 @@ namespace easy2d underline->offset + underline->thickness ); - ID2D1RectangleGeometry* pRectangleGeometry = nullptr; - hr = pD2DFactory_->CreateRectangleGeometry( + ID2D1RectangleGeometry* pRectangleGeometry = NULL; + hr = pFactory_->CreateRectangleGeometry( &rect, &pRectangleGeometry ); @@ -291,10 +320,10 @@ namespace easy2d baselineOriginX, baselineOriginY ); - ID2D1TransformedGeometry* pTransformedGeometry = nullptr; + ID2D1TransformedGeometry* pTransformedGeometry = NULL; if (SUCCEEDED(hr)) { - hr = pD2DFactory_->CreateTransformedGeometry( + hr = pFactory_->CreateTransformedGeometry( pRectangleGeometry, &matrix, &pTransformedGeometry @@ -323,13 +352,13 @@ namespace easy2d ); } - SafeRelease(pRectangleGeometry); - SafeRelease(pTransformedGeometry); + DX::SafeRelease(pRectangleGeometry); + DX::SafeRelease(pTransformedGeometry); return S_OK; } - STDMETHODIMP TextRendererImpl::DrawStrikethrough( + STDMETHODIMP TextRenderer::DrawStrikethrough( __maybenull void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, @@ -348,8 +377,8 @@ namespace easy2d strikethrough->offset + strikethrough->thickness ); - ID2D1RectangleGeometry* pRectangleGeometry = nullptr; - hr = pD2DFactory_->CreateRectangleGeometry( + ID2D1RectangleGeometry* pRectangleGeometry = NULL; + hr = pFactory_->CreateRectangleGeometry( &rect, &pRectangleGeometry ); @@ -360,10 +389,10 @@ namespace easy2d baselineOriginX, baselineOriginY ); - ID2D1TransformedGeometry* pTransformedGeometry = nullptr; + ID2D1TransformedGeometry* pTransformedGeometry = NULL; if (SUCCEEDED(hr)) { - hr = pD2DFactory_->CreateTransformedGeometry( + hr = pFactory_->CreateTransformedGeometry( pRectangleGeometry, &matrix, &pTransformedGeometry @@ -392,13 +421,13 @@ namespace easy2d ); } - SafeRelease(pRectangleGeometry); - SafeRelease(pTransformedGeometry); + DX::SafeRelease(pRectangleGeometry); + DX::SafeRelease(pTransformedGeometry); return S_OK; } - STDMETHODIMP TextRendererImpl::DrawInlineObject( + STDMETHODIMP TextRenderer::DrawInlineObject( __maybenull void* clientDrawingContext, FLOAT originX, FLOAT originY, @@ -417,12 +446,12 @@ namespace easy2d return E_NOTIMPL; } - STDMETHODIMP_(unsigned long) TextRendererImpl::AddRef() + STDMETHODIMP_(unsigned long) TextRenderer::AddRef() { return InterlockedIncrement(&cRefCount_); } - STDMETHODIMP_(unsigned long) TextRendererImpl::Release() + STDMETHODIMP_(unsigned long) TextRenderer::Release() { unsigned long newCount = InterlockedDecrement(&cRefCount_); @@ -435,7 +464,7 @@ namespace easy2d return newCount; } - STDMETHODIMP TextRendererImpl::IsPixelSnappingDisabled( + STDMETHODIMP TextRenderer::IsPixelSnappingDisabled( __maybenull void* clientDrawingContext, __out BOOL* isDisabled) { @@ -445,7 +474,7 @@ namespace easy2d return S_OK; } - STDMETHODIMP TextRendererImpl::GetCurrentTransform( + STDMETHODIMP TextRenderer::GetCurrentTransform( __maybenull void* clientDrawingContext, __out DWRITE_MATRIX* transform) { @@ -455,7 +484,7 @@ namespace easy2d return S_OK; } - STDMETHODIMP TextRendererImpl::GetPixelsPerDip( + STDMETHODIMP TextRenderer::GetPixelsPerDip( __maybenull void* clientDrawingContext, __out FLOAT* pixelsPerDip) { @@ -469,7 +498,7 @@ namespace easy2d return S_OK; } - STDMETHODIMP TextRendererImpl::QueryInterface( + STDMETHODIMP TextRenderer::QueryInterface( IID const& riid, void** ppvObject) { @@ -487,7 +516,7 @@ namespace easy2d } else { - *ppvObject = nullptr; + *ppvObject = NULL; return E_FAIL; } diff --git a/src/core/TextRenderer.h b/src/dx/TextRenderer.h similarity index 88% rename from src/core/TextRenderer.h rename to src/dx/TextRenderer.h index d70a56dc..1fe6bcb5 100644 --- a/src/core/TextRenderer.h +++ b/src/dx/TextRenderer.h @@ -19,7 +19,8 @@ // THE SOFTWARE. #pragma once -#include "d2dhelper.hpp" +#include "helper.hpp" +#include namespace easy2d { @@ -29,9 +30,7 @@ namespace easy2d public: static E2D_API HRESULT Create( _Out_ ITextRenderer** ppTextRenderer, - _In_ ID2D1Factory* pD2DFactory, - _In_ ID2D1RenderTarget* pRT, - _In_ ID2D1SolidColorBrush* pBrush + _In_ ID2D1RenderTarget* pRT ); STDMETHOD_(void, SetTextStyle)( @@ -43,5 +42,3 @@ namespace easy2d ) PURE; }; } - -E2D_DECLARE_D2D_SMART_PTR(easy2d::ITextRenderer, D2DTextRendererPtr); diff --git a/src/dx/helper.hpp b/src/dx/helper.hpp new file mode 100644 index 00000000..463a5e06 --- /dev/null +++ b/src/dx/helper.hpp @@ -0,0 +1,90 @@ +// 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 "../core/IntrusivePtr.hpp" +#include "../core/Color.h" +#include "../math/vector.hpp" +#include "../math/Rect.hpp" +#include "../math/Matrix.hpp" +#include + +namespace easy2d +{ + // ComPtr<> is a smart pointer for COM + template + using ComPtr = IntrusivePtr<_Ty>; + + + inline void IntrusivePtrAddRef(IUnknown* ptr) + { + if (ptr) { ptr->AddRef(); } + } + + inline void IntrusivePtrRelease(IUnknown* ptr) + { + if (ptr) { ptr->Release(); } + } + + namespace DX + { + template + inline void SafeRelease(T*& ptr) + { + if (ptr != nullptr) + { + ptr->Release(); + ptr = nullptr; + } + } + + inline D2D1_POINT_2F const& ConvertToPoint2F(math::Vec2 const& point) + { + return reinterpret_cast(point); + } + + inline D2D1_SIZE_F const& ConvertToSizeF(math::Vec2 const& size) + { + return reinterpret_cast(size); + } + + inline D2D1_RECT_F ConvertToRectF(math::Rect const& rect) + { + return D2D1_RECT_F{ rect.origin.x, rect.origin.y, rect.origin.x + rect.size.x, rect.origin.y + rect.size.y }; + } + + inline D2D1_COLOR_F const& ConvertToColorF(Color const& color) + { + return reinterpret_cast(color); + } + + inline D2D1_MATRIX_3X2_F const& ConvertToMatrix3x2F(math::Matrix const& matrix) + { + return reinterpret_cast(matrix); + } + + // Converts a length in device-independent pixels (DIPs) to a length in physical pixels. + inline float ConvertDipsToPixels(float dips, float dpi) + { + static const float dips_per_inch = 96.0f; + return math::Floor(dips * dpi / dips_per_inch + 0.5f); // Round to nearest integer. + } + } +} diff --git a/src/easy2d.h b/src/easy2d.h index 2b9752ed..fe99370a 100644 --- a/src/easy2d.h +++ b/src/easy2d.h @@ -77,7 +77,6 @@ #include "core/GeometryNode.h" #include "core/DebugNode.h" -#include "core/Factory.h" #include "core/Application.h" @@ -90,7 +89,7 @@ #include "math/ease.hpp" #include "math/vector.hpp" #include "math/rand.h" -#include "math/Matrix.h" +#include "math/Matrix.hpp" // diff --git a/src/math/Matrix.cpp b/src/math/Matrix.cpp deleted file mode 100644 index 478876aa..00000000 --- a/src/math/Matrix.cpp +++ /dev/null @@ -1,152 +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 "Matrix.h" - -namespace easy2d -{ - namespace math - { - Matrix::Matrix() - : _11(1.f), _12(0.f) - , _21(0.f), _22(1.f) - , _31(0.f), _32(0.f) - { - } - - Matrix::Matrix(float _11, float _12, float _21, float _22, float _31, float _32) - : _11(_11), _12(_12), _21(_21), _22(_22), _31(_31), _32(_32) - { - } - - Matrix::Matrix(const float* p) - { - for (int i = 0; i < 6; i++) - m[i] = p[i]; - } - - Matrix::Matrix(Matrix const& other) - : _11(other._11), _12(other._12) - , _21(other._21), _22(other._22) - , _31(other._31), _32(other._32) - { - } - - void Matrix::Identity() - { - _11 = 1.f; _12 = 0.f; - _21 = 0.f; _12 = 1.f; - _31 = 0.f; _32 = 0.f; - } - - Rect Matrix::Transform(const Rect & rect) const - { - Vec2 top_left = Transform(rect.GetLeftTop()); - Vec2 top_right = Transform(rect.GetRightTop()); - Vec2 bottom_left = Transform(rect.GetLeftBottom()); - Vec2 bottom_right = Transform(rect.GetRightBottom()); - - float left = std::min(std::min(top_left.x, top_right.x), std::min(bottom_left.x, bottom_right.x)); - float right = std::max(std::max(top_left.x, top_right.x), std::max(bottom_left.x, bottom_right.x)); - float top = std::min(std::min(top_left.y, top_right.y), std::min(bottom_left.y, bottom_right.y)); - float bottom = std::max(std::max(top_left.y, top_right.y), std::max(bottom_left.y, bottom_right.y)); - - return Rect{ left, top, (right - left), (bottom - top) }; - } - - Matrix Matrix::Translation(const Vec2& v) - { - return Matrix( - 1.f, 0.f, - 0.f, 1.f, - v.x, v.y - ); - } - - Matrix Matrix::Translation( - float x, - float y) - { - return Translation(Vec2(x, y)); - } - - Matrix Matrix::Scaling( - const Vec2& v, - const Vec2& center) - { - return Matrix( - v.x, 0.f, - 0.f, v.y, - center.x - v.x * center.x, - center.y - v.y * center.y - ); - } - - Matrix Matrix::Scaling( - float x, - float y, - const Vec2& center) - { - return Scaling(Vec2(x, y), center); - } - - Matrix Matrix::Rotation( - float angle, - const Vec2& center) - { - float s = math::Sin(angle); - float c = math::Cos(angle); - return Matrix( - c, s, - -s, c, - center.x * (1 - c) + center.y * s, - center.y * (1 - c) - center.x * s - ); - } - - Matrix Matrix::Skewing( - float angle_x, - float angle_y, - const Vec2& center) - { - float tx = math::Tan(angle_x); - float ty = math::Tan(angle_y); - return Matrix( - 1.f, -ty, - -tx, 1.f, - center.y * tx, center.x * ty - ); - } - - Matrix Matrix::Invert(Matrix const& matrix) - { - float det = 1.f / matrix.Determinant(); - - return Matrix( - det * matrix._22, - -det * matrix._12, - -det * matrix._21, - det * matrix._11, - det * (matrix._21 * matrix._32 - matrix._22 * matrix._31), - det * (matrix._12 * matrix._31 - matrix._11 * matrix._32) - ); - } - } -} diff --git a/src/math/Matrix.h b/src/math/Matrix.hpp similarity index 57% rename from src/math/Matrix.h rename to src/math/Matrix.hpp index 657efcd0..851487c3 100644 --- a/src/math/Matrix.h +++ b/src/math/Matrix.hpp @@ -21,12 +21,13 @@ #pragma once #include "vector.hpp" #include "Rect.hpp" +#include namespace easy2d { namespace math { - struct E2D_API Matrix + struct Matrix { union { @@ -44,13 +45,30 @@ namespace easy2d }; }; - Matrix(); + Matrix() + : _11(1.f), _12(0.f) + , _21(0.f), _22(1.f) + , _31(0.f), _32(0.f) + { + } - Matrix(float _11, float _12, float _21, float _22, float _31, float _32); + Matrix(float _11, float _12, float _21, float _22, float _31, float _32) + : _11(_11), _12(_12), _21(_21), _22(_22), _31(_31), _32(_32) + { + } - Matrix(const float* p); + Matrix(const float* p) + { + for (int i = 0; i < 6; i++) + m[i] = p[i]; + } - Matrix(Matrix const& other); + Matrix(Matrix const& other) + : _11(other._11), _12(other._12) + , _21(other._21), _22(other._22) + , _31(other._31), _32(other._32) + { + } template Matrix(T const& other) @@ -59,7 +77,12 @@ namespace easy2d m[i] = other[i]; } - void Identity(); + inline void Identity() + { + _11 = 1.f; _12 = 0.f; + _21 = 0.f; _12 = 1.f; + _31 = 0.f; _32 = 0.f; + } inline Vec2 Transform(const Vec2& v) const { @@ -69,7 +92,20 @@ namespace easy2d ); } - Rect Transform(const Rect& rect) const; + Rect Transform(const Rect & rect) const + { + Vec2 top_left = Transform(rect.GetLeftTop()); + Vec2 top_right = Transform(rect.GetRightTop()); + Vec2 bottom_left = Transform(rect.GetLeftBottom()); + Vec2 bottom_right = Transform(rect.GetRightBottom()); + + float left = std::min(std::min(top_left.x, top_right.x), std::min(bottom_left.x, bottom_right.x)); + float right = std::max(std::max(top_left.x, top_right.x), std::max(bottom_left.x, bottom_right.x)); + float top = std::min(std::min(top_left.y, top_right.y), std::min(bottom_left.y, bottom_right.y)); + float bottom = std::max(std::max(top_left.y, top_right.y), std::max(bottom_left.y, bottom_right.y)); + + return Rect{ left, top, (right - left), (bottom - top) }; + } inline void Translate(const Vec2& v) { @@ -107,46 +143,83 @@ namespace easy2d return 0 != Determinant(); } - inline operator D2D1_MATRIX_3X2_F const& () const + static inline Matrix Translation(const Vec2& v) { - return reinterpret_cast(*this); + return Matrix( + 1.f, 0.f, + 0.f, 1.f, + v.x, v.y + ); } - inline operator D2D1_MATRIX_3X2_F& () - { - return reinterpret_cast(*this); - } - - static Matrix Translation(const Vec2& v); - - static Matrix Translation( + static inline Matrix Translation( float x, - float y - ); + float y) + { + return Translation(Vec2(x, y)); + } - static Matrix Scaling( + static inline Matrix Scaling( const Vec2& v, - const Vec2& center = Vec2() - ); + const Vec2& center = Vec2()) + { + return Matrix( + v.x, 0.f, + 0.f, v.y, + center.x - v.x * center.x, + center.y - v.y * center.y + ); + } - static Matrix Scaling( + static inline Matrix Scaling( float x, float y, - const Vec2& center = Vec2() - ); + const Vec2& center = Vec2()) + { + return Scaling(Vec2(x, y), center); + } - static Matrix Rotation( + static inline Matrix Rotation( float angle, - const Vec2& center = Vec2() - ); + const Vec2& center = Vec2()) + { + float s = math::Sin(angle); + float c = math::Cos(angle); + return Matrix( + c, s, + -s, c, + center.x * (1 - c) + center.y * s, + center.y * (1 - c) - center.x * s + ); + } - static Matrix Skewing( + static inline Matrix Skewing( float angle_x, float angle_y, - const Vec2& center = Vec2() - ); + const Vec2& center = Vec2()) + { + float tx = math::Tan(angle_x); + float ty = math::Tan(angle_y); + return Matrix( + 1.f, -ty, + -tx, 1.f, + center.y * tx, center.x * ty + ); + } - static Matrix Invert(Matrix const& matrix); + static inline Matrix Invert(Matrix const& matrix) + { + float det = 1.f / matrix.Determinant(); + + return Matrix( + det * matrix._22, + -det * matrix._12, + -det * matrix._21, + det * matrix._11, + det * (matrix._21 * matrix._32 - matrix._22 * matrix._31), + det * (matrix._12 * matrix._31 - matrix._11 * matrix._32) + ); + } }; diff --git a/src/math/Rect.hpp b/src/math/Rect.hpp index 74f409db..42b70cb5 100644 --- a/src/math/Rect.hpp +++ b/src/math/Rect.hpp @@ -26,7 +26,7 @@ namespace easy2d namespace math { // 矩形 - struct E2D_API Rect + struct Rect { Vec2 origin; // 左上角坐标 Vec2 size; // 宽度和高度 diff --git a/src/math/scalar.hpp b/src/math/scalar.hpp index ed26b5c4..1d6ec463 100644 --- a/src/math/scalar.hpp +++ b/src/math/scalar.hpp @@ -19,7 +19,6 @@ // THE SOFTWARE. #pragma once -#include "../core/macros.h" #include "constants.hpp" #include diff --git a/src/math/vector.hpp b/src/math/vector.hpp index 3be0294e..55b8ec69 100644 --- a/src/math/vector.hpp +++ b/src/math/vector.hpp @@ -25,7 +25,7 @@ namespace easy2d { namespace math { - struct E2D_API Vec2 + struct Vec2 { float x; float y; @@ -81,6 +81,11 @@ namespace easy2d { return (x == other.x) && (y == other.y); } + + inline bool operator!= (const Vec2& other) const + { + return (x != other.x) || (y != other.y); + } }; using Point = Vec2; diff --git a/src/utils/Transcoder.cpp b/src/utils/Transcoder.cpp index 5ea29b8e..58a3e2d1 100644 --- a/src/utils/Transcoder.cpp +++ b/src/utils/Transcoder.cpp @@ -23,9 +23,9 @@ #endif #include "Transcoder.h" -#include "../core/d2dhelper.hpp" #include "../core/modules.h" #include "../core/logs.h" +#include "../DX/helper.hpp" #include namespace easy2d @@ -53,7 +53,7 @@ namespace easy2d { HRESULT hr = S_OK; - IntrusivePtr reader; + ComPtr reader; hr = modules::MediaFoundation::Get().MFCreateSourceReaderFromURL( file_path.c_str(), @@ -73,9 +73,9 @@ namespace easy2d { HRESULT hr = S_OK; - IntrusivePtr stream; - IntrusivePtr byte_stream; - IntrusivePtr reader; + ComPtr stream; + ComPtr byte_stream; + ComPtr reader; LPVOID buffer; DWORD buffer_size; @@ -119,8 +119,8 @@ namespace easy2d HRESULT hr = S_OK; DWORD max_stream_size = 0; - IntrusivePtr partial_type; - IntrusivePtr uncompressed_type; + ComPtr partial_type; + ComPtr uncompressed_type; hr = modules::MediaFoundation::Get().MFCreateMediaType(&partial_type); @@ -200,8 +200,8 @@ namespace easy2d DWORD position = 0; BYTE* data = new (std::nothrow) BYTE[max_stream_size]; - IntrusivePtr sample; - IntrusivePtr buffer; + ComPtr sample; + ComPtr buffer; if (data == nullptr) {