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 /* ÓÒ */
};
// ÏßÌõÏཻÑùʽ
enum class Stroke : int
// »­±ÊÑùʽ
enum class StrokeStyle : int
{
Miter = 0, /* бÇÐ */
Bevel = 1, /* б½Ç */

View File

@ -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_;
}

View File

@ -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_;

View File

@ -80,9 +80,4 @@ namespace easy2d
, 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
);
operator D2D1_COLOR_F() const;
inline operator D2D1_COLOR_F() const
{
return D2D1_COLOR_F{ r, g, b, a };
}
public:
enum Value : unsigned int

View File

@ -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 <thread>
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();
}

View File

@ -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<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
);
}
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);
}

View File

@ -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<D2D1::Matrix3x2F>(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_)

View File

@ -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_;
};
}

View File

@ -20,6 +20,7 @@
#pragma once
#include "BaseTypes.h"
#include <d2d1.h>
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 };
}
};
}

View File

@ -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_;
}

View File

@ -22,7 +22,7 @@
#include "RefCounter.h"
#include "KeyEvent.h"
#include "MouseEvent.h"
#include <d2d1.h>
#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_;
};
}

View File

@ -19,6 +19,7 @@
// THE SOFTWARE.
#pragma once
#include <d2d1.h>
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 };
}
};
}

View File

@ -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)
);
}
}

View File

@ -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<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_);
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<UINT32>(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<UINT32>(text_.length()) };
if (style_.underline)
{
text_layout_->SetUnderline(true, range);

View File

@ -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
);
// 渲染文字

View File

@ -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(

View File

@ -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());
}
}
}

View File

@ -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_;
};

View File

@ -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<void**>(&D2D.WICImagingFactory)
reinterpret_cast<void**>(&d2d.WICImagingFactory)
)
);
@ -58,7 +72,7 @@ namespace easy2d
DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&D2D.DWriteFactory)
reinterpret_cast<IUnknown**>(&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<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)
{
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<UINT32>(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
)
);
}
}
}

View File

@ -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;

View File

@ -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<float>(sec) + static_cast<float>(ms) / 1000.f))
.append(L"s");
}
else if (sec != 0)
{
result.append(std::to_wstring(sec)).append(L"s");
}
return result;
}

View File

@ -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;

View File

@ -20,6 +20,7 @@
#pragma once
#include "vector.hpp"
#include <d2d1.h>
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);

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 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

View File

@ -21,7 +21,7 @@
#pragma once
#include "../base/BaseTypes.h"
#include "../base/Size.h"
#include <d2d1.h>
#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;
};

View File

@ -20,6 +20,7 @@
#pragma once
#include "scalar.hpp"
#include <d2d1.h>
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 };
}
};
}
}