update: GraphicsDevice owns all Direct2D resources

This commit is contained in:
Haibo 2018-11-12 02:10:35 +08:00 committed by Nomango
parent c474d259c5
commit 2b366e42be
27 changed files with 861 additions and 545 deletions

View File

@ -46,8 +46,8 @@ namespace easy2d
Right /* ÓÒ */ Right /* ÓÒ */
}; };
// ÏßÌõÏཻÑùʽ // »­±ÊÑùʽ
enum class Stroke : int enum class StrokeStyle : int
{ {
Miter = 0, /* бÇÐ */ Miter = 0, /* бÇÐ */
Bevel = 1, /* б½Ç */ Bevel = 1, /* б½Ç */

View File

@ -24,15 +24,21 @@
namespace easy2d namespace easy2d
{ {
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
// FIXME!!!
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
Canvas::Canvas(float width, float height) Canvas::Canvas(float width, float height)
: render_target_(nullptr) : render_target_(nullptr)
, fill_brush_(nullptr) , fill_brush_(nullptr)
, line_brush_(nullptr) , line_brush_(nullptr)
, stroke_style_(nullptr) , stroke_style_(nullptr)
, stroke_width_(1.0f) , stroke_width_(1.0f)
, stroke_(Stroke::Miter) , stroke_(StrokeStyle::Miter)
{ {
render_target_ = render::D2D.HwndRenderTarget; // render_target_ = render::D2D.HwndRenderTarget;
render_target_->AddRef(); render_target_->AddRef();
ThrowIfFailed( ThrowIfFailed(
@ -78,22 +84,11 @@ namespace easy2d
stroke_width_ = std::max(width, 0.f); stroke_width_ = std::max(width, 0.f);
} }
void Canvas::SetStrokeStyle(Stroke strokeStyle) void Canvas::SetStrokeStyle(StrokeStyle stroke)
{ {
SafeRelease(stroke_style_); SafeRelease(stroke_style_);
switch (strokeStyle) stroke_style_ = render::instance.GetStrokeStyle(stroke);
{
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;
}
if (stroke_style_) if (stroke_style_)
stroke_style_->AddRef(); stroke_style_->AddRef();
@ -114,7 +109,7 @@ namespace easy2d
return stroke_width_; return stroke_width_;
} }
Stroke Canvas::GetStrokeStyle() const StrokeStyle Canvas::GetStrokeStyle() const
{ {
return stroke_; return stroke_;
} }

View File

@ -53,7 +53,7 @@ namespace easy2d
// ÉèÖÃÏßÌõÏཻÑùʽ // ÉèÖÃÏßÌõÏཻÑùʽ
void SetStrokeStyle( void SetStrokeStyle(
Stroke strokeStyle StrokeStyle stroke
); );
// »ñÈ¡ÏßÌõÑÕÉ« // »ñÈ¡ÏßÌõÑÕÉ«
@ -66,7 +66,7 @@ namespace easy2d
float GetStrokeWidth() const; float GetStrokeWidth() const;
// »ñÈ¡ÏßÌõÏཻÑùʽ // »ñÈ¡ÏßÌõÏཻÑùʽ
Stroke GetStrokeStyle() const; StrokeStyle GetStrokeStyle() const;
// »­Ö±Ïß // »­Ö±Ïß
void DrawLine( void DrawLine(
@ -129,7 +129,7 @@ namespace easy2d
private: private:
float stroke_width_; float stroke_width_;
Stroke stroke_; StrokeStyle stroke_;
ID2D1RenderTarget* render_target_; ID2D1RenderTarget* render_target_;
ID2D1SolidColorBrush* fill_brush_; ID2D1SolidColorBrush* fill_brush_;
ID2D1SolidColorBrush* line_brush_; ID2D1SolidColorBrush* line_brush_;

View File

@ -80,9 +80,4 @@ namespace easy2d
, a(color.a) , a(color.a)
{ {
} }
Color::operator D2D1_COLOR_F() const
{
return D2D1::ColorF(r, g, b, a);
}
} }

View File

@ -63,7 +63,10 @@ namespace easy2d
const D2D1_COLOR_F& color 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: public:
enum Value : unsigned int enum Value : unsigned int

View File

@ -23,12 +23,13 @@
#include "Scene.h" #include "Scene.h"
#include "Transition.h" #include "Transition.h"
#include "Image.h" #include "Image.h"
#include "../utils/Player.h"
#include "time.h" #include "time.h"
#include "render.h" #include "render.h"
#include "input.h" #include "input.h"
#include "audio.h" #include "audio.h"
#include "modules.h" #include "modules.h"
#include "../utils/Player.h"
#include "../math/Matrix.hpp"
#include <thread> #include <thread>
namespace easy2d namespace easy2d
@ -68,7 +69,7 @@ namespace easy2d
Image::ClearCache(); Image::ClearCache();
Player::ClearCache(); Player::ClearCache();
render::Uninitialize(); render::instance.Uninitialize();
audio::instance.Uninitialize(); audio::instance.Uninitialize();
window::instance.Destroy(); window::instance.Destroy();
modules::Uninitialize(); modules::Uninitialize();
@ -82,8 +83,8 @@ namespace easy2d
{ {
modules::Initialize(); modules::Initialize();
window::instance.Initialize(property); window::instance.Initialize(property);
render::instance.Initialize(window::instance.handle);
audio::instance.Initialize(); audio::instance.Initialize();
render::Initialize(window::instance.handle);
// 若开启了调试模式,打开控制台 // 若开启了调试模式,打开控制台
HWND console = ::GetConsoleWindow(); HWND console = ::GetConsoleWindow();
@ -291,14 +292,14 @@ namespace easy2d
{ {
if (curr_scene_ && curr_scene_->GetRoot()) if (curr_scene_ && curr_scene_->GetRoot())
{ {
render::D2D.HwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); render::instance.SetTransform(math::Matrix());
render::D2D.SolidColorBrush->SetOpacity(1.f); render::instance.SetBrushOpacity(1.f);
curr_scene_->GetRoot()->DrawBorder(); curr_scene_->GetRoot()->DrawBorder();
} }
if (next_scene_ && next_scene_->GetRoot()) if (next_scene_ && next_scene_->GetRoot())
{ {
render::D2D.HwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); render::instance.SetTransform(math::Matrix());
render::D2D.SolidColorBrush->SetOpacity(1.f); render::instance.SetBrushOpacity(1.f);
next_scene_->GetRoot()->DrawBorder(); next_scene_->GetRoot()->DrawBorder();
} }

View File

@ -20,6 +20,7 @@
#include "Image.h" #include "Image.h"
#include "render.h" #include "render.h"
#include "logs.h"
#include "../utils/File.h" #include "../utils/File.h"
namespace easy2d namespace easy2d
@ -193,91 +194,17 @@ namespace easy2d
return true; 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; ID2D1Bitmap* bitmap = nullptr;
HRESULT hr = render::instance.CreateBitmapFromResource(res, &bitmap);
// 加载资源
hr = res.Load() ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
// 创建 WIC 流
hr = imaging_factory->CreateStream(&stream);
}
if (SUCCEEDED(hr))
{
// 初始化流
hr = stream->InitializeFromMemory(
static_cast<WICInProcPointer>(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
);
}
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
bitmap_cache_.insert(std::make_pair(hash_code, bitmap)); bitmap_cache_.insert(std::make_pair(hash_code, bitmap));
} }
else
// 释放相关资源 {
SafeRelease(decoder); logs::Trace(L"CreateBitmapFromFile", hr);
SafeRelease(source); }
SafeRelease(stream);
SafeRelease(converter);
return SUCCEEDED(hr); return SUCCEEDED(hr);
} }
@ -296,68 +223,17 @@ namespace easy2d
// 默认搜索路径,所以需要通过 File::GetPath 获取完整路径 // 默认搜索路径,所以需要通过 File::GetPath 获取完整路径
String image_file_path = image_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; ID2D1Bitmap* bitmap = nullptr;
HRESULT hr = render::instance.CreateBitmapFromFile(file_name, &bitmap);
// 创建解码器
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
);
}
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
bitmap_cache_.insert(std::make_pair(hash_code, bitmap)); bitmap_cache_.insert(std::make_pair(hash_code, bitmap));
} }
else
// 释放相关资源 {
SafeRelease(decoder); logs::Trace(L"CreateBitmapFromFile", hr);
SafeRelease(source); }
SafeRelease(stream);
SafeRelease(converter);
return SUCCEEDED(hr); return SUCCEEDED(hr);
} }

View File

@ -44,8 +44,8 @@ namespace easy2d
, children_() , children_()
, actions_() , actions_()
, tasks_() , tasks_()
, initial_matrix_(D2D1::Matrix3x2F::Identity()) , initial_matrix_()
, final_matrix_(D2D1::Matrix3x2F::Identity()) , final_matrix_()
, border_color_(Color::Red, 0.6f) , border_color_(Color::Red, 0.6f)
{ {
} }
@ -75,19 +75,14 @@ namespace easy2d
if (!visible_) if (!visible_)
return; return;
auto render_target = render::D2D.HwndRenderTarget;
if (clip_enabled_) if (clip_enabled_)
{ {
render_target->SetTransform(final_matrix_); render::instance.PushClip(final_matrix_, transform_.size);
render_target->PushAxisAlignedClip(
D2D1::RectF(0, 0, transform_.size.width, transform_.size.height),
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
);
} }
if (children_.empty()) if (children_.empty())
{ {
render_target->SetTransform(final_matrix_); render::instance.SetTransform(final_matrix_);
OnDraw(); OnDraw();
} }
else else
@ -119,7 +114,7 @@ namespace easy2d
} }
} }
render_target->SetTransform(final_matrix_); render::instance.SetTransform(final_matrix_);
OnDraw(); OnDraw();
// 访问剩余节点 // 访问剩余节点
@ -129,7 +124,7 @@ namespace easy2d
if (clip_enabled_) if (clip_enabled_)
{ {
render_target->PopAxisAlignedClip(); render::instance.PopClip();
} }
} }
@ -176,12 +171,7 @@ namespace easy2d
{ {
if (border_) if (border_)
{ {
render::D2D.SolidColorBrush->SetColor(D2D1_COLOR_F(border_color_)); render::instance.DrawGeometry(border_, border_color_, 1.f, 1.5f);
render::D2D.HwndRenderTarget->DrawGeometry(
border_,
render::D2D.SolidColorBrush,
1.5f
);
} }
for (const auto& child : children_) for (const auto& child : children_)
@ -198,14 +188,14 @@ namespace easy2d
dirty_transform_ = false; dirty_transform_ = false;
final_matrix_ = static_cast<D2D1::Matrix3x2F>(transform_); final_matrix_ = transform_.ToMatrix();
// 根据自身支点计算 Initial 矩阵,子节点将根据这个矩阵进行变换 // 根据自身支点计算 Initial 矩阵,子节点将根据这个矩阵进行变换
auto pivot = Point( auto pivot = Point(
transform_.size.width * transform_.pivot_x, transform_.size.width * transform_.pivot_x,
transform_.size.height * transform_.pivot_y 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_) if (parent_)
{ {
@ -221,25 +211,9 @@ namespace easy2d
// 重新构造轮廓 // 重新构造轮廓
SafeRelease(border_); SafeRelease(border_);
ID2D1Factory * factory = render::D2D.Factory;
ID2D1RectangleGeometry * rectangle = nullptr;
ID2D1TransformedGeometry * transformed = nullptr;
ThrowIfFailed( ThrowIfFailed(
factory->CreateRectangleGeometry( render::instance.CreateRectGeometry(final_matrix_, transform_.size, &border_)
D2D1::RectF(0, 0, transform_.size.width, transform_.size.height),
&rectangle
)
); );
ThrowIfFailed(
factory->CreateTransformedGeometry(
rectangle,
final_matrix_,
&transformed
)
);
border_ = transformed;
SafeRelease(rectangle);
// 通知子节点进行转换 // 通知子节点进行转换
for (const auto& child : children_) for (const auto& child : children_)

View File

@ -21,9 +21,10 @@
#pragma once #pragma once
#include "base.h" #include "base.h"
#include "RefCounter.h" #include "RefCounter.h"
#include "../math/Transform.h"
#include "KeyEvent.h" #include "KeyEvent.h"
#include "MouseEvent.h" #include "MouseEvent.h"
#include "../math/Transform.h"
#include "../math/Matrix.hpp"
namespace easy2d namespace easy2d
{ {
@ -448,7 +449,6 @@ namespace easy2d
private: private:
String name_; String name_;
size_t hash_name_; size_t hash_name_;
math::Transform transform_;
float display_opacity_; float display_opacity_;
float real_opacity_; float real_opacity_;
int order_; int order_;
@ -463,7 +463,8 @@ namespace easy2d
Tasks tasks_; Tasks tasks_;
Nodes children_; Nodes children_;
ID2D1Geometry* border_; ID2D1Geometry* border_;
D2D1::Matrix3x2F initial_matrix_; math::Transform transform_;
D2D1::Matrix3x2F final_matrix_; math::Matrix initial_matrix_;
math::Matrix final_matrix_;
}; };
} }

View File

@ -20,6 +20,7 @@
#pragma once #pragma once
#include "BaseTypes.h" #include "BaseTypes.h"
#include <d2d1.h>
namespace easy2d namespace easy2d
{ {
@ -96,5 +97,10 @@ namespace easy2d
(origin.y + size.height) < rect.origin.y || (origin.y + size.height) < rect.origin.y ||
(rect.origin.y + rect.size.height) < 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 };
}
}; };
} }

View File

@ -25,13 +25,13 @@ namespace easy2d
{ {
Scene::Scene() Scene::Scene()
: root_(nullptr) : root_(nullptr)
, transform_(D2D1::Matrix3x2F::Identity()) , transform_()
{ {
} }
Scene::Scene(Node * root) Scene::Scene(Node * root)
: root_(nullptr) : root_(nullptr)
, transform_(D2D1::Matrix3x2F::Identity()) , transform_()
{ {
this->SetRoot(root); 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; transform_ = matrix;
@ -116,7 +116,7 @@ namespace easy2d
} }
} }
const D2D1::Matrix3x2F & Scene::GetTransform() const const math::Matrix& Scene::GetTransform() const
{ {
return transform_; return transform_;
} }

View File

@ -22,7 +22,7 @@
#include "RefCounter.h" #include "RefCounter.h"
#include "KeyEvent.h" #include "KeyEvent.h"
#include "MouseEvent.h" #include "MouseEvent.h"
#include <d2d1.h> #include "../math/Matrix.hpp"
namespace easy2d namespace easy2d
{ {
@ -73,17 +73,17 @@ namespace easy2d
// ÉèÖÃת»»¾ØÕó // ÉèÖÃת»»¾ØÕó
void SetTransform( void SetTransform(
const D2D1::Matrix3x2F& matrix const math::Matrix& matrix
); );
// »ñȡת»»¾ØÕó // »ñȡת»»¾ØÕó
const D2D1::Matrix3x2F& GetTransform() const; const math::Matrix& GetTransform() const;
private: private:
E2D_DISABLE_COPY(Scene); E2D_DISABLE_COPY(Scene);
private: private:
Node* root_; Node* root_;
D2D1::Matrix3x2F transform_; math::Matrix transform_;
}; };
} }

View File

@ -19,6 +19,7 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include <d2d1.h>
namespace easy2d namespace easy2d
{ {
@ -52,5 +53,10 @@ namespace easy2d
Size operator / (float val) const; Size operator / (float val) const;
Size operator - () const; Size operator - () const;
bool operator== (const Size& other) const; bool operator== (const Size& other) const;
inline operator D2D1_SIZE_F () const
{
return D2D1_SIZE_F{ width, height };
}
}; };
} }

View File

@ -135,17 +135,11 @@ namespace easy2d
if (image_ && image_->GetBitmap()) if (image_ && image_->GetBitmap())
{ {
auto crop_pos = image_->GetCropPos(); auto crop_pos = image_->GetCropPos();
render::D2D.HwndRenderTarget->DrawBitmap( render::instance.DrawImage(
image_->GetBitmap(), image_,
D2D1::RectF(0, 0, GetTransform().size.width, GetTransform().size.height),
GetDisplayOpacity(), GetDisplayOpacity(),
D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, Rect(Point(), GetTransform().size),
D2D1::RectF( Rect(crop_pos, GetTransform().size)
crop_pos.x,
crop_pos.y,
crop_pos.y + GetTransform().size.width,
crop_pos.y + GetTransform().size.height
)
); );
} }
} }

View File

@ -39,7 +39,7 @@ namespace easy2d
, outline(true) , outline(true)
, outline_color(Color(Color::Black, 0.5)) , outline_color(Color(Color::Black, 0.5))
, outline_width(1.f) , outline_width(1.f)
, outline_stroke(Stroke::Round) , outline_stroke(StrokeStyle::Round)
{} {}
Text::Style::Style( Text::Style::Style(
@ -53,7 +53,7 @@ namespace easy2d
bool outline, bool outline,
Color outline_color, Color outline_color,
float outline_width, float outline_width,
Stroke outline_stroke StrokeStyle outline_stroke
) )
: color(color) : color(color)
, alignment(alignment) , alignment(alignment)
@ -143,7 +143,7 @@ namespace easy2d
return style_.outline_width; return style_.outline_width;
} }
Stroke Text::GetOutlineStroke() const StrokeStyle Text::GetOutlineStroke() const
{ {
return style_.outline_stroke; return style_.outline_stroke;
} }
@ -306,7 +306,7 @@ namespace easy2d
style_.outline_width = outline_width; style_.outline_width = outline_width;
} }
void Text::SetOutlineStroke(Stroke outline_stroke) void Text::SetOutlineStroke(StrokeStyle outline_stroke)
{ {
style_.outline_stroke = 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); 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_.color,
style_.outline, style_.outline,
style_.outline_color, style_.outline_color,
style_.outline_width, style_.outline_width,
static_cast<D2D1_LINE_JOIN>(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_); SafeRelease(text_format_);
ThrowIfFailed( ThrowIfFailed(
render::D2D.DWriteFactory->CreateTextFormat( render::instance.CreateTextFormat(
font_.family.c_str(), &text_format_,
nullptr, font_
DWRITE_FONT_WEIGHT(font_.weight),
font_.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
font_.size,
L"",
&text_format_
) )
); );
@ -401,19 +395,15 @@ namespace easy2d
return; return;
} }
UINT32 length = static_cast<UINT32>(text_.size());
// 对文本自动换行情况下进行处理 // 对文本自动换行情况下进行处理
if (style_.wrap) if (style_.wrap)
{ {
ThrowIfFailed( ThrowIfFailed(
render::D2D.DWriteFactory->CreateTextLayout( render::instance.CreateTextLayout(
text_.c_str(), &text_layout_,
length, text_,
text_format_, text_format_,
style_.wrap_width, style_.wrap_width
0,
&text_layout_
) )
); );
// 获取文本布局的宽度和高度 // 获取文本布局的宽度和高度
@ -426,13 +416,11 @@ namespace easy2d
{ {
// 为防止文本对齐问题,根据先创建 layout 以获取宽度 // 为防止文本对齐问题,根据先创建 layout 以获取宽度
ThrowIfFailed( ThrowIfFailed(
render::D2D.DWriteFactory->CreateTextLayout( render::instance.CreateTextLayout(
text_.c_str(), &text_layout_,
length, text_,
text_format_, text_format_,
0, 0
0,
&text_layout_
) )
); );
@ -445,19 +433,17 @@ namespace easy2d
// 重新创建 layout // 重新创建 layout
SafeRelease(text_layout_); SafeRelease(text_layout_);
ThrowIfFailed( ThrowIfFailed(
render::D2D.DWriteFactory->CreateTextLayout( render::instance.CreateTextLayout(
text_.c_str(), &text_layout_,
length, text_,
text_format_, text_format_,
GetTransform().size.width, GetTransform().size.width
0,
&text_layout_
) )
); );
} }
// 添加下划线和删除线 // 添加下划线和删除线
DWRITE_TEXT_RANGE range = { 0, length }; DWRITE_TEXT_RANGE range = { 0, static_cast<UINT32>(text_.length()) };
if (style_.underline) if (style_.underline)
{ {
text_layout_->SetUnderline(true, range); text_layout_->SetUnderline(true, range);

View File

@ -51,7 +51,7 @@ namespace easy2d
bool outline; // 显示描边 bool outline; // 显示描边
Color outline_color; // 描边颜色 Color outline_color; // 描边颜色
float outline_width; // 描边线宽 float outline_width; // 描边线宽
Stroke outline_stroke; // Ãè±ßÏßÏཻÑùʽ StrokeStyle outline_stroke; // Ãè±ßÏßÏཻÑùʽ
public: public:
Style(); Style();
@ -67,7 +67,7 @@ namespace easy2d
bool outline = true, bool outline = true,
Color outline_color = Color(Color::Black, 0.5), Color outline_color = Color(Color::Black, 0.5),
float outline_width = 1.f, float outline_width = 1.f,
Stroke outline_stroke = Stroke::Round StrokeStyle outline_stroke = StrokeStyle::Round
); );
}; };
@ -110,7 +110,7 @@ namespace easy2d
float GetOutlineWidth() const; float GetOutlineWidth() const;
// 获取描边线相交样式 // 获取描边线相交样式
Stroke GetOutlineStroke() const; StrokeStyle GetOutlineStroke() const;
// 获取文本显示行数 // 获取文本显示行数
int GetLineCount() const; int GetLineCount() const;
@ -214,7 +214,7 @@ namespace easy2d
// 设置描边线相交样式 // 设置描边线相交样式
void SetOutlineStroke( void SetOutlineStroke(
Stroke outline_stroke StrokeStyle outline_stroke
); );
// 渲染文字 // 渲染文字

View File

@ -73,22 +73,7 @@ namespace easy2d
bShowOutline_ = outline; bShowOutline_ = outline;
sOutlineColor_ = outline_color; sOutlineColor_ = outline_color;
fOutlineWidth = 2 * outline_width; fOutlineWidth = 2 * outline_width;
pCurrStrokeStyle_ = render::instance.GetStrokeStyle(StrokeStyle(outlineJoin));
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;
}
} }
STDMETHODIMP ITextRenderer::DrawGlyphRun( STDMETHODIMP ITextRenderer::DrawGlyphRun(

View File

@ -21,8 +21,8 @@
#include "Transition.h" #include "Transition.h"
#include "Node.h" #include "Node.h"
#include "Scene.h" #include "Scene.h"
#include "render.h"
#include "window.h" #include "window.h"
#include "../math/Matrix.hpp"
namespace easy2d namespace easy2d
{ {
@ -39,8 +39,8 @@ namespace easy2d
, in_scene_(nullptr) , in_scene_(nullptr)
, out_layer_(nullptr) , out_layer_(nullptr)
, in_layer_(nullptr) , in_layer_(nullptr)
, out_layer_param_() , out_layer_prop_()
, in_layer_param_() , in_layer_prop_()
{ {
duration_ = std::max(duration, 0.f); duration_ = std::max(duration, 0.f);
} }
@ -73,32 +73,22 @@ namespace easy2d
if (in_scene_) if (in_scene_)
{ {
ThrowIfFailed( ThrowIfFailed(
render::D2D.HwndRenderTarget->CreateLayer(&in_layer_) render::instance.CreateLayer(&in_layer_)
); );
} }
if (out_scene_) if (out_scene_)
{ {
ThrowIfFailed( ThrowIfFailed(
render::D2D.HwndRenderTarget->CreateLayer(&out_layer_) render::instance.CreateLayer(&out_layer_)
); );
} }
window_size_ = window::instance.GetSize(); window_size_ = window::instance.GetSize();
out_layer_param_ = in_layer_param_ = D2D1::LayerParameters( out_layer_prop_ = in_layer_prop_ = render::LayerProperties{
D2D1::RectF( Rect(Point(), window_size_),
0.f, 1.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
);
} }
void Transition::Update() void Transition::Update()
@ -121,46 +111,32 @@ namespace easy2d
void Transition::Draw() void Transition::Draw()
{ {
auto render_target = render::D2D.HwndRenderTarget;
if (out_scene_) if (out_scene_)
{ {
render_target->SetTransform(out_scene_->GetTransform()); render::instance.PushClip(
render_target->PushAxisAlignedClip( out_scene_->GetTransform(),
D2D1::RectF( window_size_
0.f,
0.f,
window_size_.width,
window_size_.height
),
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
); );
render_target->PushLayer(out_layer_param_, out_layer_); render::instance.PushLayer(out_layer_, out_layer_prop_);
out_scene_->Draw(); out_scene_->Draw();
render_target->PopLayer(); render::instance.PopLayer();
render_target->PopAxisAlignedClip(); render::instance.PopClip();
} }
if (in_scene_) if (in_scene_)
{ {
render_target->SetTransform(in_scene_->GetTransform()); render::instance.PushClip(
render_target->PushAxisAlignedClip( in_scene_->GetTransform(),
D2D1::RectF( window_size_
0.f,
0.f,
window_size_.width,
window_size_.height
),
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
); );
render_target->PushLayer(in_layer_param_, in_layer_); render::instance.PushLayer(in_layer_, in_layer_prop_);
in_scene_->Draw(); in_scene_->Draw();
render_target->PopLayer(); render::instance.PopLayer();
render_target->PopAxisAlignedClip(); render::instance.PopClip();
} }
} }
@ -183,7 +159,7 @@ namespace easy2d
{ {
Transition::Initialize(prev, next, game); Transition::Initialize(prev, next, game);
in_layer_param_.opacity = 0; in_layer_prop_.opacity = 0;
} }
void BoxTransition::Update() void BoxTransition::Update()
@ -192,22 +168,22 @@ namespace easy2d
if (process_ < .5f) if (process_ < .5f)
{ {
out_layer_param_.contentBounds = D2D1::RectF( out_layer_prop_.area = Rect(
window_size_.width * process_, window_size_.width * process_,
window_size_.height * process_, window_size_.height * process_,
window_size_.width * (1 - process_), window_size_.width * (1 - process_ * 2),
window_size_.height * (1 - process_) window_size_.height * (1 - process_ * 2)
); );
} }
else else
{ {
out_layer_param_.opacity = 0; out_layer_prop_.opacity = 0;
in_layer_param_.opacity = 1; in_layer_prop_.opacity = 1;
in_layer_param_.contentBounds = D2D1::RectF( in_layer_prop_.area = Rect(
window_size_.width * (1 - process_), window_size_.width * (1 - process_),
window_size_.height * (1 - process_), window_size_.height * (1 - process_),
window_size_.width * process_, window_size_.width * (2 * process_ - 1),
window_size_.height * process_ window_size_.height * (2 * process_ - 1)
); );
} }
} }
@ -225,16 +201,16 @@ namespace easy2d
{ {
Transition::Initialize(prev, next, game); Transition::Initialize(prev, next, game);
out_layer_param_.opacity = 1; out_layer_prop_.opacity = 1;
in_layer_param_.opacity = 0; in_layer_prop_.opacity = 0;
} }
void EmergeTransition::Update() void EmergeTransition::Update()
{ {
Transition::Update(); Transition::Update();
out_layer_param_.opacity = 1 - process_; out_layer_prop_.opacity = 1 - process_;
in_layer_param_.opacity = process_; in_layer_prop_.opacity = process_;
} }
//------------------------------------------------------- //-------------------------------------------------------
@ -250,8 +226,8 @@ namespace easy2d
{ {
Transition::Initialize(prev, next, game); Transition::Initialize(prev, next, game);
out_layer_param_.opacity = 1; out_layer_prop_.opacity = 1;
in_layer_param_.opacity = 0; in_layer_prop_.opacity = 0;
} }
void FadeTransition::Update() void FadeTransition::Update()
@ -260,13 +236,13 @@ namespace easy2d
if (process_ < 0.5) if (process_ < 0.5)
{ {
out_layer_param_.opacity = 1 - process_ * 2; out_layer_prop_.opacity = 1 - process_ * 2;
in_layer_param_.opacity = 0; in_layer_prop_.opacity = 0;
} }
else else
{ {
out_layer_param_.opacity = 0; out_layer_prop_.opacity = 0;
in_layer_param_.opacity = (process_ - 0.5f) * 2; in_layer_prop_.opacity = (process_ - 0.5f) * 2;
} }
} }
@ -306,13 +282,13 @@ namespace easy2d
if (out_scene_) if (out_scene_)
{ {
out_scene_->SetTransform(D2D1::Matrix3x2F::Identity()); out_scene_->SetTransform(math::Matrix());
} }
if (in_scene_) if (in_scene_)
{ {
in_scene_->SetTransform( in_scene_->SetTransform(
D2D1::Matrix3x2F::Translation( math::Matrix::Translation(
start_pos_.x, start_pos_.x,
start_pos_.y start_pos_.y
) )
@ -328,7 +304,7 @@ namespace easy2d
{ {
auto translation = pos_delta_ * process_; auto translation = pos_delta_ * process_;
out_scene_->SetTransform( out_scene_->SetTransform(
D2D1::Matrix3x2F::Translation( math::Matrix::Translation(
translation.x, translation.x,
translation.y translation.y
) )
@ -339,7 +315,7 @@ namespace easy2d
{ {
auto translation = start_pos_ + pos_delta_ * process_; auto translation = start_pos_ + pos_delta_ * process_;
in_scene_->SetTransform( in_scene_->SetTransform(
D2D1::Matrix3x2F::Translation( math::Matrix::Translation(
translation.x, translation.x,
translation.y translation.y
) )
@ -351,12 +327,12 @@ namespace easy2d
{ {
if (out_scene_) if (out_scene_)
{ {
out_scene_->SetTransform(D2D1::Matrix3x2F::Identity()); out_scene_->SetTransform(math::Matrix());
} }
if (in_scene_) if (in_scene_)
{ {
in_scene_->SetTransform(D2D1::Matrix3x2F::Identity()); in_scene_->SetTransform(math::Matrix());
} }
} }
@ -376,22 +352,22 @@ namespace easy2d
if (out_scene_) if (out_scene_)
{ {
out_scene_->SetTransform(D2D1::Matrix3x2F::Identity()); out_scene_->SetTransform(math::Matrix());
} }
if (in_scene_) 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() void RotationTransition::Update()
{ {
Transition::Update(); Transition::Update();
auto center_pos = D2D1::Point2F( auto center_pos = math::Vector2(
window_size_.width / 2, window_size_.width / 2,
window_size_.height / 2 window_size_.height / 2
); );
@ -401,11 +377,11 @@ namespace easy2d
if (out_scene_) if (out_scene_)
{ {
out_scene_->SetTransform( out_scene_->SetTransform(
D2D1::Matrix3x2F::Scale( math::Matrix::Scaling(
(.5f - process_) * 2, (.5f - process_) * 2,
(.5f - process_) * 2, (.5f - process_) * 2,
center_pos center_pos
) * D2D1::Matrix3x2F::Rotation( ) * math::Matrix::Rotation(
rotation_ * (.5f - process_) * 2, rotation_ * (.5f - process_) * 2,
center_pos center_pos
) )
@ -416,15 +392,15 @@ namespace easy2d
{ {
if (in_scene_) if (in_scene_)
{ {
out_layer_param_.opacity = 0; out_layer_prop_.opacity = 0;
in_layer_param_.opacity = 1; in_layer_prop_.opacity = 1;
in_scene_->SetTransform( in_scene_->SetTransform(
D2D1::Matrix3x2F::Scale( math::Matrix::Scaling(
(process_ - .5f) * 2, (process_ - .5f) * 2,
(process_ - .5f) * 2, (process_ - .5f) * 2,
center_pos center_pos
) * D2D1::Matrix3x2F::Rotation( ) * math::Matrix::Rotation(
rotation_ * (process_ - .5f) * 2, rotation_ * (process_ - .5f) * 2,
center_pos center_pos
) )
@ -437,12 +413,12 @@ namespace easy2d
{ {
if (out_scene_) if (out_scene_)
{ {
out_scene_->SetTransform(D2D1::Matrix3x2F::Identity()); out_scene_->SetTransform(math::Matrix());
} }
if (in_scene_) if (in_scene_)
{ {
in_scene_->SetTransform(D2D1::Matrix3x2F::Identity()); in_scene_->SetTransform(math::Matrix());
} }
} }
} }

View File

@ -21,6 +21,7 @@
#pragma once #pragma once
#include "base.h" #include "base.h"
#include "time.h" #include "time.h"
#include "render.h"
#include "RefCounter.h" #include "RefCounter.h"
namespace easy2d namespace easy2d
@ -72,10 +73,10 @@ namespace easy2d
Size window_size_; Size window_size_;
Scene* out_scene_; Scene* out_scene_;
Scene* in_scene_; Scene* in_scene_;
ID2D1Layer * out_layer_; ID2D1Layer* out_layer_;
ID2D1Layer * in_layer_; ID2D1Layer* in_layer_;
D2D1_LAYER_PARAMETERS out_layer_param_; render::LayerProperties out_layer_prop_;
D2D1_LAYER_PARAMETERS in_layer_param_; render::LayerProperties in_layer_prop_;
}; };

View File

@ -30,17 +30,31 @@ namespace easy2d
{ {
namespace render 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; return;
ThrowIfFailed( ThrowIfFailed(
D2D1CreateFactory( D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED, D2D1_FACTORY_TYPE_SINGLE_THREADED,
&D2D.Factory &d2d.Factory
) )
); );
@ -50,7 +64,7 @@ namespace easy2d
nullptr, nullptr,
CLSCTX_INPROC_SERVER, CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory, IID_IWICImagingFactory,
reinterpret_cast<void**>(&D2D.WICImagingFactory) reinterpret_cast<void**>(&d2d.WICImagingFactory)
) )
); );
@ -58,7 +72,7 @@ namespace easy2d
DWriteCreateFactory( DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED, DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory), __uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&D2D.DWriteFactory) reinterpret_cast<IUnknown**>(&d2d.DWriteFactory)
) )
); );
@ -73,132 +87,65 @@ namespace easy2d
); );
ThrowIfFailed( ThrowIfFailed(
D2D.Factory->CreateStrokeStyle( d2d.Factory->CreateStrokeStyle(
stroke_style, stroke_style,
nullptr, nullptr,
0, 0,
&D2D.MiterStrokeStyle &d2d.MiterStrokeStyle
) )
); );
stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL; stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL;
ThrowIfFailed( ThrowIfFailed(
D2D.Factory->CreateStrokeStyle( d2d.Factory->CreateStrokeStyle(
stroke_style, stroke_style,
nullptr, nullptr,
0, 0,
&D2D.BevelStrokeStyle &d2d.BevelStrokeStyle
) )
); );
stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND; stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND;
ThrowIfFailed( ThrowIfFailed(
D2D.Factory->CreateStrokeStyle( d2d.Factory->CreateStrokeStyle(
stroke_style, stroke_style,
nullptr, nullptr,
0, 0,
&D2D.RoundStrokeStyle &d2d.RoundStrokeStyle
) )
); );
CreateDeviceResources(hwnd); CreateDeviceResources(hwnd);
} }
void easy2d::render::CreateDeviceResources(HWND hwnd) void GraphicsDevice::Uninitialize()
{ {
if (!D2D.HwndRenderTarget) SafeRelease(d2d.TextRenderer);
{ SafeRelease(d2d.SolidColorBrush);
RECT rc; SafeRelease(d2d.HwndRenderTarget);
::GetClientRect(hwnd, &rc);
D2D1_SIZE_U size = D2D1::SizeU( SafeRelease(d2d.MiterStrokeStyle);
rc.right - rc.left, SafeRelease(d2d.BevelStrokeStyle);
rc.bottom - rc.top SafeRelease(d2d.RoundStrokeStyle);
);
// 创建设备相关资源。这些资源应在 Direct2D 设备消失时重建 SafeRelease(d2d.WICImagingFactory);
// 创建一个 Direct2D 渲染目标 SafeRelease(d2d.DWriteFactory);
ThrowIfFailed( SafeRelease(d2d.Factory);
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_);
} }
void GraphicsDevice::BeginDraw(HWND hwnd) void GraphicsDevice::BeginDraw(HWND hwnd)
{ {
render::CreateDeviceResources(hwnd); CreateDeviceResources(hwnd);
render::D2D.HwndRenderTarget->BeginDraw();
render::D2D.HwndRenderTarget->Clear(clear_color_); d2d.HwndRenderTarget->BeginDraw();
d2d.HwndRenderTarget->Clear(clear_color_);
} }
void GraphicsDevice::EndDraw() void GraphicsDevice::EndDraw()
{ {
HRESULT hr = render::D2D.HwndRenderTarget->EndDraw(); HRESULT hr = d2d.HwndRenderTarget->EndDraw();
if (hr == D2DERR_RECREATE_TARGET) if (hr == D2DERR_RECREATE_TARGET)
{ {
@ -208,14 +155,426 @@ namespace easy2d
SafeRelease(fps_text_format_); SafeRelease(fps_text_format_);
SafeRelease(fps_text_layout_); SafeRelease(fps_text_layout_);
SafeRelease(render::D2D.TextRenderer); SafeRelease(d2d.TextRenderer);
SafeRelease(render::D2D.SolidColorBrush); SafeRelease(d2d.SolidColorBrush);
SafeRelease(render::D2D.HwndRenderTarget); SafeRelease(d2d.HwndRenderTarget);
} }
ThrowIfFailed(hr); 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<UINT32>(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<WICInProcPointer>(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<D2D1_LINE_JOIN>(outline_stroke)
);
return S_OK;
}
void GraphicsDevice::SetBackgroundColor(const Color& color) void GraphicsDevice::SetBackgroundColor(const Color& color)
{ {
clear_color_ = color; clear_color_ = color;
@ -231,7 +590,7 @@ namespace easy2d
if (!fps_text_format_) if (!fps_text_format_)
{ {
ThrowIfFailed( ThrowIfFailed(
render::D2D.DWriteFactory->CreateTextFormat( d2d.DWriteFactory->CreateTextFormat(
L"", L"",
nullptr, nullptr,
DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_WEIGHT_NORMAL,
@ -262,7 +621,7 @@ namespace easy2d
SafeRelease(fps_text_layout_); SafeRelease(fps_text_layout_);
ThrowIfFailed( ThrowIfFailed(
render::D2D.DWriteFactory->CreateTextLayout( d2d.DWriteFactory->CreateTextLayout(
fps_text, fps_text,
static_cast<UINT32>(len), static_cast<UINT32>(len),
fps_text_format_, fps_text_format_,
@ -275,9 +634,9 @@ namespace easy2d
if (fps_text_layout_) if (fps_text_layout_)
{ {
render::D2D.HwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); d2d.HwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
render::D2D.SolidColorBrush->SetOpacity(1.0f); d2d.SolidColorBrush->SetOpacity(1.0f);
render::D2D.TextRenderer->SetTextStyle( d2d.TextRenderer->SetTextStyle(
D2D1::ColorF(D2D1::ColorF::White), D2D1::ColorF(D2D1::ColorF::White),
TRUE, TRUE,
D2D1::ColorF(D2D1::ColorF::Black, 0.4f), D2D1::ColorF(D2D1::ColorF::Black, 0.4f),
@ -285,7 +644,56 @@ namespace easy2d
D2D1_LINE_JOIN_ROUND 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
)
);
} }
} }
} }

View File

@ -20,7 +20,11 @@
#pragma once #pragma once
#include "base.h" #include "base.h"
#include "Font.h"
#include "Resource.h"
#include "Image.h"
#include "TextRenderer.h" #include "TextRenderer.h"
#include "../math/Matrix.hpp"
namespace easy2d namespace easy2d
{ {
@ -37,15 +41,13 @@ namespace easy2d
ID2D1StrokeStyle* MiterStrokeStyle; ID2D1StrokeStyle* MiterStrokeStyle;
ID2D1StrokeStyle* BevelStrokeStyle; ID2D1StrokeStyle* BevelStrokeStyle;
ID2D1StrokeStyle* RoundStrokeStyle; ID2D1StrokeStyle* RoundStrokeStyle;
} _D2D_Resource; } D2DResources;
extern _D2D_Resource D2D; typedef struct
{
void Initialize(HWND hwnd); Rect area;
float opacity;
void CreateDeviceResources(HWND hwnd); } LayerProperties;
void Uninitialize();
class GraphicsDevice class GraphicsDevice
{ {
@ -54,24 +56,121 @@ namespace easy2d
~GraphicsDevice(); ~GraphicsDevice();
void Initialize(HWND hwnd);
void Uninitialize();
// ¿ªÊ¼äÖȾ // ¿ªÊ¼äÖȾ
void BeginDraw(HWND hwnd); void BeginDraw(HWND hwnd);
// ½áÊøäÖȾ // ½áÊøäÖȾ
void EndDraw(); void EndDraw();
// 渲染调试信息
void DrawDebugInfo();
// ÉèÖñ³¾°É« // ÉèÖñ³¾°É«
void SetBackgroundColor( void SetBackgroundColor(
const Color& color 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: protected:
D2D1_COLOR_F clear_color_; D2D1_COLOR_F clear_color_;
IDWriteTextFormat* fps_text_format_; IDWriteTextFormat* fps_text_format_;
IDWriteTextLayout* fps_text_layout_; IDWriteTextLayout* fps_text_layout_;
D2DResources d2d;
}; };
extern GraphicsDevice instance; extern GraphicsDevice instance;

View File

@ -173,21 +173,16 @@ namespace easy2d
std::wstring easy2d::time::Duration::ToString() const std::wstring easy2d::time::Duration::ToString() const
{ {
std::wstring result; if (milliseconds_ == 0LL)
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
{ {
wchar_t buf[10] = {}; return std::wstring(L"0s");
::swprintf_s(buf, L"%.2f", val); }
return std::wstring(buf);
}; 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) if (milliseconds_ < 0)
result.append(L"-"); result.append(L"-");
@ -202,19 +197,22 @@ namespace easy2d
result.append(std::to_wstring(min)).append(L"m"); result.append(std::to_wstring(min)).append(L"m");
} }
if (sec == 0 && ms == 0) if (ms != 0)
{ {
result.append(L"0s"); auto float_to_str = [](float val) -> std::wstring
}
else if (ms == 0)
{
result.append(std::to_wstring(sec)).append(L"s");
}
else
{ {
wchar_t buf[10] = {};
::swprintf_s(buf, L"%.2f", val);
return std::wstring(buf);
};
result.append(float_to_str(static_cast<float>(sec) + static_cast<float>(ms) / 1000.f)) result.append(float_to_str(static_cast<float>(sec) + static_cast<float>(ms) / 1000.f))
.append(L"s"); .append(L"s");
} }
else if (sec != 0)
{
result.append(std::to_wstring(sec)).append(L"s");
}
return result; return result;
} }

View File

@ -306,11 +306,7 @@ namespace easy2d
// 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染 // 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染
// 目标的大小。它可能会调用失败,但是这里可以忽略有可能的 // 目标的大小。它可能会调用失败,但是这里可以忽略有可能的
// 错误,因为这个错误将在下一次调用 EndDraw 时产生 // 错误,因为这个错误将在下一次调用 EndDraw 时产生
auto render_target = render::D2D.HwndRenderTarget; render::instance.Resize(width, height);
if (render_target)
{
render_target->Resize(D2D1::SizeU(width, height));
}
} }
break; break;

View File

@ -20,6 +20,7 @@
#pragma once #pragma once
#include "vector.hpp" #include "vector.hpp"
#include <d2d1.h>
namespace easy2d 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() inline Matrix& Identity()
{ {
_11 = 1.f; _11 = 1.f;
@ -90,12 +100,24 @@ namespace easy2d
return *this; 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) inline Matrix& Scale(const Vector2& v, const Vector2& center)
{ {
*this = *this * Matrix::Scaling(v, center); *this = *this * Matrix::Scaling(v, center);
return *this; 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) inline Matrix& Rotate(float angle, const Vector2& center)
{ {
*this = *this * Matrix::Rotation(angle, center); *this = *this * Matrix::Rotation(angle, center);

View File

@ -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 pivot = Vector2(size.width * pivot_x, size.height * pivot_y);
auto matrix = D2D1::Matrix3x2F::Scale( return Matrix().Scale(scale_x, scale_y, pivot)
scale_x, .Skew(skew_x, skew_y, pivot)
scale_y, .Rotate(rotation, pivot)
pivot .Translate(position - 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;
} }
bool Transform::operator==(const Transform & other) const bool Transform::operator==(const Transform & other) const

View File

@ -21,7 +21,7 @@
#pragma once #pragma once
#include "../base/BaseTypes.h" #include "../base/BaseTypes.h"
#include "../base/Size.h" #include "../base/Size.h"
#include <d2d1.h> #include "Matrix.hpp"
namespace easy2d namespace easy2d
{ {
@ -43,7 +43,7 @@ namespace easy2d
public: public:
Transform(); Transform();
explicit operator D2D1::Matrix3x2F() const; Matrix ToMatrix() const;
bool operator== (const Transform& other) const; bool operator== (const Transform& other) const;
}; };

View File

@ -20,6 +20,7 @@
#pragma once #pragma once
#include "scalar.hpp" #include "scalar.hpp"
#include <d2d1.h>
namespace easy2d namespace easy2d
{ {
@ -85,6 +86,11 @@ namespace easy2d
{ {
return Vector2(x - v.x, y - v.y).Length(); return Vector2(x - v.x, y - v.y).Length();
} }
inline operator D2D1_POINT_2F () const
{
return D2D1_POINT_2F{ x, y };
}
}; };
} }
} }