add TimeScale

refactoring

refactoring
This commit is contained in:
Haibo 2018-11-21 19:24:18 +08:00 committed by Nomango
parent b9ac2c3934
commit bf25bd1d41
27 changed files with 561 additions and 532 deletions

View File

@ -96,7 +96,7 @@ namespace easy2d
cache_expired_ = true; cache_expired_ = true;
} }
void Canvas::OnDraw() void Canvas::OnRender()
{ {
if (cache_expired_) if (cache_expired_)
{ {

View File

@ -218,7 +218,7 @@ namespace easy2d
// 导出为图片 // 导出为图片
spImage ExportToImage() const; spImage ExportToImage() const;
virtual void OnDraw() override; virtual void OnRender() override;
protected: protected:
cpBitmap const& GetBitmap() const; cpBitmap const& GetBitmap() const;

View File

@ -68,7 +68,7 @@ namespace easy2d
texts_.clear(); texts_.clear();
} }
void DebugerNode::OnUpdate(Duration const & dt) void DebugerNode::Update(Duration const & dt)
{ {
try try
{ {

View File

@ -39,7 +39,7 @@ namespace easy2d
void ClearDebugText(); void ClearDebugText();
void OnUpdate(Duration const& dt) override; void Update(Duration const& dt) override;
protected: protected:
spText debug_text_; spText debug_text_;

View File

@ -26,7 +26,6 @@
namespace easy2d namespace easy2d
{ {
FactoryImpl::FactoryImpl() FactoryImpl::FactoryImpl()
: initialized_(false)
{ {
} }
@ -35,42 +34,41 @@ namespace easy2d
E2D_LOG("Destroying device independent resources"); E2D_LOG("Destroying device independent resources");
} }
void FactoryImpl::Init(bool debug) HRESULT FactoryImpl::Init(bool debug)
{ {
if (initialized_)
return;
E2D_LOG("Creating device independent resources"); E2D_LOG("Creating device independent resources");
D2D1_FACTORY_OPTIONS fact_options; D2D1_FACTORY_OPTIONS fact_options;
fact_options.debugLevel = debug ? D2D1_DEBUG_LEVEL_INFORMATION : D2D1_DEBUG_LEVEL_NONE; fact_options.debugLevel = debug ? D2D1_DEBUG_LEVEL_INFORMATION : D2D1_DEBUG_LEVEL_NONE;
ThrowIfFailed( HRESULT hr = modules::DirectX().D2D1CreateFactory(
modules::DirectX().D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED, D2D1_FACTORY_TYPE_SINGLE_THREADED,
__uuidof(ID2D1Factory), __uuidof(ID2D1Factory),
&fact_options, &fact_options,
reinterpret_cast<void**>(&factory) reinterpret_cast<void**>(&factory_)
)
); );
ThrowIfFailed( if (SUCCEEDED(hr))
{
CoCreateInstance( CoCreateInstance(
CLSID_WICImagingFactory, CLSID_WICImagingFactory,
nullptr, nullptr,
CLSCTX_INPROC_SERVER, CLSCTX_INPROC_SERVER,
__uuidof(IWICImagingFactory), __uuidof(IWICImagingFactory),
reinterpret_cast<void**>(&imaging_factory) reinterpret_cast<void**>(&imaging_factory_)
)
); );
}
ThrowIfFailed( if (SUCCEEDED(hr))
{
modules::DirectX().DWriteCreateFactory( modules::DirectX().DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED, DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory), __uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&write_factory) reinterpret_cast<IUnknown**>(&write_factory_)
)
); );
}
if (SUCCEEDED(hr))
{
auto stroke_style = D2D1::StrokeStyleProperties( auto stroke_style = D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT,
@ -81,45 +79,45 @@ namespace easy2d
0.0f 0.0f
); );
ThrowIfFailed( hr = factory_->CreateStrokeStyle(
factory->CreateStrokeStyle(
stroke_style, stroke_style,
nullptr, nullptr,
0, 0,
&miter_stroke_style &miter_stroke_style_
)
); );
if (SUCCEEDED(hr))
{
stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL; stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL;
ThrowIfFailed( hr = factory_->CreateStrokeStyle(
factory->CreateStrokeStyle(
stroke_style, stroke_style,
nullptr, nullptr,
0, 0,
&bevel_stroke_style &bevel_stroke_style_
)
); );
}
if (SUCCEEDED(hr))
{
stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND; stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND;
ThrowIfFailed( hr = factory_->CreateStrokeStyle(
factory->CreateStrokeStyle(
stroke_style, stroke_style,
nullptr, nullptr,
0, 0,
&round_stroke_style &round_stroke_style_
)
); );
}
initialized_ = true; }
return hr;
} }
HRESULT FactoryImpl::CreateHwndRenderTarget(cpHwndRenderTarget & hwnd_render_target, D2D1_RENDER_TARGET_PROPERTIES const & properties, D2D1_HWND_RENDER_TARGET_PROPERTIES const & hwnd_rt_properties) const HRESULT FactoryImpl::CreateHwndRenderTarget(cpHwndRenderTarget & hwnd_render_target, D2D1_RENDER_TARGET_PROPERTIES const & properties, D2D1_HWND_RENDER_TARGET_PROPERTIES const & hwnd_rt_properties) const
{ {
if (!factory) if (!factory_)
return E_UNEXPECTED; return E_UNEXPECTED;
cpHwndRenderTarget hwnd_render_target_tmp; cpHwndRenderTarget hwnd_render_target_tmp;
HRESULT hr = factory->CreateHwndRenderTarget( HRESULT hr = factory_->CreateHwndRenderTarget(
properties, properties,
hwnd_rt_properties, hwnd_rt_properties,
&hwnd_render_target_tmp &hwnd_render_target_tmp
@ -136,13 +134,13 @@ namespace easy2d
cpSolidColorBrush const& brush cpSolidColorBrush const& brush
) )
{ {
if (!factory) if (!factory_)
return E_UNEXPECTED; return E_UNEXPECTED;
cpTextRenderer text_renderer_tmp; cpTextRenderer text_renderer_tmp;
HRESULT hr = ITextRenderer::Create( HRESULT hr = ITextRenderer::Create(
&text_renderer_tmp, &text_renderer_tmp,
factory.Get(), factory_.Get(),
render_target.Get(), render_target.Get(),
brush.Get() brush.Get()
); );
@ -154,7 +152,7 @@ namespace easy2d
HRESULT FactoryImpl::CreateBitmapFromFile(cpBitmap & bitmap, cpRenderTarget const & rt, String const & file_path) HRESULT FactoryImpl::CreateBitmapFromFile(cpBitmap & bitmap, cpRenderTarget const & rt, String const & file_path)
{ {
if (imaging_factory == nullptr) if (imaging_factory_ == nullptr)
{ {
return E_UNEXPECTED; return E_UNEXPECTED;
} }
@ -167,7 +165,7 @@ namespace easy2d
SmartPointer<IWICFormatConverter> converter; SmartPointer<IWICFormatConverter> converter;
SmartPointer<ID2D1Bitmap> bitmap_tmp; SmartPointer<ID2D1Bitmap> bitmap_tmp;
HRESULT hr = imaging_factory->CreateDecoderFromFilename( HRESULT hr = imaging_factory_->CreateDecoderFromFilename(
file_path.c_str(), file_path.c_str(),
nullptr, nullptr,
GENERIC_READ, GENERIC_READ,
@ -182,7 +180,7 @@ namespace easy2d
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = imaging_factory->CreateFormatConverter(&converter); hr = imaging_factory_->CreateFormatConverter(&converter);
} }
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
@ -215,7 +213,7 @@ namespace easy2d
HRESULT FactoryImpl::CreateBitmapFromResource(cpBitmap & bitmap, cpRenderTarget const & rt, Resource const & res) HRESULT FactoryImpl::CreateBitmapFromResource(cpBitmap & bitmap, cpRenderTarget const & rt, Resource const & res)
{ {
if (imaging_factory == nullptr) if (imaging_factory_ == nullptr)
{ {
return E_UNEXPECTED; return E_UNEXPECTED;
} }
@ -234,7 +232,7 @@ namespace easy2d
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = imaging_factory->CreateStream(&stream); hr = imaging_factory_->CreateStream(&stream);
} }
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
@ -247,7 +245,7 @@ namespace easy2d
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = imaging_factory->CreateDecoderFromStream( hr = imaging_factory_->CreateDecoderFromStream(
stream.Get(), stream.Get(),
nullptr, nullptr,
WICDecodeMetadataCacheOnLoad, WICDecodeMetadataCacheOnLoad,
@ -262,7 +260,7 @@ namespace easy2d
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = imaging_factory->CreateFormatConverter(&converter); hr = imaging_factory_->CreateFormatConverter(&converter);
} }
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
@ -297,11 +295,11 @@ namespace easy2d
HRESULT FactoryImpl::CreateRectangleGeometry(cpRectangleGeometry & geo, Rect const& rect) const HRESULT FactoryImpl::CreateRectangleGeometry(cpRectangleGeometry & geo, Rect const& rect) const
{ {
if (!factory) if (!factory_)
return E_UNEXPECTED; return E_UNEXPECTED;
cpRectangleGeometry rectangle; cpRectangleGeometry rectangle;
HRESULT hr = factory->CreateRectangleGeometry( HRESULT hr = factory_->CreateRectangleGeometry(
rect, rect,
&rectangle &rectangle
); );
@ -313,11 +311,11 @@ namespace easy2d
HRESULT FactoryImpl::CreateRoundedRectangleGeometry(cpRoundedRectangleGeometry & geo, Rect const & rect, float radius_x, float radius_y) const HRESULT FactoryImpl::CreateRoundedRectangleGeometry(cpRoundedRectangleGeometry & geo, Rect const & rect, float radius_x, float radius_y) const
{ {
if (!factory) if (!factory_)
return E_UNEXPECTED; return E_UNEXPECTED;
cpRoundedRectangleGeometry rounded_rect; cpRoundedRectangleGeometry rounded_rect;
HRESULT hr = factory->CreateRoundedRectangleGeometry( HRESULT hr = factory_->CreateRoundedRectangleGeometry(
D2D1::RoundedRect( D2D1::RoundedRect(
rect, rect,
radius_x, radius_x,
@ -333,11 +331,11 @@ namespace easy2d
HRESULT FactoryImpl::CreateEllipseGeometry(cpEllipseGeometry & geo, Point const & center, float radius_x, float radius_y) const HRESULT FactoryImpl::CreateEllipseGeometry(cpEllipseGeometry & geo, Point const & center, float radius_x, float radius_y) const
{ {
if (!factory) if (!factory_)
return E_UNEXPECTED; return E_UNEXPECTED;
cpEllipseGeometry ellipse; cpEllipseGeometry ellipse;
HRESULT hr = factory->CreateEllipseGeometry( HRESULT hr = factory_->CreateEllipseGeometry(
D2D1::Ellipse( D2D1::Ellipse(
center, center,
radius_x, radius_x,
@ -357,11 +355,11 @@ namespace easy2d
cpGeometry const& geo cpGeometry const& geo
) const ) const
{ {
if (!factory) if (!factory_)
return E_UNEXPECTED; return E_UNEXPECTED;
cpTransformedGeometry transformed_tmp; cpTransformedGeometry transformed_tmp;
HRESULT hr = factory->CreateTransformedGeometry( HRESULT hr = factory_->CreateTransformedGeometry(
geo.Get(), geo.Get(),
ConvertToD2DMatrix(matrix), ConvertToD2DMatrix(matrix),
&transformed_tmp &transformed_tmp
@ -376,19 +374,19 @@ namespace easy2d
HRESULT FactoryImpl::CreatePathGeometry(cpPathGeometry & geometry) const HRESULT FactoryImpl::CreatePathGeometry(cpPathGeometry & geometry) const
{ {
if (!factory) if (!factory_)
return E_UNEXPECTED; return E_UNEXPECTED;
return factory->CreatePathGeometry(&geometry); return factory_->CreatePathGeometry(&geometry);
} }
HRESULT FactoryImpl::CreateTextFormat(cpTextFormat & text_format, Font const & font, TextStyle const & text_style) const HRESULT FactoryImpl::CreateTextFormat(cpTextFormat & text_format, Font const & font, TextStyle const & text_style) const
{ {
if (!write_factory) if (!write_factory_)
return E_UNEXPECTED; return E_UNEXPECTED;
cpTextFormat text_format_tmp; cpTextFormat text_format_tmp;
HRESULT hr = write_factory->CreateTextFormat( HRESULT hr = write_factory_->CreateTextFormat(
font.family.c_str(), font.family.c_str(),
nullptr, nullptr,
DWRITE_FONT_WEIGHT(font.weight), DWRITE_FONT_WEIGHT(font.weight),
@ -422,7 +420,7 @@ namespace easy2d
HRESULT FactoryImpl::CreateTextLayout(cpTextLayout & text_layout, Size& layout_size, String const & text, cpTextFormat const& text_format, TextStyle const & text_style) const HRESULT FactoryImpl::CreateTextLayout(cpTextLayout & text_layout, Size& layout_size, String const & text, cpTextFormat const& text_format, TextStyle const & text_style) const
{ {
if (!write_factory) if (!write_factory_)
return E_UNEXPECTED; return E_UNEXPECTED;
text_layout = nullptr; text_layout = nullptr;
@ -433,7 +431,7 @@ namespace easy2d
if (text_style.wrap) if (text_style.wrap)
{ {
hr = write_factory->CreateTextLayout( hr = write_factory_->CreateTextLayout(
text.c_str(), text.c_str(),
length, length,
text_format.Get(), text_format.Get(),
@ -444,7 +442,7 @@ namespace easy2d
} }
else else
{ {
hr = write_factory->CreateTextLayout( hr = write_factory_->CreateTextLayout(
text.c_str(), text.c_str(),
length, length,
text_format.Get(), text_format.Get(),
@ -459,7 +457,7 @@ namespace easy2d
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
text_layout_tmp = nullptr; text_layout_tmp = nullptr;
hr = write_factory->CreateTextLayout( hr = write_factory_->CreateTextLayout(
text.c_str(), text.c_str(),
length, length,
text_format.Get(), text_format.Get(),
@ -503,16 +501,16 @@ namespace easy2d
switch (stroke) switch (stroke)
{ {
case StrokeStyle::Miter: case StrokeStyle::Miter:
return miter_stroke_style; return miter_stroke_style_;
break; break;
case StrokeStyle::Bevel: case StrokeStyle::Bevel:
return bevel_stroke_style; return bevel_stroke_style_;
break; break;
case StrokeStyle::Round: case StrokeStyle::Round:
return round_stroke_style; return round_stroke_style_;
break; break;
} }
return miter_stroke_style; return miter_stroke_style_;
} }
} }

View File

@ -35,7 +35,7 @@ namespace easy2d
E2D_DECLARE_SINGLETON(FactoryImpl); E2D_DECLARE_SINGLETON(FactoryImpl);
public: public:
void Init(bool debug); HRESULT Init(bool debug);
HRESULT CreateHwndRenderTarget( HRESULT CreateHwndRenderTarget(
cpHwndRenderTarget& hwnd_render_target, cpHwndRenderTarget& hwnd_render_target,
@ -114,13 +114,12 @@ namespace easy2d
~FactoryImpl(); ~FactoryImpl();
protected: protected:
bool initialized_; cpFactory factory_;
cpFactory factory; cpImagingFactory imaging_factory_;
cpImagingFactory imaging_factory; cpWriteFactory write_factory_;
cpWriteFactory write_factory; cpStrokeStyle miter_stroke_style_;
cpStrokeStyle miter_stroke_style; cpStrokeStyle bevel_stroke_style_;
cpStrokeStyle bevel_stroke_style; cpStrokeStyle round_stroke_style_;
cpStrokeStyle round_stroke_style;
}; };
E2D_DECLARE_SINGLETON_TYPE(FactoryImpl, Factory); E2D_DECLARE_SINGLETON_TYPE(FactoryImpl, Factory);

View File

@ -20,8 +20,6 @@
#include "Game.h" #include "Game.h"
#include "logs.h" #include "logs.h"
#include "input.h"
#include "audio.h"
#include "modules.h" #include "modules.h"
#include "Factory.h" #include "Factory.h"
#include "Scene.h" #include "Scene.h"
@ -35,13 +33,17 @@
namespace easy2d namespace easy2d
{ {
Game::Game() Game::Game()
: curr_scene_(nullptr) : initialized_(false)
, window_inactived_(false)
, curr_scene_(nullptr)
, next_scene_(nullptr) , next_scene_(nullptr)
, transition_(nullptr) , transition_(nullptr)
, window_(nullptr)
, graphics_(nullptr)
, input_(nullptr)
, audio_(nullptr)
, debug_enabled_(false) , debug_enabled_(false)
, initialized_(false) , time_scale_(1.f)
, hwnd_(nullptr)
, window_inactived_(false)
{ {
::CoInitialize(nullptr); ::CoInitialize(nullptr);
} }
@ -64,32 +66,55 @@ namespace easy2d
debug_enabled_ = options.debug; debug_enabled_ = options.debug;
Window::Instance()->Init( window_ = Window::Instance();
graphics_ = devices::Graphics::Instance();
input_ = devices::Input::Instance();
audio_ = devices::Audio::Instance();
ThrowIfFailed(
Factory::Instance()->Init(debug_enabled_)
);
ThrowIfFailed(
window_->Init(
options.title, options.title,
options.width, options.width,
options.height, options.height,
options.icon, options.icon,
Game::WndProc, Game::WndProc,
debug_enabled_ debug_enabled_
)
); );
const auto window = Window::Instance(); HWND hwnd = window_->GetHandle();
hwnd_ = window->GetHandle();
::SetWindowLongW(hwnd_, GWLP_USERDATA, PtrToUlong(this)); ThrowIfFailed(
graphics_->Init(
hwnd,
options.vsync,
debug_enabled_
)
);
Factory::Instance()->Init(debug_enabled_); ThrowIfFailed(
devices::Graphics::Instance()->Init(hwnd_, options.graphics_options, debug_enabled_); input_->Init(
devices::Input::Instance()->Init(hwnd_, window->GetContentScaleX(), window->GetContentScaleY(), debug_enabled_); hwnd,
devices::Audio::Instance()->Init(debug_enabled_); window_->GetContentScaleX(),
window_->GetContentScaleY(),
debug_enabled_
)
);
ThrowIfFailed(
audio_->Init(debug_enabled_)
);
// disable imm // disable imm
::ImmAssociateContext(hwnd_, nullptr); ::ImmAssociateContext(hwnd, nullptr);
// show console if debug mode enabled
HWND console = ::GetConsoleWindow(); HWND console = ::GetConsoleWindow();
if (debug_enabled_) if (debug_enabled_ && !console)
{
if (console == nullptr)
{ {
if (::AllocConsole()) if (::AllocConsole())
{ {
@ -100,36 +125,31 @@ namespace easy2d
freopen_s(&stderrStream, "conout$", "w+t", stderr); freopen_s(&stderrStream, "conout$", "w+t", stderr);
} }
} }
} else if (!debug_enabled_ && console)
else
{
if (console)
{ {
::ShowWindow(console, SW_HIDE); ::ShowWindow(console, SW_HIDE);
} }
}
// disable the close button of console
if (console) if (console)
{ {
// disable the close button of console
HMENU hmenu = ::GetSystemMenu(console, FALSE); HMENU hmenu = ::GetSystemMenu(console, FALSE);
::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND); ::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND);
} }
// use Game instance in message loop
::SetWindowLongW(hwnd, GWLP_USERDATA, PtrToUlong(this));
initialized_ = true; initialized_ = true;
} }
void Game::Run() void Game::Run()
{ {
if (next_scene_) if (!initialized_)
{ return;
next_scene_->OnEnter();
curr_scene_ = next_scene_;
next_scene_ = nullptr;
}
::ShowWindow(hwnd_, SW_SHOWNORMAL); ::ShowWindow(window_->GetHandle(), SW_SHOWNORMAL);
::UpdateWindow(hwnd_); ::UpdateWindow(window_->GetHandle());
MSG msg = {}; MSG msg = {};
while (::GetMessageW(&msg, nullptr, 0, 0)) while (::GetMessageW(&msg, nullptr, 0, 0))
@ -141,7 +161,8 @@ namespace easy2d
void Game::Quit() void Game::Quit()
{ {
::DestroyWindow(hwnd_); if (window_)
::DestroyWindow(window_->GetHandle());
} }
bool Game::EnterScene(spScene const & scene) bool Game::EnterScene(spScene const & scene)
@ -182,15 +203,20 @@ namespace easy2d
return curr_scene_; return curr_scene_;
} }
void Game::SetTimeScale(float scale)
{
time_scale_ = scale;
}
void Game::Update() void Game::Update()
{ {
static auto last = time::Now(); static auto last = time::Now();
const auto now = time::Now(); const auto now = time::Now();
const auto dt = now - last; const auto dt = (now - last) * time_scale_;
last = now; last = now;
devices::Input::Instance()->Update(); input_->Update();
if (curr_scene_) if (curr_scene_)
curr_scene_->Update(dt); curr_scene_->Update(dt);
@ -228,7 +254,10 @@ namespace easy2d
void Game::Render() void Game::Render()
{ {
auto graphics = devices::Graphics::Instance(); auto graphics = devices::Graphics::Instance();
graphics->BeginDraw(hwnd_);
ThrowIfFailed(
graphics->BeginDraw(window_->GetHandle())
);
if (transition_) if (transition_)
{ {
@ -236,7 +265,7 @@ namespace easy2d
} }
else if (curr_scene_) else if (curr_scene_)
{ {
curr_scene_->Visit(); curr_scene_->Render();
} }
if (debug_enabled_) if (debug_enabled_)
@ -254,13 +283,15 @@ namespace easy2d
next_scene_->DrawBorder(); next_scene_->DrawBorder();
} }
Debuger::Instance()->Visit(); Debuger::Instance()->Render();
} }
graphics->EndDraw(); ThrowIfFailed(
graphics->EndDraw()
);
if (!window_inactived_) if (!window_inactived_)
::InvalidateRect(hwnd_, NULL, FALSE); ::InvalidateRect(window_->GetHandle(), NULL, FALSE);
} }
void Game::Dispatch(MouseEvent const & e) void Game::Dispatch(MouseEvent const & e)

View File

@ -20,9 +20,11 @@
#pragma once #pragma once
#include "base.hpp" #include "base.hpp"
#include "window.h"
#include "time.h" #include "time.h"
#include "window.h"
#include "render.h" #include "render.h"
#include "input.h"
#include "audio.h"
#include "KeyEvent.h" #include "KeyEvent.h"
#include "MouseEvent.h" #include "MouseEvent.h"
@ -34,17 +36,16 @@ namespace easy2d
int width; // 宽度 int width; // 宽度
int height; // 高度 int height; // 高度
LPCWSTR icon; // 图标 LPCWSTR icon; // 图标
bool vsync; // ´¹Ö±Í¬²½
bool debug; // 调试模式 bool debug; // 调试模式
GraphicsOptions graphics_options; // ͼÐÎäÖȾѡÏî
Options() Options()
: title(L"Easy2D Game") : title(L"Easy2D Game")
, width(640) , width(640)
, height(480) , height(480)
, icon(nullptr) , icon(nullptr)
, vsync(true)
, debug(false) , debug(false)
, graphics_options()
{} {}
}; };
@ -93,6 +94,9 @@ namespace easy2d
// 获取当前场景 // 获取当前场景
spScene const& GetCurrentScene(); spScene const& GetCurrentScene();
// ÉèÖñäËÙ
void SetTimeScale(float scale);
private: private:
void Render(); void Render();
@ -112,9 +116,14 @@ namespace easy2d
bool initialized_; bool initialized_;
bool debug_enabled_; bool debug_enabled_;
bool window_inactived_; bool window_inactived_;
HWND hwnd_; float time_scale_;
spScene curr_scene_; spScene curr_scene_;
spScene next_scene_; spScene next_scene_;
spTransition transition_; spTransition transition_;
WindowImpl* window_;
devices::GraphicsDevice* graphics_;
devices::InputDevice* input_;
devices::AudioDevice* audio_;
}; };
} }

View File

@ -66,7 +66,7 @@ namespace easy2d
outline_join_ = outline_join; outline_join_ = outline_join;
} }
void GeometryNode::OnDraw() void GeometryNode::OnRender()
{ {
if (geometry_ && geometry_->geo_) if (geometry_ && geometry_->geo_)
{ {
@ -87,12 +87,4 @@ namespace easy2d
} }
} }
void GeometryNode::DrawBorder()
{
if (visible_)
{
DrawChildrenBorder();
}
}
} }

View File

@ -77,10 +77,7 @@ namespace easy2d
// ťńČĄĎßĚőĎཝŃůĘ˝ // ťńČĄĎßĚőĎཝŃůĘ˝
StrokeStyle SetOutlineJoinStyle() const { return outline_join_; } StrokeStyle SetOutlineJoinStyle() const { return outline_join_; }
virtual void OnDraw() override; virtual void OnRender() override;
protected:
virtual void DrawBorder() override;
protected: protected:
Color fill_color_; Color fill_color_;

View File

@ -27,8 +27,7 @@ namespace easy2d
namespace devices namespace devices
{ {
InputDevice::InputDevice() InputDevice::InputDevice()
: initialized_(false) : hwnd_(nullptr)
, hwnd_(nullptr)
, scale_x_(1.f) , scale_x_(1.f)
, scale_y_(1.f) , scale_y_(1.f)
{ {
@ -41,18 +40,15 @@ namespace easy2d
E2D_LOG("Destroying input device"); E2D_LOG("Destroying input device");
} }
void InputDevice::Init(HWND hwnd, float scale_x, float scale_y, bool debug) HRESULT InputDevice::Init(HWND hwnd, float scale_x, float scale_y, bool debug)
{ {
if (initialized_)
return;
E2D_LOG("Initing input device"); E2D_LOG("Initing input device");
hwnd_ = hwnd; hwnd_ = hwnd;
scale_x_ = scale_x; scale_x_ = scale_x;
scale_y_ = scale_y; scale_y_ = scale_y;
initialized_ = true; return S_OK;
} }
void InputDevice::Update() void InputDevice::Update()

View File

@ -32,7 +32,7 @@ namespace easy2d
E2D_DECLARE_SINGLETON(InputDevice); E2D_DECLARE_SINGLETON(InputDevice);
public: public:
void Init(HWND hwnd, float scale_x, float scale_y, bool debug); HRESULT Init(HWND hwnd, float scale_x, float scale_y, bool debug);
// 检测键盘某按键是否正被按下 // 检测键盘某按键是否正被按下
bool IsDown( bool IsDown(
@ -71,7 +71,6 @@ namespace easy2d
~InputDevice(); ~InputDevice();
protected: protected:
bool initialized_;
HWND hwnd_; HWND hwnd_;
float scale_x_; float scale_x_;
float scale_y_; float scale_y_;

View File

@ -32,6 +32,7 @@ namespace easy2d
{ {
float default_pivot_x = 0.f; float default_pivot_x = 0.f;
float default_pivot_y = 0.f; float default_pivot_y = 0.f;
bool border_enabled = false;
} }
void Node::SetDefaultPivot(float pivot_x, float pivot_y) void Node::SetDefaultPivot(float pivot_x, float pivot_y)
@ -40,12 +41,23 @@ namespace easy2d
default_pivot_y = pivot_y; default_pivot_y = pivot_y;
} }
void easy2d::Node::EnableBorder()
{
border_enabled = true;
}
void easy2d::Node::DisableBorder()
{
border_enabled = false;
}
Node::Node() Node::Node()
: visible_(true) : inited_(false)
, visible_(true)
, dirty_sort_(false)
, parent_(nullptr) , parent_(nullptr)
, hash_name_(0) , hash_name_(0)
, dirty_sort_(false) , z_order_(0)
, order_(0)
, opacity_(1.f) , opacity_(1.f)
, display_opacity_(1.f) , display_opacity_(1.f)
, children_() , children_()
@ -57,11 +69,36 @@ namespace easy2d
{ {
} }
Node::~Node() void Node::Init()
{ {
inited_ = true;
} }
void Node::Visit() void Node::OnRender()
{
// normal node renders nothing
}
void Node::Update(Duration const & dt)
{
if (!inited_)
{
Init();
}
UpdateActions(this, dt);
UpdateTasks(dt);
if (!children_.IsEmpty())
{
for (auto child = children_.First(); child; child = child->NextItem())
{
child->Update(dt);
}
}
}
void Node::Render()
{ {
if (!visible_) if (!visible_)
return; return;
@ -74,26 +111,21 @@ namespace easy2d
{ {
graphics->SetTransform(final_matrix_); graphics->SetTransform(final_matrix_);
graphics->SetOpacity(display_opacity_); graphics->SetOpacity(display_opacity_);
OnDraw();
OnRender();
} }
else else
{ {
if (dirty_sort_) SortChildren();
{
children_.Sort(
[](spNode const& n1, spNode const& n2) { return n1->GetOrder() < n2->GetOrder(); }
);
dirty_sort_ = false;
}
// render children those are less than 0 in Z-Order
spNode child = children_.First(); spNode child = children_.First();
for (spNode next; child; child = next) for (spNode next; child; child = next)
{ {
next = child->NextItem(); next = child->NextItem();
if (child->GetOrder() < 0) if (child->GetZOrder() < 0)
{ {
child->Visit(); child->Render();
} }
else else
{ {
@ -103,49 +135,13 @@ namespace easy2d
graphics->SetTransform(final_matrix_); graphics->SetTransform(final_matrix_);
graphics->SetOpacity(display_opacity_); graphics->SetOpacity(display_opacity_);
OnDraw();
OnRender();
for (spNode next; child; child = next) for (spNode next; child; child = next)
{ {
next = child->NextItem(); next = child->NextItem();
child->Visit(); child->Render();
}
}
}
void Node::Update(Duration const& dt)
{
if (children_.IsEmpty())
{
OnUpdate(dt);
UpdateActions(this, dt);
UpdateTasks(dt);
}
else
{
// 访问 Order 小于零的节点
spNode child = children_.First();
for (spNode next; child; child = next)
{
if (child->GetOrder() < 0)
{
next = child->NextItem();
child->Update(dt);
}
else
{
break;
}
}
OnUpdate(dt);
UpdateActions(this, dt);
UpdateTasks(dt);
for (spNode next; child; child = next)
{
next = child->NextItem();
child->Update(dt);
} }
} }
} }
@ -159,17 +155,24 @@ namespace easy2d
devices::Graphics::Instance()->DrawGeometry(border_, border_color_, 1.5f); devices::Graphics::Instance()->DrawGeometry(border_, border_color_, 1.5f);
} }
DrawChildrenBorder();
}
}
void Node::DrawChildrenBorder()
{
for (auto child = children_.First(); child; child = child->NextItem()) for (auto child = children_.First(); child; child = child->NextItem())
{ {
child->DrawBorder(); child->DrawBorder();
} }
} }
}
void Node::SortChildren()
{
if (dirty_sort_)
{
children_.Sort(
[](spNode const& n1, spNode const& n2) { return n1->GetZOrder() < n2->GetZOrder(); }
);
dirty_sort_ = false;
}
}
math::Matrix const & Node::GetTransformMatrix() math::Matrix const & Node::GetTransformMatrix()
{ {
@ -200,12 +203,17 @@ namespace easy2d
final_matrix_ = final_matrix_ * parent_->initial_matrix_; final_matrix_ = final_matrix_ * parent_->initial_matrix_;
} }
UpdateBorder(); // update children's transform
for (auto child = children_.First(); child; child = child->NextItem()) for (auto child = children_.First(); child; child = child->NextItem())
{ {
child->dirty_transform_ = true; child->dirty_transform_ = true;
} }
// update border
if (border_enabled)
{
UpdateBorder();
}
} }
void Node::UpdateBorder() void Node::UpdateBorder()
@ -213,23 +221,25 @@ namespace easy2d
cpRectangleGeometry rect; cpRectangleGeometry rect;
cpTransformedGeometry transformed; cpTransformedGeometry transformed;
ThrowIfFailed( HRESULT hr = Factory::Instance()->CreateRectangleGeometry(
Factory::Instance()->CreateRectangleGeometry(
rect, rect,
Rect(Point{}, size_) Rect(Point{}, size_)
)
); );
ThrowIfFailed( if (SUCCEEDED(hr))
Factory::Instance()->CreateTransformedGeometry( {
hr = Factory::Instance()->CreateTransformedGeometry(
transformed, transformed,
final_matrix_, final_matrix_,
rect rect
)
); );
}
if (SUCCEEDED(hr))
{
border_ = transformed; border_ = transformed;
} }
}
bool Node::Dispatch(const MouseEvent & e, bool handled) bool Node::Dispatch(const MouseEvent & e, bool handled)
{ {
@ -281,12 +291,12 @@ namespace easy2d
} }
} }
void Node::SetOrder(int order) void Node::SetZOrder(int order)
{ {
if (order_ == order) if (z_order_ == order)
return; return;
order_ = order; z_order_ = order;
if (parent_) if (parent_)
{ {
parent_->dirty_sort_ = true; parent_->dirty_sort_ = true;
@ -358,7 +368,21 @@ namespace easy2d
border_color_ = color; border_color_ = color;
} }
void Node::AddChild(spNode const& child, int order) void Node::SetVisible(bool val)
{
visible_ = val;
}
void Node::SetName(String const& name)
{
if (name_ != name)
{
name_ = name;
hash_name_ = std::hash<String>{}(name);
}
}
void Node::AddChild(spNode const& child, int z_order)
{ {
if (!child) if (!child)
logs::Warningln("Node::AddChild failed, child is nullptr"); logs::Warningln("Node::AddChild failed, child is nullptr");
@ -366,28 +390,31 @@ namespace easy2d
if (child) if (child)
{ {
#ifdef E2D_DEBUG #ifdef E2D_DEBUG
if (child->parent_) if (child->parent_)
logs::Errorln("The node to be added already has a parent"); logs::Errorln("The node to be added already has a parent");
for (Node* parent = parent_; parent; parent = parent->parent_) for (Node* parent = parent_; parent; parent = parent->parent_)
if (parent == child) if (parent == child)
logs::Errorln("A node cannot be its own parent"); logs::Errorln("A node cannot be its own parent");
#endif // E2D_DEBUG #endif // E2D_DEBUG
children_.PushBack(Node::ItemType(child)); children_.PushBack(Node::ItemType(child));
child->parent_ = this; child->parent_ = this;
child->dirty_transform_ = true; child->dirty_transform_ = true;
child->SetOrder(order); child->SetZOrder(z_order);
child->UpdateOpacity(); child->UpdateOpacity();
dirty_sort_ = true; dirty_sort_ = true;
} }
} }
void Node::AddChild(const Nodes& nodes, int order) void Node::AddChild(const Nodes& nodes, int z_order)
{ {
for (const auto& node : nodes) for (const auto& node : nodes)
{ {
this->AddChild(node, order); this->AddChild(node, z_order);
} }
} }
@ -486,30 +513,22 @@ namespace easy2d
UpdateTransform(); UpdateTransform();
BOOL ret = 0; cpRectangleGeometry border;
ThrowIfFailed( ThrowIfFailed(
border_->FillContainsPoint( Factory::Instance()->CreateRectangleGeometry(
point, border,
D2D1::Matrix3x2F::Identity(), Rect(Point{}, size_)
&ret
) )
); );
BOOL ret = 0;
// no matter it failed or not
border->FillContainsPoint(
point,
ConvertToD2DMatrix(final_matrix_),
&ret
);
return !!ret; return !!ret;
} }
void Node::SetVisible(bool val)
{
visible_ = val;
}
void Node::SetName(String const& name)
{
if (name_ != name)
{
// 保存节点名
name_ = name;
// 保存节点 Hash 名
hash_name_ = std::hash<String>{}(name);
}
}
} }

View File

@ -50,13 +50,14 @@ namespace easy2d
public: public:
Node(); Node();
virtual ~Node(); // 初始化节点
virtual void Init();
// 渲染节点
virtual void OnDraw() {}
// 更新节点 // 更新节点
virtual void OnUpdate(Duration const& dt) {} virtual void Update(Duration const& dt);
// 渲染节点
virtual void OnRender();
// 获取显示状态 // 获取显示状态
bool IsVisible() const { return visible_; } bool IsVisible() const { return visible_; }
@ -67,8 +68,8 @@ namespace easy2d
// 获取名称的 Hash 值 // 获取名称的 Hash 值
size_t GetHashName() const { return hash_name_; } size_t GetHashName() const { return hash_name_; }
// 获取绘图顺序 // 获取 Z 轴顺序
int GetOrder() const { return order_; } int GetZOrder() const { return z_order_; }
// 获取宽度 // 获取宽度
virtual float GetWidth() const { return size_.width * transform_.scale.x; } virtual float GetWidth() const { return size_.width * transform_.scale.x; }
@ -157,9 +158,9 @@ namespace easy2d
float opacity float opacity
); );
// 设置绘图顺序 // 设置 Z 轴顺序
// 默认为 0 // 默认为 0
void SetOrder( void SetZOrder(
int order int order
); );
@ -176,13 +177,13 @@ namespace easy2d
// 添加子节点 // 添加子节点
void AddChild( void AddChild(
spNode const& child, spNode const& child,
int order = 0 /* 渲染顺序 */ int z_order = 0 /* Z 轴顺序 */
); );
// 添加多个子节点 // 添加多个子节点
void AddChild( void AddChild(
const Nodes& nodes, /* 节点数组 */ const Nodes& nodes, /* 节点数组 */
int order = 0 /* 渲染顺序 */ int z_order = 0 /* Z 轴顺序 */
); );
// 获取所有名称相同的子节点 // 获取所有名称相同的子节点
@ -220,8 +221,24 @@ namespace easy2d
float pivot_y float pivot_y
); );
// 启用边框自动生成
static void EnableBorder();
// 禁用边框自动生成
static void DisableBorder();
protected: protected:
virtual void Visit(); void Render();
void DrawBorder();
void SortChildren();
void UpdateBorder();
void UpdateTransform();
void UpdateOpacity();
virtual bool Dispatch( virtual bool Dispatch(
const MouseEvent& e, const MouseEvent& e,
@ -234,26 +251,14 @@ namespace easy2d
); );
protected: protected:
virtual void Update(Duration const& dt); bool inited_;
virtual void DrawBorder();
void DrawChildrenBorder();
void UpdateBorder();
void UpdateTransform();
void UpdateOpacity();
protected:
String name_;
size_t hash_name_;
float display_opacity_;
float opacity_;
int order_;
bool visible_; bool visible_;
bool dirty_sort_; bool dirty_sort_;
int z_order_;
float opacity_;
float display_opacity_;
String name_;
size_t hash_name_;
Node* parent_; Node* parent_;
Color border_color_; Color border_color_;
Children children_; Children children_;

View File

@ -127,7 +127,7 @@ namespace easy2d
return image_; return image_;
} }
void Sprite::OnDraw() void Sprite::OnRender()
{ {
if (image_) if (image_)
{ {

View File

@ -79,7 +79,7 @@ namespace easy2d
spImage const& GetImage() const; spImage const& GetImage() const;
// äÖȾ¾«Áé // äÖȾ¾«Áé
virtual void OnDraw() override; virtual void OnRender() override;
protected: protected:
spImage image_; spImage image_;

View File

@ -291,7 +291,7 @@ namespace easy2d
style_.outline_stroke = outline_stroke; style_.outline_stroke = outline_stroke;
} }
void Text::OnDraw() void Text::OnRender()
{ {
if (text_layout_) if (text_layout_)
{ {

View File

@ -199,7 +199,7 @@ namespace easy2d
TextStyle const& style TextStyle const& style
); );
virtual void OnDraw() override; virtual void OnRender() override;
protected: protected:
void UpdateLayout(); void UpdateLayout();

View File

@ -111,7 +111,7 @@ namespace easy2d
); );
graphics->PushLayer(out_layer_, out_layer_prop_); graphics->PushLayer(out_layer_, out_layer_prop_);
out_scene_->Visit(); out_scene_->Render();
graphics->PopLayer(); graphics->PopLayer();
graphics->PopClip(); graphics->PopClip();
@ -125,7 +125,7 @@ namespace easy2d
); );
graphics->PushLayer(in_layer_, in_layer_prop_); graphics->PushLayer(in_layer_, in_layer_prop_);
in_scene_->Visit(); in_scene_->Render();
graphics->PopLayer(); graphics->PopLayer();
graphics->PopClip(); graphics->PopClip();

View File

@ -164,7 +164,6 @@ namespace easy2d
AudioDevice::AudioDevice() AudioDevice::AudioDevice()
: x_audio2_(nullptr) : x_audio2_(nullptr)
, mastering_voice_(nullptr) , mastering_voice_(nullptr)
, initialized_(false)
{ {
} }
@ -185,26 +184,23 @@ namespace easy2d
modules::MediaFoundation().MFShutdown(); modules::MediaFoundation().MFShutdown();
} }
void AudioDevice::Init(bool debug) HRESULT AudioDevice::Init(bool debug)
{ {
if (initialized_)
return;
E2D_LOG("Initing audio device"); E2D_LOG("Initing audio device");
ThrowIfFailed( HRESULT hr = modules::MediaFoundation().MFStartup(MF_VERSION, MFSTARTUP_FULL);
modules::MediaFoundation().MFStartup(MF_VERSION, MFSTARTUP_FULL)
);
ThrowIfFailed( if (SUCCEEDED(hr))
modules::XAudio2().XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR) {
); hr = modules::XAudio2().XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR);
}
ThrowIfFailed( if (SUCCEEDED(hr))
x_audio2_->CreateMasteringVoice(&mastering_voice_) {
); hr = x_audio2_->CreateMasteringVoice(&mastering_voice_);
}
initialized_ = true; return hr;
} }
HRESULT AudioDevice::CreateVoice(Voice& voice, const WAVEFORMATEX* wfx) HRESULT AudioDevice::CreateVoice(Voice& voice, const WAVEFORMATEX* wfx)

View File

@ -80,7 +80,7 @@ namespace easy2d
E2D_DECLARE_SINGLETON(AudioDevice); E2D_DECLARE_SINGLETON(AudioDevice);
public: public:
void Init(bool debug); HRESULT Init(bool debug);
// 开启设备 // 开启设备
void Open(); void Open();
@ -105,7 +105,6 @@ namespace easy2d
~AudioDevice(); ~AudioDevice();
protected: protected:
bool initialized_;
IXAudio2* x_audio2_; IXAudio2* x_audio2_;
IXAudio2MasteringVoice* mastering_voice_; IXAudio2MasteringVoice* mastering_voice_;
std::set<Voice*> voice_cache_; std::set<Voice*> voice_cache_;

View File

@ -36,8 +36,9 @@ namespace easy2d
, clear_color_(D2D1::ColorF(D2D1::ColorF::Black)) , clear_color_(D2D1::ColorF(D2D1::ColorF::Black))
, opacity_(1.f) , opacity_(1.f)
, window_occluded_(false) , window_occluded_(false)
, initialized_(false) , vsync_enabled_(true)
, options_() , antialias_(true)
, text_antialias_(TextAntialias::ClearType)
{ {
} }
@ -48,54 +49,53 @@ namespace easy2d
ClearImageCache(); ClearImageCache();
} }
void GraphicsDevice::Init(HWND hwnd, GraphicsOptions options, bool debug) HRESULT GraphicsDevice::Init(HWND hwnd, bool vsync, bool debug)
{ {
if (initialized_)
return;
E2D_LOG("Initing graphics device"); E2D_LOG("Initing graphics device");
options_ = options; HRESULT hr = CreateResources(hwnd);
CreateDeviceResources(hwnd); if (SUCCEEDED(hr))
{
initialized_ = true; vsync_enabled_ = vsync;
}
return hr;
} }
void GraphicsDevice::BeginDraw(HWND hwnd) HRESULT GraphicsDevice::BeginDraw(HWND hwnd)
{ {
CreateDeviceResources(hwnd); HRESULT hr = CreateResources(hwnd);
window_occluded_ = !!(render_target->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED); if (SUCCEEDED(hr))
{
window_occluded_ = !!(render_target_->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED);
if (!window_occluded_) if (!window_occluded_)
{ {
render_target->BeginDraw(); render_target_->BeginDraw();
render_target->Clear(clear_color_); render_target_->Clear(clear_color_);
} }
} }
void GraphicsDevice::EndDraw() return hr;
}
HRESULT GraphicsDevice::EndDraw()
{ {
HRESULT hr = S_OK;
if (!window_occluded_) if (!window_occluded_)
{ {
HRESULT hr = render_target->EndDraw(); hr = render_target_->EndDraw();
if (hr == D2DERR_RECREATE_TARGET) if (hr == D2DERR_RECREATE_TARGET)
{ {
// 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源 // 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源
// 并在下一次调用时重建资源 // 并在下一次调用时重建资源
DiscardResources();
hr = S_OK; hr = S_OK;
fps_text_format_ = nullptr;
fps_text_layout_ = nullptr;
text_renderer = nullptr;
solid_brush = nullptr;
render_target = nullptr;
} }
ThrowIfFailed(hr);
} }
return hr;
} }
void GraphicsDevice::ClearImageCache() void GraphicsDevice::ClearImageCache()
@ -105,20 +105,20 @@ namespace easy2d
HRESULT GraphicsDevice::CreateLayer(cpLayer& layer) HRESULT GraphicsDevice::CreateLayer(cpLayer& layer)
{ {
if (!render_target) if (!render_target_)
return E_UNEXPECTED; return E_UNEXPECTED;
layer = nullptr; layer = nullptr;
return render_target->CreateLayer(&layer); return render_target_->CreateLayer(&layer);
} }
HRESULT GraphicsDevice::CreateSolidColorBrush(cpSolidColorBrush & brush) const HRESULT GraphicsDevice::CreateSolidColorBrush(cpSolidColorBrush & brush) const
{ {
if (!render_target) if (!render_target_)
return E_UNEXPECTED; return E_UNEXPECTED;
brush = nullptr; brush = nullptr;
return render_target->CreateSolidColorBrush( return render_target_->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::White), D2D1::ColorF(D2D1::ColorF::White),
&brush &brush
); );
@ -131,18 +131,18 @@ namespace easy2d
StrokeStyle stroke StrokeStyle stroke
) )
{ {
if (!solid_brush || if (!solid_brush_ ||
!render_target) !render_target_)
return E_UNEXPECTED; return E_UNEXPECTED;
if (window_occluded_) if (window_occluded_)
return S_OK; return S_OK;
solid_brush->SetColor(stroke_color); solid_brush_->SetColor(stroke_color);
auto stroke_style = Factory::Instance()->GetStrokeStyle(stroke); auto stroke_style = Factory::Instance()->GetStrokeStyle(stroke);
render_target->DrawGeometry( render_target_->DrawGeometry(
geometry.Get(), geometry.Get(),
solid_brush.Get(), solid_brush_.Get(),
stroke_width, stroke_width,
stroke_style.Get() stroke_style.Get()
); );
@ -151,24 +151,24 @@ namespace easy2d
HRESULT GraphicsDevice::FillGeometry(cpGeometry const & geometry, const Color & fill_color) HRESULT GraphicsDevice::FillGeometry(cpGeometry const & geometry, const Color & fill_color)
{ {
if (!solid_brush || if (!solid_brush_ ||
!render_target) !render_target_)
return E_UNEXPECTED; return E_UNEXPECTED;
if (window_occluded_) if (window_occluded_)
return S_OK; return S_OK;
solid_brush->SetColor(fill_color); solid_brush_->SetColor(fill_color);
render_target->FillGeometry( render_target_->FillGeometry(
geometry.Get(), geometry.Get(),
solid_brush.Get() solid_brush_.Get()
); );
return S_OK; return S_OK;
} }
HRESULT GraphicsDevice::DrawImage(spImage const & image) HRESULT GraphicsDevice::DrawImage(spImage const & image)
{ {
if (!render_target) if (!render_target_)
return E_UNEXPECTED; return E_UNEXPECTED;
if (!image->GetBitmap()) if (!image->GetBitmap())
@ -177,7 +177,7 @@ namespace easy2d
if (window_occluded_) if (window_occluded_)
return S_OK; return S_OK;
render_target->DrawBitmap( render_target_->DrawBitmap(
image->GetBitmap().Get(), image->GetBitmap().Get(),
D2D1::RectF(0.f, 0.f, image->GetWidth(), image->GetHeight()), D2D1::RectF(0.f, 0.f, image->GetWidth(), image->GetHeight()),
opacity_, opacity_,
@ -191,7 +191,7 @@ namespace easy2d
cpBitmap const& bitmap cpBitmap const& bitmap
) )
{ {
if (!render_target) if (!render_target_)
return E_UNEXPECTED; return E_UNEXPECTED;
if (window_occluded_) if (window_occluded_)
@ -199,7 +199,7 @@ namespace easy2d
// Do not crop bitmap // Do not crop bitmap
auto rect = D2D1::RectF(0.f, 0.f, bitmap->GetSize().width, bitmap->GetSize().height); auto rect = D2D1::RectF(0.f, 0.f, bitmap->GetSize().width, bitmap->GetSize().height);
render_target->DrawBitmap( render_target_->DrawBitmap(
bitmap.Get(), bitmap.Get(),
rect, rect,
opacity_, opacity_,
@ -211,25 +211,25 @@ namespace easy2d
HRESULT GraphicsDevice::DrawTextLayout(cpTextLayout const& text_layout) HRESULT GraphicsDevice::DrawTextLayout(cpTextLayout const& text_layout)
{ {
if (!text_renderer) if (!text_renderer_)
return E_UNEXPECTED; return E_UNEXPECTED;
if (window_occluded_) if (window_occluded_)
return S_OK; return S_OK;
return text_layout->Draw(nullptr, text_renderer.Get(), 0, 0); return text_layout->Draw(nullptr, text_renderer_.Get(), 0, 0);
} }
HRESULT GraphicsDevice::PushClip(const math::Matrix & clip_matrix, const Size & clip_size) HRESULT GraphicsDevice::PushClip(const math::Matrix & clip_matrix, const Size & clip_size)
{ {
if (!render_target) if (!render_target_)
return E_UNEXPECTED; return E_UNEXPECTED;
if (window_occluded_) if (window_occluded_)
return S_OK; return S_OK;
render_target->SetTransform(ConvertToD2DMatrix(clip_matrix)); render_target_->SetTransform(ConvertToD2DMatrix(clip_matrix));
render_target->PushAxisAlignedClip( render_target_->PushAxisAlignedClip(
D2D1::RectF(0, 0, clip_size.width, clip_size.height), D2D1::RectF(0, 0, clip_size.width, clip_size.height),
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
); );
@ -238,33 +238,33 @@ namespace easy2d
HRESULT GraphicsDevice::PopClip() HRESULT GraphicsDevice::PopClip()
{ {
if (!render_target) if (!render_target_)
return E_UNEXPECTED; return E_UNEXPECTED;
if (window_occluded_) if (window_occluded_)
return S_OK; return S_OK;
render_target->PopAxisAlignedClip(); render_target_->PopAxisAlignedClip();
return S_OK; return S_OK;
} }
HRESULT GraphicsDevice::PushLayer(cpLayer const& layer, LayerProperties const& properties) HRESULT GraphicsDevice::PushLayer(cpLayer const& layer, LayerProperties const& properties)
{ {
if (!render_target || if (!render_target_ ||
!solid_brush) !solid_brush_)
return E_UNEXPECTED; return E_UNEXPECTED;
if (window_occluded_) if (window_occluded_)
return S_OK; return S_OK;
render_target->PushLayer( render_target_->PushLayer(
D2D1::LayerParameters( D2D1::LayerParameters(
properties.area, properties.area,
nullptr, nullptr,
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
D2D1::Matrix3x2F::Identity(), D2D1::Matrix3x2F::Identity(),
properties.opacity, properties.opacity,
solid_brush.Get(), solid_brush_.Get(),
D2D1_LAYER_OPTIONS_NONE D2D1_LAYER_OPTIONS_NONE
), ),
layer.Get() layer.Get()
@ -274,22 +274,22 @@ namespace easy2d
HRESULT GraphicsDevice::PopLayer() HRESULT GraphicsDevice::PopLayer()
{ {
if (!render_target) if (!render_target_)
return E_UNEXPECTED; return E_UNEXPECTED;
if (window_occluded_) if (window_occluded_)
return S_OK; return S_OK;
render_target->PopLayer(); render_target_->PopLayer();
return S_OK; return S_OK;
} }
HRESULT GraphicsDevice::GetSize(Size & size) HRESULT GraphicsDevice::GetSize(Size & size)
{ {
if (!render_target) if (!render_target_)
return E_UNEXPECTED; return E_UNEXPECTED;
auto rtsize = render_target->GetSize(); auto rtsize = render_target_->GetSize();
size.width = rtsize.width; size.width = rtsize.width;
size.height = rtsize.height; size.height = rtsize.height;
return S_OK; return S_OK;
@ -297,7 +297,7 @@ namespace easy2d
HRESULT GraphicsDevice::CreateBitmapFromFile(cpBitmap& bitmap, String const& file_path) HRESULT GraphicsDevice::CreateBitmapFromFile(cpBitmap& bitmap, String const& file_path)
{ {
if (render_target == nullptr) if (render_target_ == nullptr)
{ {
return E_UNEXPECTED; return E_UNEXPECTED;
} }
@ -312,7 +312,7 @@ namespace easy2d
cpBitmap bitmap_tmp; cpBitmap bitmap_tmp;
HRESULT hr = Factory::Instance()->CreateBitmapFromFile( HRESULT hr = Factory::Instance()->CreateBitmapFromFile(
bitmap, bitmap,
render_target, render_target_,
file_path file_path
); );
@ -326,7 +326,7 @@ namespace easy2d
HRESULT GraphicsDevice::CreateBitmapFromResource(cpBitmap& bitmap, Resource const& res) HRESULT GraphicsDevice::CreateBitmapFromResource(cpBitmap& bitmap, Resource const& res)
{ {
if (render_target == nullptr) if (render_target_ == nullptr)
{ {
return E_UNEXPECTED; return E_UNEXPECTED;
} }
@ -340,7 +340,7 @@ namespace easy2d
HRESULT hr = Factory::Instance()->CreateBitmapFromResource( HRESULT hr = Factory::Instance()->CreateBitmapFromResource(
bitmap, bitmap,
render_target, render_target_,
res res
); );
@ -354,38 +354,38 @@ namespace easy2d
HRESULT GraphicsDevice::CreateBitmapRenderTarget(cpBitmapRenderTarget & brt) HRESULT GraphicsDevice::CreateBitmapRenderTarget(cpBitmapRenderTarget & brt)
{ {
if (!render_target) if (!render_target_)
return E_UNEXPECTED; return E_UNEXPECTED;
brt = nullptr; brt = nullptr;
return render_target->CreateCompatibleRenderTarget(&brt); return render_target_->CreateCompatibleRenderTarget(&brt);
} }
HRESULT GraphicsDevice::Resize(UINT32 width, UINT32 height) HRESULT GraphicsDevice::Resize(UINT32 width, UINT32 height)
{ {
if (!render_target) if (!render_target_)
return E_UNEXPECTED; return E_UNEXPECTED;
render_target->Resize(D2D1::SizeU(width, height)); render_target_->Resize(D2D1::SizeU(width, height));
return S_OK; return S_OK;
} }
HRESULT GraphicsDevice::SetTransform(const math::Matrix & matrix) HRESULT GraphicsDevice::SetTransform(const math::Matrix & matrix)
{ {
if (!render_target) if (!render_target_)
return E_UNEXPECTED; return E_UNEXPECTED;
render_target->SetTransform(ConvertToD2DMatrix(matrix)); render_target_->SetTransform(ConvertToD2DMatrix(matrix));
return S_OK; return S_OK;
} }
HRESULT GraphicsDevice::SetOpacity(float opacity) HRESULT GraphicsDevice::SetOpacity(float opacity)
{ {
if (!render_target) if (!render_target_)
return E_UNEXPECTED; return E_UNEXPECTED;
opacity_ = opacity; opacity_ = opacity;
solid_brush->SetOpacity(opacity); solid_brush_->SetOpacity(opacity);
return S_OK; return S_OK;
} }
@ -397,11 +397,11 @@ namespace easy2d
StrokeStyle outline_stroke StrokeStyle outline_stroke
) )
{ {
if (!text_renderer) if (!text_renderer_)
return E_UNEXPECTED; return E_UNEXPECTED;
auto stroke_style = Factory::Instance()->GetStrokeStyle(outline_stroke); auto stroke_style = Factory::Instance()->GetStrokeStyle(outline_stroke);
text_renderer->SetTextStyle( text_renderer_->SetTextStyle(
color, color,
has_outline, has_outline,
outline_color, outline_color,
@ -411,14 +411,56 @@ namespace easy2d
return S_OK; return S_OK;
} }
void GraphicsDevice::SetBackgroundColor(const Color& color) void GraphicsDevice::SetClearColor(const Color& color)
{ {
clear_color_ = color; clear_color_ = color;
} }
void GraphicsDevice::CreateDeviceResources(HWND hwnd) HRESULT GraphicsDevice::SetAntialiasMode(bool enabled)
{ {
if (!render_target) if (!render_target_)
return E_UNEXPECTED;
render_target_->SetAntialiasMode(
enabled ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED
);
antialias_ = enabled;
return S_OK;
}
HRESULT GraphicsDevice::SetTextAntialiasMode(TextAntialias mode)
{
if (!render_target_)
return E_UNEXPECTED;
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);
return S_OK;
}
HRESULT GraphicsDevice::CreateResources(HWND hwnd)
{
HRESULT hr = S_OK;
if (!render_target_)
{ {
RECT rc; RECT rc;
::GetClientRect(hwnd, &rc); ::GetClientRect(hwnd, &rc);
@ -428,66 +470,51 @@ namespace easy2d
rc.bottom - rc.top rc.bottom - rc.top
); );
// 创建设备相关资源。这些资源应在 Direct2D 设备消失时重建 hr = Factory::Instance()->CreateHwndRenderTarget(
// 创建一个 Direct2D 渲染目标 render_target_,
ThrowIfFailed(
Factory::Instance()->CreateHwndRenderTarget(
render_target,
D2D1::RenderTargetProperties(), D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties( D2D1::HwndRenderTargetProperties(
hwnd, hwnd,
size, size,
options_.vsync ? D2D1_PRESENT_OPTIONS_NONE : D2D1_PRESENT_OPTIONS_IMMEDIATELY vsync_enabled_ ? D2D1_PRESENT_OPTIONS_NONE : D2D1_PRESENT_OPTIONS_IMMEDIATELY
)
) )
); );
render_target->SetAntialiasMode( if (SUCCEEDED(hr))
options_.antialias ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED
);
D2D1_TEXT_ANTIALIAS_MODE mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
switch (options_.text_antialias)
{ {
case TextAntialias::Default: SetAntialiasMode(antialias_);
mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; SetTextAntialiasMode(text_antialias_);
break;
case TextAntialias::ClearType:
mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
break;
case TextAntialias::GrayScale:
mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
break;
case TextAntialias::None:
mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
break;
default:
break;
}
render_target->SetTextAntialiasMode(mode);
} }
if (!solid_brush) if (SUCCEEDED(hr))
{ {
ThrowIfFailed( hr = render_target_->CreateSolidColorBrush(
render_target->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::White), D2D1::ColorF(D2D1::ColorF::White),
&solid_brush &solid_brush_
)
); );
} }
if (!text_renderer) if (SUCCEEDED(hr))
{ {
ThrowIfFailed( hr = Factory::Instance()->CreateTextRenderer(
Factory::Instance()->CreateTextRenderer( text_renderer_,
text_renderer, render_target_,
render_target, solid_brush_
solid_brush
)
); );
} }
} }
return hr;
}
void GraphicsDevice::DiscardResources()
{
// FIXME! 应通知 Game 类销毁所有节点的 device resources
fps_text_format_ = nullptr;
fps_text_layout_ = nullptr;
text_renderer_ = nullptr;
solid_brush_ = nullptr;
render_target_ = nullptr;
}
} }
} }

View File

@ -37,20 +37,6 @@ namespace easy2d
None // 不启用抗锯齿 None // 不启用抗锯齿
}; };
// 图形渲染选项
struct GraphicsOptions
{
bool vsync; // 垂直同步
bool antialias; // 抗锯齿
TextAntialias text_antialias; // 文字抗锯齿模式
GraphicsOptions()
: vsync(true)
, antialias(true)
, text_antialias(TextAntialias::ClearType)
{}
};
namespace devices namespace devices
{ {
class GraphicsDevice class GraphicsDevice
@ -59,20 +45,34 @@ namespace easy2d
E2D_DECLARE_SINGLETON(GraphicsDevice); E2D_DECLARE_SINGLETON(GraphicsDevice);
public: public:
void Init(HWND hwnd, GraphicsOptions options, bool debug); HRESULT Init(HWND hwnd, bool vsync, bool debug);
// 开始渲染 // 开始渲染
void BeginDraw(HWND hwnd); HRESULT BeginDraw(HWND hwnd);
// 结束渲染 // 结束渲染
void EndDraw(); HRESULT EndDraw();
// 设置背景 // 设置清空屏幕的颜
void SetBackgroundColor( void SetClearColor(
const Color& color const Color& color
); );
void CreateDeviceResources(HWND hwnd); // 设置抗锯齿模式
HRESULT SetAntialiasMode(
bool enabled
);
// 设置文字抗锯齿模式
HRESULT SetTextAntialiasMode(
TextAntialias mode
);
HRESULT CreateResources(
HWND hwnd
);
void DiscardResources();
HRESULT CreateLayer( HRESULT CreateLayer(
cpLayer& layer cpLayer& layer
@ -167,13 +167,14 @@ namespace easy2d
~GraphicsDevice(); ~GraphicsDevice();
protected: protected:
bool initialized_;
bool window_occluded_; bool window_occluded_;
bool vsync_enabled_;
bool antialias_;
TextAntialias text_antialias_;
float opacity_; float opacity_;
GraphicsOptions options_; cpTextRenderer text_renderer_;
cpTextRenderer text_renderer; cpSolidColorBrush solid_brush_;
cpSolidColorBrush solid_brush; cpHwndRenderTarget render_target_;
cpHwndRenderTarget render_target;
D2D1_COLOR_F clear_color_; D2D1_COLOR_F clear_color_;
cpTextFormat fps_text_format_; cpTextFormat fps_text_format_;
cpTextLayout fps_text_layout_; cpTextLayout fps_text_layout_;

View File

@ -39,7 +39,6 @@ namespace easy2d
: handle(nullptr) : handle(nullptr)
, scale_x(1.f) , scale_x(1.f)
, scale_y(1.f) , scale_y(1.f)
, initialized_(false)
{ {
} }
@ -48,11 +47,8 @@ namespace easy2d
E2D_LOG("Destroying window"); E2D_LOG("Destroying window");
} }
void WindowImpl::Init(String title, int width, int height, LPCWSTR icon, WNDPROC proc, bool debug) HRESULT WindowImpl::Init(String title, int width, int height, LPCWSTR icon, WNDPROC proc, bool debug)
{ {
if (initialized_)
return;
E2D_LOG("Creating window"); E2D_LOG("Creating window");
HINSTANCE hinstance = GetModuleHandle(nullptr); HINSTANCE hinstance = GetModuleHandle(nullptr);
@ -85,10 +81,8 @@ namespace easy2d
GetContentScale(&scale_x, &scale_y); GetContentScale(&scale_x, &scale_y);
// 计算窗口大小
Rect client_rect = LocateWindow(width, height, scale_x, scale_y);
// 创建窗口 Rect client_rect = LocateWindow(width, height, scale_x, scale_y);
handle = ::CreateWindowEx( handle = ::CreateWindowEx(
NULL, NULL,
REGISTER_CLASS, REGISTER_CLASS,
@ -107,13 +101,9 @@ namespace easy2d
if (handle == nullptr) if (handle == nullptr)
{ {
::UnregisterClass(REGISTER_CLASS, hinstance); ::UnregisterClass(REGISTER_CLASS, hinstance);
return HRESULT_FROM_WIN32(GetLastError());
const char* err = "Create window failed!";
logs::Errorln(HRESULT_FROM_WIN32(GetLastError()), err);
throw std::runtime_error(err);
} }
return S_OK;
initialized_ = true;
} }
String WindowImpl::GetTitle() const String WindowImpl::GetTitle() const

View File

@ -30,7 +30,7 @@ namespace easy2d
E2D_DECLARE_SINGLETON(WindowImpl); E2D_DECLARE_SINGLETON(WindowImpl);
public: public:
void Init( HRESULT Init(
String title, String title,
int width, int width,
int height, int height,
@ -72,7 +72,6 @@ namespace easy2d
~WindowImpl(); ~WindowImpl();
private: private:
bool initialized_;
HWND handle; HWND handle;
float scale_x; float scale_x;
float scale_y; float scale_y;

View File

@ -220,31 +220,6 @@ namespace easy2d
return Node::Dispatch(e, handled); return Node::Dispatch(e, handled);
} }
void Button::Visit()
{
Node::Visit();
if (IsVisible() &&
!enabled_ &&
normal_ &&
normal_->ContainsPoint(devices::Input::Instance()->GetMousePos()))
{
HCURSOR hcursor = ::LoadCursor(nullptr, IDC_NO);
if (hcursor)
{
::SetCursor(hcursor);
}
}
else if (status_ == Status::Mouseover || status_ == Status::Selected)
{
HCURSOR hcursor = ::LoadCursor(nullptr, IDC_HAND);
if (hcursor)
{
::SetCursor(hcursor);
}
}
}
void Button::SetStatus(Status status) void Button::SetStatus(Status status)
{ {
if (status_ != status) if (status_ != status)

View File

@ -120,9 +120,6 @@ namespace easy2d
bool handled bool handled
) override; ) override;
// 遍历节点
virtual void Visit() override;
private: private:
spNode normal_; spNode normal_;
spNode mouseover_; spNode mouseover_;