diff --git a/core/base/BaseTypes.h b/core/base/BaseTypes.h index 4ed38fbd..3cb91864 100644 --- a/core/base/BaseTypes.h +++ b/core/base/BaseTypes.h @@ -46,8 +46,8 @@ namespace easy2d Right /* 右 */ }; - // 线条相交样式 - enum class Stroke : int + // 画笔样式 + enum class StrokeStyle : int { Miter = 0, /* 斜切 */ Bevel = 1, /* 斜角 */ diff --git a/core/base/Canvas.cpp b/core/base/Canvas.cpp index 6b89ecc9..23b2e8eb 100644 --- a/core/base/Canvas.cpp +++ b/core/base/Canvas.cpp @@ -24,15 +24,21 @@ namespace easy2d { + /////////////////////////////////////////////////////// + /////////////////////////////////////////////////////// + // FIXME!!! + /////////////////////////////////////////////////////// + /////////////////////////////////////////////////////// + Canvas::Canvas(float width, float height) : render_target_(nullptr) , fill_brush_(nullptr) , line_brush_(nullptr) , stroke_style_(nullptr) , stroke_width_(1.0f) - , stroke_(Stroke::Miter) + , stroke_(StrokeStyle::Miter) { - render_target_ = render::D2D.HwndRenderTarget; + // render_target_ = render::D2D.HwndRenderTarget; render_target_->AddRef(); ThrowIfFailed( @@ -78,22 +84,11 @@ namespace easy2d stroke_width_ = std::max(width, 0.f); } - void Canvas::SetStrokeStyle(Stroke strokeStyle) + void Canvas::SetStrokeStyle(StrokeStyle stroke) { SafeRelease(stroke_style_); - switch (strokeStyle) - { - case Stroke::Miter: - stroke_style_ = render::D2D.MiterStrokeStyle; - break; - case Stroke::Bevel: - stroke_style_ = render::D2D.BevelStrokeStyle; - break; - case Stroke::Round: - stroke_style_ = render::D2D.RoundStrokeStyle; - break; - } + stroke_style_ = render::instance.GetStrokeStyle(stroke); if (stroke_style_) stroke_style_->AddRef(); @@ -114,7 +109,7 @@ namespace easy2d return stroke_width_; } - Stroke Canvas::GetStrokeStyle() const + StrokeStyle Canvas::GetStrokeStyle() const { return stroke_; } diff --git a/core/base/Canvas.h b/core/base/Canvas.h index a26bb4e2..0c48f2ae 100644 --- a/core/base/Canvas.h +++ b/core/base/Canvas.h @@ -53,7 +53,7 @@ namespace easy2d // 设置线条相交样式 void SetStrokeStyle( - Stroke strokeStyle + StrokeStyle stroke ); // 获取线条颜色 @@ -66,7 +66,7 @@ namespace easy2d float GetStrokeWidth() const; // 获取线条相交样式 - Stroke GetStrokeStyle() const; + StrokeStyle GetStrokeStyle() const; // 画直线 void DrawLine( @@ -129,7 +129,7 @@ namespace easy2d private: float stroke_width_; - Stroke stroke_; + StrokeStyle stroke_; ID2D1RenderTarget* render_target_; ID2D1SolidColorBrush* fill_brush_; ID2D1SolidColorBrush* line_brush_; diff --git a/core/base/Color.cpp b/core/base/Color.cpp index 4a2f4ab9..9c815d46 100644 --- a/core/base/Color.cpp +++ b/core/base/Color.cpp @@ -80,9 +80,4 @@ namespace easy2d , a(color.a) { } - - Color::operator D2D1_COLOR_F() const - { - return D2D1::ColorF(r, g, b, a); - } } \ No newline at end of file diff --git a/core/base/Color.h b/core/base/Color.h index 3209df43..ecb90b9a 100644 --- a/core/base/Color.h +++ b/core/base/Color.h @@ -63,7 +63,10 @@ namespace easy2d const D2D1_COLOR_F& color ); - operator D2D1_COLOR_F() const; + inline operator D2D1_COLOR_F() const + { + return D2D1_COLOR_F{ r, g, b, a }; + } public: enum Value : unsigned int diff --git a/core/base/Game.cpp b/core/base/Game.cpp index ecd2d715..3bc6c535 100644 --- a/core/base/Game.cpp +++ b/core/base/Game.cpp @@ -23,12 +23,13 @@ #include "Scene.h" #include "Transition.h" #include "Image.h" -#include "../utils/Player.h" #include "time.h" #include "render.h" #include "input.h" #include "audio.h" #include "modules.h" +#include "../utils/Player.h" +#include "../math/Matrix.hpp" #include namespace easy2d @@ -68,7 +69,7 @@ namespace easy2d Image::ClearCache(); Player::ClearCache(); - render::Uninitialize(); + render::instance.Uninitialize(); audio::instance.Uninitialize(); window::instance.Destroy(); modules::Uninitialize(); @@ -82,8 +83,8 @@ namespace easy2d { modules::Initialize(); window::instance.Initialize(property); + render::instance.Initialize(window::instance.handle); audio::instance.Initialize(); - render::Initialize(window::instance.handle); // 若开启了调试模式,打开控制台 HWND console = ::GetConsoleWindow(); @@ -291,14 +292,14 @@ namespace easy2d { if (curr_scene_ && curr_scene_->GetRoot()) { - render::D2D.HwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); - render::D2D.SolidColorBrush->SetOpacity(1.f); + render::instance.SetTransform(math::Matrix()); + render::instance.SetBrushOpacity(1.f); curr_scene_->GetRoot()->DrawBorder(); } if (next_scene_ && next_scene_->GetRoot()) { - render::D2D.HwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); - render::D2D.SolidColorBrush->SetOpacity(1.f); + render::instance.SetTransform(math::Matrix()); + render::instance.SetBrushOpacity(1.f); next_scene_->GetRoot()->DrawBorder(); } diff --git a/core/base/Image.cpp b/core/base/Image.cpp index fe7e64ac..b8c3a959 100644 --- a/core/base/Image.cpp +++ b/core/base/Image.cpp @@ -20,6 +20,7 @@ #include "Image.h" #include "render.h" +#include "logs.h" #include "../utils/File.h" namespace easy2d @@ -193,91 +194,17 @@ namespace easy2d return true; } - HRESULT hr; - - HINSTANCE hinstance = GetModuleHandle(nullptr); - IWICImagingFactory* imaging_factory = render::D2D.WICImagingFactory; - ID2D1HwndRenderTarget* render_target = render::D2D.HwndRenderTarget; - IWICBitmapDecoder* decoder = nullptr; - IWICBitmapFrameDecode* source = nullptr; - IWICStream* stream = nullptr; - IWICFormatConverter* converter = nullptr; - ID2D1Bitmap* bitmap = nullptr; - - // 加载资源 - hr = res.Load() ? S_OK : E_FAIL; - - if (SUCCEEDED(hr)) - { - // 创建 WIC 流 - hr = imaging_factory->CreateStream(&stream); - } - - if (SUCCEEDED(hr)) - { - // 初始化流 - hr = stream->InitializeFromMemory( - static_cast(res.GetData()), - res.GetDataSize() - ); - } - - if (SUCCEEDED(hr)) - { - // 创建流的解码器 - hr = imaging_factory->CreateDecoderFromStream( - stream, - nullptr, - WICDecodeMetadataCacheOnLoad, - &decoder - ); - } - - if (SUCCEEDED(hr)) - { - // 创建初始化框架 - hr = decoder->GetFrame(0, &source); - } - - if (SUCCEEDED(hr)) - { - // 创建图片格式转换器 - hr = imaging_factory->CreateFormatConverter(&converter); - } - - if (SUCCEEDED(hr)) - { - // 图片格式转换成 32bppPBGRA - hr = converter->Initialize( - source, - GUID_WICPixelFormat32bppPBGRA, - WICBitmapDitherTypeNone, - nullptr, - 0.f, - WICBitmapPaletteTypeMedianCut - ); - } - - if (SUCCEEDED(hr)) - { - // 从 WIC 位图创建一个 Direct2D 位图 - hr = render_target->CreateBitmapFromWicBitmap( - converter, - nullptr, - &bitmap - ); - } + ID2D1Bitmap* bitmap = nullptr; + HRESULT hr = render::instance.CreateBitmapFromResource(res, &bitmap); if (SUCCEEDED(hr)) { bitmap_cache_.insert(std::make_pair(hash_code, bitmap)); } - - // 释放相关资源 - SafeRelease(decoder); - SafeRelease(source); - SafeRelease(stream); - SafeRelease(converter); + else + { + logs::Trace(L"CreateBitmapFromFile", hr); + } return SUCCEEDED(hr); } @@ -296,68 +223,17 @@ namespace easy2d // 默认搜索路径,所以需要通过 File::GetPath 获取完整路径 String image_file_path = image_file.GetPath(); - IWICImagingFactory* imaging_factory = render::D2D.WICImagingFactory; - ID2D1HwndRenderTarget* render_target = render::D2D.HwndRenderTarget; - IWICBitmapDecoder* decoder = nullptr; - IWICBitmapFrameDecode* source = nullptr; - IWICStream* stream = nullptr; - IWICFormatConverter* converter = nullptr; - ID2D1Bitmap* bitmap = nullptr; - - // 创建解码器 - HRESULT hr = imaging_factory->CreateDecoderFromFilename( - image_file_path.c_str(), - nullptr, - GENERIC_READ, - WICDecodeMetadataCacheOnLoad, - &decoder - ); - - if (SUCCEEDED(hr)) - { - // 创建初始化框架 - hr = decoder->GetFrame(0, &source); - } - - if (SUCCEEDED(hr)) - { - // 创建图片格式转换器 - hr = imaging_factory->CreateFormatConverter(&converter); - } - - if (SUCCEEDED(hr)) - { - // 图片格式转换成 32bppPBGRA - hr = converter->Initialize( - source, - GUID_WICPixelFormat32bppPBGRA, - WICBitmapDitherTypeNone, - nullptr, - 0.f, - WICBitmapPaletteTypeMedianCut - ); - } - - if (SUCCEEDED(hr)) - { - // 从 WIC 位图创建一个 Direct2D 位图 - hr = render_target->CreateBitmapFromWicBitmap( - converter, - nullptr, - &bitmap - ); - } + ID2D1Bitmap* bitmap = nullptr; + HRESULT hr = render::instance.CreateBitmapFromFile(file_name, &bitmap); if (SUCCEEDED(hr)) { bitmap_cache_.insert(std::make_pair(hash_code, bitmap)); } - - // 释放相关资源 - SafeRelease(decoder); - SafeRelease(source); - SafeRelease(stream); - SafeRelease(converter); + else + { + logs::Trace(L"CreateBitmapFromFile", hr); + } return SUCCEEDED(hr); } diff --git a/core/base/Node.cpp b/core/base/Node.cpp index 37948e9a..9cf3d965 100644 --- a/core/base/Node.cpp +++ b/core/base/Node.cpp @@ -44,8 +44,8 @@ namespace easy2d , children_() , actions_() , tasks_() - , initial_matrix_(D2D1::Matrix3x2F::Identity()) - , final_matrix_(D2D1::Matrix3x2F::Identity()) + , initial_matrix_() + , final_matrix_() , border_color_(Color::Red, 0.6f) { } @@ -75,19 +75,14 @@ namespace easy2d if (!visible_) return; - auto render_target = render::D2D.HwndRenderTarget; if (clip_enabled_) { - render_target->SetTransform(final_matrix_); - render_target->PushAxisAlignedClip( - D2D1::RectF(0, 0, transform_.size.width, transform_.size.height), - D2D1_ANTIALIAS_MODE_PER_PRIMITIVE - ); + render::instance.PushClip(final_matrix_, transform_.size); } if (children_.empty()) { - render_target->SetTransform(final_matrix_); + render::instance.SetTransform(final_matrix_); OnDraw(); } else @@ -119,7 +114,7 @@ namespace easy2d } } - render_target->SetTransform(final_matrix_); + render::instance.SetTransform(final_matrix_); OnDraw(); // 访问剩余节点 @@ -129,7 +124,7 @@ namespace easy2d if (clip_enabled_) { - render_target->PopAxisAlignedClip(); + render::instance.PopClip(); } } @@ -176,12 +171,7 @@ namespace easy2d { if (border_) { - render::D2D.SolidColorBrush->SetColor(D2D1_COLOR_F(border_color_)); - render::D2D.HwndRenderTarget->DrawGeometry( - border_, - render::D2D.SolidColorBrush, - 1.5f - ); + render::instance.DrawGeometry(border_, border_color_, 1.f, 1.5f); } for (const auto& child : children_) @@ -198,14 +188,14 @@ namespace easy2d dirty_transform_ = false; - final_matrix_ = static_cast(transform_); + final_matrix_ = transform_.ToMatrix(); // 根据自身支点计算 Initial 矩阵,子节点将根据这个矩阵进行变换 auto pivot = Point( transform_.size.width * transform_.pivot_x, transform_.size.height * transform_.pivot_y ); - initial_matrix_ = final_matrix_ * D2D1::Matrix3x2F::Translation(pivot.x, pivot.y); + initial_matrix_ = final_matrix_ * math::Matrix::Translation(pivot); if (parent_) { @@ -220,26 +210,10 @@ namespace easy2d // 重新构造轮廓 SafeRelease(border_); - - ID2D1Factory * factory = render::D2D.Factory; - ID2D1RectangleGeometry * rectangle = nullptr; - ID2D1TransformedGeometry * transformed = nullptr; + ThrowIfFailed( - factory->CreateRectangleGeometry( - D2D1::RectF(0, 0, transform_.size.width, transform_.size.height), - &rectangle - ) + render::instance.CreateRectGeometry(final_matrix_, transform_.size, &border_) ); - ThrowIfFailed( - factory->CreateTransformedGeometry( - rectangle, - final_matrix_, - &transformed - ) - ); - border_ = transformed; - - SafeRelease(rectangle); // 通知子节点进行转换 for (const auto& child : children_) diff --git a/core/base/Node.h b/core/base/Node.h index cbdb2599..578a5e34 100644 --- a/core/base/Node.h +++ b/core/base/Node.h @@ -21,9 +21,10 @@ #pragma once #include "base.h" #include "RefCounter.h" -#include "../math/Transform.h" #include "KeyEvent.h" #include "MouseEvent.h" +#include "../math/Transform.h" +#include "../math/Matrix.hpp" namespace easy2d { @@ -446,9 +447,8 @@ namespace easy2d void UpdateTime(); private: - String name_; + String name_; size_t hash_name_; - math::Transform transform_; float display_opacity_; float real_opacity_; int order_; @@ -463,7 +463,8 @@ namespace easy2d Tasks tasks_; Nodes children_; ID2D1Geometry* border_; - D2D1::Matrix3x2F initial_matrix_; - D2D1::Matrix3x2F final_matrix_; + math::Transform transform_; + math::Matrix initial_matrix_; + math::Matrix final_matrix_; }; } diff --git a/core/base/Rect.hpp b/core/base/Rect.hpp index d429dd78..ac194c70 100644 --- a/core/base/Rect.hpp +++ b/core/base/Rect.hpp @@ -20,6 +20,7 @@ #pragma once #include "BaseTypes.h" +#include namespace easy2d { @@ -96,5 +97,10 @@ namespace easy2d (origin.y + size.height) < rect.origin.y || (rect.origin.y + rect.size.height) < origin.y); } + + inline operator D2D1_RECT_F () const + { + return D2D1_RECT_F{ origin.x, origin.y, origin.x + size.width, origin.y + size.height }; + } }; } diff --git a/core/base/Scene.cpp b/core/base/Scene.cpp index a08aad31..ef4e4569 100644 --- a/core/base/Scene.cpp +++ b/core/base/Scene.cpp @@ -25,13 +25,13 @@ namespace easy2d { Scene::Scene() : root_(nullptr) - , transform_(D2D1::Matrix3x2F::Identity()) + , transform_() { } Scene::Scene(Node * root) : root_(nullptr) - , transform_(D2D1::Matrix3x2F::Identity()) + , transform_() { this->SetRoot(root); } @@ -106,7 +106,7 @@ namespace easy2d } } - void Scene::SetTransform(const D2D1::Matrix3x2F& matrix) + void Scene::SetTransform(const math::Matrix& matrix) { transform_ = matrix; @@ -116,7 +116,7 @@ namespace easy2d } } - const D2D1::Matrix3x2F & Scene::GetTransform() const + const math::Matrix& Scene::GetTransform() const { return transform_; } diff --git a/core/base/Scene.h b/core/base/Scene.h index 2894109a..d6da1fda 100644 --- a/core/base/Scene.h +++ b/core/base/Scene.h @@ -22,7 +22,7 @@ #include "RefCounter.h" #include "KeyEvent.h" #include "MouseEvent.h" -#include +#include "../math/Matrix.hpp" namespace easy2d { @@ -73,17 +73,17 @@ namespace easy2d // 设置转换矩阵 void SetTransform( - const D2D1::Matrix3x2F& matrix + const math::Matrix& matrix ); // 获取转换矩阵 - const D2D1::Matrix3x2F& GetTransform() const; + const math::Matrix& GetTransform() const; private: E2D_DISABLE_COPY(Scene); private: - Node* root_; - D2D1::Matrix3x2F transform_; + Node* root_; + math::Matrix transform_; }; } diff --git a/core/base/Size.h b/core/base/Size.h index 6ff7025e..71b14fbc 100644 --- a/core/base/Size.h +++ b/core/base/Size.h @@ -19,6 +19,7 @@ // THE SOFTWARE. #pragma once +#include namespace easy2d { @@ -52,5 +53,10 @@ namespace easy2d Size operator / (float val) const; Size operator - () const; bool operator== (const Size& other) const; + + inline operator D2D1_SIZE_F () const + { + return D2D1_SIZE_F{ width, height }; + } }; } diff --git a/core/base/Sprite.cpp b/core/base/Sprite.cpp index 47825552..3ea0bf95 100644 --- a/core/base/Sprite.cpp +++ b/core/base/Sprite.cpp @@ -135,17 +135,11 @@ namespace easy2d if (image_ && image_->GetBitmap()) { auto crop_pos = image_->GetCropPos(); - render::D2D.HwndRenderTarget->DrawBitmap( - image_->GetBitmap(), - D2D1::RectF(0, 0, GetTransform().size.width, GetTransform().size.height), + render::instance.DrawImage( + image_, GetDisplayOpacity(), - D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, - D2D1::RectF( - crop_pos.x, - crop_pos.y, - crop_pos.y + GetTransform().size.width, - crop_pos.y + GetTransform().size.height - ) + Rect(Point(), GetTransform().size), + Rect(crop_pos, GetTransform().size) ); } } diff --git a/core/base/Text.cpp b/core/base/Text.cpp index cb15051f..34a7fd3c 100644 --- a/core/base/Text.cpp +++ b/core/base/Text.cpp @@ -39,7 +39,7 @@ namespace easy2d , outline(true) , outline_color(Color(Color::Black, 0.5)) , outline_width(1.f) - , outline_stroke(Stroke::Round) + , outline_stroke(StrokeStyle::Round) {} Text::Style::Style( @@ -53,7 +53,7 @@ namespace easy2d bool outline, Color outline_color, float outline_width, - Stroke outline_stroke + StrokeStyle outline_stroke ) : color(color) , alignment(alignment) @@ -143,7 +143,7 @@ namespace easy2d return style_.outline_width; } - Stroke Text::GetOutlineStroke() const + StrokeStyle Text::GetOutlineStroke() const { return style_.outline_stroke; } @@ -306,7 +306,7 @@ namespace easy2d style_.outline_width = outline_width; } - void Text::SetOutlineStroke(Stroke outline_stroke) + void Text::SetOutlineStroke(StrokeStyle outline_stroke) { style_.outline_stroke = outline_stroke; } @@ -318,16 +318,16 @@ namespace easy2d // 创建文本区域 D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, GetTransform().size.width, GetTransform().size.height); // 设置画刷颜色和透明度 - render::D2D.SolidColorBrush->SetOpacity(GetDisplayOpacity()); + render::instance.SetBrushOpacity(GetDisplayOpacity()); // 获取文本渲染器 - render::D2D.TextRenderer->SetTextStyle( + render::instance.SetTextStyle( style_.color, style_.outline, style_.outline_color, style_.outline_width, - static_cast(style_.outline_stroke) + style_.outline_stroke ); - text_layout_->Draw(nullptr, render::D2D.TextRenderer, 0, 0); + render::instance.DrawTextLayout(text_layout_); } } @@ -344,15 +344,9 @@ namespace easy2d SafeRelease(text_format_); ThrowIfFailed( - render::D2D.DWriteFactory->CreateTextFormat( - font_.family.c_str(), - nullptr, - DWRITE_FONT_WEIGHT(font_.weight), - font_.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, - DWRITE_FONT_STRETCH_NORMAL, - font_.size, - L"", - &text_format_ + render::instance.CreateTextFormat( + &text_format_, + font_ ) ); @@ -401,19 +395,15 @@ namespace easy2d return; } - UINT32 length = static_cast(text_.size()); - // 对文本自动换行情况下进行处理 if (style_.wrap) { ThrowIfFailed( - render::D2D.DWriteFactory->CreateTextLayout( - text_.c_str(), - length, + render::instance.CreateTextLayout( + &text_layout_, + text_, text_format_, - style_.wrap_width, - 0, - &text_layout_ + style_.wrap_width ) ); // 获取文本布局的宽度和高度 @@ -426,13 +416,11 @@ namespace easy2d { // 为防止文本对齐问题,根据先创建 layout 以获取宽度 ThrowIfFailed( - render::D2D.DWriteFactory->CreateTextLayout( - text_.c_str(), - length, + render::instance.CreateTextLayout( + &text_layout_, + text_, text_format_, - 0, - 0, - &text_layout_ + 0 ) ); @@ -445,19 +433,17 @@ namespace easy2d // 重新创建 layout SafeRelease(text_layout_); ThrowIfFailed( - render::D2D.DWriteFactory->CreateTextLayout( - text_.c_str(), - length, + render::instance.CreateTextLayout( + &text_layout_, + text_, text_format_, - GetTransform().size.width, - 0, - &text_layout_ + GetTransform().size.width ) ); } // 添加下划线和删除线 - DWRITE_TEXT_RANGE range = { 0, length }; + DWRITE_TEXT_RANGE range = { 0, static_cast(text_.length()) }; if (style_.underline) { text_layout_->SetUnderline(true, range); diff --git a/core/base/Text.h b/core/base/Text.h index 609a38fa..cb676210 100644 --- a/core/base/Text.h +++ b/core/base/Text.h @@ -51,7 +51,7 @@ namespace easy2d bool outline; // 显示描边 Color outline_color; // 描边颜色 float outline_width; // 描边线宽 - Stroke outline_stroke; // 描边线相交样式 + StrokeStyle outline_stroke; // 描边线相交样式 public: Style(); @@ -67,7 +67,7 @@ namespace easy2d bool outline = true, Color outline_color = Color(Color::Black, 0.5), float outline_width = 1.f, - Stroke outline_stroke = Stroke::Round + StrokeStyle outline_stroke = StrokeStyle::Round ); }; @@ -110,7 +110,7 @@ namespace easy2d float GetOutlineWidth() const; // 获取描边线相交样式 - Stroke GetOutlineStroke() const; + StrokeStyle GetOutlineStroke() const; // 获取文本显示行数 int GetLineCount() const; @@ -214,7 +214,7 @@ namespace easy2d // 设置描边线相交样式 void SetOutlineStroke( - Stroke outline_stroke + StrokeStyle outline_stroke ); // 渲染文字 diff --git a/core/base/TextRenderer.cpp b/core/base/TextRenderer.cpp index 78c04942..0c7dd899 100644 --- a/core/base/TextRenderer.cpp +++ b/core/base/TextRenderer.cpp @@ -73,22 +73,7 @@ namespace easy2d bShowOutline_ = outline; sOutlineColor_ = outline_color; fOutlineWidth = 2 * outline_width; - - switch (outlineJoin) - { - case D2D1_LINE_JOIN_MITER: - pCurrStrokeStyle_ = render::D2D.MiterStrokeStyle; - break; - case D2D1_LINE_JOIN_BEVEL: - pCurrStrokeStyle_ = render::D2D.BevelStrokeStyle; - break; - case D2D1_LINE_JOIN_ROUND: - pCurrStrokeStyle_ = render::D2D.RoundStrokeStyle; - break; - default: - pCurrStrokeStyle_ = nullptr; - break; - } + pCurrStrokeStyle_ = render::instance.GetStrokeStyle(StrokeStyle(outlineJoin)); } STDMETHODIMP ITextRenderer::DrawGlyphRun( diff --git a/core/base/Transition.cpp b/core/base/Transition.cpp index 9c74b170..efa4dd13 100644 --- a/core/base/Transition.cpp +++ b/core/base/Transition.cpp @@ -21,8 +21,8 @@ #include "Transition.h" #include "Node.h" #include "Scene.h" -#include "render.h" #include "window.h" +#include "../math/Matrix.hpp" namespace easy2d { @@ -39,8 +39,8 @@ namespace easy2d , in_scene_(nullptr) , out_layer_(nullptr) , in_layer_(nullptr) - , out_layer_param_() - , in_layer_param_() + , out_layer_prop_() + , in_layer_prop_() { duration_ = std::max(duration, 0.f); } @@ -73,32 +73,22 @@ namespace easy2d if (in_scene_) { ThrowIfFailed( - render::D2D.HwndRenderTarget->CreateLayer(&in_layer_) + render::instance.CreateLayer(&in_layer_) ); } if (out_scene_) { ThrowIfFailed( - render::D2D.HwndRenderTarget->CreateLayer(&out_layer_) + render::instance.CreateLayer(&out_layer_) ); } window_size_ = window::instance.GetSize(); - out_layer_param_ = in_layer_param_ = D2D1::LayerParameters( - D2D1::RectF( - 0.f, - 0.f, - window_size_.width, - window_size_.height - ), - nullptr, - D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, - D2D1::Matrix3x2F::Identity(), - 1.f, - render::D2D.SolidColorBrush, - D2D1_LAYER_OPTIONS_NONE - ); + out_layer_prop_ = in_layer_prop_ = render::LayerProperties{ + Rect(Point(), window_size_), + 1.f + }; } void Transition::Update() @@ -121,46 +111,32 @@ namespace easy2d void Transition::Draw() { - auto render_target = render::D2D.HwndRenderTarget; - if (out_scene_) { - render_target->SetTransform(out_scene_->GetTransform()); - render_target->PushAxisAlignedClip( - D2D1::RectF( - 0.f, - 0.f, - window_size_.width, - window_size_.height - ), - D2D1_ANTIALIAS_MODE_PER_PRIMITIVE + render::instance.PushClip( + out_scene_->GetTransform(), + window_size_ ); - render_target->PushLayer(out_layer_param_, out_layer_); + render::instance.PushLayer(out_layer_, out_layer_prop_); out_scene_->Draw(); - render_target->PopLayer(); - render_target->PopAxisAlignedClip(); + render::instance.PopLayer(); + render::instance.PopClip(); } if (in_scene_) { - render_target->SetTransform(in_scene_->GetTransform()); - render_target->PushAxisAlignedClip( - D2D1::RectF( - 0.f, - 0.f, - window_size_.width, - window_size_.height - ), - D2D1_ANTIALIAS_MODE_PER_PRIMITIVE + render::instance.PushClip( + in_scene_->GetTransform(), + window_size_ ); - render_target->PushLayer(in_layer_param_, in_layer_); + render::instance.PushLayer(in_layer_, in_layer_prop_); in_scene_->Draw(); - render_target->PopLayer(); - render_target->PopAxisAlignedClip(); + render::instance.PopLayer(); + render::instance.PopClip(); } } @@ -183,7 +159,7 @@ namespace easy2d { Transition::Initialize(prev, next, game); - in_layer_param_.opacity = 0; + in_layer_prop_.opacity = 0; } void BoxTransition::Update() @@ -192,22 +168,22 @@ namespace easy2d if (process_ < .5f) { - out_layer_param_.contentBounds = D2D1::RectF( + out_layer_prop_.area = Rect( window_size_.width * process_, window_size_.height * process_, - window_size_.width * (1 - process_), - window_size_.height * (1 - process_) + window_size_.width * (1 - process_ * 2), + window_size_.height * (1 - process_ * 2) ); } else { - out_layer_param_.opacity = 0; - in_layer_param_.opacity = 1; - in_layer_param_.contentBounds = D2D1::RectF( + out_layer_prop_.opacity = 0; + in_layer_prop_.opacity = 1; + in_layer_prop_.area = Rect( window_size_.width * (1 - process_), window_size_.height * (1 - process_), - window_size_.width * process_, - window_size_.height * process_ + window_size_.width * (2 * process_ - 1), + window_size_.height * (2 * process_ - 1) ); } } @@ -225,16 +201,16 @@ namespace easy2d { Transition::Initialize(prev, next, game); - out_layer_param_.opacity = 1; - in_layer_param_.opacity = 0; + out_layer_prop_.opacity = 1; + in_layer_prop_.opacity = 0; } void EmergeTransition::Update() { Transition::Update(); - out_layer_param_.opacity = 1 - process_; - in_layer_param_.opacity = process_; + out_layer_prop_.opacity = 1 - process_; + in_layer_prop_.opacity = process_; } //------------------------------------------------------- @@ -250,8 +226,8 @@ namespace easy2d { Transition::Initialize(prev, next, game); - out_layer_param_.opacity = 1; - in_layer_param_.opacity = 0; + out_layer_prop_.opacity = 1; + in_layer_prop_.opacity = 0; } void FadeTransition::Update() @@ -260,13 +236,13 @@ namespace easy2d if (process_ < 0.5) { - out_layer_param_.opacity = 1 - process_ * 2; - in_layer_param_.opacity = 0; + out_layer_prop_.opacity = 1 - process_ * 2; + in_layer_prop_.opacity = 0; } else { - out_layer_param_.opacity = 0; - in_layer_param_.opacity = (process_ - 0.5f) * 2; + out_layer_prop_.opacity = 0; + in_layer_prop_.opacity = (process_ - 0.5f) * 2; } } @@ -306,13 +282,13 @@ namespace easy2d if (out_scene_) { - out_scene_->SetTransform(D2D1::Matrix3x2F::Identity()); + out_scene_->SetTransform(math::Matrix()); } if (in_scene_) { in_scene_->SetTransform( - D2D1::Matrix3x2F::Translation( + math::Matrix::Translation( start_pos_.x, start_pos_.y ) @@ -328,7 +304,7 @@ namespace easy2d { auto translation = pos_delta_ * process_; out_scene_->SetTransform( - D2D1::Matrix3x2F::Translation( + math::Matrix::Translation( translation.x, translation.y ) @@ -339,7 +315,7 @@ namespace easy2d { auto translation = start_pos_ + pos_delta_ * process_; in_scene_->SetTransform( - D2D1::Matrix3x2F::Translation( + math::Matrix::Translation( translation.x, translation.y ) @@ -351,12 +327,12 @@ namespace easy2d { if (out_scene_) { - out_scene_->SetTransform(D2D1::Matrix3x2F::Identity()); + out_scene_->SetTransform(math::Matrix()); } if (in_scene_) { - in_scene_->SetTransform(D2D1::Matrix3x2F::Identity()); + in_scene_->SetTransform(math::Matrix()); } } @@ -376,22 +352,22 @@ namespace easy2d if (out_scene_) { - out_scene_->SetTransform(D2D1::Matrix3x2F::Identity()); + out_scene_->SetTransform(math::Matrix()); } if (in_scene_) { - in_scene_->SetTransform(D2D1::Matrix3x2F::Identity()); + in_scene_->SetTransform(math::Matrix()); } - in_layer_param_.opacity = 0; + in_layer_prop_.opacity = 0; } void RotationTransition::Update() { Transition::Update(); - auto center_pos = D2D1::Point2F( + auto center_pos = math::Vector2( window_size_.width / 2, window_size_.height / 2 ); @@ -401,11 +377,11 @@ namespace easy2d if (out_scene_) { out_scene_->SetTransform( - D2D1::Matrix3x2F::Scale( - (.5f - process_) * 2, + math::Matrix::Scaling( + (.5f - process_) * 2, (.5f - process_) * 2, center_pos - ) * D2D1::Matrix3x2F::Rotation( + ) * math::Matrix::Rotation( rotation_ * (.5f - process_) * 2, center_pos ) @@ -416,15 +392,15 @@ namespace easy2d { if (in_scene_) { - out_layer_param_.opacity = 0; - in_layer_param_.opacity = 1; + out_layer_prop_.opacity = 0; + in_layer_prop_.opacity = 1; in_scene_->SetTransform( - D2D1::Matrix3x2F::Scale( + math::Matrix::Scaling( (process_ - .5f) * 2, (process_ - .5f) * 2, center_pos - ) * D2D1::Matrix3x2F::Rotation( + ) * math::Matrix::Rotation( rotation_ * (process_ - .5f) * 2, center_pos ) @@ -437,12 +413,12 @@ namespace easy2d { if (out_scene_) { - out_scene_->SetTransform(D2D1::Matrix3x2F::Identity()); + out_scene_->SetTransform(math::Matrix()); } if (in_scene_) { - in_scene_->SetTransform(D2D1::Matrix3x2F::Identity()); + in_scene_->SetTransform(math::Matrix()); } } } diff --git a/core/base/Transition.h b/core/base/Transition.h index d8fc34db..29c3e237 100644 --- a/core/base/Transition.h +++ b/core/base/Transition.h @@ -21,6 +21,7 @@ #pragma once #include "base.h" #include "time.h" +#include "render.h" #include "RefCounter.h" namespace easy2d @@ -65,17 +66,17 @@ namespace easy2d virtual void Reset() { }; protected: - bool done_; - float duration_; - float process_; + bool done_; + float duration_; + float process_; time::TimePoint started_; - Size window_size_; - Scene* out_scene_; - Scene* in_scene_; - ID2D1Layer * out_layer_; - ID2D1Layer * in_layer_; - D2D1_LAYER_PARAMETERS out_layer_param_; - D2D1_LAYER_PARAMETERS in_layer_param_; + Size window_size_; + Scene* out_scene_; + Scene* in_scene_; + ID2D1Layer* out_layer_; + ID2D1Layer* in_layer_; + render::LayerProperties out_layer_prop_; + render::LayerProperties in_layer_prop_; }; diff --git a/core/base/render.cpp b/core/base/render.cpp index 55dbf181..6344daff 100644 --- a/core/base/render.cpp +++ b/core/base/render.cpp @@ -30,17 +30,31 @@ namespace easy2d { namespace render { - _D2D_Resource D2D = { 0 }; + GraphicsDevice instance; - void easy2d::render::Initialize(HWND hwnd) + GraphicsDevice::GraphicsDevice() + : fps_text_format_(nullptr) + , fps_text_layout_(nullptr) + , clear_color_(D2D1::ColorF(D2D1::ColorF::Black)) { - if (D2D.Factory) + ZeroMemory(&d2d, sizeof(D2DResources)); + } + + GraphicsDevice::~GraphicsDevice() + { + SafeRelease(fps_text_format_); + SafeRelease(fps_text_layout_); + } + + void GraphicsDevice::Initialize(HWND hwnd) + { + if (d2d.Factory) return; ThrowIfFailed( D2D1CreateFactory( D2D1_FACTORY_TYPE_SINGLE_THREADED, - &D2D.Factory + &d2d.Factory ) ); @@ -50,7 +64,7 @@ namespace easy2d nullptr, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, - reinterpret_cast(&D2D.WICImagingFactory) + reinterpret_cast(&d2d.WICImagingFactory) ) ); @@ -58,7 +72,7 @@ namespace easy2d DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), - reinterpret_cast(&D2D.DWriteFactory) + reinterpret_cast(&d2d.DWriteFactory) ) ); @@ -73,132 +87,65 @@ namespace easy2d ); ThrowIfFailed( - D2D.Factory->CreateStrokeStyle( + d2d.Factory->CreateStrokeStyle( stroke_style, nullptr, 0, - &D2D.MiterStrokeStyle + &d2d.MiterStrokeStyle ) ); stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL; ThrowIfFailed( - D2D.Factory->CreateStrokeStyle( + d2d.Factory->CreateStrokeStyle( stroke_style, nullptr, 0, - &D2D.BevelStrokeStyle + &d2d.BevelStrokeStyle ) ); stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND; ThrowIfFailed( - D2D.Factory->CreateStrokeStyle( + d2d.Factory->CreateStrokeStyle( stroke_style, nullptr, 0, - &D2D.RoundStrokeStyle + &d2d.RoundStrokeStyle ) ); CreateDeviceResources(hwnd); } - void easy2d::render::CreateDeviceResources(HWND hwnd) + void GraphicsDevice::Uninitialize() { - if (!D2D.HwndRenderTarget) - { - RECT rc; - ::GetClientRect(hwnd, &rc); + SafeRelease(d2d.TextRenderer); + SafeRelease(d2d.SolidColorBrush); + SafeRelease(d2d.HwndRenderTarget); - D2D1_SIZE_U size = D2D1::SizeU( - rc.right - rc.left, - rc.bottom - rc.top - ); + SafeRelease(d2d.MiterStrokeStyle); + SafeRelease(d2d.BevelStrokeStyle); + SafeRelease(d2d.RoundStrokeStyle); - // 创建设备相关资源。这些资源应在 Direct2D 设备消失时重建 - // 创建一个 Direct2D 渲染目标 - ThrowIfFailed( - D2D.Factory->CreateHwndRenderTarget( - D2D1::RenderTargetProperties(), - D2D1::HwndRenderTargetProperties( - hwnd, - size, - D2D1_PRESENT_OPTIONS_NONE), - &D2D.HwndRenderTarget - ) - ); - } - - if (!D2D.SolidColorBrush) - { - ThrowIfFailed( - D2D.HwndRenderTarget->CreateSolidColorBrush( - D2D1::ColorF(D2D1::ColorF::White), - &D2D.SolidColorBrush - ) - ); - } - - if (!D2D.TextRenderer) - { - ThrowIfFailed( - ITextRenderer::Create( - &D2D.TextRenderer, - D2D.Factory, - D2D.HwndRenderTarget, - D2D.SolidColorBrush - ) - ); - } - } - - void easy2d::render::Uninitialize() - { - SafeRelease(D2D.TextRenderer); - SafeRelease(D2D.SolidColorBrush); - SafeRelease(D2D.HwndRenderTarget); - - SafeRelease(D2D.MiterStrokeStyle); - SafeRelease(D2D.BevelStrokeStyle); - SafeRelease(D2D.RoundStrokeStyle); - - SafeRelease(D2D.WICImagingFactory); - SafeRelease(D2D.DWriteFactory); - SafeRelease(D2D.Factory); - } - - //------------------------------------------------------- - // GraphicsDevice - //------------------------------------------------------- - - GraphicsDevice instance; - - GraphicsDevice::GraphicsDevice() - : fps_text_format_(nullptr) - , fps_text_layout_(nullptr) - , clear_color_(D2D1::ColorF(D2D1::ColorF::Black)) - { - } - - GraphicsDevice::~GraphicsDevice() - { - SafeRelease(fps_text_format_); - SafeRelease(fps_text_layout_); + SafeRelease(d2d.WICImagingFactory); + SafeRelease(d2d.DWriteFactory); + SafeRelease(d2d.Factory); } void GraphicsDevice::BeginDraw(HWND hwnd) { - render::CreateDeviceResources(hwnd); - render::D2D.HwndRenderTarget->BeginDraw(); - render::D2D.HwndRenderTarget->Clear(clear_color_); + CreateDeviceResources(hwnd); + + d2d.HwndRenderTarget->BeginDraw(); + d2d.HwndRenderTarget->Clear(clear_color_); } void GraphicsDevice::EndDraw() { - HRESULT hr = render::D2D.HwndRenderTarget->EndDraw(); + HRESULT hr = d2d.HwndRenderTarget->EndDraw(); if (hr == D2DERR_RECREATE_TARGET) { @@ -208,14 +155,426 @@ namespace easy2d SafeRelease(fps_text_format_); SafeRelease(fps_text_layout_); - SafeRelease(render::D2D.TextRenderer); - SafeRelease(render::D2D.SolidColorBrush); - SafeRelease(render::D2D.HwndRenderTarget); + SafeRelease(d2d.TextRenderer); + SafeRelease(d2d.SolidColorBrush); + SafeRelease(d2d.HwndRenderTarget); } ThrowIfFailed(hr); } + HRESULT GraphicsDevice::CreateRectGeometry( + const math::Matrix& matrix, + const Size& size, + ID2D1Geometry** geometry + ) const + { + if (!d2d.Factory) + return E_UNEXPECTED; + + HRESULT hr; + + ID2D1RectangleGeometry * rectangle = nullptr; + ID2D1TransformedGeometry * transformed = nullptr; + + hr = d2d.Factory->CreateRectangleGeometry( + D2D1::RectF(0, 0, size.width, size.height), + &rectangle + ); + + if (SUCCEEDED(hr)) + { + hr = d2d.Factory->CreateTransformedGeometry( + rectangle, + matrix, + &transformed + ); + } + + if (SUCCEEDED(hr)) + { + *geometry = transformed; + } + + SafeRelease(rectangle); + return hr; + } + + HRESULT GraphicsDevice::CreateTextFormat(IDWriteTextFormat ** text_format, const Font & font) const + { + if (!d2d.DWriteFactory) + return E_UNEXPECTED; + + return d2d.DWriteFactory->CreateTextFormat( + font.family.c_str(), + nullptr, + DWRITE_FONT_WEIGHT(font.weight), + font.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, + DWRITE_FONT_STRETCH_NORMAL, + font.size, + L"", + text_format + ); + } + + HRESULT GraphicsDevice::CreateTextLayout(IDWriteTextLayout ** text_layout, const String & text, IDWriteTextFormat * text_format, float wrap_width) const + { + if (!d2d.DWriteFactory) + return E_UNEXPECTED; + + UINT32 length = static_cast(text.length()); + return d2d.DWriteFactory->CreateTextLayout( + text.c_str(), + length, + text_format, + wrap_width, + 0, + text_layout + ); + } + + HRESULT GraphicsDevice::CreateLayer(ID2D1Layer ** layer) + { + if (!d2d.HwndRenderTarget) + return E_UNEXPECTED; + + return d2d.HwndRenderTarget->CreateLayer(layer); + } + + HRESULT GraphicsDevice::DrawGeometry( + ID2D1Geometry * geometry, + const Color & border_color, + float opacity, + float stroke_width, + StrokeStyle stroke + ) + { + if (!d2d.SolidColorBrush || + !d2d.HwndRenderTarget) + return E_UNEXPECTED; + + d2d.SolidColorBrush->SetColor(border_color); + d2d.SolidColorBrush->SetOpacity(opacity); + d2d.HwndRenderTarget->DrawGeometry( + geometry, + d2d.SolidColorBrush, + stroke_width, + GetStrokeStyle(stroke) + ); + return S_OK; + } + + ID2D1StrokeStyle * GraphicsDevice::GetStrokeStyle(StrokeStyle stroke) const + { + ID2D1StrokeStyle * stroke_style = nullptr; + switch (stroke) + { + case StrokeStyle::Miter: + stroke_style = d2d.MiterStrokeStyle; + break; + case StrokeStyle::Bevel: + stroke_style = d2d.BevelStrokeStyle; + break; + case StrokeStyle::Round: + stroke_style = d2d.RoundStrokeStyle; + break; + } + return stroke_style; + } + + HRESULT GraphicsDevice::DrawImage( + Image * image, + float opacity, + const Rect & dest_rect, + const Rect & source_rect + ) + { + if (!d2d.HwndRenderTarget) + return E_UNEXPECTED; + + d2d.HwndRenderTarget->DrawBitmap( + image->GetBitmap(), + dest_rect, + opacity, + D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, + source_rect + ); + return S_OK; + } + + HRESULT GraphicsDevice::DrawTextLayout(IDWriteTextLayout * text_layout) + { + if (!d2d.TextRenderer) + return E_UNEXPECTED; + + return text_layout->Draw(nullptr, d2d.TextRenderer, 0, 0); + } + + HRESULT GraphicsDevice::PushClip(const math::Matrix & clip_matrix, const Size & clip_size) + { + if (!d2d.HwndRenderTarget) + return E_UNEXPECTED; + + d2d.HwndRenderTarget->SetTransform(clip_matrix); + d2d.HwndRenderTarget->PushAxisAlignedClip( + D2D1::RectF(0, 0, clip_size.width, clip_size.height), + D2D1_ANTIALIAS_MODE_PER_PRIMITIVE + ); + return S_OK; + } + + HRESULT GraphicsDevice::PopClip() + { + if (!d2d.HwndRenderTarget) + return E_UNEXPECTED; + + d2d.HwndRenderTarget->PopAxisAlignedClip(); + return S_OK; + } + + HRESULT GraphicsDevice::PushLayer(ID2D1Layer * layer, LayerProperties properties) + { + if (!d2d.HwndRenderTarget || + !d2d.SolidColorBrush) + return E_UNEXPECTED; + + d2d.HwndRenderTarget->PushLayer( + D2D1::LayerParameters( + properties.area, + nullptr, + D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, + D2D1::Matrix3x2F::Identity(), + properties.opacity, + d2d.SolidColorBrush, + D2D1_LAYER_OPTIONS_NONE + ), + layer + ); + return S_OK; + } + + HRESULT GraphicsDevice::PopLayer() + { + if (!d2d.HwndRenderTarget) + return E_UNEXPECTED; + + d2d.HwndRenderTarget->PopLayer(); + return S_OK; + } + + HRESULT GraphicsDevice::CreateBitmapFromFile(const String & file_path, ID2D1Bitmap ** bitmap) + { + if (d2d.WICImagingFactory == nullptr || + d2d.HwndRenderTarget == nullptr) + { + return E_UNEXPECTED; + } + + if (bitmap == nullptr) + { + return E_POINTER; + } + + IWICBitmapDecoder* decoder = nullptr; + IWICBitmapFrameDecode* source = nullptr; + IWICStream* stream = nullptr; + IWICFormatConverter* converter = nullptr; + + // 创建解码器 + HRESULT hr = d2d.WICImagingFactory->CreateDecoderFromFilename( + file_path.c_str(), + nullptr, + GENERIC_READ, + WICDecodeMetadataCacheOnLoad, + &decoder + ); + + if (SUCCEEDED(hr)) + { + // 创建初始化框架 + hr = decoder->GetFrame(0, &source); + } + + if (SUCCEEDED(hr)) + { + // 创建图片格式转换器 + hr = d2d.WICImagingFactory->CreateFormatConverter(&converter); + } + + if (SUCCEEDED(hr)) + { + // 图片格式转换成 32bppPBGRA + hr = converter->Initialize( + source, + GUID_WICPixelFormat32bppPBGRA, + WICBitmapDitherTypeNone, + nullptr, + 0.f, + WICBitmapPaletteTypeMedianCut + ); + } + + if (SUCCEEDED(hr)) + { + // 从 WIC 位图创建一个 Direct2D 位图 + hr = d2d.HwndRenderTarget->CreateBitmapFromWicBitmap( + converter, + nullptr, + bitmap + ); + } + + // 释放相关资源 + SafeRelease(decoder); + SafeRelease(source); + SafeRelease(stream); + SafeRelease(converter); + + return hr; + } + + HRESULT GraphicsDevice::CreateBitmapFromResource(Resource & res, ID2D1Bitmap ** bitmap) + { + if (d2d.WICImagingFactory == nullptr || + d2d.HwndRenderTarget == nullptr) + { + return E_UNEXPECTED; + } + + if (bitmap == nullptr) + { + return E_POINTER; + } + + HRESULT hr; + + HINSTANCE hinstance = GetModuleHandle(nullptr); + IWICBitmapDecoder* decoder = nullptr; + IWICBitmapFrameDecode* source = nullptr; + IWICStream* stream = nullptr; + IWICFormatConverter* converter = nullptr; + + // 加载资源 + hr = res.Load() ? S_OK : E_FAIL; + + if (SUCCEEDED(hr)) + { + // 创建 WIC 流 + hr = d2d.WICImagingFactory->CreateStream(&stream); + } + + if (SUCCEEDED(hr)) + { + // 初始化流 + hr = stream->InitializeFromMemory( + static_cast(res.GetData()), + res.GetDataSize() + ); + } + + if (SUCCEEDED(hr)) + { + // 创建流的解码器 + hr = d2d.WICImagingFactory->CreateDecoderFromStream( + stream, + nullptr, + WICDecodeMetadataCacheOnLoad, + &decoder + ); + } + + if (SUCCEEDED(hr)) + { + // 创建初始化框架 + hr = decoder->GetFrame(0, &source); + } + + if (SUCCEEDED(hr)) + { + // 创建图片格式转换器 + hr = d2d.WICImagingFactory->CreateFormatConverter(&converter); + } + + if (SUCCEEDED(hr)) + { + // 图片格式转换成 32bppPBGRA + hr = converter->Initialize( + source, + GUID_WICPixelFormat32bppPBGRA, + WICBitmapDitherTypeNone, + nullptr, + 0.f, + WICBitmapPaletteTypeMedianCut + ); + } + + if (SUCCEEDED(hr)) + { + // 从 WIC 位图创建一个 Direct2D 位图 + hr = d2d.HwndRenderTarget->CreateBitmapFromWicBitmap( + converter, + nullptr, + bitmap + ); + } + + // 释放相关资源 + SafeRelease(decoder); + SafeRelease(source); + SafeRelease(stream); + SafeRelease(converter); + + return hr; + } + + HRESULT GraphicsDevice::Resize(UINT32 width, UINT32 height) + { + if (!d2d.HwndRenderTarget) + return E_UNEXPECTED; + + d2d.HwndRenderTarget->Resize(D2D1::SizeU(width, height)); + return S_OK; + } + + HRESULT GraphicsDevice::SetTransform(const math::Matrix & matrix) + { + if (!d2d.HwndRenderTarget) + return E_UNEXPECTED; + + d2d.HwndRenderTarget->SetTransform(matrix); + return S_OK; + } + + HRESULT GraphicsDevice::SetBrushOpacity(float opacity) + { + if (!d2d.HwndRenderTarget) + return E_UNEXPECTED; + + d2d.SolidColorBrush->SetOpacity(opacity); + return S_OK; + } + + HRESULT GraphicsDevice::SetTextStyle( + const Color & color, + bool has_outline, + const Color & outline_color, + float outline_width, + StrokeStyle outline_stroke + ) + { + if (!d2d.TextRenderer) + return E_UNEXPECTED; + + d2d.TextRenderer->SetTextStyle( + color, + has_outline, + outline_color, + outline_width, + static_cast(outline_stroke) + ); + return S_OK; + } + void GraphicsDevice::SetBackgroundColor(const Color& color) { clear_color_ = color; @@ -231,7 +590,7 @@ namespace easy2d if (!fps_text_format_) { ThrowIfFailed( - render::D2D.DWriteFactory->CreateTextFormat( + d2d.DWriteFactory->CreateTextFormat( L"", nullptr, DWRITE_FONT_WEIGHT_NORMAL, @@ -262,7 +621,7 @@ namespace easy2d SafeRelease(fps_text_layout_); ThrowIfFailed( - render::D2D.DWriteFactory->CreateTextLayout( + d2d.DWriteFactory->CreateTextLayout( fps_text, static_cast(len), fps_text_format_, @@ -275,9 +634,9 @@ namespace easy2d if (fps_text_layout_) { - render::D2D.HwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); - render::D2D.SolidColorBrush->SetOpacity(1.0f); - render::D2D.TextRenderer->SetTextStyle( + d2d.HwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); + d2d.SolidColorBrush->SetOpacity(1.0f); + d2d.TextRenderer->SetTextStyle( D2D1::ColorF(D2D1::ColorF::White), TRUE, D2D1::ColorF(D2D1::ColorF::Black, 0.4f), @@ -285,7 +644,56 @@ namespace easy2d D2D1_LINE_JOIN_ROUND ); - fps_text_layout_->Draw(nullptr, render::D2D.TextRenderer, 10, 0); + fps_text_layout_->Draw(nullptr, d2d.TextRenderer, 10, 0); + } + } + + void GraphicsDevice::CreateDeviceResources(HWND hwnd) + { + if (!d2d.HwndRenderTarget) + { + RECT rc; + ::GetClientRect(hwnd, &rc); + + D2D1_SIZE_U size = D2D1::SizeU( + rc.right - rc.left, + rc.bottom - rc.top + ); + + // 创建设备相关资源。这些资源应在 Direct2D 设备消失时重建 + // 创建一个 Direct2D 渲染目标 + ThrowIfFailed( + d2d.Factory->CreateHwndRenderTarget( + D2D1::RenderTargetProperties(), + D2D1::HwndRenderTargetProperties( + hwnd, + size, + D2D1_PRESENT_OPTIONS_NONE), + &d2d.HwndRenderTarget + ) + ); + } + + if (!d2d.SolidColorBrush) + { + ThrowIfFailed( + d2d.HwndRenderTarget->CreateSolidColorBrush( + D2D1::ColorF(D2D1::ColorF::White), + &d2d.SolidColorBrush + ) + ); + } + + if (!d2d.TextRenderer) + { + ThrowIfFailed( + ITextRenderer::Create( + &d2d.TextRenderer, + d2d.Factory, + d2d.HwndRenderTarget, + d2d.SolidColorBrush + ) + ); } } } diff --git a/core/base/render.h b/core/base/render.h index 47ab40dc..2d446bd0 100644 --- a/core/base/render.h +++ b/core/base/render.h @@ -20,7 +20,11 @@ #pragma once #include "base.h" +#include "Font.h" +#include "Resource.h" +#include "Image.h" #include "TextRenderer.h" +#include "../math/Matrix.hpp" namespace easy2d { @@ -37,15 +41,13 @@ namespace easy2d ID2D1StrokeStyle* MiterStrokeStyle; ID2D1StrokeStyle* BevelStrokeStyle; ID2D1StrokeStyle* RoundStrokeStyle; - } _D2D_Resource; + } D2DResources; - extern _D2D_Resource D2D; - - void Initialize(HWND hwnd); - - void CreateDeviceResources(HWND hwnd); - - void Uninitialize(); + typedef struct + { + Rect area; + float opacity; + } LayerProperties; class GraphicsDevice { @@ -54,24 +56,121 @@ namespace easy2d ~GraphicsDevice(); + void Initialize(HWND hwnd); + + void Uninitialize(); + // 开始渲染 void BeginDraw(HWND hwnd); // 结束渲染 void EndDraw(); - // 渲染调试信息 - void DrawDebugInfo(); - // 设置背景色 void SetBackgroundColor( const Color& color ); + // 渲染调试信息 + void DrawDebugInfo(); + + void CreateDeviceResources(HWND hwnd); + + HRESULT CreateRectGeometry( + const math::Matrix& matrix, + const Size& size, + ID2D1Geometry** geometry + ) const; + + HRESULT CreateTextFormat( + IDWriteTextFormat** text_format, + const Font& font + ) const; + + HRESULT CreateTextLayout( + IDWriteTextLayout** text_layout, + const String& text, + IDWriteTextFormat* text_format, + float wrap_width + ) const; + + HRESULT CreateLayer( + ID2D1Layer** layer + ); + + ID2D1StrokeStyle* GetStrokeStyle( + StrokeStyle stroke + ) const; + + HRESULT SetTransform( + const math::Matrix& matrix + ); + + HRESULT SetBrushOpacity( + float opacity + ); + + HRESULT SetTextStyle( + const Color& color, + bool has_outline, + const Color& outline_color, + float outline_width, + StrokeStyle outline_stroke + ); + + HRESULT DrawGeometry( + ID2D1Geometry* geometry, + const Color& border_color, + float opacity, + float stroke_width, + StrokeStyle stroke = StrokeStyle::Miter + ); + + HRESULT DrawImage( + Image* image, + float opacity, + const Rect& dest_rect, + const Rect& source_rect + ); + + HRESULT DrawTextLayout( + IDWriteTextLayout* text_layout + ); + + HRESULT PushClip( + const math::Matrix& clip_matrix, + const Size& clip_size + ); + + HRESULT PopClip(); + + HRESULT PushLayer( + ID2D1Layer* layer, + LayerProperties properties + ); + + HRESULT PopLayer(); + + HRESULT CreateBitmapFromFile( + const String& file_path, + ID2D1Bitmap** bitmap + ); + + HRESULT CreateBitmapFromResource( + Resource& res, + ID2D1Bitmap** bitmap + ); + + HRESULT Resize( + UINT32 width, + UINT32 height + ); + protected: D2D1_COLOR_F clear_color_; IDWriteTextFormat* fps_text_format_; IDWriteTextLayout* fps_text_layout_; + D2DResources d2d; }; extern GraphicsDevice instance; diff --git a/core/base/time.cpp b/core/base/time.cpp index a1f1e323..62bf2c3a 100644 --- a/core/base/time.cpp +++ b/core/base/time.cpp @@ -173,21 +173,16 @@ namespace easy2d std::wstring easy2d::time::Duration::ToString() const { - std::wstring result; - int64_t ms = milliseconds_ % Second.milliseconds_; - int64_t sec = milliseconds_ / Second.milliseconds_; - int64_t min = milliseconds_ / Minute.milliseconds_; - int64_t hour = milliseconds_ / Hour.milliseconds_; - - min -= hour * 60; - sec -= (hour * 60 * 60 + min * 60); - - auto float_to_str = [](float val) -> std::wstring + if (milliseconds_ == 0LL) { - wchar_t buf[10] = {}; - ::swprintf_s(buf, L"%.2f", val); - return std::wstring(buf); - }; + return std::wstring(L"0s"); + } + + std::wstring result; + int64_t hour = milliseconds_ / Hour.milliseconds_; + int64_t min = milliseconds_ / Minute.milliseconds_ - hour * 60; + int64_t sec = milliseconds_ / Second.milliseconds_ - (hour * 60 * 60 + min * 60); + int64_t ms = milliseconds_ % Second.milliseconds_; if (milliseconds_ < 0) result.append(L"-"); @@ -202,19 +197,22 @@ namespace easy2d result.append(std::to_wstring(min)).append(L"m"); } - if (sec == 0 && ms == 0) - { - result.append(L"0s"); - } - else if (ms == 0) - { - result.append(std::to_wstring(sec)).append(L"s"); - } - else + if (ms != 0) { + auto float_to_str = [](float val) -> std::wstring + { + wchar_t buf[10] = {}; + ::swprintf_s(buf, L"%.2f", val); + return std::wstring(buf); + }; + result.append(float_to_str(static_cast(sec) + static_cast(ms) / 1000.f)) .append(L"s"); } + else if (sec != 0) + { + result.append(std::to_wstring(sec)).append(L"s"); + } return result; } diff --git a/core/base/window.cpp b/core/base/window.cpp index ddcc67df..5cf11407 100644 --- a/core/base/window.cpp +++ b/core/base/window.cpp @@ -306,11 +306,7 @@ namespace easy2d // 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染 // 目标的大小。它可能会调用失败,但是这里可以忽略有可能的 // 错误,因为这个错误将在下一次调用 EndDraw 时产生 - auto render_target = render::D2D.HwndRenderTarget; - if (render_target) - { - render_target->Resize(D2D1::SizeU(width, height)); - } + render::instance.Resize(width, height); } break; diff --git a/core/math/Matrix.hpp b/core/math/Matrix.hpp index baf613be..367d5b64 100644 --- a/core/math/Matrix.hpp +++ b/core/math/Matrix.hpp @@ -20,6 +20,7 @@ #pragma once #include "vector.hpp" +#include namespace easy2d { @@ -73,6 +74,15 @@ namespace easy2d ); } + inline operator D2D1_MATRIX_3X2_F () const + { + return D2D1_MATRIX_3X2_F{ + _11, _12, + _21, _22, + _31, _32 + }; + } + inline Matrix& Identity() { _11 = 1.f; @@ -90,12 +100,24 @@ namespace easy2d return *this; } + inline Matrix& Translate(float x, float y) + { + *this = *this * Matrix::Translation(x, y); + return *this; + } + inline Matrix& Scale(const Vector2& v, const Vector2& center) { *this = *this * Matrix::Scaling(v, center); return *this; } + inline Matrix& Scale(float xscale, float yscale, const Vector2& center) + { + *this = *this * Matrix::Scaling(xscale, yscale, center); + return *this; + } + inline Matrix& Rotate(float angle, const Vector2& center) { *this = *this * Matrix::Rotation(angle, center); diff --git a/core/math/Transform.cpp b/core/math/Transform.cpp index ecfe3192..fa691f61 100644 --- a/core/math/Transform.cpp +++ b/core/math/Transform.cpp @@ -37,25 +37,13 @@ namespace easy2d { } - Transform::operator D2D1::Matrix3x2F() const + Matrix Transform::ToMatrix() const { - auto pivot = D2D1::Point2F(size.width * pivot_x, size.height * pivot_y); - auto matrix = D2D1::Matrix3x2F::Scale( - scale_x, - scale_y, - pivot - ) * D2D1::Matrix3x2F::Skew( - skew_x, - skew_y, - pivot - ) * D2D1::Matrix3x2F::Rotation( - rotation, - pivot - ) * D2D1::Matrix3x2F::Translation( - position.x - pivot.x, - position.y - pivot.y - ); - return matrix; + auto pivot = Vector2(size.width * pivot_x, size.height * pivot_y); + return Matrix().Scale(scale_x, scale_y, pivot) + .Skew(skew_x, skew_y, pivot) + .Rotate(rotation, pivot) + .Translate(position - pivot); } bool Transform::operator==(const Transform & other) const diff --git a/core/math/Transform.h b/core/math/Transform.h index b733ea18..6af36321 100644 --- a/core/math/Transform.h +++ b/core/math/Transform.h @@ -21,7 +21,7 @@ #pragma once #include "../base/BaseTypes.h" #include "../base/Size.h" -#include +#include "Matrix.hpp" namespace easy2d { @@ -43,7 +43,7 @@ namespace easy2d public: Transform(); - explicit operator D2D1::Matrix3x2F() const; + Matrix ToMatrix() const; bool operator== (const Transform& other) const; }; diff --git a/core/math/vector.hpp b/core/math/vector.hpp index abbe020c..311e8aa5 100644 --- a/core/math/vector.hpp +++ b/core/math/vector.hpp @@ -20,6 +20,7 @@ #pragma once #include "scalar.hpp" +#include namespace easy2d { @@ -85,6 +86,11 @@ namespace easy2d { return Vector2(x - v.x, y - v.y).Length(); } + + inline operator D2D1_POINT_2F () const + { + return D2D1_POINT_2F{ x, y }; + } }; } } \ No newline at end of file