Add RenderTarget
This commit is contained in:
parent
ed79c69e7a
commit
7257ebf12b
|
|
@ -77,6 +77,7 @@
|
||||||
<ClInclude Include="..\src\kiwano\renderer\Image.h" />
|
<ClInclude Include="..\src\kiwano\renderer\Image.h" />
|
||||||
<ClInclude Include="..\src\kiwano\renderer\ImageCache.h" />
|
<ClInclude Include="..\src\kiwano\renderer\ImageCache.h" />
|
||||||
<ClInclude Include="..\src\kiwano\renderer\Renderer.h" />
|
<ClInclude Include="..\src\kiwano\renderer\Renderer.h" />
|
||||||
|
<ClInclude Include="..\src\kiwano\renderer\RenderTarget.h" />
|
||||||
<ClInclude Include="..\src\kiwano\renderer\TextLayout.h" />
|
<ClInclude Include="..\src\kiwano\renderer\TextLayout.h" />
|
||||||
<ClInclude Include="..\src\kiwano\renderer\TextRenderer.h" />
|
<ClInclude Include="..\src\kiwano\renderer\TextRenderer.h" />
|
||||||
<ClInclude Include="..\src\kiwano\third-party\StackWalker\StackWalker.h" />
|
<ClInclude Include="..\src\kiwano\third-party\StackWalker\StackWalker.h" />
|
||||||
|
|
@ -131,6 +132,7 @@
|
||||||
<ClCompile Include="..\src\kiwano\renderer\Image.cpp" />
|
<ClCompile Include="..\src\kiwano\renderer\Image.cpp" />
|
||||||
<ClCompile Include="..\src\kiwano\renderer\ImageCache.cpp" />
|
<ClCompile Include="..\src\kiwano\renderer\ImageCache.cpp" />
|
||||||
<ClCompile Include="..\src\kiwano\renderer\Renderer.cpp" />
|
<ClCompile Include="..\src\kiwano\renderer\Renderer.cpp" />
|
||||||
|
<ClCompile Include="..\src\kiwano\renderer\RenderTarget.cpp" />
|
||||||
<ClCompile Include="..\src\kiwano\renderer\TextLayout.cpp" />
|
<ClCompile Include="..\src\kiwano\renderer\TextLayout.cpp" />
|
||||||
<ClCompile Include="..\src\kiwano\renderer\TextRenderer.cpp" />
|
<ClCompile Include="..\src\kiwano\renderer\TextRenderer.cpp" />
|
||||||
<ClCompile Include="..\src\kiwano\third-party\StackWalker\StackWalker.cpp" />
|
<ClCompile Include="..\src\kiwano\third-party\StackWalker\StackWalker.cpp" />
|
||||||
|
|
|
||||||
|
|
@ -291,6 +291,9 @@
|
||||||
<ClInclude Include="..\src\kiwano\renderer\TextLayout.h">
|
<ClInclude Include="..\src\kiwano\renderer\TextLayout.h">
|
||||||
<Filter>renderer</Filter>
|
<Filter>renderer</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\kiwano\renderer\RenderTarget.h">
|
||||||
|
<Filter>renderer</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\src\kiwano\ui\Button.cpp">
|
<ClCompile Include="..\src\kiwano\ui\Button.cpp">
|
||||||
|
|
@ -449,5 +452,8 @@
|
||||||
<ClCompile Include="..\src\kiwano\renderer\TextLayout.cpp">
|
<ClCompile Include="..\src\kiwano\renderer\TextLayout.cpp">
|
||||||
<Filter>renderer</Filter>
|
<Filter>renderer</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\kiwano\renderer\RenderTarget.cpp">
|
||||||
|
<Filter>renderer</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -27,35 +27,11 @@ namespace kiwano
|
||||||
Canvas::Canvas()
|
Canvas::Canvas()
|
||||||
: cache_expired_(false)
|
: cache_expired_(false)
|
||||||
, stroke_width_(1.0f)
|
, stroke_width_(1.0f)
|
||||||
|
, fill_color_(0, 0, 0)
|
||||||
|
, stroke_color_(Color::White)
|
||||||
|
, stroke_style_(StrokeStyle::Miter)
|
||||||
{
|
{
|
||||||
auto ctx = Renderer::GetInstance()->GetD2DDeviceResources()->GetDeviceContext();
|
Renderer::GetInstance()->CreateImageRenderTarget(rt_);
|
||||||
|
|
||||||
ThrowIfFailed(
|
|
||||||
ctx->CreateCompatibleRenderTarget(&render_target_)
|
|
||||||
);
|
|
||||||
|
|
||||||
ThrowIfFailed(
|
|
||||||
render_target_->CreateSolidColorBrush(
|
|
||||||
D2D1::ColorF(0, 0, 0, 0),
|
|
||||||
D2D1::BrushProperties(),
|
|
||||||
&fill_brush_)
|
|
||||||
);
|
|
||||||
|
|
||||||
ThrowIfFailed(
|
|
||||||
render_target_->CreateSolidColorBrush(
|
|
||||||
D2D1::ColorF(Color::White),
|
|
||||||
D2D1::BrushProperties(),
|
|
||||||
&stroke_brush_)
|
|
||||||
);
|
|
||||||
|
|
||||||
ThrowIfFailed(
|
|
||||||
ITextRenderer::Create(
|
|
||||||
&text_renderer_,
|
|
||||||
render_target_.get()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
SetTextStyle(Font{}, TextStyle{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Canvas::Canvas(float width, float height)
|
Canvas::Canvas(float width, float height)
|
||||||
|
|
@ -75,45 +51,36 @@ namespace kiwano
|
||||||
|
|
||||||
void Canvas::BeginDraw()
|
void Canvas::BeginDraw()
|
||||||
{
|
{
|
||||||
render_target_->BeginDraw();
|
rt_.BeginDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::EndDraw()
|
void Canvas::EndDraw()
|
||||||
{
|
{
|
||||||
ThrowIfFailed(
|
rt_.EndDraw();
|
||||||
render_target_->EndDraw()
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
cache_expired_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::OnRender(Renderer* renderer)
|
void Canvas::OnRender(Renderer* renderer)
|
||||||
{
|
{
|
||||||
if (cache_expired_)
|
UpdateCache();
|
||||||
{
|
|
||||||
GetBitmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bitmap_cached_)
|
if (image_cached_.IsValid())
|
||||||
{
|
{
|
||||||
PrepareRender(renderer);
|
PrepareRender(renderer);
|
||||||
|
|
||||||
Rect bitmap_rect(0.f, 0.f, bitmap_cached_->GetSize().width, bitmap_cached_->GetSize().height);
|
Rect bitmap_rect(0.f, 0.f, image_cached_.GetWidth(), image_cached_.GetHeight());
|
||||||
renderer->DrawBitmap(
|
renderer->DrawImage(image_cached_, bitmap_rect, bitmap_rect);
|
||||||
bitmap_cached_,
|
|
||||||
bitmap_rect,
|
|
||||||
bitmap_rect
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::SetStrokeColor(Color const& color)
|
void Canvas::SetStrokeColor(Color const& color)
|
||||||
{
|
{
|
||||||
stroke_brush_->SetColor(DX::ConvertToColorF(color));
|
stroke_color_ = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::SetFillColor(Color const& color)
|
void Canvas::SetFillColor(Color const& color)
|
||||||
{
|
{
|
||||||
fill_brush_->SetColor(DX::ConvertToColorF(color));
|
fill_color_ = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::SetStrokeWidth(float width)
|
void Canvas::SetStrokeWidth(float width)
|
||||||
|
|
@ -121,39 +88,34 @@ namespace kiwano
|
||||||
stroke_width_ = std::max(width, 0.f);
|
stroke_width_ = std::max(width, 0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::SetOutlineJoinStyle(StrokeStyle outline_join)
|
void Canvas::SetStrokeStyle(StrokeStyle stroke_style)
|
||||||
{
|
{
|
||||||
outline_join_style_ = Renderer::GetInstance()->GetD2DDeviceResources()->GetStrokeStyle(outline_join);
|
stroke_style_ = stroke_style;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::SetTextStyle(Font const& font, TextStyle const & text_style)
|
void Canvas::SetTextFont(Font const& font)
|
||||||
{
|
{
|
||||||
text_font_ = font;
|
text_font_ = font;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::SetTextStyle(TextStyle const & text_style)
|
||||||
|
{
|
||||||
text_style_ = text_style;
|
text_style_ = text_style;
|
||||||
|
}
|
||||||
|
|
||||||
text_renderer_->SetTextStyle(
|
void Canvas::SetBrushOpacity(float opacity)
|
||||||
1.f,
|
{
|
||||||
DX::ConvertToColorF(text_style_.color),
|
rt_.SetOpacity(opacity);
|
||||||
text_style_.outline,
|
|
||||||
DX::ConvertToColorF(text_style_.outline_color),
|
|
||||||
text_style_.outline_width,
|
|
||||||
Renderer::GetInstance()->GetD2DDeviceResources()->GetStrokeStyle(text_style_.outline_stroke)
|
|
||||||
);
|
|
||||||
|
|
||||||
// clear text format
|
|
||||||
text_format_ = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Color Canvas::GetStrokeColor() const
|
Color Canvas::GetStrokeColor() const
|
||||||
{
|
{
|
||||||
auto color_f = stroke_brush_->GetColor();
|
return stroke_color_;
|
||||||
return Color{ color_f.r, color_f.g, color_f.b, color_f.a };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Color Canvas::GetFillColor() const
|
Color Canvas::GetFillColor() const
|
||||||
{
|
{
|
||||||
auto color_f = fill_brush_->GetColor();
|
return fill_color_;
|
||||||
return Color{ color_f.r, color_f.g, color_f.b, color_f.a };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float Canvas::GetStrokeWidth() const
|
float Canvas::GetStrokeWidth() const
|
||||||
|
|
@ -161,321 +123,219 @@ namespace kiwano
|
||||||
return stroke_width_;
|
return stroke_width_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Canvas::GetBrushOpacity() const
|
||||||
|
{
|
||||||
|
return rt_.GetOpacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::SetBrushTransform(Transform const& transform)
|
||||||
|
{
|
||||||
|
Matrix3x2 matrix = Matrix3x2::SRT(transform.position, transform.scale, transform.rotation);
|
||||||
|
if (!transform.skew.IsOrigin())
|
||||||
|
{
|
||||||
|
matrix = Matrix3x2::Skewing(transform.skew) * matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_.SetTransform(matrix);
|
||||||
|
}
|
||||||
|
|
||||||
void Canvas::SetBrushTransform(Matrix3x2 const & transform)
|
void Canvas::SetBrushTransform(Matrix3x2 const & transform)
|
||||||
{
|
{
|
||||||
render_target_->SetTransform(DX::ConvertToMatrix3x2F(transform));
|
rt_.SetTransform(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::DrawLine(const Point & begin, const Point & end)
|
void Canvas::DrawLine(Point const& begin, Point const& end)
|
||||||
{
|
{
|
||||||
render_target_->DrawLine(
|
rt_.DrawLine(
|
||||||
D2D1::Point2F(begin.x, begin.y),
|
begin,
|
||||||
D2D1::Point2F(end.x, end.y),
|
end,
|
||||||
stroke_brush_.get(),
|
stroke_color_,
|
||||||
stroke_width_,
|
stroke_width_,
|
||||||
outline_join_style_.get()
|
stroke_style_
|
||||||
);
|
);
|
||||||
cache_expired_ = true;
|
cache_expired_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::DrawCircle(const Point & center, float radius)
|
void Canvas::DrawCircle(Point const& center, float radius)
|
||||||
{
|
{
|
||||||
render_target_->DrawEllipse(
|
rt_.DrawEllipse(
|
||||||
D2D1::Ellipse(
|
center,
|
||||||
D2D1::Point2F(
|
Vec2(radius, radius),
|
||||||
center.x,
|
stroke_color_,
|
||||||
center.y
|
|
||||||
),
|
|
||||||
radius,
|
|
||||||
radius
|
|
||||||
),
|
|
||||||
stroke_brush_.get(),
|
|
||||||
stroke_width_,
|
stroke_width_,
|
||||||
outline_join_style_.get()
|
stroke_style_
|
||||||
);
|
);
|
||||||
cache_expired_ = true;
|
cache_expired_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::DrawEllipse(const Point & center, float radius_x, float radius_y)
|
void Canvas::DrawEllipse(Point const& center, Vec2 const& radius)
|
||||||
{
|
{
|
||||||
render_target_->DrawEllipse(
|
rt_.DrawEllipse(
|
||||||
D2D1::Ellipse(
|
center,
|
||||||
D2D1::Point2F(
|
radius,
|
||||||
center.x,
|
stroke_color_,
|
||||||
center.y
|
|
||||||
),
|
|
||||||
radius_x,
|
|
||||||
radius_y
|
|
||||||
),
|
|
||||||
stroke_brush_.get(),
|
|
||||||
stroke_width_,
|
stroke_width_,
|
||||||
outline_join_style_.get()
|
stroke_style_
|
||||||
);
|
);
|
||||||
cache_expired_ = true;
|
cache_expired_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::DrawRect(const Rect & rect)
|
void Canvas::DrawRect(Rect const& rect)
|
||||||
{
|
{
|
||||||
render_target_->DrawRectangle(
|
rt_.DrawRectangle(
|
||||||
D2D1::RectF(
|
rect,
|
||||||
rect.origin.x,
|
stroke_color_,
|
||||||
rect.origin.y,
|
|
||||||
rect.origin.x + rect.size.x,
|
|
||||||
rect.origin.y + rect.size.y
|
|
||||||
),
|
|
||||||
stroke_brush_.get(),
|
|
||||||
stroke_width_,
|
stroke_width_,
|
||||||
outline_join_style_.get()
|
stroke_style_
|
||||||
);
|
);
|
||||||
cache_expired_ = true;
|
cache_expired_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::DrawRoundedRect(const Rect & rect, float radius_x, float radius_y)
|
void Canvas::DrawRoundedRect(Rect const& rect, Vec2 const& radius)
|
||||||
{
|
{
|
||||||
render_target_->DrawRoundedRectangle(
|
rt_.DrawRoundedRectangle(
|
||||||
D2D1::RoundedRect(
|
rect,
|
||||||
D2D1::RectF(
|
radius,
|
||||||
rect.origin.x,
|
stroke_color_,
|
||||||
rect.origin.y,
|
|
||||||
rect.origin.x + rect.size.x,
|
|
||||||
rect.origin.y + rect.size.y
|
|
||||||
),
|
|
||||||
radius_x,
|
|
||||||
radius_y
|
|
||||||
),
|
|
||||||
stroke_brush_.get(),
|
|
||||||
stroke_width_,
|
stroke_width_,
|
||||||
outline_join_style_.get()
|
stroke_style_
|
||||||
);
|
);
|
||||||
cache_expired_ = true;
|
cache_expired_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::DrawImage(ImagePtr image, float opacity)
|
void Canvas::FillCircle(Point const& center, float radius)
|
||||||
{
|
{
|
||||||
if (image && image->GetBitmap())
|
rt_.FillEllipse(
|
||||||
|
center,
|
||||||
|
Vec2(radius, radius),
|
||||||
|
fill_color_
|
||||||
|
);
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::FillEllipse(Point const& center, Vec2 const& radius)
|
||||||
|
{
|
||||||
|
rt_.FillEllipse(
|
||||||
|
center,
|
||||||
|
radius,
|
||||||
|
fill_color_
|
||||||
|
);
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::FillRect(Rect const& rect)
|
||||||
|
{
|
||||||
|
rt_.FillRectangle(
|
||||||
|
rect,
|
||||||
|
fill_color_
|
||||||
|
);
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::FillRoundedRect(Rect const& rect, Vec2 const& radius)
|
||||||
|
{
|
||||||
|
rt_.FillRoundedRectangle(
|
||||||
|
rect,
|
||||||
|
radius,
|
||||||
|
fill_color_
|
||||||
|
);
|
||||||
|
cache_expired_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::DrawImage(Image const& image, const Rect* src_rect, const Rect* dest_rect)
|
||||||
|
{
|
||||||
|
if (image.IsValid())
|
||||||
{
|
{
|
||||||
render_target_->DrawBitmap(
|
rt_.DrawImage(image, src_rect, dest_rect);
|
||||||
image->GetBitmap().get(),
|
|
||||||
D2D1::RectF(0, 0, image->GetWidth(), image->GetHeight()),
|
|
||||||
opacity,
|
|
||||||
D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
|
|
||||||
D2D1::RectF(0, 0, image->GetWidth(), image->GetHeight())
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
cache_expired_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::DrawText(String const & text, Point const & point)
|
void Canvas::DrawText(String const& text, Point const& point)
|
||||||
{
|
{
|
||||||
if (text.empty())
|
if (text.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!text_format_)
|
TextLayout layout(text, text_font_, text_style_);
|
||||||
{
|
|
||||||
ThrowIfFailed(
|
|
||||||
Renderer::GetInstance()->GetD2DDeviceResources()->CreateTextFormat(
|
|
||||||
text_format_,
|
|
||||||
text_font_
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ComPtr<IDWriteTextLayout> text_layout;
|
rt_.DrawTextLayout(layout, point);
|
||||||
ThrowIfFailed(
|
|
||||||
Renderer::GetInstance()->GetD2DDeviceResources()->CreateTextLayout(
|
|
||||||
text_layout,
|
|
||||||
text,
|
|
||||||
text_style_,
|
|
||||||
text_format_
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
ThrowIfFailed(
|
|
||||||
text_layout->Draw(nullptr, text_renderer_.get(), point.x, point.y)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::FillCircle(const Point & center, float radius)
|
|
||||||
{
|
|
||||||
render_target_->FillEllipse(
|
|
||||||
D2D1::Ellipse(
|
|
||||||
D2D1::Point2F(
|
|
||||||
center.x,
|
|
||||||
center.y
|
|
||||||
),
|
|
||||||
radius,
|
|
||||||
radius
|
|
||||||
),
|
|
||||||
fill_brush_.get()
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::FillEllipse(const Point & center, float radius_x, float radius_y)
|
|
||||||
{
|
|
||||||
render_target_->FillEllipse(
|
|
||||||
D2D1::Ellipse(
|
|
||||||
D2D1::Point2F(
|
|
||||||
center.x,
|
|
||||||
center.y
|
|
||||||
),
|
|
||||||
radius_x,
|
|
||||||
radius_y
|
|
||||||
),
|
|
||||||
fill_brush_.get()
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::FillRect(const Rect & rect)
|
|
||||||
{
|
|
||||||
render_target_->FillRectangle(
|
|
||||||
D2D1::RectF(
|
|
||||||
rect.origin.x,
|
|
||||||
rect.origin.y,
|
|
||||||
rect.origin.x + rect.size.x,
|
|
||||||
rect.origin.y + rect.size.y
|
|
||||||
),
|
|
||||||
fill_brush_.get()
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Canvas::FillRoundedRect(const Rect & rect, float radius_x, float radius_y)
|
|
||||||
{
|
|
||||||
render_target_->FillRoundedRectangle(
|
|
||||||
D2D1::RoundedRect(
|
|
||||||
D2D1::RectF(
|
|
||||||
rect.origin.x,
|
|
||||||
rect.origin.y,
|
|
||||||
rect.origin.x + rect.size.x,
|
|
||||||
rect.origin.y + rect.size.y
|
|
||||||
),
|
|
||||||
radius_x,
|
|
||||||
radius_y
|
|
||||||
),
|
|
||||||
fill_brush_.get()
|
|
||||||
);
|
|
||||||
cache_expired_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::BeginPath(Point const& begin_pos)
|
void Canvas::BeginPath(Point const& begin_pos)
|
||||||
{
|
{
|
||||||
current_geometry_ = nullptr;
|
geo_sink_.BeginPath(begin_pos);
|
||||||
|
|
||||||
ThrowIfFailed(
|
|
||||||
Renderer::GetInstance()->GetD2DDeviceResources()->GetFactory()->CreatePathGeometry(¤t_geometry_)
|
|
||||||
);
|
|
||||||
|
|
||||||
ThrowIfFailed(
|
|
||||||
current_geometry_->Open(¤t_sink_)
|
|
||||||
);
|
|
||||||
|
|
||||||
current_sink_->BeginFigure(DX::ConvertToPoint2F(begin_pos), D2D1_FIGURE_BEGIN_FILLED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::EndPath(bool closed)
|
void Canvas::EndPath(bool closed)
|
||||||
{
|
{
|
||||||
if (current_sink_)
|
geo_sink_.EndPath(closed);
|
||||||
{
|
|
||||||
current_sink_->EndFigure(closed ? D2D1_FIGURE_END_CLOSED : D2D1_FIGURE_END_OPEN);
|
|
||||||
ThrowIfFailed(
|
|
||||||
current_sink_->Close()
|
|
||||||
);
|
|
||||||
current_sink_ = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::AddLine(Point const & point)
|
void Canvas::AddLine(Point const & point)
|
||||||
{
|
{
|
||||||
if (current_sink_)
|
geo_sink_.AddLine(point);
|
||||||
current_sink_->AddLine(DX::ConvertToPoint2F(point));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::AddLines(Vector<Point> const& points)
|
void Canvas::AddLines(Vector<Point> const& points)
|
||||||
{
|
{
|
||||||
if (current_sink_ && !points.empty())
|
geo_sink_.AddLines(points);
|
||||||
{
|
|
||||||
current_sink_->AddLines(
|
|
||||||
reinterpret_cast<const D2D_POINT_2F*>(&points[0]),
|
|
||||||
static_cast<UINT32>(points.size())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::AddBezier(Point const & point1, Point const & point2, Point const & point3)
|
void Canvas::AddBezier(Point const & point1, Point const & point2, Point const & point3)
|
||||||
{
|
{
|
||||||
if (current_sink_)
|
geo_sink_.AddBezier(point1, point2, point3);
|
||||||
{
|
|
||||||
current_sink_->AddBezier(
|
|
||||||
D2D1::BezierSegment(
|
|
||||||
DX::ConvertToPoint2F(point1),
|
|
||||||
DX::ConvertToPoint2F(point2),
|
|
||||||
DX::ConvertToPoint2F(point3)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::AddArc(Point const & point, Point const & radius, float rotation, bool clockwise, bool is_small)
|
void Canvas::AddArc(Point const & point, Point const & radius, float rotation, bool clockwise, bool is_small)
|
||||||
{
|
{
|
||||||
if (current_sink_)
|
geo_sink_.AddArc(point, radius, rotation, clockwise, is_small);
|
||||||
{
|
|
||||||
current_sink_->AddArc(
|
|
||||||
D2D1::ArcSegment(
|
|
||||||
DX::ConvertToPoint2F(point),
|
|
||||||
DX::ConvertToSizeF(radius),
|
|
||||||
rotation,
|
|
||||||
clockwise ? D2D1_SWEEP_DIRECTION_CLOCKWISE : D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE,
|
|
||||||
is_small ? D2D1_ARC_SIZE_SMALL : D2D1_ARC_SIZE_LARGE
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::StrokePath()
|
void Canvas::StrokePath()
|
||||||
{
|
{
|
||||||
render_target_->DrawGeometry(
|
rt_.DrawGeometry(
|
||||||
current_geometry_.get(),
|
geo_sink_.GetGeometry(),
|
||||||
stroke_brush_.get(),
|
stroke_color_,
|
||||||
stroke_width_,
|
stroke_width_,
|
||||||
outline_join_style_.get()
|
stroke_style_
|
||||||
);
|
);
|
||||||
cache_expired_ = true;
|
cache_expired_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::FillPath()
|
void Canvas::FillPath()
|
||||||
{
|
{
|
||||||
render_target_->FillGeometry(
|
rt_.FillGeometry(
|
||||||
current_geometry_.get(),
|
geo_sink_.GetGeometry(),
|
||||||
fill_brush_.get()
|
fill_color_
|
||||||
);
|
);
|
||||||
cache_expired_ = true;
|
cache_expired_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::Clear()
|
void Canvas::Clear()
|
||||||
{
|
{
|
||||||
render_target_->Clear();
|
rt_.Clear();
|
||||||
cache_expired_ = true;
|
cache_expired_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagePtr Canvas::ExportToImage() const
|
void Canvas::Clear(Color const& clear_color)
|
||||||
{
|
{
|
||||||
ImagePtr image = new Image(GetBitmap());
|
rt_.Clear(clear_color);
|
||||||
return image;
|
cache_expired_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ComPtr<ID2D1Bitmap> const& kiwano::Canvas::GetBitmap() const
|
Image Canvas::ExportToImage() const
|
||||||
|
{
|
||||||
|
UpdateCache();
|
||||||
|
return image_cached_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::UpdateCache() const
|
||||||
{
|
{
|
||||||
if (cache_expired_)
|
if (cache_expired_)
|
||||||
{
|
{
|
||||||
bitmap_cached_ = nullptr;
|
rt_.GetOutput(image_cached_);
|
||||||
ThrowIfFailed(
|
|
||||||
render_target_->GetBitmap(&bitmap_cached_)
|
|
||||||
);
|
|
||||||
cache_expired_ = false;
|
cache_expired_ = false;
|
||||||
}
|
}
|
||||||
return bitmap_cached_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "Actor.h"
|
#include "Actor.h"
|
||||||
#include "Font.hpp"
|
#include "../renderer/RenderTarget.h"
|
||||||
#include "TextStyle.hpp"
|
|
||||||
#include "../renderer/Image.h"
|
|
||||||
#include "../renderer/TextRenderer.h"
|
|
||||||
|
|
||||||
#ifdef DrawText
|
#ifdef DrawText
|
||||||
# undef DrawText
|
# undef DrawText
|
||||||
|
|
@ -57,39 +54,61 @@ namespace kiwano
|
||||||
|
|
||||||
// 画直线
|
// 画直线
|
||||||
void DrawLine(
|
void DrawLine(
|
||||||
const Point& begin,
|
Point const& begin,
|
||||||
const Point& end
|
Point const& end
|
||||||
);
|
);
|
||||||
|
|
||||||
// 画圆形边框
|
// 画圆形边框
|
||||||
void DrawCircle(
|
void DrawCircle(
|
||||||
const Point& center,
|
Point const& center,
|
||||||
float radius
|
float radius
|
||||||
);
|
);
|
||||||
|
|
||||||
// 画椭圆形边框
|
// 画椭圆形边框
|
||||||
void DrawEllipse(
|
void DrawEllipse(
|
||||||
const Point& center,
|
Point const& center,
|
||||||
float radius_x,
|
Vec2 const& radius
|
||||||
float radius_y
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// 画矩形边框
|
// 画矩形边框
|
||||||
void DrawRect(
|
void DrawRect(
|
||||||
const Rect& rect
|
Rect const& rect
|
||||||
);
|
);
|
||||||
|
|
||||||
// 画圆角矩形边框
|
// 画圆角矩形边框
|
||||||
void DrawRoundedRect(
|
void DrawRoundedRect(
|
||||||
const Rect& rect,
|
Rect const& rect,
|
||||||
float radius_x,
|
Vec2 const& radius
|
||||||
float radius_y
|
);
|
||||||
|
|
||||||
|
// Ìî³äÔ²ÐÎ
|
||||||
|
void FillCircle(
|
||||||
|
Point const& center,
|
||||||
|
float radius
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ìî³äÍÖÔ²ÐÎ
|
||||||
|
void FillEllipse(
|
||||||
|
Point const& center,
|
||||||
|
Vec2 const& radius
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ìî³ä¾ØÐÎ
|
||||||
|
void FillRect(
|
||||||
|
Rect const& rect
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ìî³äÔ²½Ç¾ØÐÎ
|
||||||
|
void FillRoundedRect(
|
||||||
|
Rect const& rect,
|
||||||
|
Vec2 const& radius
|
||||||
);
|
);
|
||||||
|
|
||||||
// 画图片
|
// 画图片
|
||||||
void DrawImage(
|
void DrawImage(
|
||||||
ImagePtr image,
|
Image const& image,
|
||||||
float opacity = 1.f
|
const Rect* src_rect = nullptr,
|
||||||
|
const Rect* dest_rect = nullptr
|
||||||
);
|
);
|
||||||
|
|
||||||
// 画文字
|
// 画文字
|
||||||
|
|
@ -98,31 +117,6 @@ namespace kiwano
|
||||||
Point const& point /* 文字位置 */
|
Point const& point /* 文字位置 */
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ìî³äÔ²ÐÎ
|
|
||||||
void FillCircle(
|
|
||||||
const Point& center,
|
|
||||||
float radius
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ìî³äÍÖÔ²ÐÎ
|
|
||||||
void FillEllipse(
|
|
||||||
const Point& center,
|
|
||||||
float radius_x,
|
|
||||||
float radius_y
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ìî³ä¾ØÐÎ
|
|
||||||
void FillRect(
|
|
||||||
const Rect& rect
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ìî³äÔ²½Ç¾ØÐÎ
|
|
||||||
void FillRoundedRect(
|
|
||||||
const Rect& rect,
|
|
||||||
float radius_x,
|
|
||||||
float radius_y
|
|
||||||
);
|
|
||||||
|
|
||||||
// 开始绘制路径
|
// 开始绘制路径
|
||||||
void BeginPath(
|
void BeginPath(
|
||||||
Point const& begin_pos /* 路径起始点 */
|
Point const& begin_pos /* 路径起始点 */
|
||||||
|
|
@ -168,14 +162,19 @@ namespace kiwano
|
||||||
// 清空画布
|
// 清空画布
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
|
// Çå¿Õ»²¼
|
||||||
|
void Clear(
|
||||||
|
Color const& clear_color
|
||||||
|
);
|
||||||
|
|
||||||
// 设置填充颜色
|
// 设置填充颜色
|
||||||
void SetFillColor(
|
void SetFillColor(
|
||||||
const Color& color
|
Color const& color
|
||||||
);
|
);
|
||||||
|
|
||||||
// 设置线条颜色
|
// 设置线条颜色
|
||||||
void SetStrokeColor(
|
void SetStrokeColor(
|
||||||
const Color& color
|
Color const& color
|
||||||
);
|
);
|
||||||
|
|
||||||
// 设置线条宽度
|
// 设置线条宽度
|
||||||
|
|
@ -183,17 +182,26 @@ namespace kiwano
|
||||||
float width
|
float width
|
||||||
);
|
);
|
||||||
|
|
||||||
// ÉèÖÃÏßÌõÏཻÑùʽ
|
// ÉèÖÃÏßÌõÑùʽ
|
||||||
void SetOutlineJoinStyle(
|
void SetStrokeStyle(
|
||||||
StrokeStyle outline_join
|
StrokeStyle stroke_style
|
||||||
|
);
|
||||||
|
|
||||||
|
// ÉèÖÃÎÄ×Ö×ÖÌå
|
||||||
|
void SetTextFont(
|
||||||
|
Font const& font
|
||||||
);
|
);
|
||||||
|
|
||||||
// 设置文字画刷样式
|
// 设置文字画刷样式
|
||||||
void SetTextStyle(
|
void SetTextStyle(
|
||||||
Font const& font,
|
|
||||||
TextStyle const& text_style
|
TextStyle const& text_style
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ÉèÖû±Ê͸Ã÷¶È
|
||||||
|
void SetBrushOpacity(
|
||||||
|
float opacity
|
||||||
|
);
|
||||||
|
|
||||||
// 获取填充颜色
|
// 获取填充颜色
|
||||||
Color GetFillColor() const;
|
Color GetFillColor() const;
|
||||||
|
|
||||||
|
|
@ -203,34 +211,38 @@ namespace kiwano
|
||||||
// 获取线条宽度
|
// 获取线条宽度
|
||||||
float GetStrokeWidth() const;
|
float GetStrokeWidth() const;
|
||||||
|
|
||||||
// ±ä»»»±Ê
|
// »ñÈ¡»±Ê͸Ã÷¶È
|
||||||
|
float GetBrushOpacity() const;
|
||||||
|
|
||||||
|
// »±Ê¶þά±ä»»
|
||||||
|
void SetBrushTransform(
|
||||||
|
Transform const& transform
|
||||||
|
);
|
||||||
|
|
||||||
|
// »±Ê¶þά±ä»»
|
||||||
void SetBrushTransform(
|
void SetBrushTransform(
|
||||||
Matrix3x2 const& transform
|
Matrix3x2 const& transform
|
||||||
);
|
);
|
||||||
|
|
||||||
// 导出为图片
|
// 导出为图片
|
||||||
ImagePtr ExportToImage() const;
|
Image ExportToImage() const;
|
||||||
|
|
||||||
void OnRender(Renderer* renderer) override;
|
void OnRender(Renderer* renderer) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ComPtr<ID2D1Bitmap> const& GetBitmap() const;
|
void UpdateCache() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float stroke_width_;
|
float stroke_width_;
|
||||||
Font text_font_;
|
Color fill_color_;
|
||||||
TextStyle text_style_;
|
Color stroke_color_;
|
||||||
|
Font text_font_;
|
||||||
|
TextStyle text_style_;
|
||||||
|
StrokeStyle stroke_style_;
|
||||||
|
GeometrySink geo_sink_;
|
||||||
|
ImageRenderTarget rt_;
|
||||||
|
|
||||||
ComPtr<ID2D1PathGeometry> current_geometry_;
|
mutable bool cache_expired_;
|
||||||
ComPtr<ID2D1GeometrySink> current_sink_;
|
mutable Image image_cached_;
|
||||||
ComPtr<ID2D1StrokeStyle> outline_join_style_;
|
|
||||||
ComPtr<ID2D1SolidColorBrush> fill_brush_;
|
|
||||||
ComPtr<ID2D1SolidColorBrush> stroke_brush_;
|
|
||||||
ComPtr<IDWriteTextFormat> text_format_;
|
|
||||||
ComPtr<ITextRenderer> text_renderer_;
|
|
||||||
ComPtr<ID2D1BitmapRenderTarget> render_target_;
|
|
||||||
|
|
||||||
mutable bool cache_expired_;
|
|
||||||
mutable ComPtr<ID2D1Bitmap> bitmap_cached_;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,15 +32,15 @@ namespace kiwano
|
||||||
Load(res);
|
Load(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame::Frame(ImagePtr image)
|
Frame::Frame(Image const& image)
|
||||||
: image_(image)
|
: image_(image)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Frame::Load(Resource const& res)
|
bool Frame::Load(Resource const& res)
|
||||||
{
|
{
|
||||||
ImagePtr image = ImageCache::GetInstance()->AddImage(res);
|
Image image = ImageCache::GetInstance()->AddImage(res);
|
||||||
if (image && image->IsValid())
|
if (image.IsValid())
|
||||||
{
|
{
|
||||||
SetImage(image);
|
SetImage(image);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -48,11 +48,11 @@ namespace kiwano
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Frame::Crop(Rect const& crop_rect)
|
void Frame::SetCropRect(Rect const& crop_rect)
|
||||||
{
|
{
|
||||||
if (image_)
|
if (image_.IsValid())
|
||||||
{
|
{
|
||||||
auto bitmap_size = image_->GetSize();
|
auto bitmap_size = image_.GetSize();
|
||||||
crop_rect_.origin.x = std::min(std::max(crop_rect.origin.x, 0.f), bitmap_size.x);
|
crop_rect_.origin.x = std::min(std::max(crop_rect.origin.x, 0.f), bitmap_size.x);
|
||||||
crop_rect_.origin.y = std::min(std::max(crop_rect.origin.y, 0.f), bitmap_size.y);
|
crop_rect_.origin.y = std::min(std::max(crop_rect.origin.y, 0.f), bitmap_size.y);
|
||||||
crop_rect_.size.x = std::min(std::max(crop_rect.size.x, 0.f), bitmap_size.x - crop_rect.origin.x);
|
crop_rect_.size.x = std::min(std::max(crop_rect.size.x, 0.f), bitmap_size.x - crop_rect.origin.x);
|
||||||
|
|
@ -60,14 +60,14 @@ namespace kiwano
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Frame::SetImage(ImagePtr image)
|
void Frame::SetImage(Image const& image)
|
||||||
{
|
{
|
||||||
image_ = image;
|
image_ = image;
|
||||||
if (image_)
|
if (image_.IsValid())
|
||||||
{
|
{
|
||||||
crop_rect_.origin.x = crop_rect_.origin.y = 0;
|
crop_rect_.origin.x = crop_rect_.origin.y = 0;
|
||||||
crop_rect_.size.x = image_->GetWidth();
|
crop_rect_.size.x = image_.GetWidth();
|
||||||
crop_rect_.size.y = image_->GetHeight();
|
crop_rect_.size.y = image_.GetHeight();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ namespace kiwano
|
||||||
);
|
);
|
||||||
|
|
||||||
explicit Frame(
|
explicit Frame(
|
||||||
ImagePtr image
|
Image const& image
|
||||||
);
|
);
|
||||||
|
|
||||||
bool Load(
|
bool Load(
|
||||||
|
|
@ -43,7 +43,7 @@ namespace kiwano
|
||||||
);
|
);
|
||||||
|
|
||||||
// ²Ã¼ô¾ØÐÎ
|
// ²Ã¼ô¾ØÐÎ
|
||||||
void Crop(
|
void SetCropRect(
|
||||||
Rect const& crop_rect /* ²Ã¼ô¾ØÐÎ */
|
Rect const& crop_rect /* ²Ã¼ô¾ØÐÎ */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -63,13 +63,13 @@ namespace kiwano
|
||||||
inline Rect const& GetCropRect() const { return crop_rect_; }
|
inline Rect const& GetCropRect() const { return crop_rect_; }
|
||||||
|
|
||||||
// »ñȡλͼ
|
// »ñȡλͼ
|
||||||
inline ImagePtr GetImage() const { return image_; }
|
inline Image const& GetImage() const { return image_; }
|
||||||
|
|
||||||
// ÉèÖÃλͼ
|
// ÉèÖÃλͼ
|
||||||
void SetImage(ImagePtr image);
|
void SetImage(Image const& image);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ImagePtr image_;
|
Image image_;
|
||||||
Rect crop_rect_;
|
Rect crop_rect_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@
|
||||||
|
|
||||||
#include "GifSprite.h"
|
#include "GifSprite.h"
|
||||||
#include "../base/Logger.h"
|
#include "../base/Logger.h"
|
||||||
#include "../platform/modules.h"
|
#include "../renderer/ImageCache.h"
|
||||||
|
#include "../renderer/Renderer.h"
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
|
|
@ -29,6 +30,7 @@ namespace kiwano
|
||||||
, next_index_(0)
|
, next_index_(0)
|
||||||
, total_loop_count_(1)
|
, total_loop_count_(1)
|
||||||
, loop_count_(0)
|
, loop_count_(0)
|
||||||
|
, disposal_type_(DisposalType::Unknown)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,12 +47,8 @@ namespace kiwano
|
||||||
|
|
||||||
bool GifSprite::Load(Resource const& res)
|
bool GifSprite::Load(Resource const& res)
|
||||||
{
|
{
|
||||||
GifImagePtr image = new (std::nothrow) GifImage;
|
GifImagePtr image = ImageCache::GetInstance()->AddGifImage(res);
|
||||||
if (image->Load(res))
|
return Load(image);
|
||||||
{
|
|
||||||
return Load(image);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GifSprite::Load(GifImagePtr image)
|
bool GifSprite::Load(GifImagePtr image)
|
||||||
|
|
@ -61,18 +59,16 @@ namespace kiwano
|
||||||
|
|
||||||
next_index_ = 0;
|
next_index_ = 0;
|
||||||
loop_count_ = 0;
|
loop_count_ = 0;
|
||||||
|
disposal_type_ = DisposalType::None;
|
||||||
|
|
||||||
SetSize(
|
SetSize(
|
||||||
static_cast<float>(image_->GetWidthInPixels()),
|
static_cast<float>(image_->GetWidthInPixels()),
|
||||||
static_cast<float>(image_->GetHeightInPixels())
|
static_cast<float>(image_->GetHeightInPixels())
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!frame_rt_)
|
if (!frame_rt_.IsValid())
|
||||||
{
|
{
|
||||||
auto ctx = Renderer::GetInstance()->GetD2DDeviceResources()->GetDeviceContext();
|
Renderer::GetInstance()->CreateImageRenderTarget(frame_rt_);
|
||||||
ThrowIfFailed(
|
|
||||||
ctx->CreateCompatibleRenderTarget(&frame_rt_)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (image_->GetFramesCount() > 0)
|
if (image_->GetFramesCount() > 0)
|
||||||
|
|
@ -84,6 +80,16 @@ namespace kiwano
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GifSprite::OnRender(Renderer* renderer)
|
||||||
|
{
|
||||||
|
if (frame_.IsValid() && renderer->CheckVisibility(size_, transform_matrix_))
|
||||||
|
{
|
||||||
|
PrepareRender(renderer);
|
||||||
|
|
||||||
|
renderer->DrawImage(frame_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GifSprite::Update(Duration dt)
|
void GifSprite::Update(Duration dt)
|
||||||
{
|
{
|
||||||
Actor::Update(dt);
|
Actor::Update(dt);
|
||||||
|
|
@ -100,84 +106,94 @@ namespace kiwano
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GifSprite::OnRender(Renderer* renderer)
|
|
||||||
{
|
|
||||||
if (frame_to_render_ && renderer->CheckVisibility(size_, transform_matrix_))
|
|
||||||
{
|
|
||||||
PrepareRender(renderer);
|
|
||||||
|
|
||||||
Rect bounds = GetBounds();
|
|
||||||
renderer->DrawBitmap(frame_to_render_, bounds, bounds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GifSprite::RestartAnimation()
|
void GifSprite::RestartAnimation()
|
||||||
{
|
{
|
||||||
animating_ = true;
|
animating_ = true;
|
||||||
next_index_ = 0;
|
next_index_ = 0;
|
||||||
loop_count_ = 0;
|
loop_count_ = 0;
|
||||||
image_->SetDisposalType(GifImage::DisposalType::None);
|
disposal_type_ = DisposalType::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GifSprite::ComposeNextFrame()
|
void GifSprite::ComposeNextFrame()
|
||||||
{
|
{
|
||||||
if (frame_rt_)
|
if (frame_rt_.IsValid())
|
||||||
{
|
{
|
||||||
// 找到延迟大于 0 的帧 (0 延迟帧是不可见的中间帧)
|
|
||||||
HRESULT hr = E_FAIL;
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
hr = image_->DisposeCurrentFrame(frame_rt_);
|
DisposeCurrentFrame();
|
||||||
if (SUCCEEDED(hr))
|
OverlayNextFrame();
|
||||||
{
|
} while (frame_delay_.IsZero() && !IsLastFrame());
|
||||||
hr = OverlayNextFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
frame_delay_.SetMilliseconds(static_cast<long>(image_->GetFrameDelay()));
|
|
||||||
}
|
|
||||||
} while (SUCCEEDED(hr) && frame_delay_.IsZero() && !IsLastFrame());
|
|
||||||
|
|
||||||
animating_ = (SUCCEEDED(hr) && !EndOfAnimation() && image_->GetFramesCount() > 1);
|
animating_ = (!EndOfAnimation() && image_->GetFramesCount() > 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT GifSprite::OverlayNextFrame()
|
void GifSprite::DisposeCurrentFrame()
|
||||||
{
|
{
|
||||||
HRESULT hr = image_->GetRawFrame(next_index_);
|
switch (disposal_type_)
|
||||||
|
{
|
||||||
|
case DisposalType::Unknown:
|
||||||
|
case DisposalType::None:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DisposalType::Background:
|
||||||
|
{
|
||||||
|
ClearCurrentFrameArea();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DisposalType::Previous:
|
||||||
|
{
|
||||||
|
RestoreSavedFrame();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
ThrowIfFailed(E_FAIL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSprite::OverlayNextFrame()
|
||||||
|
{
|
||||||
|
Image raw_image;
|
||||||
|
|
||||||
|
HRESULT hr = image_->GetRawFrame(next_index_, raw_image, frame_rect_, frame_delay_, disposal_type_);
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
if (image_->GetDisposalType() == GifImage::DisposalType::Previous)
|
if (disposal_type_ == DisposalType::Previous)
|
||||||
{
|
{
|
||||||
hr = image_->SaveComposedFrame(frame_rt_);
|
SaveComposedFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
frame_rt_->BeginDraw();
|
frame_rt_.BeginDraw();
|
||||||
|
|
||||||
if (next_index_ == 0)
|
if (next_index_ == 0)
|
||||||
{
|
{
|
||||||
// ÖØÐ»æÖƱ³¾°
|
// ÖØÐ»æÖƱ³¾°
|
||||||
frame_rt_->Clear(image_->GetBackgroundColor());
|
frame_rt_.Clear(image_->GetBackgroundColor());
|
||||||
loop_count_++;
|
loop_count_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame_rt_->DrawBitmap(image_->GetRawFrame().get(), image_->GetFramePosition());
|
frame_rt_.DrawImage(raw_image, nullptr, &frame_rect_);
|
||||||
hr = frame_rt_->EndDraw();
|
frame_rt_.EndDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
frame_to_render_ = nullptr;
|
Image frame_to_render;
|
||||||
hr = frame_rt_->GetBitmap(&frame_to_render_);
|
frame_rt_.GetOutput(frame_to_render);
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
hr = frame_to_render.IsValid() ? S_OK : E_FAIL;
|
||||||
{
|
|
||||||
next_index_ = (++next_index_) % image_->GetFramesCount();
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
frame_ = frame_to_render;
|
||||||
|
next_index_ = (++next_index_) % image_->GetFramesCount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsLastFrame() && loop_cb_)
|
if (IsLastFrame() && loop_cb_)
|
||||||
|
|
@ -189,7 +205,71 @@ namespace kiwano
|
||||||
{
|
{
|
||||||
done_cb_();
|
done_cb_();
|
||||||
}
|
}
|
||||||
return hr;
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSprite::SaveComposedFrame()
|
||||||
|
{
|
||||||
|
Image frame_to_be_saved;
|
||||||
|
frame_rt_.GetOutput(frame_to_be_saved);
|
||||||
|
|
||||||
|
HRESULT hr = frame_to_be_saved.IsValid() ? S_OK : E_FAIL;
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
if (!saved_frame_.IsValid())
|
||||||
|
{
|
||||||
|
auto size = frame_to_be_saved.GetSizeInPixels();
|
||||||
|
auto prop = D2D1::BitmapProperties(frame_to_be_saved.GetPixelFormat());
|
||||||
|
|
||||||
|
ComPtr<ID2D1Bitmap> saved_bitmap;
|
||||||
|
hr = frame_rt_.GetRenderTarget()->CreateBitmap(D2D1::SizeU(size.x, size.y), prop, &saved_bitmap);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
saved_frame_.SetBitmap(saved_bitmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
saved_frame_.CopyFrom(frame_to_be_saved);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSprite::RestoreSavedFrame()
|
||||||
|
{
|
||||||
|
HRESULT hr = saved_frame_.IsValid() ? S_OK : E_FAIL;
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
Image frame_to_copy_to;
|
||||||
|
frame_rt_.GetOutput(frame_to_copy_to);
|
||||||
|
|
||||||
|
hr = frame_to_copy_to.IsValid() ? S_OK : E_FAIL;
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
frame_to_copy_to.CopyFrom(saved_frame_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GifSprite::ClearCurrentFrameArea()
|
||||||
|
{
|
||||||
|
frame_rt_.BeginDraw();
|
||||||
|
|
||||||
|
frame_rt_.PushClipRect(frame_rect_);
|
||||||
|
frame_rt_.Clear(image_->GetBackgroundColor());
|
||||||
|
frame_rt_.PopClipRect();
|
||||||
|
|
||||||
|
return frame_rt_.EndDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,17 +21,19 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "Actor.h"
|
#include "Actor.h"
|
||||||
#include "../base/Resource.h"
|
#include "../base/Resource.h"
|
||||||
#include "../renderer/Renderer.h"
|
#include "../renderer/RenderTarget.h"
|
||||||
#include "../renderer/GifImage.h"
|
#include "../renderer/GifImage.h"
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
|
// GIF ¾«Áé
|
||||||
class KGE_API GifSprite
|
class KGE_API GifSprite
|
||||||
: public Actor
|
: public Actor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using LoopDoneCallback = Function<void(int)>;
|
using DisposalType = GifImage::DisposalType;
|
||||||
using DoneCallback = Function<void()>;
|
using LoopDoneCallback = Function<void(int)>;
|
||||||
|
using DoneCallback = Function<void()>;
|
||||||
|
|
||||||
GifSprite();
|
GifSprite();
|
||||||
|
|
||||||
|
|
@ -72,27 +74,36 @@ namespace kiwano
|
||||||
protected:
|
protected:
|
||||||
void Update(Duration dt) override;
|
void Update(Duration dt) override;
|
||||||
|
|
||||||
void ComposeNextFrame();
|
|
||||||
|
|
||||||
HRESULT OverlayNextFrame();
|
|
||||||
|
|
||||||
inline bool IsLastFrame() const { return (next_index_ == 0); }
|
inline bool IsLastFrame() const { return (next_index_ == 0); }
|
||||||
|
|
||||||
inline bool EndOfAnimation() const { return IsLastFrame() && loop_count_ == total_loop_count_ + 1; }
|
inline bool EndOfAnimation() const { return IsLastFrame() && loop_count_ == total_loop_count_ + 1; }
|
||||||
|
|
||||||
protected:
|
void ComposeNextFrame();
|
||||||
bool animating_;
|
|
||||||
int total_loop_count_;
|
|
||||||
int loop_count_;
|
|
||||||
unsigned int next_index_;
|
|
||||||
Duration frame_delay_;
|
|
||||||
Duration frame_elapsed_;
|
|
||||||
|
|
||||||
|
void DisposeCurrentFrame();
|
||||||
|
|
||||||
|
void OverlayNextFrame();
|
||||||
|
|
||||||
|
void SaveComposedFrame();
|
||||||
|
|
||||||
|
void RestoreSavedFrame();
|
||||||
|
|
||||||
|
void ClearCurrentFrameArea();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool animating_;
|
||||||
|
int total_loop_count_;
|
||||||
|
int loop_count_;
|
||||||
|
UINT next_index_;
|
||||||
|
Duration frame_delay_;
|
||||||
|
Duration frame_elapsed_;
|
||||||
|
DisposalType disposal_type_;
|
||||||
LoopDoneCallback loop_cb_;
|
LoopDoneCallback loop_cb_;
|
||||||
DoneCallback done_cb_;
|
DoneCallback done_cb_;
|
||||||
|
GifImagePtr image_;
|
||||||
GifImagePtr image_;
|
Image frame_;
|
||||||
ComPtr<ID2D1Bitmap> frame_to_render_;
|
Rect frame_rect_;
|
||||||
ComPtr<ID2D1BitmapRenderTarget> frame_rt_;
|
Image saved_frame_;
|
||||||
|
ImageRenderTarget frame_rt_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ namespace kiwano
|
||||||
: fill_color_(Color::White)
|
: fill_color_(Color::White)
|
||||||
, stroke_color_(Color(Color::Black, 0))
|
, stroke_color_(Color(Color::Black, 0))
|
||||||
, stroke_width_(1.f)
|
, stroke_width_(1.f)
|
||||||
, outline_join_(StrokeStyle::Miter)
|
, stroke_style_(StrokeStyle::Miter)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,9 +73,9 @@ namespace kiwano
|
||||||
stroke_width_ = std::max(width, 0.f);
|
stroke_width_ = std::max(width, 0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeActor::SetOutlineJoinStyle(StrokeStyle outline_join)
|
void ShapeActor::SetStrokeStyle(StrokeStyle stroke_style)
|
||||||
{
|
{
|
||||||
outline_join_ = outline_join;
|
stroke_style_ = stroke_style;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeActor::OnRender(Renderer* renderer)
|
void ShapeActor::OnRender(Renderer* renderer)
|
||||||
|
|
@ -93,7 +93,7 @@ namespace kiwano
|
||||||
geo_,
|
geo_,
|
||||||
stroke_color_,
|
stroke_color_,
|
||||||
stroke_width_,
|
stroke_width_,
|
||||||
outline_join_
|
stroke_style_
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,8 @@ namespace kiwano
|
||||||
// ťńČĄĎßĚőżíśČ
|
// ťńČĄĎßĚőżíśČ
|
||||||
float GetStrokeWidth() const { return stroke_width_; }
|
float GetStrokeWidth() const { return stroke_width_; }
|
||||||
|
|
||||||
// ťńČĄĎßĚőĎཝŃůĘ˝
|
// »ñÈ¡ÏßÌõÑùʽ
|
||||||
StrokeStyle SetOutlineJoinStyle() const { return outline_join_; }
|
StrokeStyle SetStrokeStyle() const { return stroke_style_; }
|
||||||
|
|
||||||
// ťńČĄąß˝ç
|
// ťńČĄąß˝ç
|
||||||
Rect GetBounds() const override;
|
Rect GetBounds() const override;
|
||||||
|
|
@ -70,9 +70,9 @@ namespace kiwano
|
||||||
float width
|
float width
|
||||||
);
|
);
|
||||||
|
|
||||||
// ÉčÖĂĎßĚőĎཝŃůĘ˝
|
// ÉèÖÃÏßÌõÑùʽ
|
||||||
void SetOutlineJoinStyle(
|
void SetStrokeStyle(
|
||||||
StrokeStyle outline_join
|
StrokeStyle stroke_style
|
||||||
);
|
);
|
||||||
|
|
||||||
// ÉčÖĂĐÎ×´
|
// ÉčÖĂĐÎ×´
|
||||||
|
|
@ -87,7 +87,7 @@ namespace kiwano
|
||||||
Color fill_color_;
|
Color fill_color_;
|
||||||
Color stroke_color_;
|
Color stroke_color_;
|
||||||
float stroke_width_;
|
float stroke_width_;
|
||||||
StrokeStyle outline_join_;
|
StrokeStyle stroke_style_;
|
||||||
Geometry geo_;
|
Geometry geo_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ namespace kiwano
|
||||||
: frame_(nullptr)
|
: frame_(nullptr)
|
||||||
{
|
{
|
||||||
Load(res);
|
Load(res);
|
||||||
Crop(crop_rect);
|
SetCropRect(crop_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sprite::Sprite(FramePtr frame)
|
Sprite::Sprite(FramePtr frame)
|
||||||
|
|
@ -62,11 +62,11 @@ namespace kiwano
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sprite::Crop(const Rect& crop_rect)
|
void Sprite::SetCropRect(const Rect& crop_rect)
|
||||||
{
|
{
|
||||||
if (frame_)
|
if (frame_)
|
||||||
{
|
{
|
||||||
frame_->Crop(crop_rect);
|
frame_->SetCropRect(crop_rect);
|
||||||
SetSize(frame_->GetWidth(), frame_->GetHeight());
|
SetSize(frame_->GetWidth(), frame_->GetHeight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -89,7 +89,7 @@ namespace kiwano
|
||||||
{
|
{
|
||||||
PrepareRender(renderer);
|
PrepareRender(renderer);
|
||||||
|
|
||||||
renderer->DrawBitmap(frame_->GetImage()->GetBitmap(), frame_->GetCropRect(), GetBounds());
|
renderer->DrawImage(frame_->GetImage(), &frame_->GetCropRect(), nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ namespace kiwano
|
||||||
);
|
);
|
||||||
|
|
||||||
// ²Ã¼ô¾ØÐÎ
|
// ²Ã¼ô¾ØÐÎ
|
||||||
void Crop(
|
void SetCropRect(
|
||||||
const Rect& crop_rect
|
const Rect& crop_rect
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ namespace kiwano
|
||||||
if (text_layout_ && renderer->CheckVisibility(size_, transform_matrix_))
|
if (text_layout_ && renderer->CheckVisibility(size_, transform_matrix_))
|
||||||
{
|
{
|
||||||
PrepareRender(renderer);
|
PrepareRender(renderer);
|
||||||
renderer->DrawTextLayout(text_layout_);
|
renderer->DrawTextLayout(text_layout_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,30 +99,26 @@ namespace kiwano
|
||||||
{
|
{
|
||||||
if (out_scene_)
|
if (out_scene_)
|
||||||
{
|
{
|
||||||
renderer->PushClip(
|
renderer->SetTransform(out_scene_->GetTransformMatrix());
|
||||||
out_scene_->GetTransformMatrix(),
|
renderer->PushClipRect(Rect{ Point{}, window_size_ });
|
||||||
window_size_
|
|
||||||
);
|
|
||||||
renderer->PushLayer(out_layer_, out_layer_prop_);
|
renderer->PushLayer(out_layer_, out_layer_prop_);
|
||||||
|
|
||||||
out_scene_->Render(renderer);
|
out_scene_->Render(renderer);
|
||||||
|
|
||||||
renderer->PopLayer();
|
renderer->PopLayer();
|
||||||
renderer->PopClip();
|
renderer->PopClipRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_scene_)
|
if (in_scene_)
|
||||||
{
|
{
|
||||||
renderer->PushClip(
|
renderer->SetTransform(in_scene_->GetTransformMatrix());
|
||||||
in_scene_->GetTransformMatrix(),
|
renderer->PushClipRect(Rect{ Point{}, window_size_ });
|
||||||
window_size_
|
|
||||||
);
|
|
||||||
renderer->PushLayer(in_layer_, in_layer_prop_);
|
renderer->PushLayer(in_layer_, in_layer_prop_);
|
||||||
|
|
||||||
in_scene_->Render(renderer);
|
in_scene_->Render(renderer);
|
||||||
|
|
||||||
renderer->PopLayer();
|
renderer->PopLayer();
|
||||||
renderer->PopClip();
|
renderer->PopClipRect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
// サュアハム<EFBFBD>ス
|
// マ゚フ<EFBFBD><EFBFBD>ス
|
||||||
enum class StrokeStyle : int
|
enum class StrokeStyle : int
|
||||||
{
|
{
|
||||||
Miter = 0, /* бÇÐ */
|
Miter = 0, /* бÇÐ */
|
||||||
|
|
@ -68,4 +68,4 @@ namespace kiwano
|
||||||
Rect area;
|
Rect area;
|
||||||
float opacity;
|
float opacity;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,12 +56,22 @@
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// base
|
// renderer
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "renderer/Renderer.h"
|
|
||||||
#include "renderer/Image.h"
|
#include "renderer/Image.h"
|
||||||
#include "renderer/GifImage.h"
|
#include "renderer/GifImage.h"
|
||||||
|
#include "renderer/TextLayout.h"
|
||||||
|
#include "renderer/TextRenderer.h"
|
||||||
|
#include "renderer/Geometry.h"
|
||||||
|
#include "renderer/ImageCache.h"
|
||||||
|
#include "renderer/RenderTarget.h"
|
||||||
|
#include "renderer/Renderer.h"
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// base
|
||||||
|
//
|
||||||
|
|
||||||
#include "base/time.h"
|
#include "base/time.h"
|
||||||
#include "base/Window.h"
|
#include "base/Window.h"
|
||||||
|
|
@ -81,6 +91,11 @@
|
||||||
#include "base/AsyncTask.h"
|
#include "base/AsyncTask.h"
|
||||||
#include "base/Resource.h"
|
#include "base/Resource.h"
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 2d
|
||||||
|
//
|
||||||
|
|
||||||
#include "2d/Font.hpp"
|
#include "2d/Font.hpp"
|
||||||
#include "2d/Color.h"
|
#include "2d/Color.h"
|
||||||
#include "2d/Transform.hpp"
|
#include "2d/Transform.hpp"
|
||||||
|
|
@ -110,9 +125,15 @@
|
||||||
#include "2d/ShapeActor.h"
|
#include "2d/ShapeActor.h"
|
||||||
#include "2d/DebugActor.h"
|
#include "2d/DebugActor.h"
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// platform
|
||||||
|
//
|
||||||
|
|
||||||
#include "platform/modules.h"
|
#include "platform/modules.h"
|
||||||
#include "platform/Application.h"
|
#include "platform/Application.h"
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// utils
|
// utils
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -19,18 +19,15 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include "GifImage.h"
|
#include "GifImage.h"
|
||||||
|
#include "Renderer.h"
|
||||||
#include "../base/Logger.h"
|
#include "../base/Logger.h"
|
||||||
#include "../utils/FileUtil.h"
|
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
GifImage::GifImage()
|
GifImage::GifImage()
|
||||||
: frames_count_(0)
|
: frames_count_(0)
|
||||||
, disposal_type_(DisposalType::Unknown)
|
|
||||||
, width_in_pixels_(0)
|
, width_in_pixels_(0)
|
||||||
, height_in_pixels_(0)
|
, height_in_pixels_(0)
|
||||||
, frame_delay_(0)
|
|
||||||
, frame_position_{}
|
|
||||||
, bg_color_{}
|
, bg_color_{}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -43,234 +40,23 @@ namespace kiwano
|
||||||
|
|
||||||
bool GifImage::Load(Resource const& res)
|
bool GifImage::Load(Resource const& res)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
Renderer::GetInstance()->CreateGifImage(*this, res);
|
||||||
|
|
||||||
frames_count_ = 0;
|
if (IsValid())
|
||||||
disposal_type_ = DisposalType::None;
|
|
||||||
|
|
||||||
saved_frame_.reset();
|
|
||||||
decoder_.reset();
|
|
||||||
|
|
||||||
auto factory = Renderer::GetInstance()->GetD2DDeviceResources()->GetWICImagingFactory();
|
|
||||||
|
|
||||||
if (res.IsFileType())
|
|
||||||
{
|
{
|
||||||
#ifdef KGE_DEBUG
|
if (FAILED(GetGlobalMetadata()))
|
||||||
if (!FileUtil::ExistsFile(res.GetFileName().c_str()))
|
|
||||||
{
|
{
|
||||||
KGE_WARNING_LOG(L"Gif file '%s' not found!", res.GetFileName().c_str());
|
SetDecoder(nullptr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
return true;
|
||||||
|
|
||||||
hr = factory->CreateDecoderFromFilename(
|
|
||||||
res.GetFileName().c_str(),
|
|
||||||
nullptr,
|
|
||||||
GENERIC_READ,
|
|
||||||
WICDecodeMetadataCacheOnLoad,
|
|
||||||
&decoder_);
|
|
||||||
}
|
}
|
||||||
else
|
return false;
|
||||||
{
|
|
||||||
LPVOID buffer;
|
|
||||||
DWORD buffer_size;
|
|
||||||
HRESULT hr = res.Load(buffer, buffer_size) ? S_OK : E_FAIL;
|
|
||||||
|
|
||||||
ComPtr<IWICStream> stream;
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = factory->CreateStream(&stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = stream->InitializeFromMemory(
|
|
||||||
static_cast<WICInProcPointer>(buffer),
|
|
||||||
buffer_size
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = factory->CreateDecoderFromStream(
|
|
||||||
stream.get(),
|
|
||||||
nullptr,
|
|
||||||
WICDecodeMetadataCacheOnLoad,
|
|
||||||
&decoder_
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = GetGlobalMetadata();
|
|
||||||
}
|
|
||||||
|
|
||||||
return SUCCEEDED(hr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT GifImage::GetRawFrame(UINT frame_index)
|
bool GifImage::IsValid() const
|
||||||
{
|
{
|
||||||
ComPtr<IWICFormatConverter> converter;
|
return decoder_ != nullptr;
|
||||||
ComPtr<IWICBitmapFrameDecode> wic_frame;
|
|
||||||
ComPtr<IWICMetadataQueryReader> metadata_reader;
|
|
||||||
|
|
||||||
PROPVARIANT prop_val;
|
|
||||||
PropVariantInit(&prop_val);
|
|
||||||
|
|
||||||
// Retrieve the current frame
|
|
||||||
HRESULT hr = decoder_->GetFrame(frame_index, &wic_frame);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
// Format convert to 32bppPBGRA which D2D expects
|
|
||||||
auto factory = Renderer::GetInstance()->GetD2DDeviceResources()->GetWICImagingFactory();
|
|
||||||
hr = factory->CreateFormatConverter(&converter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = converter->Initialize(
|
|
||||||
wic_frame.get(),
|
|
||||||
GUID_WICPixelFormat32bppPBGRA,
|
|
||||||
WICBitmapDitherTypeNone,
|
|
||||||
nullptr,
|
|
||||||
0.f,
|
|
||||||
WICBitmapPaletteTypeCustom);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
auto ctx = Renderer::GetInstance()->GetD2DDeviceResources()->GetDeviceContext();
|
|
||||||
|
|
||||||
// Create a D2DBitmap from IWICBitmapSource
|
|
||||||
raw_frame_.reset();
|
|
||||||
hr = ctx->CreateBitmapFromWicBitmap(
|
|
||||||
converter.get(),
|
|
||||||
nullptr,
|
|
||||||
&raw_frame_);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
// Get Metadata Query Reader from the frame
|
|
||||||
hr = wic_frame->GetMetadataQueryReader(&metadata_reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the Metadata for the current frame
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Left", &prop_val);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
frame_position_.left = static_cast<float>(prop_val.uiVal);
|
|
||||||
}
|
|
||||||
PropVariantClear(&prop_val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Top", &prop_val);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
frame_position_.top = static_cast<float>(prop_val.uiVal);
|
|
||||||
}
|
|
||||||
PropVariantClear(&prop_val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Width", &prop_val);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
frame_position_.right = static_cast<float>(prop_val.uiVal)
|
|
||||||
+ frame_position_.left;
|
|
||||||
}
|
|
||||||
PropVariantClear(&prop_val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Height", &prop_val);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
frame_position_.bottom = static_cast<float>(prop_val.uiVal)
|
|
||||||
+ frame_position_.top;
|
|
||||||
}
|
|
||||||
PropVariantClear(&prop_val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
frame_delay_ = 0;
|
|
||||||
|
|
||||||
hr = metadata_reader->GetMetadataByName(
|
|
||||||
L"/grctlext/Delay",
|
|
||||||
&prop_val);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = UIntMult(prop_val.uiVal, 10, &frame_delay_);
|
|
||||||
}
|
|
||||||
PropVariantClear(&prop_val);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
frame_delay_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
// 插入一个强制延迟
|
|
||||||
if (frame_delay_ < 90)
|
|
||||||
{
|
|
||||||
frame_delay_ = 90;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = metadata_reader->GetMetadataByName(
|
|
||||||
L"/grctlext/Disposal",
|
|
||||||
&prop_val);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = (prop_val.vt == VT_UI1) ? S_OK : E_FAIL;
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
disposal_type_ = DisposalType(prop_val.bVal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 获取 DisposalType 失败,可能图片是只有一帧的图片
|
|
||||||
disposal_type_ = DisposalType::Unknown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
::PropVariantClear(&prop_val);
|
|
||||||
return hr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT GifImage::GetGlobalMetadata()
|
HRESULT GifImage::GetGlobalMetadata()
|
||||||
|
|
@ -284,7 +70,12 @@ namespace kiwano
|
||||||
ComPtr<IWICMetadataQueryReader> metadata_reader;
|
ComPtr<IWICMetadataQueryReader> metadata_reader;
|
||||||
|
|
||||||
// 获取帧数量
|
// 获取帧数量
|
||||||
HRESULT hr = decoder_->GetFrameCount(&frames_count_);
|
HRESULT hr = decoder_ ? S_OK : E_FAIL;
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = decoder_->GetFrameCount(&frames_count_);
|
||||||
|
}
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
|
|
@ -297,7 +88,7 @@ namespace kiwano
|
||||||
if (FAILED(GetBackgroundColor(metadata_reader.get())))
|
if (FAILED(GetBackgroundColor(metadata_reader.get())))
|
||||||
{
|
{
|
||||||
// 如果未能获得颜色,则默认为透明
|
// 如果未能获得颜色,则默认为透明
|
||||||
bg_color_ = D2D1::ColorF(0, 0.f);
|
bg_color_ = Color(0, 0.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -305,9 +96,7 @@ namespace kiwano
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
// 获取宽度
|
// 获取宽度
|
||||||
hr = metadata_reader->GetMetadataByName(
|
hr = metadata_reader->GetMetadataByName(L"/logscrdesc/Width", &prop_val);
|
||||||
L"/logscrdesc/Width",
|
|
||||||
&prop_val);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
|
|
@ -323,9 +112,7 @@ namespace kiwano
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
// 获取高度
|
// 获取高度
|
||||||
hr = metadata_reader->GetMetadataByName(
|
hr = metadata_reader->GetMetadataByName(L"/logscrdesc/Height", &prop_val);
|
||||||
L"/logscrdesc/Height",
|
|
||||||
&prop_val);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
|
|
@ -341,9 +128,7 @@ namespace kiwano
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
// 获得像素纵横比
|
// 获得像素纵横比
|
||||||
hr = metadata_reader->GetMetadataByName(
|
hr = metadata_reader->GetMetadataByName(L"/logscrdesc/PixelAspectRatio", &prop_val);
|
||||||
L"/logscrdesc/PixelAspectRatio",
|
|
||||||
&prop_val);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
|
|
@ -383,101 +168,17 @@ namespace kiwano
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT GifImage::DisposeCurrentFrame(ComPtr<ID2D1BitmapRenderTarget> frame_rt)
|
HRESULT GifImage::GetBackgroundColor(ComPtr<IWICMetadataQueryReader> metadata_reader)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
|
||||||
|
|
||||||
switch (disposal_type_)
|
|
||||||
{
|
|
||||||
case DisposalType::Unknown:
|
|
||||||
case DisposalType::None:
|
|
||||||
break;
|
|
||||||
case DisposalType::Background:
|
|
||||||
// 用背景颜色清除当前原始帧覆盖的区域
|
|
||||||
hr = ClearCurrentFrameArea(frame_rt);
|
|
||||||
break;
|
|
||||||
case DisposalType::Previous:
|
|
||||||
// 恢复先前构图的帧
|
|
||||||
hr = RestoreSavedFrame(frame_rt);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
hr = E_FAIL;
|
|
||||||
}
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT GifImage::SaveComposedFrame(ComPtr<ID2D1BitmapRenderTarget> frame_rt)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
|
|
||||||
ComPtr<ID2D1Bitmap> frame_to_be_saved;
|
|
||||||
|
|
||||||
hr = frame_rt->GetBitmap(&frame_to_be_saved);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
if (saved_frame_ == nullptr)
|
|
||||||
{
|
|
||||||
auto size = frame_to_be_saved->GetPixelSize();
|
|
||||||
auto prop = D2D1::BitmapProperties(frame_to_be_saved->GetPixelFormat());
|
|
||||||
|
|
||||||
hr = frame_rt->CreateBitmap(size, prop, &saved_frame_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = saved_frame_->CopyFromBitmap(nullptr, frame_to_be_saved.get(), nullptr);
|
|
||||||
}
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT GifImage::RestoreSavedFrame(ComPtr<ID2D1BitmapRenderTarget> frame_rt)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
|
|
||||||
ComPtr<ID2D1Bitmap> frame_to_copy_to;
|
|
||||||
|
|
||||||
hr = saved_frame_ ? S_OK : E_FAIL;
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = frame_rt->GetBitmap(&frame_to_copy_to);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = frame_to_copy_to->CopyFromBitmap(nullptr, saved_frame_.get(), nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT GifImage::ClearCurrentFrameArea(ComPtr<ID2D1BitmapRenderTarget> frame_rt)
|
|
||||||
{
|
|
||||||
frame_rt->BeginDraw();
|
|
||||||
|
|
||||||
frame_rt->PushAxisAlignedClip(&frame_position_, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
|
|
||||||
frame_rt->Clear(bg_color_);
|
|
||||||
frame_rt->PopAxisAlignedClip();
|
|
||||||
|
|
||||||
return frame_rt->EndDraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT GifImage::GetBackgroundColor(IWICMetadataQueryReader* metadata_reader)
|
|
||||||
{
|
|
||||||
DWORD bgcolor = 0;
|
|
||||||
BYTE bg_index = 0;
|
BYTE bg_index = 0;
|
||||||
WICColor bgcolors[256];
|
WICColor bgcolors[256];
|
||||||
UINT colors_copied = 0;
|
UINT colors_copied = 0;
|
||||||
|
ComPtr<IWICPalette> wic_palette;
|
||||||
|
|
||||||
PROPVARIANT prop_val;
|
PROPVARIANT prop_val;
|
||||||
PropVariantInit(&prop_val);
|
PropVariantInit(&prop_val);
|
||||||
|
|
||||||
ComPtr<IWICPalette> wic_palette;
|
HRESULT hr = metadata_reader->GetMetadataByName(L"/logscrdesc/GlobalColorTableFlag", &prop_val);
|
||||||
|
|
||||||
HRESULT hr = metadata_reader->GetMetadataByName(
|
|
||||||
L"/logscrdesc/GlobalColorTableFlag",
|
|
||||||
&prop_val);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
|
|
@ -487,9 +188,7 @@ namespace kiwano
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
hr = metadata_reader->GetMetadataByName(
|
hr = metadata_reader->GetMetadataByName(L"/logscrdesc/BackgroundColorIndex", &prop_val);
|
||||||
L"/logscrdesc/BackgroundColorIndex",
|
|
||||||
&prop_val);
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
|
|
@ -523,19 +222,175 @@ namespace kiwano
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
// 检查下标
|
|
||||||
hr = (bg_index >= colors_copied) ? E_FAIL : S_OK;
|
hr = (bg_index >= colors_copied) ? E_FAIL : S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
bgcolor = bgcolors[bg_index];
|
|
||||||
|
|
||||||
// 转换为 ARGB 格式
|
// 转换为 ARGB 格式
|
||||||
float alpha = (bgcolor >> 24) / 255.f;
|
float alpha = (bgcolors[bg_index] >> 24) / 255.f;
|
||||||
bg_color_ = D2D1::ColorF(bgcolor, alpha);
|
bg_color_ = Color(bgcolors[bg_index], alpha);
|
||||||
}
|
}
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HRESULT GifImage::GetRawFrame(UINT frame_index, Image& raw_frame, Rect& frame_rect, Duration& delay, DisposalType& disposal_type)
|
||||||
|
{
|
||||||
|
ComPtr<IWICFormatConverter> converter;
|
||||||
|
ComPtr<IWICBitmapFrameDecode> wic_frame;
|
||||||
|
ComPtr<IWICMetadataQueryReader> metadata_reader;
|
||||||
|
|
||||||
|
PROPVARIANT prop_val;
|
||||||
|
PropVariantInit(&prop_val);
|
||||||
|
|
||||||
|
// Retrieve the current frame
|
||||||
|
HRESULT hr = decoder_->GetFrame(frame_index, &wic_frame);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
// Format convert to 32bppPBGRA which D2D expects
|
||||||
|
auto factory = Renderer::GetInstance()->GetD2DDeviceResources()->GetWICImagingFactory();
|
||||||
|
hr = factory->CreateFormatConverter(&converter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = converter->Initialize(
|
||||||
|
wic_frame.get(),
|
||||||
|
GUID_WICPixelFormat32bppPBGRA,
|
||||||
|
WICBitmapDitherTypeNone,
|
||||||
|
nullptr,
|
||||||
|
0.f,
|
||||||
|
WICBitmapPaletteTypeCustom);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
auto ctx = Renderer::GetInstance()->GetD2DDeviceResources()->GetDeviceContext();
|
||||||
|
|
||||||
|
// Create a D2DBitmap from IWICBitmapSource
|
||||||
|
ComPtr<ID2D1Bitmap> raw_bitmap;
|
||||||
|
hr = ctx->CreateBitmapFromWicBitmap(
|
||||||
|
converter.get(),
|
||||||
|
nullptr,
|
||||||
|
&raw_bitmap
|
||||||
|
);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
raw_frame.SetBitmap(raw_bitmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
// Get Metadata Query Reader from the frame
|
||||||
|
hr = wic_frame->GetMetadataQueryReader(&metadata_reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the Metadata for the current frame
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Left", &prop_val);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
frame_rect.origin.x = static_cast<float>(prop_val.uiVal);
|
||||||
|
}
|
||||||
|
PropVariantClear(&prop_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Top", &prop_val);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
frame_rect.origin.y = static_cast<float>(prop_val.uiVal);
|
||||||
|
}
|
||||||
|
PropVariantClear(&prop_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Width", &prop_val);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
frame_rect.size.x = static_cast<float>(prop_val.uiVal);
|
||||||
|
}
|
||||||
|
PropVariantClear(&prop_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = metadata_reader->GetMetadataByName(L"/imgdesc/Height", &prop_val);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
frame_rect.size.y = static_cast<float>(prop_val.uiVal);
|
||||||
|
}
|
||||||
|
PropVariantClear(&prop_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = metadata_reader->GetMetadataByName(L"/grctlext/Delay", &prop_val);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = (prop_val.vt == VT_UI2 ? S_OK : E_FAIL);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
UINT udelay = 0;
|
||||||
|
hr = UIntMult(prop_val.uiVal, 10, &udelay);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
delay.SetMilliseconds(static_cast<long>(udelay));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PropVariantClear(&prop_val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delay = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = metadata_reader->GetMetadataByName(L"/grctlext/Disposal", &prop_val);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = (prop_val.vt == VT_UI1) ? S_OK : E_FAIL;
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
disposal_type = DisposalType(prop_val.bVal);
|
||||||
|
}
|
||||||
|
::PropVariantClear(&prop_val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 获取 DisposalType 失败,可能图片是只有一帧的图片
|
||||||
|
disposal_type = DisposalType::Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::PropVariantClear(&prop_val);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,7 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../base/Resource.h"
|
#include "Image.h"
|
||||||
#include "Renderer.h"
|
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
|
|
@ -32,21 +31,19 @@ namespace kiwano
|
||||||
public:
|
public:
|
||||||
GifImage();
|
GifImage();
|
||||||
|
|
||||||
GifImage(
|
GifImage(Resource const& res);
|
||||||
Resource const& res
|
|
||||||
);
|
|
||||||
|
|
||||||
bool Load(
|
bool Load(Resource const& res);
|
||||||
Resource const& res
|
|
||||||
);
|
|
||||||
|
|
||||||
inline unsigned int GetWidthInPixels() const { return width_in_pixels_; }
|
bool IsValid() const;
|
||||||
|
|
||||||
inline unsigned int GetHeightInPixels() const { return height_in_pixels_; }
|
inline UINT GetWidthInPixels() const { return width_in_pixels_; }
|
||||||
|
|
||||||
inline unsigned int GetFrameDelay() const { return frame_delay_; }
|
inline UINT GetHeightInPixels() const { return height_in_pixels_; }
|
||||||
|
|
||||||
inline unsigned int GetFramesCount() const { return frames_count_; }
|
inline UINT GetFramesCount() const { return frames_count_; }
|
||||||
|
|
||||||
|
inline Color GetBackgroundColor() const { return bg_color_; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class DisposalType
|
enum class DisposalType
|
||||||
|
|
@ -57,37 +54,31 @@ namespace kiwano
|
||||||
Previous
|
Previous
|
||||||
};
|
};
|
||||||
|
|
||||||
inline DisposalType GetDisposalType() const { return disposal_type_; }
|
HRESULT GetRawFrame(
|
||||||
|
UINT frame_index,
|
||||||
|
Image& raw_frame,
|
||||||
|
Rect& frame_rect,
|
||||||
|
Duration& delay,
|
||||||
|
DisposalType& disposal_type
|
||||||
|
);
|
||||||
|
|
||||||
inline D2D1_COLOR_F GetBackgroundColor() const { return bg_color_; }
|
inline ComPtr<IWICBitmapDecoder> GetDecoder() const { return decoder_; }
|
||||||
|
|
||||||
inline D2D1_RECT_F const& GetFramePosition() const { return frame_position_; }
|
inline void SetDecoder(ComPtr<IWICBitmapDecoder> decoder) { decoder_ = decoder; }
|
||||||
|
|
||||||
inline ComPtr<ID2D1Bitmap> GetRawFrame() const { return raw_frame_; }
|
|
||||||
|
|
||||||
inline void SetDisposalType(DisposalType type) { disposal_type_ = type; }
|
|
||||||
|
|
||||||
public:
|
|
||||||
HRESULT GetRawFrame(UINT frame_index);
|
|
||||||
HRESULT GetGlobalMetadata();
|
|
||||||
HRESULT GetBackgroundColor(IWICMetadataQueryReader* metadata_reader);
|
|
||||||
|
|
||||||
HRESULT DisposeCurrentFrame(ComPtr<ID2D1BitmapRenderTarget> frame_rt);
|
|
||||||
HRESULT SaveComposedFrame(ComPtr<ID2D1BitmapRenderTarget> frame_rt);
|
|
||||||
HRESULT RestoreSavedFrame(ComPtr<ID2D1BitmapRenderTarget> frame_rt);
|
|
||||||
HRESULT ClearCurrentFrameArea(ComPtr<ID2D1BitmapRenderTarget> frame_rt);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ComPtr<ID2D1Bitmap> raw_frame_;
|
HRESULT GetGlobalMetadata();
|
||||||
ComPtr<ID2D1Bitmap> saved_frame_;
|
|
||||||
ComPtr<IWICBitmapDecoder> decoder_;
|
|
||||||
|
|
||||||
unsigned int frames_count_;
|
HRESULT GetBackgroundColor(
|
||||||
unsigned int frame_delay_;
|
ComPtr<IWICMetadataQueryReader> metadata_reader
|
||||||
unsigned int width_in_pixels_;
|
);
|
||||||
unsigned int height_in_pixels_;
|
|
||||||
DisposalType disposal_type_;
|
protected:
|
||||||
D2D1_RECT_F frame_position_;
|
UINT frames_count_;
|
||||||
D2D1_COLOR_F bg_color_;
|
UINT width_in_pixels_;
|
||||||
|
UINT height_in_pixels_;
|
||||||
|
Color bg_color_;
|
||||||
|
|
||||||
|
ComPtr<IWICBitmapDecoder> decoder_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,16 +19,20 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
|
#include "Renderer.h"
|
||||||
#include "../base/Logger.h"
|
#include "../base/Logger.h"
|
||||||
#include "../platform/modules.h"
|
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
Image::Image()
|
Image::Image()
|
||||||
: bitmap_(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Image::Image(Resource const& res)
|
||||||
|
{
|
||||||
|
Load(res);
|
||||||
|
}
|
||||||
|
|
||||||
Image::Image(ComPtr<ID2D1Bitmap> const & bitmap)
|
Image::Image(ComPtr<ID2D1Bitmap> const & bitmap)
|
||||||
: Image()
|
: Image()
|
||||||
{
|
{
|
||||||
|
|
@ -39,9 +43,15 @@ namespace kiwano
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Image::Load(Resource const& res)
|
||||||
|
{
|
||||||
|
Renderer::GetInstance()->CreateImage(*this, res);
|
||||||
|
return IsValid();
|
||||||
|
}
|
||||||
|
|
||||||
bool Image::IsValid() const
|
bool Image::IsValid() const
|
||||||
{
|
{
|
||||||
return !!bitmap_;
|
return bitmap_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Image::GetWidth() const
|
float Image::GetWidth() const
|
||||||
|
|
@ -100,6 +110,43 @@ namespace kiwano
|
||||||
return math::Vec2T<UINT32>{};
|
return math::Vec2T<UINT32>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Image::CopyFrom(Image const& copy_from)
|
||||||
|
{
|
||||||
|
if (IsValid() && copy_from.IsValid())
|
||||||
|
{
|
||||||
|
HRESULT hr = bitmap_->CopyFromBitmap(nullptr, copy_from.GetBitmap().get(), nullptr);
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::CopyFrom(Image const& copy_from, Rect const& src_rect, Point const& dest_point)
|
||||||
|
{
|
||||||
|
if (IsValid() && copy_from.IsValid())
|
||||||
|
{
|
||||||
|
HRESULT hr = bitmap_->CopyFromBitmap(
|
||||||
|
&D2D1::Point2U(UINT(dest_point.x), UINT(dest_point.y)),
|
||||||
|
copy_from.GetBitmap().get(),
|
||||||
|
&D2D1::RectU(
|
||||||
|
UINT(src_rect.GetLeft()),
|
||||||
|
UINT(src_rect.GetTop()),
|
||||||
|
UINT(src_rect.GetRight()),
|
||||||
|
UINT(src_rect.GetBottom()))
|
||||||
|
);
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
D2D1_PIXEL_FORMAT Image::GetPixelFormat() const
|
||||||
|
{
|
||||||
|
if (bitmap_)
|
||||||
|
{
|
||||||
|
return bitmap_->GetPixelFormat();
|
||||||
|
}
|
||||||
|
return D2D1_PIXEL_FORMAT();
|
||||||
|
}
|
||||||
|
|
||||||
ComPtr<ID2D1Bitmap> Image::GetBitmap() const
|
ComPtr<ID2D1Bitmap> Image::GetBitmap() const
|
||||||
{
|
{
|
||||||
return bitmap_;
|
return bitmap_;
|
||||||
|
|
|
||||||
|
|
@ -25,19 +25,26 @@
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
// 图像
|
// 图像
|
||||||
KGE_DECLARE_SMART_PTR(Image);
|
|
||||||
class KGE_API Image
|
class KGE_API Image
|
||||||
: public Object
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Image();
|
Image();
|
||||||
|
|
||||||
|
explicit Image(
|
||||||
|
Resource const& res
|
||||||
|
);
|
||||||
|
|
||||||
explicit Image(
|
explicit Image(
|
||||||
ComPtr<ID2D1Bitmap> const& bitmap
|
ComPtr<ID2D1Bitmap> const& bitmap
|
||||||
);
|
);
|
||||||
|
|
||||||
virtual ~Image();
|
virtual ~Image();
|
||||||
|
|
||||||
|
// ¼ÓÔØ×ÊÔ´
|
||||||
|
bool Load(
|
||||||
|
Resource const& res
|
||||||
|
);
|
||||||
|
|
||||||
// 资源是否有效
|
// 资源是否有效
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
|
|
@ -59,12 +66,22 @@ namespace kiwano
|
||||||
// 获取位图像素大小
|
// 获取位图像素大小
|
||||||
math::Vec2T<UINT32> GetSizeInPixels() const;
|
math::Vec2T<UINT32> GetSizeInPixels() const;
|
||||||
|
|
||||||
|
// ¿½±´Î»Í¼ÄÚ´æ
|
||||||
|
void CopyFrom(Image const& copy_from);
|
||||||
|
|
||||||
|
// ¿½±´Î»Í¼ÄÚ´æ
|
||||||
|
void CopyFrom(Image const& copy_from, Rect const& src_rect, Point const& dest_point);
|
||||||
|
|
||||||
|
public:
|
||||||
// 获取源位图
|
// 获取源位图
|
||||||
ComPtr<ID2D1Bitmap> GetBitmap() const;
|
ComPtr<ID2D1Bitmap> GetBitmap() const;
|
||||||
|
|
||||||
// 设置源位图
|
// 设置源位图
|
||||||
void SetBitmap(ComPtr<ID2D1Bitmap> bitmap);
|
void SetBitmap(ComPtr<ID2D1Bitmap> bitmap);
|
||||||
|
|
||||||
|
// »ñÈ¡ÏñËØ¸ñʽ
|
||||||
|
D2D1_PIXEL_FORMAT GetPixelFormat() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ComPtr<ID2D1Bitmap> bitmap_;
|
ComPtr<ID2D1Bitmap> bitmap_;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
#include "ImageCache.h"
|
#include "ImageCache.h"
|
||||||
|
#include "Renderer.h"
|
||||||
#include "../base/Logger.h"
|
#include "../base/Logger.h"
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
|
|
@ -32,43 +33,28 @@ namespace kiwano
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagePtr ImageCache::AddImage(Resource const& res)
|
Image ImageCache::AddImage(Resource const& res)
|
||||||
{
|
{
|
||||||
size_t hash_code = res.GetHashCode();
|
size_t hash_code = res.GetHashCode();
|
||||||
|
|
||||||
auto iter = image_cache_.find(hash_code);
|
auto iter = image_cache_.find(hash_code);
|
||||||
if (iter != image_cache_.end())
|
if (iter != image_cache_.end())
|
||||||
{
|
{
|
||||||
return iter->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT hr = S_OK;
|
Image image;
|
||||||
ComPtr<ID2D1Bitmap> bitmap;
|
if (image.Load(res))
|
||||||
|
|
||||||
if (res.IsFileType())
|
|
||||||
{
|
{
|
||||||
hr = Renderer::GetInstance()->GetD2DDeviceResources()->CreateBitmapFromFile(bitmap, res.GetFileName());
|
image_cache_.insert(std::make_pair(hash_code, image));
|
||||||
}
|
}
|
||||||
else
|
return image;
|
||||||
{
|
|
||||||
hr = Renderer::GetInstance()->GetD2DDeviceResources()->CreateBitmapFromResource(bitmap, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
ImagePtr ptr = new Image(bitmap);
|
|
||||||
image_cache_.insert(std::make_pair(hash_code, ptr));
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
KGE_ERROR_LOG(L"Load image file failed with HRESULT of %08X", hr);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageCache::RemoveImage(Resource const& res)
|
void ImageCache::RemoveImage(Resource const& res)
|
||||||
{
|
{
|
||||||
size_t hash_code = res.GetHashCode();
|
size_t hash_code = res.GetHashCode();
|
||||||
|
|
||||||
auto iter = image_cache_.find(hash_code);
|
auto iter = image_cache_.find(hash_code);
|
||||||
if (iter != image_cache_.end())
|
if (iter != image_cache_.end())
|
||||||
{
|
{
|
||||||
|
|
@ -76,9 +62,39 @@ namespace kiwano
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GifImagePtr ImageCache::AddGifImage(Resource const& res)
|
||||||
|
{
|
||||||
|
size_t hash_code = res.GetHashCode();
|
||||||
|
|
||||||
|
auto iter = gif_image_cache_.find(hash_code);
|
||||||
|
if (iter != gif_image_cache_.end())
|
||||||
|
{
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
GifImagePtr ptr = new GifImage;
|
||||||
|
if (ptr->Load(res))
|
||||||
|
{
|
||||||
|
gif_image_cache_.insert(std::make_pair(hash_code, ptr));
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageCache::RemoveGifImage(Resource const& res)
|
||||||
|
{
|
||||||
|
size_t hash_code = res.GetHashCode();
|
||||||
|
|
||||||
|
auto iter = gif_image_cache_.find(hash_code);
|
||||||
|
if (iter != gif_image_cache_.end())
|
||||||
|
{
|
||||||
|
gif_image_cache_.erase(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ImageCache::Clear()
|
void ImageCache::Clear()
|
||||||
{
|
{
|
||||||
image_cache_.clear();
|
image_cache_.clear();
|
||||||
|
gif_image_cache_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../core/singleton.hpp"
|
#include "../core/singleton.hpp"
|
||||||
#include "Renderer.h"
|
#include "Image.h"
|
||||||
|
#include "GifImage.h"
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
|
|
@ -30,10 +31,14 @@ namespace kiwano
|
||||||
KGE_DECLARE_SINGLETON(ImageCache);
|
KGE_DECLARE_SINGLETON(ImageCache);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ImagePtr AddImage(Resource const& res);
|
Image AddImage(Resource const& res);
|
||||||
|
|
||||||
void RemoveImage(Resource const& res);
|
void RemoveImage(Resource const& res);
|
||||||
|
|
||||||
|
GifImagePtr AddGifImage(Resource const& res);
|
||||||
|
|
||||||
|
void RemoveGifImage(Resource const& res);
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -42,7 +47,10 @@ namespace kiwano
|
||||||
virtual ~ImageCache();
|
virtual ~ImageCache();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using ImageMap = UnorderedMap<size_t, ImagePtr>;
|
using ImageMap = UnorderedMap<size_t, Image>;
|
||||||
ImageMap image_cache_;
|
ImageMap image_cache_;
|
||||||
|
|
||||||
|
using GifImageMap = UnorderedMap<size_t, GifImagePtr>;
|
||||||
|
GifImageMap gif_image_cache_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,660 @@
|
||||||
|
// Copyright (c) 2016-2019 Kiwano - Nomango
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "RenderTarget.h"
|
||||||
|
#include "../base/Logger.h"
|
||||||
|
|
||||||
|
namespace kiwano
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// RenderTarget
|
||||||
|
//
|
||||||
|
|
||||||
|
RenderTarget::RenderTarget()
|
||||||
|
: opacity_(1.f)
|
||||||
|
, collecting_status_(false)
|
||||||
|
, antialias_(true)
|
||||||
|
, text_antialias_(TextAntialias::GrayScale)
|
||||||
|
{
|
||||||
|
status_.primitives = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT RenderTarget::InitDeviceResources(ComPtr<ID2D1RenderTarget> rt, ComPtr<ID2DDeviceResources> dev_res)
|
||||||
|
{
|
||||||
|
HRESULT hr = E_FAIL;
|
||||||
|
|
||||||
|
if (rt && dev_res)
|
||||||
|
{
|
||||||
|
render_target_ = rt;
|
||||||
|
d2d_res_ = dev_res;
|
||||||
|
hr = S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
text_renderer_.reset();
|
||||||
|
hr = ITextRenderer::Create(
|
||||||
|
&text_renderer_,
|
||||||
|
render_target_.get()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
solid_color_brush_.reset();
|
||||||
|
hr = render_target_->CreateSolidColorBrush(
|
||||||
|
D2D1::ColorF(D2D1::ColorF::White),
|
||||||
|
D2D1::BrushProperties(),
|
||||||
|
&solid_color_brush_
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderTarget::IsValid() const
|
||||||
|
{
|
||||||
|
return render_target_ && d2d_res_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::BeginDraw()
|
||||||
|
{
|
||||||
|
HRESULT hr = E_FAIL;
|
||||||
|
|
||||||
|
if (collecting_status_)
|
||||||
|
{
|
||||||
|
status_.start = Time::Now();
|
||||||
|
status_.primitives = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (render_target_)
|
||||||
|
{
|
||||||
|
render_target_->BeginDraw();
|
||||||
|
hr = S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::EndDraw()
|
||||||
|
{
|
||||||
|
ThrowIfFailed(render_target_->EndDraw());
|
||||||
|
|
||||||
|
if (collecting_status_)
|
||||||
|
{
|
||||||
|
status_.duration = Time::Now() - status_.start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::DrawGeometry(
|
||||||
|
Geometry const& geometry,
|
||||||
|
Color const& stroke_color,
|
||||||
|
float stroke_width,
|
||||||
|
StrokeStyle stroke
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!solid_color_brush_ || !render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr) && geometry.GetGeometry())
|
||||||
|
{
|
||||||
|
solid_color_brush_->SetColor(DX::ConvertToColorF(stroke_color));
|
||||||
|
|
||||||
|
render_target_->DrawGeometry(
|
||||||
|
geometry.GetGeometry().get(),
|
||||||
|
solid_color_brush_.get(),
|
||||||
|
stroke_width,
|
||||||
|
d2d_res_->GetStrokeStyle(stroke)
|
||||||
|
);
|
||||||
|
|
||||||
|
IncreasePrimitivesCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::FillGeometry(Geometry const& geometry, Color const& fill_color) const
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!solid_color_brush_ || !render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr) && geometry.GetGeometry())
|
||||||
|
{
|
||||||
|
solid_color_brush_->SetColor(DX::ConvertToColorF(fill_color));
|
||||||
|
render_target_->FillGeometry(
|
||||||
|
geometry.GetGeometry().get(),
|
||||||
|
solid_color_brush_.get()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::DrawLine(Point const& point1, Point const& point2, Color const& stroke_color, float stroke_width, StrokeStyle stroke) const
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!solid_color_brush_ || !render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
solid_color_brush_->SetColor(DX::ConvertToColorF(stroke_color));
|
||||||
|
|
||||||
|
render_target_->DrawLine(
|
||||||
|
DX::ConvertToPoint2F(point1),
|
||||||
|
DX::ConvertToPoint2F(point2),
|
||||||
|
solid_color_brush_.get(),
|
||||||
|
stroke_width,
|
||||||
|
d2d_res_->GetStrokeStyle(stroke)
|
||||||
|
);
|
||||||
|
|
||||||
|
IncreasePrimitivesCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::DrawRectangle(Rect const& rect, Color const& stroke_color, float stroke_width, StrokeStyle stroke) const
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!solid_color_brush_ || !render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
solid_color_brush_->SetColor(DX::ConvertToColorF(stroke_color));
|
||||||
|
|
||||||
|
render_target_->DrawRectangle(
|
||||||
|
DX::ConvertToRectF(rect),
|
||||||
|
solid_color_brush_.get(),
|
||||||
|
stroke_width,
|
||||||
|
d2d_res_->GetStrokeStyle(stroke)
|
||||||
|
);
|
||||||
|
|
||||||
|
IncreasePrimitivesCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::FillRectangle(Rect const& rect, Color const& fill_color) const
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!solid_color_brush_ || !render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
solid_color_brush_->SetColor(DX::ConvertToColorF(fill_color));
|
||||||
|
render_target_->FillRectangle(
|
||||||
|
DX::ConvertToRectF(rect),
|
||||||
|
solid_color_brush_.get()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::DrawRoundedRectangle(Rect const& rect, Vec2 const& radius, Color const& stroke_color, float stroke_width, StrokeStyle stroke) const
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!solid_color_brush_ || !render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
solid_color_brush_->SetColor(DX::ConvertToColorF(stroke_color));
|
||||||
|
|
||||||
|
render_target_->DrawRoundedRectangle(
|
||||||
|
D2D1::RoundedRect(
|
||||||
|
DX::ConvertToRectF(rect),
|
||||||
|
radius.x,
|
||||||
|
radius.y
|
||||||
|
),
|
||||||
|
solid_color_brush_.get(),
|
||||||
|
stroke_width,
|
||||||
|
d2d_res_->GetStrokeStyle(stroke)
|
||||||
|
);
|
||||||
|
|
||||||
|
IncreasePrimitivesCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::FillRoundedRectangle(Rect const& rect, Vec2 const& radius, Color const& fill_color) const
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!solid_color_brush_ || !render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
solid_color_brush_->SetColor(DX::ConvertToColorF(fill_color));
|
||||||
|
render_target_->FillRoundedRectangle(
|
||||||
|
D2D1::RoundedRect(
|
||||||
|
DX::ConvertToRectF(rect),
|
||||||
|
radius.x,
|
||||||
|
radius.y
|
||||||
|
),
|
||||||
|
solid_color_brush_.get()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::DrawEllipse(Point const& center, Vec2 const& radius, Color const& stroke_color, float stroke_width, StrokeStyle stroke) const
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!solid_color_brush_ || !render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
solid_color_brush_->SetColor(DX::ConvertToColorF(stroke_color));
|
||||||
|
|
||||||
|
render_target_->DrawEllipse(
|
||||||
|
D2D1::Ellipse(
|
||||||
|
DX::ConvertToPoint2F(center),
|
||||||
|
radius.x,
|
||||||
|
radius.y
|
||||||
|
),
|
||||||
|
solid_color_brush_.get(),
|
||||||
|
stroke_width,
|
||||||
|
d2d_res_->GetStrokeStyle(stroke)
|
||||||
|
);
|
||||||
|
|
||||||
|
IncreasePrimitivesCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::FillEllipse(Point const& center, Vec2 const& radius, Color const& fill_color) const
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!solid_color_brush_ || !render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
solid_color_brush_->SetColor(DX::ConvertToColorF(fill_color));
|
||||||
|
render_target_->FillEllipse(
|
||||||
|
D2D1::Ellipse(
|
||||||
|
DX::ConvertToPoint2F(center),
|
||||||
|
radius.x,
|
||||||
|
radius.y
|
||||||
|
),
|
||||||
|
solid_color_brush_.get()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::DrawImage(Image const& image, Rect const& src_rect, Rect const& dest_rect) const
|
||||||
|
{
|
||||||
|
DrawImage(image, &src_rect, &dest_rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::DrawImage(Image const& image, const Rect* src_rect, const Rect* dest_rect) const
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr) && image.IsValid())
|
||||||
|
{
|
||||||
|
render_target_->DrawBitmap(
|
||||||
|
image.GetBitmap().get(),
|
||||||
|
dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr,
|
||||||
|
opacity_,
|
||||||
|
D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
|
||||||
|
src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
IncreasePrimitivesCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::DrawTextLayout(TextLayout const& layout, Point const& offset) const
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!text_renderer_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
text_renderer_->SetTextStyle(
|
||||||
|
opacity_,
|
||||||
|
DX::ConvertToColorF(layout.GetTextStyle().color),
|
||||||
|
layout.GetTextStyle().outline,
|
||||||
|
DX::ConvertToColorF(layout.GetTextStyle().outline_color),
|
||||||
|
layout.GetTextStyle().outline_width,
|
||||||
|
d2d_res_->GetStrokeStyle(layout.GetTextStyle().outline_stroke)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = layout.GetTextLayout()->Draw(nullptr, text_renderer_.get(), offset.x, offset.y);
|
||||||
|
|
||||||
|
IncreasePrimitivesCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::CreateLayer(ComPtr<ID2D1Layer>& layer) const
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
ComPtr<ID2D1Layer> new_layer;
|
||||||
|
|
||||||
|
if (!render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = render_target_->CreateLayer(&new_layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
layer = new_layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::PushClipRect(Rect const& clip_rect)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
render_target_->PushAxisAlignedClip(
|
||||||
|
DX::ConvertToRectF(clip_rect),
|
||||||
|
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::PopClipRect()
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
render_target_->PopAxisAlignedClip();
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::PushLayer(ComPtr<ID2D1Layer> const& layer, LayerProperties const& properties)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!render_target_ || !solid_color_brush_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
render_target_->PushLayer(
|
||||||
|
D2D1::LayerParameters(
|
||||||
|
DX::ConvertToRectF(properties.area),
|
||||||
|
nullptr,
|
||||||
|
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
|
||||||
|
D2D1::Matrix3x2F::Identity(),
|
||||||
|
properties.opacity,
|
||||||
|
nullptr,
|
||||||
|
D2D1_LAYER_OPTIONS_NONE
|
||||||
|
),
|
||||||
|
layer.get()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::PopLayer()
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
render_target_->PopLayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::Clear()
|
||||||
|
{
|
||||||
|
HRESULT hr = E_FAIL;
|
||||||
|
|
||||||
|
if (render_target_)
|
||||||
|
{
|
||||||
|
render_target_->Clear();
|
||||||
|
hr = S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::Clear(Color const& clear_color)
|
||||||
|
{
|
||||||
|
HRESULT hr = E_FAIL;
|
||||||
|
|
||||||
|
if (render_target_)
|
||||||
|
{
|
||||||
|
render_target_->Clear(DX::ConvertToColorF(clear_color));
|
||||||
|
hr = S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
float RenderTarget::GetOpacity() const
|
||||||
|
{
|
||||||
|
return opacity_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::SetTransform(const Matrix3x2& matrix)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
render_target_->SetTransform(DX::ConvertToMatrix3x2F(&matrix));
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::SetOpacity(float opacity)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!solid_color_brush_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
if (opacity_ != opacity)
|
||||||
|
{
|
||||||
|
opacity_ = opacity;
|
||||||
|
solid_color_brush_->SetOpacity(opacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::SetAntialiasMode(bool enabled)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
render_target_->SetAntialiasMode(
|
||||||
|
enabled ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED
|
||||||
|
);
|
||||||
|
antialias_ = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::SetTextAntialiasMode(TextAntialias mode)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!render_target_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
text_antialias_ = mode;
|
||||||
|
D2D1_TEXT_ANTIALIAS_MODE antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
||||||
|
switch (text_antialias_)
|
||||||
|
{
|
||||||
|
case TextAntialias::Default:
|
||||||
|
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
|
||||||
|
break;
|
||||||
|
case TextAntialias::ClearType:
|
||||||
|
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
||||||
|
break;
|
||||||
|
case TextAntialias::GrayScale:
|
||||||
|
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
|
||||||
|
break;
|
||||||
|
case TextAntialias::None:
|
||||||
|
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
render_target_->SetTextAntialiasMode(antialias_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::SetCollectingStatus(bool collecting)
|
||||||
|
{
|
||||||
|
collecting_status_ = collecting;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::IncreasePrimitivesCount() const
|
||||||
|
{
|
||||||
|
if (collecting_status_)
|
||||||
|
{
|
||||||
|
++status_.primitives;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// ImageRenderTarget
|
||||||
|
//
|
||||||
|
|
||||||
|
ImageRenderTarget::ImageRenderTarget()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageRenderTarget::GetOutput(Image& output) const
|
||||||
|
{
|
||||||
|
HRESULT hr = E_FAIL;
|
||||||
|
|
||||||
|
ComPtr<ID2D1BitmapRenderTarget> bitmap_rt;
|
||||||
|
if (render_target_)
|
||||||
|
{
|
||||||
|
hr = render_target_->QueryInterface<ID2D1BitmapRenderTarget>(&bitmap_rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
ComPtr<ID2D1Bitmap> bitmap;
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = bitmap_rt->GetBitmap(&bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
output.SetBitmap(bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,207 @@
|
||||||
|
// Copyright (c) 2016-2019 Kiwano - Nomango
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "D2DDeviceResources.h"
|
||||||
|
#include "Image.h"
|
||||||
|
#include "Geometry.h"
|
||||||
|
#include "TextLayout.h"
|
||||||
|
#include "TextRenderer.h"
|
||||||
|
|
||||||
|
namespace kiwano
|
||||||
|
{
|
||||||
|
// äÖȾĿ±ê
|
||||||
|
class KGE_API RenderTarget
|
||||||
|
: public noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void BeginDraw();
|
||||||
|
|
||||||
|
void EndDraw();
|
||||||
|
|
||||||
|
void CreateLayer(
|
||||||
|
ComPtr<ID2D1Layer>& layer
|
||||||
|
) const;
|
||||||
|
|
||||||
|
void DrawGeometry(
|
||||||
|
Geometry const& geometry,
|
||||||
|
Color const& stroke_color,
|
||||||
|
float stroke_width,
|
||||||
|
StrokeStyle stroke = StrokeStyle::Miter
|
||||||
|
) const;
|
||||||
|
|
||||||
|
void FillGeometry(
|
||||||
|
Geometry const& geometry,
|
||||||
|
Color const& fill_color
|
||||||
|
) const;
|
||||||
|
|
||||||
|
void DrawLine(
|
||||||
|
Point const& point1,
|
||||||
|
Point const& point2,
|
||||||
|
Color const& stroke_color,
|
||||||
|
float stroke_width,
|
||||||
|
StrokeStyle stroke = StrokeStyle::Miter
|
||||||
|
) const;
|
||||||
|
|
||||||
|
void DrawRectangle(
|
||||||
|
Rect const& rect,
|
||||||
|
Color const& stroke_color,
|
||||||
|
float stroke_width,
|
||||||
|
StrokeStyle stroke = StrokeStyle::Miter
|
||||||
|
) const;
|
||||||
|
|
||||||
|
void FillRectangle(
|
||||||
|
Rect const& rect,
|
||||||
|
Color const& fill_color
|
||||||
|
) const;
|
||||||
|
|
||||||
|
void DrawRoundedRectangle(
|
||||||
|
Rect const& rect,
|
||||||
|
Vec2 const& radius,
|
||||||
|
Color const& stroke_color,
|
||||||
|
float stroke_width,
|
||||||
|
StrokeStyle stroke = StrokeStyle::Miter
|
||||||
|
) const;
|
||||||
|
|
||||||
|
void FillRoundedRectangle(
|
||||||
|
Rect const& rect,
|
||||||
|
Vec2 const& radius,
|
||||||
|
Color const& fill_color
|
||||||
|
) const;
|
||||||
|
|
||||||
|
void DrawEllipse(
|
||||||
|
Point const& center,
|
||||||
|
Vec2 const& radius,
|
||||||
|
Color const& stroke_color,
|
||||||
|
float stroke_width,
|
||||||
|
StrokeStyle stroke = StrokeStyle::Miter
|
||||||
|
) const;
|
||||||
|
|
||||||
|
void FillEllipse(
|
||||||
|
Point const& center,
|
||||||
|
Vec2 const& radius,
|
||||||
|
Color const& fill_color
|
||||||
|
) const;
|
||||||
|
|
||||||
|
void DrawImage(
|
||||||
|
Image const& image,
|
||||||
|
Rect const& src_rect,
|
||||||
|
Rect const& dest_rect
|
||||||
|
) const;
|
||||||
|
|
||||||
|
void DrawImage(
|
||||||
|
Image const& image,
|
||||||
|
const Rect* src_rect = nullptr,
|
||||||
|
const Rect* dest_rect = nullptr
|
||||||
|
) const;
|
||||||
|
|
||||||
|
void DrawTextLayout(
|
||||||
|
TextLayout const& layout,
|
||||||
|
Point const& offset = Point{}
|
||||||
|
) const;
|
||||||
|
|
||||||
|
void PushClipRect(
|
||||||
|
Rect const& clip_rect
|
||||||
|
);
|
||||||
|
|
||||||
|
void PopClipRect();
|
||||||
|
|
||||||
|
void PushLayer(
|
||||||
|
ComPtr<ID2D1Layer> const& layer,
|
||||||
|
LayerProperties const& properties
|
||||||
|
);
|
||||||
|
|
||||||
|
void PopLayer();
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
void Clear(
|
||||||
|
Color const& clear_color
|
||||||
|
);
|
||||||
|
|
||||||
|
float GetOpacity() const;
|
||||||
|
|
||||||
|
void SetOpacity(
|
||||||
|
float opacity
|
||||||
|
);
|
||||||
|
|
||||||
|
void SetTransform(
|
||||||
|
const Matrix3x2& matrix
|
||||||
|
);
|
||||||
|
|
||||||
|
// ÉèÖÿ¹¾â³Ýģʽ
|
||||||
|
void SetAntialiasMode(
|
||||||
|
bool enabled
|
||||||
|
);
|
||||||
|
|
||||||
|
// ÉèÖÃÎÄ×Ö¿¹¾â³Ýģʽ
|
||||||
|
void SetTextAntialiasMode(
|
||||||
|
TextAntialias mode
|
||||||
|
);
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct Status
|
||||||
|
{
|
||||||
|
int primitives;
|
||||||
|
Time start;
|
||||||
|
Duration duration;
|
||||||
|
};
|
||||||
|
|
||||||
|
void SetCollectingStatus(bool collecting);
|
||||||
|
|
||||||
|
void IncreasePrimitivesCount() const;
|
||||||
|
|
||||||
|
inline Status const& GetStatus() const { return status_; }
|
||||||
|
|
||||||
|
inline ComPtr<ID2D1RenderTarget> GetRenderTarget() const { return render_target_; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
RenderTarget();
|
||||||
|
|
||||||
|
HRESULT InitDeviceResources(
|
||||||
|
ComPtr<ID2D1RenderTarget> rt,
|
||||||
|
ComPtr<ID2DDeviceResources> dev_res
|
||||||
|
);
|
||||||
|
|
||||||
|
bool IsValid() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float opacity_;
|
||||||
|
bool antialias_;
|
||||||
|
mutable bool collecting_status_;
|
||||||
|
mutable Status status_;
|
||||||
|
TextAntialias text_antialias_;
|
||||||
|
ComPtr<ID2D1RenderTarget> render_target_;
|
||||||
|
ComPtr<ITextRenderer> text_renderer_;
|
||||||
|
ComPtr<ID2D1SolidColorBrush> solid_color_brush_;
|
||||||
|
ComPtr<ID2DDeviceResources> d2d_res_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// λͼäÖȾĿ±ê
|
||||||
|
class KGE_API ImageRenderTarget
|
||||||
|
: public RenderTarget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ImageRenderTarget();
|
||||||
|
|
||||||
|
void GetOutput(Image& output) const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -21,19 +21,15 @@
|
||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
#include "../base/Logger.h"
|
#include "../base/Logger.h"
|
||||||
#include "../base/Window.h"
|
#include "../base/Window.h"
|
||||||
|
#include "../utils/FileUtil.h"
|
||||||
|
|
||||||
namespace kiwano
|
namespace kiwano
|
||||||
{
|
{
|
||||||
Renderer::Renderer()
|
Renderer::Renderer()
|
||||||
: hwnd_(nullptr)
|
: hwnd_(nullptr)
|
||||||
, antialias_(true)
|
|
||||||
, vsync_(true)
|
, vsync_(true)
|
||||||
, text_antialias_(TextAntialias::GrayScale)
|
|
||||||
, clear_color_(Color::Black)
|
, clear_color_(Color::Black)
|
||||||
, opacity_(1.f)
|
|
||||||
, collecting_status_(false)
|
|
||||||
{
|
{
|
||||||
status_.primitives = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer::~Renderer()
|
Renderer::~Renderer()
|
||||||
|
|
@ -74,8 +70,6 @@ namespace kiwano
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
device_context_ = d2d_res_->GetDeviceContext();
|
|
||||||
|
|
||||||
ThrowIfFailed(
|
ThrowIfFailed(
|
||||||
d2d_res_->GetFactory()->CreateDrawingStateBlock(
|
d2d_res_->GetFactory()->CreateDrawingStateBlock(
|
||||||
&drawing_state_block_
|
&drawing_state_block_
|
||||||
|
|
@ -101,16 +95,55 @@ namespace kiwano
|
||||||
|
|
||||||
void Renderer::BeforeRender()
|
void Renderer::BeforeRender()
|
||||||
{
|
{
|
||||||
ThrowIfFailed(
|
HRESULT hr = S_OK;
|
||||||
BeginDraw()
|
|
||||||
);
|
if (!IsValid())
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
render_target_->SaveDrawingState(drawing_state_block_.get());
|
||||||
|
BeginDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = d3d_res_->ClearRenderTarget(clear_color_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::AfterRender()
|
void Renderer::AfterRender()
|
||||||
{
|
{
|
||||||
ThrowIfFailed(
|
HRESULT hr = S_OK;
|
||||||
EndDraw()
|
|
||||||
);
|
if (!IsValid())
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
EndDraw();
|
||||||
|
|
||||||
|
render_target_->RestoreDrawingState(drawing_state_block_.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = d3d_res_->Present(vsync_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
|
||||||
|
{
|
||||||
|
// 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源
|
||||||
|
hr = HandleDeviceLost();
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowIfFailed(hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::HandleMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
void Renderer::HandleMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||||
|
|
@ -130,24 +163,11 @@ namespace kiwano
|
||||||
|
|
||||||
HRESULT Renderer::CreateDeviceResources()
|
HRESULT Renderer::CreateDeviceResources()
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = InitDeviceResources(
|
||||||
|
d2d_res_->GetDeviceContext(),
|
||||||
solid_color_brush_.reset();
|
d2d_res_
|
||||||
hr = device_context_->CreateSolidColorBrush(
|
|
||||||
D2D1::ColorF(D2D1::ColorF::White),
|
|
||||||
D2D1::BrushProperties(),
|
|
||||||
&solid_color_brush_
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
text_renderer_.reset();
|
|
||||||
hr = ITextRenderer::Create(
|
|
||||||
&text_renderer_,
|
|
||||||
device_context_.get()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
SetAntialiasMode(antialias_);
|
SetAntialiasMode(antialias_);
|
||||||
|
|
@ -167,82 +187,104 @@ namespace kiwano
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT Renderer::BeginDraw()
|
void Renderer::CreateImage(Image& image, Resource const& res)
|
||||||
{
|
|
||||||
if (!device_context_)
|
|
||||||
return E_UNEXPECTED;
|
|
||||||
|
|
||||||
if (collecting_status_)
|
|
||||||
{
|
|
||||||
status_.start = Time::Now();
|
|
||||||
status_.primitives = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
device_context_->SaveDrawingState(drawing_state_block_.get());
|
|
||||||
|
|
||||||
device_context_->BeginDraw();
|
|
||||||
|
|
||||||
HRESULT hr = d3d_res_->ClearRenderTarget(clear_color_);
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT Renderer::EndDraw()
|
|
||||||
{
|
|
||||||
if (!device_context_)
|
|
||||||
return E_UNEXPECTED;
|
|
||||||
|
|
||||||
HRESULT hr = device_context_->EndDraw();
|
|
||||||
|
|
||||||
device_context_->RestoreDrawingState(drawing_state_block_.get());
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = d3d_res_->Present(vsync_);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
|
|
||||||
{
|
|
||||||
// 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源
|
|
||||||
hr = HandleDeviceLost();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collecting_status_)
|
|
||||||
{
|
|
||||||
status_.duration = Time::Now() - status_.start;
|
|
||||||
}
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::IncreasePrimitivesCount()
|
|
||||||
{
|
|
||||||
if (collecting_status_)
|
|
||||||
{
|
|
||||||
++status_.primitives;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::CreateLayer(ComPtr<ID2D1Layer>& layer)
|
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
ComPtr<ID2D1Layer> new_layer;
|
if (!d2d_res_)
|
||||||
|
|
||||||
if (!device_context_)
|
|
||||||
{
|
{
|
||||||
hr = E_UNEXPECTED;
|
hr = E_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
ComPtr<ID2D1Bitmap> bitmap;
|
||||||
|
if (res.IsFileType())
|
||||||
{
|
{
|
||||||
hr = device_context_->CreateLayer(&new_layer);
|
hr = d2d_res_->CreateBitmapFromFile(bitmap, res.GetFileName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hr = d2d_res_->CreateBitmapFromResource(bitmap, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
layer = new_layer;
|
image.SetBitmap(bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
KGE_WARNING_LOG(L"Load image failed with HRESULT of %08X!", hr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::CreateGifImage(GifImage& image, Resource const& res)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (!d2d_res_)
|
||||||
|
{
|
||||||
|
hr = E_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComPtr<IWICBitmapDecoder> decoder;
|
||||||
|
if (res.IsFileType())
|
||||||
|
{
|
||||||
|
if (!FileUtil::ExistsFile(res.GetFileName().c_str()))
|
||||||
|
{
|
||||||
|
KGE_WARNING_LOG(L"Gif image file '%s' not found!", res.GetFileName().c_str());
|
||||||
|
hr = E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = d2d_res_->GetWICImagingFactory()->CreateDecoderFromFilename(
|
||||||
|
res.GetFileName().c_str(),
|
||||||
|
nullptr,
|
||||||
|
GENERIC_READ,
|
||||||
|
WICDecodeMetadataCacheOnLoad,
|
||||||
|
&decoder
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LPVOID buffer;
|
||||||
|
DWORD buffer_size;
|
||||||
|
HRESULT hr = res.Load(buffer, buffer_size) ? S_OK : E_FAIL;
|
||||||
|
|
||||||
|
ComPtr<IWICStream> stream;
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = d2d_res_->GetWICImagingFactory()->CreateStream(&stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = stream->InitializeFromMemory(
|
||||||
|
static_cast<WICInProcPointer>(buffer),
|
||||||
|
buffer_size
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = d2d_res_->GetWICImagingFactory()->CreateDecoderFromStream(
|
||||||
|
stream.get(),
|
||||||
|
nullptr,
|
||||||
|
WICDecodeMetadataCacheOnLoad,
|
||||||
|
&decoder
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
image.SetDecoder(decoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
KGE_WARNING_LOG(L"Load GIF image failed with HRESULT of %08X!", hr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::CreateTextFormat(TextFormat& format, Font const& font)
|
void Renderer::CreateTextFormat(TextFormat& format, Font const& font)
|
||||||
|
|
@ -297,7 +339,7 @@ namespace kiwano
|
||||||
void Renderer::CreateLineGeometry(Geometry& geo, Point const& begin_pos, Point const& end_pos)
|
void Renderer::CreateLineGeometry(Geometry& geo, Point const& begin_pos, Point const& end_pos)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
if (!device_context_ || !d2d_res_)
|
if (!d2d_res_)
|
||||||
{
|
{
|
||||||
hr = E_UNEXPECTED;
|
hr = E_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
@ -333,7 +375,7 @@ namespace kiwano
|
||||||
void Renderer::CreateRectGeometry(Geometry& geo, Rect const& rect)
|
void Renderer::CreateRectGeometry(Geometry& geo, Rect const& rect)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
if (!device_context_ || !d2d_res_)
|
if (!d2d_res_)
|
||||||
{
|
{
|
||||||
hr = E_UNEXPECTED;
|
hr = E_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
@ -355,7 +397,7 @@ namespace kiwano
|
||||||
void Renderer::CreateRoundedRectGeometry(Geometry& geo, Rect const& rect, Vec2 const& radius)
|
void Renderer::CreateRoundedRectGeometry(Geometry& geo, Rect const& rect, Vec2 const& radius)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
if (!device_context_ || !d2d_res_)
|
if (!d2d_res_)
|
||||||
{
|
{
|
||||||
hr = E_UNEXPECTED;
|
hr = E_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
@ -383,7 +425,7 @@ namespace kiwano
|
||||||
void Renderer::CreateEllipseGeometry(Geometry& geo, Point const& center, Vec2 const& radius)
|
void Renderer::CreateEllipseGeometry(Geometry& geo, Point const& center, Vec2 const& radius)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
if (!device_context_ || !d2d_res_)
|
if (!d2d_res_)
|
||||||
{
|
{
|
||||||
hr = E_UNEXPECTED;
|
hr = E_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
@ -411,7 +453,7 @@ namespace kiwano
|
||||||
void Renderer::CreatePathGeometrySink(GeometrySink& sink)
|
void Renderer::CreatePathGeometrySink(GeometrySink& sink)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
if (!device_context_ || !d2d_res_)
|
if (!d2d_res_)
|
||||||
{
|
{
|
||||||
hr = E_UNEXPECTED;
|
hr = E_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
@ -430,150 +472,23 @@ namespace kiwano
|
||||||
ThrowIfFailed(hr);
|
ThrowIfFailed(hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::DrawGeometry(
|
void Renderer::CreateImageRenderTarget(ImageRenderTarget& render_target)
|
||||||
Geometry const& geometry,
|
|
||||||
Color const& stroke_color,
|
|
||||||
float stroke_width,
|
|
||||||
StrokeStyle stroke
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
if (!solid_color_brush_ || !device_context_)
|
if (!d2d_res_)
|
||||||
{
|
{
|
||||||
hr = E_UNEXPECTED;
|
hr = E_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SUCCEEDED(hr) && geometry.GetGeometry())
|
ComPtr<ID2D1BitmapRenderTarget> output;
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
solid_color_brush_->SetColor(DX::ConvertToColorF(stroke_color));
|
hr = d2d_res_->GetDeviceContext()->CreateCompatibleRenderTarget(&output);
|
||||||
|
|
||||||
device_context_->DrawGeometry(
|
|
||||||
geometry.GetGeometry().get(),
|
|
||||||
solid_color_brush_.get(),
|
|
||||||
stroke_width,
|
|
||||||
d2d_res_->GetStrokeStyle(stroke)
|
|
||||||
);
|
|
||||||
|
|
||||||
IncreasePrimitivesCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::FillGeometry(Geometry const & geometry, Color const& fill_color)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
if (!solid_color_brush_ || !device_context_)
|
|
||||||
{
|
|
||||||
hr = E_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr) && geometry.GetGeometry())
|
|
||||||
{
|
|
||||||
solid_color_brush_->SetColor(DX::ConvertToColorF(fill_color));
|
|
||||||
device_context_->FillGeometry(
|
|
||||||
geometry.GetGeometry().get(),
|
|
||||||
solid_color_brush_.get()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::DrawRectangle(Rect const& rect, Color const& stroke_color, float stroke_width, StrokeStyle stroke)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
if (!solid_color_brush_ || !device_context_)
|
|
||||||
{
|
|
||||||
hr = E_UNEXPECTED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
solid_color_brush_->SetColor(DX::ConvertToColorF(stroke_color));
|
hr = render_target.InitDeviceResources(output, d2d_res_);
|
||||||
|
|
||||||
device_context_->DrawRectangle(
|
|
||||||
DX::ConvertToRectF(rect),
|
|
||||||
solid_color_brush_.get(),
|
|
||||||
stroke_width,
|
|
||||||
d2d_res_->GetStrokeStyle(stroke)
|
|
||||||
);
|
|
||||||
|
|
||||||
IncreasePrimitivesCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::FillRectangle(Rect const& rect, Color const& fill_color)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
if (!solid_color_brush_ || !device_context_)
|
|
||||||
{
|
|
||||||
hr = E_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
solid_color_brush_->SetColor(DX::ConvertToColorF(fill_color));
|
|
||||||
device_context_->FillRectangle(
|
|
||||||
DX::ConvertToRectF(rect),
|
|
||||||
solid_color_brush_.get()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::DrawBitmap(ComPtr<ID2D1Bitmap> const & bitmap, Rect const& src_rect, Rect const& dest_rect)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
if (!device_context_)
|
|
||||||
{
|
|
||||||
hr = E_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr) && bitmap)
|
|
||||||
{
|
|
||||||
device_context_->DrawBitmap(
|
|
||||||
bitmap.get(),
|
|
||||||
DX::ConvertToRectF(dest_rect),
|
|
||||||
opacity_,
|
|
||||||
D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
|
|
||||||
DX::ConvertToRectF(src_rect)
|
|
||||||
);
|
|
||||||
|
|
||||||
IncreasePrimitivesCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::DrawTextLayout(TextLayout const& layout)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
if (!text_renderer_)
|
|
||||||
{
|
|
||||||
hr = E_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
SetTextStyle(
|
|
||||||
opacity_,
|
|
||||||
layout.GetTextStyle().color,
|
|
||||||
layout.GetTextStyle().outline,
|
|
||||||
layout.GetTextStyle().outline_color,
|
|
||||||
layout.GetTextStyle().outline_width,
|
|
||||||
layout.GetTextStyle().outline_stroke
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
hr = layout.GetTextLayout()->Draw(nullptr, text_renderer_.get(), 0, 0);
|
|
||||||
|
|
||||||
IncreasePrimitivesCount();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
ThrowIfFailed(hr);
|
||||||
|
|
@ -584,85 +499,6 @@ namespace kiwano
|
||||||
vsync_ = enabled;
|
vsync_ = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::PushClip(const Matrix3x2 & clip_matrix, const Size & clip_size)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
if (!device_context_)
|
|
||||||
{
|
|
||||||
hr = E_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
device_context_->SetTransform(DX::ConvertToMatrix3x2F(clip_matrix));
|
|
||||||
device_context_->PushAxisAlignedClip(
|
|
||||||
D2D1::RectF(0, 0, clip_size.x, clip_size.y),
|
|
||||||
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::PopClip()
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
if (!device_context_)
|
|
||||||
{
|
|
||||||
hr = E_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
device_context_->PopAxisAlignedClip();
|
|
||||||
}
|
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::PushLayer(ComPtr<ID2D1Layer> const& layer, LayerProperties const& properties)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
if (!device_context_ || !solid_color_brush_)
|
|
||||||
{
|
|
||||||
hr = E_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
device_context_->PushLayer(
|
|
||||||
D2D1::LayerParameters(
|
|
||||||
DX::ConvertToRectF(properties.area),
|
|
||||||
nullptr,
|
|
||||||
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
|
|
||||||
D2D1::Matrix3x2F::Identity(),
|
|
||||||
properties.opacity,
|
|
||||||
nullptr,
|
|
||||||
D2D1_LAYER_OPTIONS_NONE
|
|
||||||
),
|
|
||||||
layer.get()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::PopLayer()
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
if (!device_context_)
|
|
||||||
{
|
|
||||||
hr = E_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
device_context_->PopLayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::Resize(UINT width, UINT height)
|
void Renderer::Resize(UINT width, UINT height)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
|
|
@ -681,136 +517,11 @@ namespace kiwano
|
||||||
ThrowIfFailed(hr);
|
ThrowIfFailed(hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetCollectingStatus(bool collecting)
|
void Renderer::SetClearColor(const Color& color)
|
||||||
{
|
|
||||||
collecting_status_ = collecting;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetClearColor(const Color & color)
|
|
||||||
{
|
{
|
||||||
clear_color_ = color;
|
clear_color_ = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetTransform(const Matrix3x2 & matrix)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
if (!device_context_)
|
|
||||||
{
|
|
||||||
hr = E_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
device_context_->SetTransform(DX::ConvertToMatrix3x2F(&matrix));
|
|
||||||
}
|
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetOpacity(float opacity)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
if (!solid_color_brush_)
|
|
||||||
{
|
|
||||||
hr = E_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
if (opacity_ != opacity)
|
|
||||||
{
|
|
||||||
opacity_ = opacity;
|
|
||||||
solid_color_brush_->SetOpacity(opacity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetTextStyle(
|
|
||||||
float opacity,
|
|
||||||
Color const& color,
|
|
||||||
bool has_outline,
|
|
||||||
Color const& outline_color,
|
|
||||||
float outline_width,
|
|
||||||
StrokeStyle outline_stroke
|
|
||||||
)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
if (!text_renderer_)
|
|
||||||
{
|
|
||||||
hr = E_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
text_renderer_->SetTextStyle(
|
|
||||||
opacity,
|
|
||||||
DX::ConvertToColorF(color),
|
|
||||||
has_outline,
|
|
||||||
DX::ConvertToColorF(outline_color),
|
|
||||||
outline_width,
|
|
||||||
d2d_res_->GetStrokeStyle(outline_stroke)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetAntialiasMode(bool enabled)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
if (!device_context_)
|
|
||||||
{
|
|
||||||
hr = E_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
device_context_->SetAntialiasMode(
|
|
||||||
enabled ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED
|
|
||||||
);
|
|
||||||
antialias_ = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetTextAntialiasMode(TextAntialias mode)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
if (!device_context_)
|
|
||||||
{
|
|
||||||
hr = E_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
text_antialias_ = mode;
|
|
||||||
D2D1_TEXT_ANTIALIAS_MODE antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
|
||||||
switch (text_antialias_)
|
|
||||||
{
|
|
||||||
case TextAntialias::Default:
|
|
||||||
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
|
|
||||||
break;
|
|
||||||
case TextAntialias::ClearType:
|
|
||||||
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
|
||||||
break;
|
|
||||||
case TextAntialias::GrayScale:
|
|
||||||
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
|
|
||||||
break;
|
|
||||||
case TextAntialias::None:
|
|
||||||
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
device_context_->SetTextAntialiasMode(antialias_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
ThrowIfFailed(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Renderer::CheckVisibility(Size const& content_size, Matrix3x2 const& transform)
|
bool Renderer::CheckVisibility(Size const& content_size, Matrix3x2 const& transform)
|
||||||
{
|
{
|
||||||
return Rect{ Point{}, output_size_ }.Intersects(
|
return Rect{ Point{}, output_size_ }.Intersects(
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,8 @@
|
||||||
#include "../base/Resource.h"
|
#include "../base/Resource.h"
|
||||||
#include "../2d/include-forwards.h"
|
#include "../2d/include-forwards.h"
|
||||||
#include "helper.hpp"
|
#include "helper.hpp"
|
||||||
#include "Image.h"
|
#include "RenderTarget.h"
|
||||||
#include "Geometry.h"
|
#include "GifImage.h"
|
||||||
#include "TextLayout.h"
|
|
||||||
#include "TextRenderer.h"
|
|
||||||
|
|
||||||
#if defined(KGE_USE_DIRECTX10)
|
#if defined(KGE_USE_DIRECTX10)
|
||||||
# include "D3D10DeviceResources.h"
|
# include "D3D10DeviceResources.h"
|
||||||
|
|
@ -47,6 +45,7 @@ namespace kiwano
|
||||||
class KGE_API Renderer
|
class KGE_API Renderer
|
||||||
: public Singleton<Renderer>
|
: public Singleton<Renderer>
|
||||||
, public Component
|
, public Component
|
||||||
|
, public RenderTarget
|
||||||
{
|
{
|
||||||
KGE_DECLARE_SINGLETON(Renderer);
|
KGE_DECLARE_SINGLETON(Renderer);
|
||||||
|
|
||||||
|
|
@ -56,24 +55,20 @@ namespace kiwano
|
||||||
Color const& clear_color
|
Color const& clear_color
|
||||||
);
|
);
|
||||||
|
|
||||||
// 设置抗锯齿模式
|
|
||||||
void SetAntialiasMode(
|
|
||||||
bool enabled
|
|
||||||
);
|
|
||||||
|
|
||||||
// 设置文字抗锯齿模式
|
|
||||||
void SetTextAntialiasMode(
|
|
||||||
TextAntialias mode
|
|
||||||
);
|
|
||||||
|
|
||||||
// ¿ªÆô»ò¹Ø±Õ´¹Ö±Í¬²½
|
// ¿ªÆô»ò¹Ø±Õ´¹Ö±Í¬²½
|
||||||
void SetVSyncEnabled(
|
void SetVSyncEnabled(
|
||||||
bool enabled
|
bool enabled
|
||||||
);
|
);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void CreateLayer(
|
void CreateImage(
|
||||||
ComPtr<ID2D1Layer>& layer
|
Image& image,
|
||||||
|
Resource const& res
|
||||||
|
);
|
||||||
|
|
||||||
|
void CreateGifImage(
|
||||||
|
GifImage& image,
|
||||||
|
Resource const& res
|
||||||
);
|
);
|
||||||
|
|
||||||
void CreateTextFormat(
|
void CreateTextFormat(
|
||||||
|
|
@ -115,71 +110,10 @@ namespace kiwano
|
||||||
GeometrySink& sink
|
GeometrySink& sink
|
||||||
);
|
);
|
||||||
|
|
||||||
void DrawGeometry(
|
void CreateImageRenderTarget(
|
||||||
Geometry const& geometry,
|
ImageRenderTarget& render_target
|
||||||
const Color& stroke_color,
|
|
||||||
float stroke_width,
|
|
||||||
StrokeStyle stroke = StrokeStyle::Miter
|
|
||||||
);
|
);
|
||||||
|
|
||||||
void FillGeometry(
|
|
||||||
Geometry const& geometry,
|
|
||||||
Color const& fill_color
|
|
||||||
);
|
|
||||||
|
|
||||||
void DrawRectangle(
|
|
||||||
Rect const& rect,
|
|
||||||
Color const& stroke_color,
|
|
||||||
float stroke_width,
|
|
||||||
StrokeStyle stroke = StrokeStyle::Miter
|
|
||||||
);
|
|
||||||
|
|
||||||
void FillRectangle(
|
|
||||||
Rect const& rect,
|
|
||||||
Color const& fill_color
|
|
||||||
);
|
|
||||||
|
|
||||||
void DrawBitmap(
|
|
||||||
ComPtr<ID2D1Bitmap> const& bitmap,
|
|
||||||
Rect const& src_rect,
|
|
||||||
Rect const& dest_rect
|
|
||||||
);
|
|
||||||
|
|
||||||
void DrawTextLayout(
|
|
||||||
TextLayout const& layout
|
|
||||||
);
|
|
||||||
|
|
||||||
void SetOpacity(
|
|
||||||
float opacity
|
|
||||||
);
|
|
||||||
|
|
||||||
void SetTransform(
|
|
||||||
const Matrix3x2& matrix
|
|
||||||
);
|
|
||||||
|
|
||||||
void SetTextStyle(
|
|
||||||
float opacity,
|
|
||||||
const Color& color,
|
|
||||||
bool has_outline,
|
|
||||||
const Color& outline_color,
|
|
||||||
float outline_width,
|
|
||||||
StrokeStyle outline_stroke
|
|
||||||
);
|
|
||||||
|
|
||||||
void PushClip(
|
|
||||||
const Matrix3x2& clip_matrix,
|
|
||||||
const Size& clip_size
|
|
||||||
);
|
|
||||||
|
|
||||||
void PopClip();
|
|
||||||
|
|
||||||
void PushLayer(
|
|
||||||
ComPtr<ID2D1Layer> const& layer,
|
|
||||||
LayerProperties const& properties
|
|
||||||
);
|
|
||||||
|
|
||||||
void PopLayer();
|
|
||||||
|
|
||||||
void Resize(
|
void Resize(
|
||||||
UINT width,
|
UINT width,
|
||||||
UINT height
|
UINT height
|
||||||
|
|
@ -201,20 +135,9 @@ namespace kiwano
|
||||||
|
|
||||||
void HandleMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) override;
|
void HandleMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) override;
|
||||||
|
|
||||||
void SetCollectingStatus(bool collecting);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct Status
|
|
||||||
{
|
|
||||||
Time start;
|
|
||||||
Duration duration;
|
|
||||||
int primitives;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline HWND GetTargetWindow() const { return hwnd_; }
|
inline HWND GetTargetWindow() const { return hwnd_; }
|
||||||
|
|
||||||
inline Status const& GetStatus() const { return status_; }
|
|
||||||
|
|
||||||
inline Size const& GetOutputSize() const { return output_size_; }
|
inline Size const& GetOutputSize() const { return output_size_; }
|
||||||
|
|
||||||
inline ID2DDeviceResources* GetD2DDeviceResources() const { KGE_ASSERT(d2d_res_); return d2d_res_.get(); }
|
inline ID2DDeviceResources* GetD2DDeviceResources() const { KGE_ASSERT(d2d_res_); return d2d_res_.get(); }
|
||||||
|
|
@ -234,28 +157,14 @@ namespace kiwano
|
||||||
|
|
||||||
HRESULT HandleDeviceLost();
|
HRESULT HandleDeviceLost();
|
||||||
|
|
||||||
HRESULT BeginDraw();
|
|
||||||
|
|
||||||
HRESULT EndDraw();
|
|
||||||
|
|
||||||
void IncreasePrimitivesCount();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool vsync_;
|
bool vsync_;
|
||||||
bool antialias_;
|
HWND hwnd_;
|
||||||
bool collecting_status_;
|
Size output_size_;
|
||||||
float opacity_;
|
Color clear_color_;
|
||||||
HWND hwnd_;
|
|
||||||
Size output_size_;
|
|
||||||
Color clear_color_;
|
|
||||||
TextAntialias text_antialias_;
|
|
||||||
Status status_;
|
|
||||||
|
|
||||||
ComPtr<ID2DDeviceResources> d2d_res_;
|
ComPtr<ID2DDeviceResources> d2d_res_;
|
||||||
ComPtr<ID3DDeviceResources> d3d_res_;
|
ComPtr<ID3DDeviceResources> d3d_res_;
|
||||||
ComPtr<ID2D1DeviceContext> device_context_;
|
|
||||||
ComPtr<ID2D1DrawingStateBlock> drawing_state_block_;
|
ComPtr<ID2D1DrawingStateBlock> drawing_state_block_;
|
||||||
ComPtr<ITextRenderer> text_renderer_;
|
|
||||||
ComPtr<ID2D1SolidColorBrush> solid_color_brush_;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,7 @@ namespace kiwano
|
||||||
FramePtr ptr = new (std::nothrow) Frame(raw->GetImage());
|
FramePtr ptr = new (std::nothrow) Frame(raw->GetImage());
|
||||||
if (ptr)
|
if (ptr)
|
||||||
{
|
{
|
||||||
ptr->Crop(Rect{ j * width, i * height, width, height });
|
ptr->SetCropRect(Rect{ j * width, i * height, width, height });
|
||||||
image_arr.push_back(ptr);
|
image_arr.push_back(ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -304,7 +304,7 @@ namespace kiwano
|
||||||
FramePtr ptr = new (std::nothrow) Frame(raw->GetImage());
|
FramePtr ptr = new (std::nothrow) Frame(raw->GetImage());
|
||||||
if (ptr)
|
if (ptr)
|
||||||
{
|
{
|
||||||
ptr->Crop(rect);
|
ptr->SetCropRect(rect);
|
||||||
image_arr.push_back(ptr);
|
image_arr.push_back(ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue