update:modules

This commit is contained in:
Haibo 2018-09-30 14:54:43 +08:00
parent 190a04a24f
commit 9039dff8d3
19 changed files with 649 additions and 832 deletions

View File

@ -8,7 +8,7 @@ namespace e2d
{ {
// 窗 // 窗
class Window class Window
{ {
public: public:
@ -31,123 +31,36 @@ namespace e2d
}; };
public: public:
// 获取窗体实例
static Window * GetInstance();
// 销毁窗体实例
static void DestroyInstance();
// 获取屏幕大小
static Size GetScreenSize();
// 获取窗体标题
const String& GetTitle() const;
// 获取窗体宽度
int GetWidth() const;
// 获取窗体高度
int GetHeight() const;
// 获取窗体大小
Size GetSize() const;
// 获取窗口 DPI
float GetDpi() const;
// 获取窗口句柄
HWND GetHWnd();
// 修改窗体大小
void SetSize(
int width, /* 窗体宽度 */
int height /* 窗体高度 */
);
// 设置窗体标题
void SetTitle(
const String& title /* 窗体标题 */
);
// 设置窗体图标
void SetIcon(
int resource_id /* 图标资源 ID */
);
// 设置鼠标指针样式 // 设置鼠标指针样式
void SetCursor( static void SetCursor(
Cursor cursor Cursor cursor
); );
// 打开或隐藏控制台 // 打开或隐藏控制台
void SetConsoleEnabled( static void ShowConsole(
bool enabled bool enabled
); );
// 是否允许响应输入法
void SetTypewritingEnabled(
bool enabled
);
// 检测窗口是否唯一
// 返回值:返回 false 说明游戏已经正在进行,可以防止用户同时打开多个游戏窗口
bool CheckUnique();
// 弹出窗口 // 弹出窗口
// 返回值:当窗口包含取消按钮时,返回值表示用户是否点击确认按钮 // 返回值:当窗口包含取消按钮时,返回值表示用户是否点击确认按钮
bool Popup( static bool Popup(
const String& text, /* 窗口内容 */ const String& text, /* 窗口内容 */
const String& title, /* 窗口标题 */ const String& title, /* 窗口标题 */
PopupStyle style = PopupStyle::Info,/* 弹窗样式 */ PopupStyle style = PopupStyle::Info,/* 弹窗样式 */
bool has_cancel = false /* 包含取消按钮 */ bool has_cancel = false /* 包含取消按钮 */
); );
// 处理窗体消息 // 获取屏幕大小
void Poll(); static Size GetScreenSize();
private:
Window();
~Window();
E2D_DISABLE_COPY(Window);
// 根据客户区大小定位窗口
Rect Locate(
int width,
int height
);
// Win32 窗口消息回调程序
static LRESULT CALLBACK WndProc(
HWND hwnd,
UINT msg,
WPARAM w_param,
LPARAM l_param
);
private:
HWND hwnd_;
MSG msg_;
int width_;
int height_;
int icon_id_;
float dpi_;
String title_;
static Window * instance_;
}; };
// 渲染器 // 渲染器
class Renderer class Graphics
{ {
public: public:
// 获取渲染器实例 // 获取渲染器实例
static Renderer * GetInstance(); static Graphics * Get();
// 销毁实例
static void DestroyInstance();
// 获取 ID2D1Factory 对象 // 获取 ID2D1Factory 对象
static ID2D1Factory * GetFactory(); static ID2D1Factory * GetFactory();
@ -176,14 +89,6 @@ namespace e2d
// 获取 ID2D1SolidColorBrush 对象 // 获取 ID2D1SolidColorBrush 对象
ID2D1SolidColorBrush * GetSolidBrush(); ID2D1SolidColorBrush * GetSolidBrush();
// 获取背景色
Color GetBackgroundColor();
// 修改背景色
void SetBackgroundColor(
const Color& color
);
// 显示或隐藏 FPS // 显示或隐藏 FPS
// 默认:隐藏 // 默认:隐藏
void ShowFps( void ShowFps(
@ -196,12 +101,15 @@ namespace e2d
// 结束渲染 // 结束渲染
void EndDraw(); void EndDraw();
// 渲染调试信息
void DrawDebugInfo();
protected: protected:
Renderer(); Graphics();
~Renderer(); ~Graphics();
E2D_DISABLE_COPY(Renderer); E2D_DISABLE_COPY(Graphics);
protected: protected:
bool show_fps_; bool show_fps_;
@ -220,7 +128,7 @@ namespace e2d
static ID2D1StrokeStyle* miter_stroke_style_; static ID2D1StrokeStyle* miter_stroke_style_;
static ID2D1StrokeStyle* bevel_stroke_style_; static ID2D1StrokeStyle* bevel_stroke_style_;
static ID2D1StrokeStyle* round_stroke_style_; static ID2D1StrokeStyle* round_stroke_style_;
static Renderer * instance_; static Graphics * instance_;
}; };
@ -288,16 +196,13 @@ namespace e2d
{ {
public: public:
// 获取音频设备实例 // 获取音频设备实例
static Audio * GetInstance(); static Audio * Get();
// 销毁实例
static void DestroyInstance();
// 获取 XAudio2 实例对象 // 获取 XAudio2 实例对象
IXAudio2 * GetXAudio2(); IXAudio2 * GetXAudio2() const;
// 获取 MasteringVoice 实例对象 // 获取 MasteringVoice 实例对象
IXAudio2MasteringVoice* GetMasteringVoice(); IXAudio2MasteringVoice* GetMasteringVoice() const;
protected: protected:
Audio(); Audio();
@ -309,35 +214,78 @@ namespace e2d
protected: protected:
IXAudio2 * x_audio2_; IXAudio2 * x_audio2_;
IXAudio2MasteringVoice* mastering_voice_; IXAudio2MasteringVoice* mastering_voice_;
static Audio * instance_;
}; };
// 游戏 // 选项
struct Option
{
String title; // 窗口标题
int width; // 窗口宽度
int height; // 窗口高度
int icon; // 窗口图标
Color background_color; // 背景色
bool debug_mode; // Debug 模式
Option()
: title(L"Easy2D Game")
, width(640)
, height(480)
, icon(0)
, background_color(Color::Black)
, debug_mode(false)
{
}
};
// 游戏控制器
class Game class Game
{ {
public: public:
// 获取 Game 实例 static Game * New(
static Game * GetInstance(); const Option& option
);
// 销毁实例 // 获取控制器
static void DestroyInstance(); static Game * Get();
// 启动游戏 // 启动游戏
void Start(); void Run();
// 暂停游戏
void Pause();
// 继续游戏
void Resume();
// 结束游戏 // 结束游戏
void Quit(); void Quit();
// 游戏是否暂停 // 获取窗体标题
bool IsPaused(); const String& GetTitle() const;
// 获取窗体宽度
int GetWidth() const;
// 获取窗体高度
int GetHeight() const;
// 获取窗体大小
Size GetSize() const;
// 获取窗口句柄
HWND GetHWnd() const;
// 修改窗体大小
void SetSize(
int width, /* 窗体宽度 */
int height /* 窗体高度 */
);
// 设置窗体标题
void SetTitle(
const String& title /* 窗体标题 */
);
// 设置窗体图标
void SetIcon(
int resource_id /* 图标资源 ID */
);
// 切换场景 // 切换场景
void EnterScene( void EnterScene(
@ -364,12 +312,34 @@ namespace e2d
E2D_DISABLE_COPY(Game); E2D_DISABLE_COPY(Game);
// 初始化
void Init();
// 根据客户区大小定位窗口
Rect Locate(
int width,
int height
);
// Win32 窗口消息回调程序
static LRESULT CALLBACK WndProc(
HWND hwnd,
UINT msg,
WPARAM w_param,
LPARAM l_param
);
private: private:
bool quit_; HWND hwnd_;
bool paused_; String title_;
Scene* curr_scene_; int width_;
Scene* next_scene_; int height_;
Transition* transition_; int icon_;
bool debug_mode_;
bool quit_;
Scene* curr_scene_;
Scene* next_scene_;
Transition* transition_;
static Game * instance_; static Game * instance_;
}; };

View File

@ -144,18 +144,6 @@ namespace e2d
// 获取根节点 // 获取根节点
Node* GetRoot() const; Node* GetRoot() const;
// 显示或隐藏节点边缘
// 默认:隐藏
void ShowBorder(
bool visible
);
// 显示或隐藏碰撞体
// 默认:隐藏
void ShowCollider(
bool visible
);
// 渲染场景 // 渲染场景
void Draw(); void Draw();
@ -182,8 +170,6 @@ namespace e2d
protected: protected:
Node* root_; Node* root_;
bool border_visible_;
bool collider_visible_;
D2D1::Matrix3x2F transform_; D2D1::Matrix3x2F transform_;
}; };

View File

@ -62,13 +62,13 @@ STDMETHODIMP_(void) E2DTextRenderer::SetTextStyle(
switch (outlineJoin) switch (outlineJoin)
{ {
case D2D1_LINE_JOIN_MITER: case D2D1_LINE_JOIN_MITER:
pCurrStrokeStyle_ = Renderer::GetMiterStrokeStyle(); pCurrStrokeStyle_ = Graphics::GetMiterStrokeStyle();
break; break;
case D2D1_LINE_JOIN_BEVEL: case D2D1_LINE_JOIN_BEVEL:
pCurrStrokeStyle_ = Renderer::GetBevelStrokeStyle(); pCurrStrokeStyle_ = Graphics::GetBevelStrokeStyle();
break; break;
case D2D1_LINE_JOIN_ROUND: case D2D1_LINE_JOIN_ROUND:
pCurrStrokeStyle_ = Renderer::GetRoundStrokeStyle(); pCurrStrokeStyle_ = Graphics::GetRoundStrokeStyle();
break; break;
default: default:
pCurrStrokeStyle_ = nullptr; pCurrStrokeStyle_ = nullptr;

View File

@ -36,10 +36,10 @@ void e2d::CollisionManager::RemoveCollider(Collider * collider)
void e2d::CollisionManager::UpdateCollider(Collider* active) void e2d::CollisionManager::UpdateCollider(Collider* active)
{ {
if (!collision_enabled_ || if (!collision_enabled_ ||
Game::GetInstance()->IsTransitioning()) Game::Get()->IsTransitioning())
return; return;
auto currScene = Game::GetInstance()->GetCurrentScene(); auto currScene = Game::Get()->GetCurrentScene();
if (active->GetNode()->GetParentScene() != currScene) if (active->GetNode()->GetParentScene() != currScene)
return; return;

View File

@ -1,24 +1,10 @@
#include "..\e2dmodule.h" #include "..\e2dmodule.h"
e2d::Audio * e2d::Audio::instance_ = nullptr; e2d::Audio * e2d::Audio::Get()
e2d::Audio * e2d::Audio::GetInstance()
{ {
if (!instance_) static Audio audio;
{ return &audio;
instance_ = new (std::nothrow) Audio;
}
return instance_;
}
void e2d::Audio::DestroyInstance()
{
if (instance_)
{
delete instance_;
instance_ = nullptr;
}
} }
e2d::Audio::Audio() e2d::Audio::Audio()
@ -49,12 +35,12 @@ e2d::Audio::~Audio()
::CoUninitialize(); ::CoUninitialize();
} }
IXAudio2 * e2d::Audio::GetXAudio2() IXAudio2 * e2d::Audio::GetXAudio2() const
{ {
return x_audio2_; return x_audio2_;
} }
IXAudio2MasteringVoice * e2d::Audio::GetMasteringVoice() IXAudio2MasteringVoice * e2d::Audio::GetMasteringVoice() const
{ {
return mastering_voice_; return mastering_voice_;
} }

View File

@ -14,7 +14,7 @@ e2d::GC::~GC()
Player::DestroyInstance(); Player::DestroyInstance();
Audio::DestroyInstance(); Audio::DestroyInstance();
Renderer::DestroyInstance(); Graphics::DestroyInstance();
Input::DestroyInstance(); Input::DestroyInstance();
Window::DestroyInstance(); Window::DestroyInstance();
Game::DestroyInstance(); Game::DestroyInstance();

View File

@ -3,29 +3,18 @@
#include "..\e2dtransition.h" #include "..\e2dtransition.h"
#include "..\e2dmanager.h" #include "..\e2dmanager.h"
#include <thread> #include <thread>
#include <imm.h>
#pragma comment (lib ,"imm32.lib")
#define WINDOW_STYLE WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME
#define REGISTER_CLASS L"Easy2DApp"
e2d::Game * e2d::Game::instance_ = nullptr; e2d::Game * e2d::Game::instance_ = nullptr;
e2d::Game * e2d::Game::GetInstance()
{
if (!instance_)
instance_ = new (std::nothrow) Game;
return instance_;
}
void e2d::Game::DestroyInstance()
{
if (instance_)
{
delete instance_;
instance_ = nullptr;
}
}
e2d::Game::Game() e2d::Game::Game()
: quit_(true) : hwnd_(nullptr)
, paused_(false) , quit_(true)
, curr_scene_(nullptr) , curr_scene_(nullptr)
, next_scene_(nullptr) , next_scene_(nullptr)
, transition_(nullptr) , transition_(nullptr)
@ -39,24 +28,47 @@ e2d::Game::~Game()
SafeRelease(curr_scene_); SafeRelease(curr_scene_);
SafeRelease(next_scene_); SafeRelease(next_scene_);
if (hwnd_)
{
::DestroyWindow(hwnd_);
}
::CoUninitialize(); ::CoUninitialize();
} }
void e2d::Game::Start() e2d::Game * e2d::Game::New(const Option & option)
{
static Game game;
game.title_ = option.title;
game.width_ = option.width;
game.height_ = option.height;
game.icon_ = option.icon;
game.debug_mode_ = option.debug_mode;
game.Init();
instance_ = &game;
return instance_;
}
e2d::Game * e2d::Game::Get()
{
return instance_;
}
void e2d::Game::Run()
{ {
quit_ = false; quit_ = false;
auto window = Window::GetInstance();
auto input = Input::GetInstance(); auto input = Input::GetInstance();
auto renderer = Renderer::GetInstance(); auto graphics = Graphics::Get();
const int minInterval = 5; const int min_interval = 5;
Time last = Time::Now(); Time last = Time::Now();
HWND hwnd = window->GetHWnd(); MSG msg = { 0 };
::ShowWindow(hwnd, SW_SHOWNORMAL); ::ShowWindow(hwnd_, SW_SHOWNORMAL);
::UpdateWindow(hwnd); ::UpdateWindow(hwnd_);
window->Poll();
UpdateScene(); UpdateScene();
while (!quit_) while (!quit_)
@ -64,7 +76,7 @@ void e2d::Game::Start()
auto now = Time::Now(); auto now = Time::Now();
auto dur = now - last; auto dur = now - last;
if (dur.Milliseconds() > minInterval) if (dur.Milliseconds() > min_interval)
{ {
last = now; last = now;
input->Update(); input->Update();
@ -72,14 +84,18 @@ void e2d::Game::Start()
UpdateScene(); UpdateScene();
DrawScene(); DrawScene();
window->Poll(); while (::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
} }
else else
{ {
// ID2D1HwndRenderTarget 开启了垂直同步,在渲染时会等待显示器刷新, // ID2D1HwndRenderTarget 开启了垂直同步,在渲染时会等待显示器刷新,
// 它起到了非常稳定的延时作用,所以大部分时候不需要手动挂起线程进行延时。 // 它起到了非常稳定的延时作用,所以大部分时候不需要手动挂起线程进行延时。
// 下面的代码仅在一些情况下(例如窗口最小化时)挂起线程,防止占用过高 CPU 。 // 下面的代码仅在一些情况下(例如窗口最小化时)挂起线程,防止占用过高 CPU 。
int wait = minInterval - dur.Milliseconds(); int wait = min_interval - dur.Milliseconds();
if (wait > 1) if (wait > 1)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(wait)); std::this_thread::sleep_for(std::chrono::milliseconds(wait));
@ -88,28 +104,6 @@ void e2d::Game::Start()
} }
} }
void e2d::Game::Pause()
{
paused_ = true;
}
void e2d::Game::Resume()
{
if (paused_ && !quit_)
{
if (curr_scene_)
{
curr_scene_->GetRoot()->UpdateTime();
}
}
paused_ = false;
}
bool e2d::Game::IsPaused()
{
return paused_;
}
void e2d::Game::Quit() void e2d::Game::Quit()
{ {
quit_ = true; quit_ = true;
@ -162,9 +156,6 @@ bool e2d::Game::IsTransitioning() const
void e2d::Game::UpdateScene() void e2d::Game::UpdateScene()
{ {
if (paused_)
return;
if (transition_) if (transition_)
{ {
transition_->Update(); transition_->Update();
@ -197,16 +188,360 @@ void e2d::Game::UpdateScene()
void e2d::Game::DrawScene() void e2d::Game::DrawScene()
{ {
Renderer::GetInstance()->BeginDraw(); auto graphics = Graphics::Get();
graphics->BeginDraw();
if (transition_)
{ {
if (transition_) transition_->Draw();
}
else if (curr_scene_)
{
curr_scene_->Draw();
}
// TODO @Nomango if debug_mode_
/*
{
graphics->GetRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity());
graphics->GetSolidBrush()->SetOpacity(1.f);
root_->DrawBorder();
}
{
graphics->GetRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity());
root_->DrawCollider();
}
*/
if (debug_mode_)
{
graphics->DrawDebugInfo();
}
graphics->EndDraw();
}
void e2d::Game::Init()
{
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpszClassName = REGISTER_CLASS;
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcex.lpfnWndProc = Game::WndProc;
wcex.hIcon = nullptr;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = HINST_THISCOMPONENT;
wcex.hbrBackground = nullptr;
wcex.lpszMenuName = nullptr;
wcex.hCursor = ::LoadCursor(nullptr, IDC_ARROW);
if (icon_ != 0)
{
wcex.hIcon = (HICON)::LoadImage(
HINST_THISCOMPONENT,
MAKEINTRESOURCE(icon_),
IMAGE_ICON,
0,
0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE
);
}
// 注册窗口类
RegisterClassEx(&wcex);
// 计算窗口大小
Rect client_rect = Locate(width_, height_);
// 创建窗口
hwnd_ = ::CreateWindowEx(
NULL,
REGISTER_CLASS,
(LPCTSTR)title_,
WINDOW_STYLE,
int(client_rect.origin.x),
int(client_rect.origin.y),
int(client_rect.size.width),
int(client_rect.size.height),
nullptr,
nullptr,
HINST_THISCOMPONENT,
this
);
if (hwnd_)
{
// 禁用输入法
::ImmAssociateContext(hwnd_, nullptr);
// 禁用控制台关闭按钮
HWND console_hwnd = ::GetConsoleWindow();
if (console_hwnd)
{ {
transition_->Draw(); HMENU hmenu = ::GetSystemMenu(console_hwnd, FALSE);
} ::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND);
else if (curr_scene_)
{
curr_scene_->Draw();
} }
} }
Renderer::GetInstance()->EndDraw(); else
{
::UnregisterClass(REGISTER_CLASS, HINST_THISCOMPONENT);
throw RuntimeException("Create window failed");
}
}
e2d::Rect e2d::Game::Locate(int width, int height)
{
int max_width = ::GetSystemMetrics(SM_CXSCREEN);
int max_height = ::GetSystemMetrics(SM_CYSCREEN);
float dpi_x, dpi_y;
Graphics::GetFactory()->GetDesktopDpi(&dpi_x, &dpi_y);
RECT rect = { 0, 0, LONG(ceil(width * dpi_x / 96.f)), LONG(ceil(height * dpi_y / 96.f)) };
// 计算合适的窗口大小
::AdjustWindowRectEx(&rect, WINDOW_STYLE, FALSE, NULL);
width = static_cast<int>(rect.right - rect.left);
height = static_cast<int>(rect.bottom - rect.top);
// 当输入的窗口大小比分辨率大时,给出警告
WARN_IF(max_width < width || max_height < height, "The window Is larger than screen!");
width = std::min(width, max_width);
height = std::min(height, max_height);
Rect client_rect(
static_cast<float>((max_width - width) / 2),
static_cast<float>((max_height - height) / 2),
static_cast<float>(width),
static_cast<float>(height)
);
return std::move(client_rect);
}
int e2d::Game::GetWidth() const
{
return width_;
}
int e2d::Game::GetHeight() const
{
return height_;
}
e2d::Size e2d::Game::GetSize() const
{
e2d::Size size(
static_cast<float>(width_),
static_cast<float>(height_)
);
return std::move(size);
}
HWND e2d::Game::GetHWnd() const
{
return hwnd_;
}
const e2d::String& e2d::Game::GetTitle() const
{
return title_;
}
void e2d::Game::SetSize(int width, int height)
{
if (width_ == width && height_ == height)
return;
width_ = width;
height_ = height;
Rect rect = Locate(width, height);
::MoveWindow(
hwnd_,
int(rect.origin.x),
int(rect.origin.y),
int(rect.size.width),
int(rect.size.height),
TRUE
);
}
void e2d::Game::SetTitle(const String& title)
{
title_ = title;
::SetWindowText(hwnd_, (LPCWSTR)title);
}
void e2d::Game::SetIcon(int resource_id)
{
icon_ = resource_id;
HICON icon = (HICON)::LoadImage(
HINST_THISCOMPONENT,
MAKEINTRESOURCE(resource_id),
IMAGE_ICON,
0,
0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE
);
::SendMessage(hwnd_, WM_SETICON, ICON_BIG, (LPARAM)icon);
::SendMessage(hwnd_, WM_SETICON, ICON_SMALL, (LPARAM)icon);
}
LRESULT e2d::Game::WndProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param)
{
LRESULT result = 0;
if (msg == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)l_param;
Game * game = (Game *)pcs->lpCreateParams;
::SetWindowLongPtrW(
hwnd,
GWLP_USERDATA,
PtrToUlong(game)
);
result = 1;
}
else
{
bool has_handled = false;
Game * game = reinterpret_cast<Game*>(
static_cast<LONG_PTR>(
::GetWindowLongPtrW(hwnd, GWLP_USERDATA)
)
);
switch (msg)
{
// 处理鼠标消息
case WM_LBUTTONUP:
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_MBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK:
case WM_RBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
case WM_MOUSEMOVE:
case WM_MOUSEWHEEL:
{
if (game->IsTransitioning())
break;
auto curr_scene = game->GetCurrentScene();
if (curr_scene)
{
curr_scene->Dispatch(MouseEvent(msg, w_param, l_param));
}
}
result = 0;
has_handled = true;
break;
// 处理按键消息
case WM_KEYDOWN:
case WM_KEYUP:
{
if (game->IsTransitioning())
break;
auto curr_scene = game->GetCurrentScene();
if (curr_scene)
{
curr_scene->Dispatch(KeyEvent(msg, w_param, l_param));
}
}
result = 0;
has_handled = true;
break;
// 处理窗口大小变化消息
case WM_SIZE:
{
UINT width = LOWORD(l_param);
UINT height = HIWORD(l_param);
if (w_param == SIZE_RESTORED)
{
float dpi_x, dpi_y;
Graphics::GetFactory()->GetDesktopDpi(&dpi_x, &dpi_y);
game->width_ = static_cast<int>(width * 96.f / dpi_x);
game->height_ = static_cast<int>(height * 96.f / dpi_y);
}
// 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染
// 目标的大小。它可能会调用失败,但是这里可以忽略有可能的
// 错误,因为这个错误将在下一次调用 EndDraw 时产生
auto render_target = Graphics::Get()->GetRenderTarget();
if (render_target)
{
render_target->Resize(D2D1::SizeU(width, height));
}
}
break;
// 处理窗口标题变化消息
case WM_SETTEXT:
{
game->title_ = (const wchar_t*)l_param;
}
break;
// 处理分辨率变化消息
case WM_DISPLAYCHANGE:
{
// 重绘客户区
::InvalidateRect(hwnd, nullptr, FALSE);
}
result = 0;
has_handled = true;
break;
// 重绘窗口
case WM_PAINT:
{
game->DrawScene();
::ValidateRect(hwnd, nullptr);
}
result = 0;
has_handled = true;
break;
// 窗口关闭消息
case WM_CLOSE:
{
auto currScene = game->GetCurrentScene();
if (!currScene || currScene->OnCloseWindow())
{
game->Quit();
}
}
result = 0;
has_handled = true;
break;
// 窗口销毁消息
case WM_DESTROY:
{
::PostQuitMessage(0);
}
result = 1;
has_handled = true;
break;
}
if (!has_handled)
{
result = ::DefWindowProc(hwnd, msg, w_param, l_param);
}
}
return result;
} }

View File

@ -3,24 +3,24 @@
#include "..\e2dobject.h" #include "..\e2dobject.h"
e2d::Renderer* e2d::Renderer::instance_ = nullptr; e2d::Graphics* e2d::Graphics::instance_ = nullptr;
ID2D1Factory* e2d::Renderer::factory_ = nullptr; ID2D1Factory* e2d::Graphics::factory_ = nullptr;
IWICImagingFactory* e2d::Renderer::imaging_factory_ = nullptr; IWICImagingFactory* e2d::Graphics::imaging_factory_ = nullptr;
IDWriteFactory* e2d::Renderer::write_factory_ = nullptr; IDWriteFactory* e2d::Graphics::write_factory_ = nullptr;
ID2D1StrokeStyle* e2d::Renderer::miter_stroke_style_ = nullptr; ID2D1StrokeStyle* e2d::Graphics::miter_stroke_style_ = nullptr;
ID2D1StrokeStyle* e2d::Renderer::bevel_stroke_style_ = nullptr; ID2D1StrokeStyle* e2d::Graphics::bevel_stroke_style_ = nullptr;
ID2D1StrokeStyle* e2d::Renderer::round_stroke_style_ = nullptr; ID2D1StrokeStyle* e2d::Graphics::round_stroke_style_ = nullptr;
e2d::Renderer * e2d::Renderer::GetInstance() e2d::Graphics * e2d::Graphics::GetInstance()
{ {
if (!instance_) if (!instance_)
{ {
instance_ = new (std::nothrow) Renderer; instance_ = new (std::nothrow) Graphics;
} }
return instance_; return instance_;
} }
void e2d::Renderer::DestroyInstance() void e2d::Graphics::DestroyInstance()
{ {
if (instance_) if (instance_)
{ {
@ -36,7 +36,7 @@ void e2d::Renderer::DestroyInstance()
} }
} }
e2d::Renderer::Renderer() e2d::Graphics::Graphics()
: show_fps_(false) : show_fps_(false)
, last_render_time_(Time::Now()) , last_render_time_(Time::Now())
, render_times_(0) , render_times_(0)
@ -50,7 +50,7 @@ e2d::Renderer::Renderer()
::CoInitialize(nullptr); ::CoInitialize(nullptr);
} }
e2d::Renderer::~Renderer() e2d::Graphics::~Graphics()
{ {
SafeRelease(fps_text_format_); SafeRelease(fps_text_format_);
SafeRelease(fps_text_layout_); SafeRelease(fps_text_layout_);
@ -61,7 +61,7 @@ e2d::Renderer::~Renderer()
::CoUninitialize(); ::CoUninitialize();
} }
void e2d::Renderer::BeginDraw() void e2d::Graphics::BeginDraw()
{ {
auto render_target = GetRenderTarget(); auto render_target = GetRenderTarget();
render_target->BeginDraw(); render_target->BeginDraw();
@ -69,71 +69,8 @@ void e2d::Renderer::BeginDraw()
render_target->Clear(clear_color_); render_target->Clear(clear_color_);
} }
void e2d::Renderer::EndDraw() void e2d::Graphics::EndDraw()
{ {
if (show_fps_)
{
int duration = (Time::Now() - last_render_time_).Milliseconds();
++render_times_;
if (duration >= 100)
{
String fpsText = String::Format(L"FPS: %.1f", (1000.f / duration * render_times_));
last_render_time_ = Time::Now();
render_times_ = 0;
if (!fps_text_format_)
{
ThrowIfFailed(
GetWriteFactory()->CreateTextFormat(
L"",
nullptr,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
20,
L"",
&fps_text_format_
)
);
ThrowIfFailed(
fps_text_format_->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP)
);
}
SafeRelease(fps_text_layout_);
ThrowIfFailed(
GetWriteFactory()->CreateTextLayout(
(const wchar_t *)fpsText,
(UINT32)fpsText.GetLength(),
fps_text_format_,
0,
0,
&fps_text_layout_
)
);
}
if (fps_text_layout_)
{
GetRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity());
GetSolidBrush()->SetOpacity(1.0f);
GetTextRenderer()->SetTextStyle(
D2D1::ColorF(D2D1::ColorF::White),
TRUE,
D2D1::ColorF(D2D1::ColorF::Black, 0.4f),
1.5f,
D2D1_LINE_JOIN_ROUND
);
ThrowIfFailed(
fps_text_layout_->Draw(nullptr, text_renderer_, 10, 0)
);
}
}
HRESULT hr = render_target_->EndDraw(); HRESULT hr = render_target_->EndDraw();
if (hr == D2DERR_RECREATE_TARGET) if (hr == D2DERR_RECREATE_TARGET)
@ -152,7 +89,70 @@ void e2d::Renderer::EndDraw()
ThrowIfFailed(hr); ThrowIfFailed(hr);
} }
e2d::E2DTextRenderer * e2d::Renderer::GetTextRenderer() void e2d::Graphics::DrawDebugInfo()
{
int duration = (Time::Now() - last_render_time_).Milliseconds();
++render_times_;
if (duration >= 100)
{
String fpsText = String::Format(L"FPS: %.1f", (1000.f / duration * render_times_));
last_render_time_ = Time::Now();
render_times_ = 0;
if (!fps_text_format_)
{
ThrowIfFailed(
GetWriteFactory()->CreateTextFormat(
L"",
nullptr,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
20,
L"",
&fps_text_format_
)
);
ThrowIfFailed(
fps_text_format_->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP)
);
}
SafeRelease(fps_text_layout_);
ThrowIfFailed(
GetWriteFactory()->CreateTextLayout(
(const wchar_t *)fpsText,
(UINT32)fpsText.GetLength(),
fps_text_format_,
0,
0,
&fps_text_layout_
)
);
}
if (fps_text_layout_)
{
GetRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity());
GetSolidBrush()->SetOpacity(1.0f);
GetTextRenderer()->SetTextStyle(
D2D1::ColorF(D2D1::ColorF::White),
TRUE,
D2D1::ColorF(D2D1::ColorF::Black, 0.4f),
1.5f,
D2D1_LINE_JOIN_ROUND
);
ThrowIfFailed(
fps_text_layout_->Draw(nullptr, text_renderer_, 10, 0)
);
}
}
e2d::E2DTextRenderer * e2d::Graphics::GetTextRenderer()
{ {
if (!text_renderer_) if (!text_renderer_)
{ {
@ -169,11 +169,11 @@ e2d::E2DTextRenderer * e2d::Renderer::GetTextRenderer()
return text_renderer_; return text_renderer_;
} }
ID2D1HwndRenderTarget * e2d::Renderer::GetRenderTarget() ID2D1HwndRenderTarget * e2d::Graphics::GetRenderTarget()
{ {
if (!render_target_) if (!render_target_)
{ {
HWND hwnd = Window::GetInstance()->GetHWnd(); HWND hwnd = Game::Get()->GetHWnd();
RECT rc; RECT rc;
GetClientRect(hwnd, &rc); GetClientRect(hwnd, &rc);
@ -199,7 +199,7 @@ ID2D1HwndRenderTarget * e2d::Renderer::GetRenderTarget()
return render_target_; return render_target_;
} }
ID2D1SolidColorBrush * e2d::Renderer::GetSolidBrush() ID2D1SolidColorBrush * e2d::Graphics::GetSolidBrush()
{ {
if (!solid_brush_) if (!solid_brush_)
{ {
@ -213,22 +213,12 @@ ID2D1SolidColorBrush * e2d::Renderer::GetSolidBrush()
return solid_brush_; return solid_brush_;
} }
e2d::Color e2d::Renderer::GetBackgroundColor() void e2d::Graphics::ShowFps(bool show)
{
return clear_color_;
}
void e2d::Renderer::SetBackgroundColor(const Color& color)
{
clear_color_ = (D2D1_COLOR_F)color;
}
void e2d::Renderer::ShowFps(bool show)
{ {
show_fps_ = show; show_fps_ = show;
} }
ID2D1Factory * e2d::Renderer::GetFactory() ID2D1Factory * e2d::Graphics::GetFactory()
{ {
if (!factory_) if (!factory_)
{ {
@ -246,7 +236,7 @@ ID2D1Factory * e2d::Renderer::GetFactory()
return factory_; return factory_;
} }
IWICImagingFactory * e2d::Renderer::GetImagingFactory() IWICImagingFactory * e2d::Graphics::GetImagingFactory()
{ {
if (!imaging_factory_) if (!imaging_factory_)
{ {
@ -267,7 +257,7 @@ IWICImagingFactory * e2d::Renderer::GetImagingFactory()
return imaging_factory_; return imaging_factory_;
} }
IDWriteFactory * e2d::Renderer::GetWriteFactory() IDWriteFactory * e2d::Graphics::GetWriteFactory()
{ {
if (!write_factory_) if (!write_factory_)
{ {
@ -286,7 +276,7 @@ IDWriteFactory * e2d::Renderer::GetWriteFactory()
return write_factory_; return write_factory_;
} }
ID2D1StrokeStyle * e2d::Renderer::GetMiterStrokeStyle() ID2D1StrokeStyle * e2d::Graphics::GetMiterStrokeStyle()
{ {
if (!miter_stroke_style_) if (!miter_stroke_style_)
{ {
@ -309,7 +299,7 @@ ID2D1StrokeStyle * e2d::Renderer::GetMiterStrokeStyle()
return miter_stroke_style_; return miter_stroke_style_;
} }
ID2D1StrokeStyle * e2d::Renderer::GetBevelStrokeStyle() ID2D1StrokeStyle * e2d::Graphics::GetBevelStrokeStyle()
{ {
if (!bevel_stroke_style_) if (!bevel_stroke_style_)
{ {
@ -332,7 +322,7 @@ ID2D1StrokeStyle * e2d::Renderer::GetBevelStrokeStyle()
return bevel_stroke_style_; return bevel_stroke_style_;
} }
ID2D1StrokeStyle * e2d::Renderer::GetRoundStrokeStyle() ID2D1StrokeStyle * e2d::Graphics::GetRoundStrokeStyle()
{ {
if (!round_stroke_style_) if (!round_stroke_style_)
{ {

View File

@ -1,30 +1,5 @@
#include "..\e2dmodule.h" #include "..\e2dmodule.h"
#include "..\e2dmanager.h"
#include "..\e2dobject.h"
#include <imm.h>
#pragma comment (lib ,"imm32.lib")
#define WINDOW_STYLE WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME
#define REGISTER_CLASS L"Easy2DApp"
e2d::Window * e2d::Window::instance_ = nullptr;
e2d::Window * e2d::Window::GetInstance()
{
if (!instance_)
instance_ = new (std::nothrow) Window;
return instance_;
}
void e2d::Window::DestroyInstance()
{
if (instance_)
{
delete instance_;
instance_ = nullptr;
}
}
e2d::Size e2d::Window::GetScreenSize() e2d::Size e2d::Window::GetScreenSize()
{ {
@ -37,229 +12,6 @@ e2d::Size e2d::Window::GetScreenSize()
return std::move(screen_size); return std::move(screen_size);
} }
e2d::Window::Window()
: hwnd_(nullptr)
, width_(640)
, height_(480)
, title_(L"Easy2D Game")
, icon_id_(0)
, dpi_(0.f)
{
::CoInitialize(nullptr);
// 获取系统 DPI
Renderer::GetFactory()->GetDesktopDpi(&dpi_, &dpi_);
}
e2d::Window::~Window()
{
if (::GetConsoleWindow())
::FreeConsole();
if (hwnd_)
::DestroyWindow(hwnd_);
::CoUninitialize();
}
bool e2d::Window::CheckUnique()
{
HANDLE mutex = ::CreateMutex(nullptr, TRUE, LPCWSTR(L"Easy2DApp-" + title_));
if (mutex == nullptr)
{
WARN("CreateMutex Failed!");
return false;
}
else if (::GetLastError() == ERROR_ALREADY_EXISTS)
{
::CloseHandle(mutex);
return false;
}
return true;
}
e2d::Rect e2d::Window::Locate(int width, int height)
{
Rect result;
RECT rect = { 0, 0, LONG(ceil(width * dpi_ / 96.f)), LONG(ceil(height * dpi_ / 96.f)) };
int max_width = ::GetSystemMetrics(SM_CXSCREEN);
int max_height = ::GetSystemMetrics(SM_CYSCREEN);
// 计算合适的窗口大小
::AdjustWindowRectEx(&rect, WINDOW_STYLE, FALSE, NULL);
width = static_cast<int>(rect.right - rect.left);
height = static_cast<int>(rect.bottom - rect.top);
// 当输入的窗口大小比分辨率大时,给出警告
WARN_IF(max_width < width || max_height < height, "The window Is larger than screen!");
width = std::min(width, max_width);
height = std::min(height, max_height);
float x = float((max_width - width) / 2), y = float((max_height - height) / 2);
return std::move(Rect(x, y, float(width), float(height)));
}
void e2d::Window::Poll()
{
while (::PeekMessage(&msg_, nullptr, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg_);
::DispatchMessage(&msg_);
}
}
int e2d::Window::GetWidth() const
{
return width_;
}
int e2d::Window::GetHeight() const
{
return height_;
}
e2d::Size e2d::Window::GetSize() const
{
e2d::Size size(
static_cast<float>(width_),
static_cast<float>(height_)
);
return std::move(size);
}
float e2d::Window::GetDpi() const
{
return dpi_;
}
const e2d::String& e2d::Window::GetTitle() const
{
return title_;
}
HWND e2d::Window::GetHWnd()
{
if (!hwnd_)
{
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpszClassName = REGISTER_CLASS;
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcex.lpfnWndProc = Window::WndProc;
wcex.hIcon = nullptr;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = HINST_THISCOMPONENT;
wcex.hbrBackground = nullptr;
wcex.lpszMenuName = nullptr;
wcex.hCursor = ::LoadCursor(nullptr, IDC_ARROW);
if (icon_id_ != 0)
{
wcex.hIcon = (HICON)::LoadImage(
HINST_THISCOMPONENT,
MAKEINTRESOURCE(icon_id_),
IMAGE_ICON,
0,
0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE
);
}
// 注册窗口类
RegisterClassEx(&wcex);
// 计算窗口大小
Rect clientRect = Locate(width_, height_);
// 创建窗口
hwnd_ = ::CreateWindowEx(
NULL,
REGISTER_CLASS,
(LPCTSTR)title_,
WINDOW_STYLE,
int(clientRect.origin.x),
int(clientRect.origin.y),
int(clientRect.size.width),
int(clientRect.size.height),
nullptr,
nullptr,
HINST_THISCOMPONENT,
this
);
if (hwnd_)
{
// 禁用输入法
SetTypewritingEnabled(false);
// 禁用控制台关闭按钮
HWND console_hwnd = ::GetConsoleWindow();
if (console_hwnd)
{
HMENU hmenu = ::GetSystemMenu(console_hwnd, FALSE);
::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND);
}
}
else
{
::UnregisterClass(REGISTER_CLASS, HINST_THISCOMPONENT);
throw RuntimeException("Create window failed");
}
}
return hwnd_;
}
void e2d::Window::SetSize(int width, int height)
{
if (width_ == width && height_ == height)
return;
width_ = width;
height_ = height;
if (hwnd_)
{
Rect rect = Locate(width, height);
::MoveWindow(
hwnd_,
int(rect.origin.x),
int(rect.origin.y),
int(rect.size.width),
int(rect.size.height),
TRUE
);
}
}
void e2d::Window::SetTitle(const String& title)
{
title_ = title;
if (hwnd_)
{
::SetWindowText(hwnd_, (LPCWSTR)title);
}
}
void e2d::Window::SetIcon(int resource_id)
{
this->icon_id_ = resource_id;
if (hwnd_)
{
HICON icon = (HICON)::LoadImage(
HINST_THISCOMPONENT,
MAKEINTRESOURCE(resource_id),
IMAGE_ICON,
0,
0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE
);
// 设置窗口的图标
::SendMessage(hwnd_, WM_SETICON, ICON_BIG, (LPARAM)icon);
::SendMessage(hwnd_, WM_SETICON, ICON_SMALL, (LPARAM)icon);
}
}
void e2d::Window::SetCursor(Cursor cursor) void e2d::Window::SetCursor(Cursor cursor)
{ {
LPCWSTR cursor_name = nullptr; LPCWSTR cursor_name = nullptr;
@ -296,7 +48,7 @@ void e2d::Window::SetCursor(Cursor cursor)
} }
} }
void e2d::Window::SetConsoleEnabled(bool enabled) void e2d::Window::ShowConsole(bool enabled)
{ {
// 查找已存在的控制台句柄 // 查找已存在的控制台句柄
HWND hwnd = ::GetConsoleWindow(); HWND hwnd = ::GetConsoleWindow();
@ -333,27 +85,6 @@ void e2d::Window::SetConsoleEnabled(bool enabled)
} }
} }
void e2d::Window::SetTypewritingEnabled(bool enabled)
{
static HIMC himc = nullptr;
if (enabled)
{
if (himc != nullptr)
{
::ImmAssociateContext(GetHWnd(), himc);
himc = nullptr;
}
}
else
{
if (himc == nullptr)
{
himc = ::ImmAssociateContext(GetHWnd(), nullptr);
}
}
}
bool e2d::Window::Popup(const String & text, const String & title, PopupStyle style, bool has_cancel) bool e2d::Window::Popup(const String & text, const String & title, PopupStyle style, bool has_cancel)
{ {
UINT type = 0; UINT type = 0;
@ -377,166 +108,6 @@ bool e2d::Window::Popup(const String & text, const String & title, PopupStyle st
type |= MB_OKCANCEL; type |= MB_OKCANCEL;
} }
Game::GetInstance()->Pause(); int ret = ::MessageBoxW(nullptr, (LPCWSTR)text, (LPCWSTR)title, type);
int ret = ::MessageBox(hwnd_, (LPCWSTR)text, (LPCWSTR)title, type);
Game::GetInstance()->Resume();
return ret == IDOK; return ret == IDOK;
} }
LRESULT e2d::Window::WndProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param)
{
LRESULT result = 0;
if (msg == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)l_param;
Window *window = (Window *)pcs->lpCreateParams;
::SetWindowLongPtrW(
hwnd,
GWLP_USERDATA,
PtrToUlong(window)
);
result = 1;
}
else
{
bool has_handled = false;
Window *window = reinterpret_cast<Window *>(
static_cast<LONG_PTR>(
::GetWindowLongPtrW(hwnd, GWLP_USERDATA)
)
);
switch (msg)
{
// 处理鼠标消息
case WM_LBUTTONUP:
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_MBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK:
case WM_RBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
case WM_MOUSEMOVE:
case WM_MOUSEWHEEL:
{
auto game = Game::GetInstance();
if (game->IsTransitioning())
break;
auto curr_scene = game->GetCurrentScene();
if (curr_scene)
{
curr_scene->Dispatch(MouseEvent(msg, w_param, l_param));
}
}
result = 0;
has_handled = true;
break;
// 处理按键消息
case WM_KEYDOWN:
case WM_KEYUP:
{
auto game = Game::GetInstance();
if (game->IsTransitioning())
break;
auto curr_scene = game->GetCurrentScene();
if (curr_scene)
{
curr_scene->Dispatch(KeyEvent(msg, w_param, l_param));
}
}
result = 0;
has_handled = true;
break;
// 处理窗口大小变化消息
case WM_SIZE:
{
UINT width = LOWORD(l_param);
UINT height = HIWORD(l_param);
if (w_param == SIZE_RESTORED)
{
window->width_ = static_cast<int>(width * 96.f / window->dpi_);
window->height_ = static_cast<int>(height * 96.f / window->dpi_);
}
// 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染
// 目标的大小。它可能会调用失败,但是这里可以忽略有可能的
// 错误,因为这个错误将在下一次调用 EndDraw 时产生
auto render_target = Renderer::GetInstance()->GetRenderTarget();
if (render_target)
{
render_target->Resize(D2D1::SizeU(width, height));
}
}
break;
// 处理窗口标题变化消息
case WM_SETTEXT:
{
window->title_ = (const wchar_t*)l_param;
}
break;
// 处理分辨率变化消息
case WM_DISPLAYCHANGE:
{
// 重绘客户区
::InvalidateRect(hwnd, nullptr, FALSE);
}
result = 0;
has_handled = true;
break;
// 重绘窗口
case WM_PAINT:
{
Game::GetInstance()->DrawScene();
::ValidateRect(hwnd, nullptr);
}
result = 0;
has_handled = true;
break;
// 窗口关闭消息
case WM_CLOSE:
{
auto game = Game::GetInstance();
auto currScene = game->GetCurrentScene();
if (!currScene || currScene->OnCloseWindow())
{
game->Quit();
}
}
result = 0;
has_handled = true;
break;
// 窗口销毁消息
case WM_DESTROY:
{
::PostQuitMessage(0);
}
result = 1;
has_handled = true;
break;
}
if (!has_handled)
{
result = ::DefWindowProc(hwnd, msg, w_param, l_param);
}
}
return result;
}

View File

@ -9,7 +9,7 @@ e2d::Canvas::Canvas(float width, float height)
, stroke_width_(1.0f) , stroke_width_(1.0f)
, stroke_(Stroke::Miter) , stroke_(Stroke::Miter)
{ {
render_target_ = Renderer::GetInstance()->GetRenderTarget(); render_target_ = Graphics::Get()->GetRenderTarget();
render_target_->AddRef(); render_target_->AddRef();
ThrowIfFailed( ThrowIfFailed(
@ -59,13 +59,13 @@ void e2d::Canvas::SetStrokeStyle(Stroke strokeStyle)
switch (strokeStyle) switch (strokeStyle)
{ {
case e2d::Stroke::Miter: case e2d::Stroke::Miter:
stroke_style_ = Renderer::GetMiterStrokeStyle(); stroke_style_ = Graphics::GetMiterStrokeStyle();
break; break;
case e2d::Stroke::Bevel: case e2d::Stroke::Bevel:
stroke_style_ = Renderer::GetBevelStrokeStyle(); stroke_style_ = Graphics::GetBevelStrokeStyle();
break; break;
case e2d::Stroke::Round: case e2d::Stroke::Round:
stroke_style_ = Renderer::GetRoundStrokeStyle(); stroke_style_ = Graphics::GetRoundStrokeStyle();
break; break;
} }
} }

View File

@ -84,14 +84,14 @@ void e2d::Collider::Draw()
{ {
if (geometry_ && enabled_ && visible_) if (geometry_ && enabled_ && visible_)
{ {
auto renderer = Renderer::GetInstance(); auto graphics = Graphics::GetInstance();
// 获取纯色画刷 // 获取纯色画刷
ID2D1SolidColorBrush * brush = renderer->GetSolidBrush(); ID2D1SolidColorBrush * brush = graphics->GetSolidBrush();
// 设置画刷颜色和透明度 // 设置画刷颜色和透明度
brush->SetColor((D2D1_COLOR_F)border_color_); brush->SetColor((D2D1_COLOR_F)border_color_);
brush->SetOpacity(1.f); brush->SetOpacity(1.f);
// 绘制几何碰撞体 // 绘制几何碰撞体
renderer->GetRenderTarget()->DrawGeometry(geometry_, brush, 1.5f); graphics->GetRenderTarget()->DrawGeometry(geometry_, brush, 1.5f);
} }
} }
@ -135,7 +135,7 @@ void e2d::Collider::Recreate()
return; return;
SafeRelease(geometry_); SafeRelease(geometry_);
auto factory = Renderer::GetFactory(); auto factory = Graphics::GetFactory();
switch (shape_) switch (shape_)
{ {

View File

@ -164,8 +164,8 @@ bool e2d::Image::Preload(const Resource& res)
return true; return true;
} }
IWICImagingFactory *imaging_factory = Renderer::GetImagingFactory(); IWICImagingFactory *imaging_factory = Graphics::GetImagingFactory();
ID2D1HwndRenderTarget* render_target = Renderer::GetInstance()->GetRenderTarget(); ID2D1HwndRenderTarget* render_target = Graphics::GetInstance()->GetRenderTarget();
IWICBitmapDecoder *decoder = nullptr; IWICBitmapDecoder *decoder = nullptr;
IWICBitmapFrameDecode *source = nullptr; IWICBitmapFrameDecode *source = nullptr;
IWICStream *stream = nullptr; IWICStream *stream = nullptr;
@ -297,8 +297,8 @@ bool e2d::Image::Preload(const String & file_name)
// 默认搜索路径,所以需要通过 File::GetPath 获取完整路径 // 默认搜索路径,所以需要通过 File::GetPath 获取完整路径
String image_file_path = image_file.GetPath(); String image_file_path = image_file.GetPath();
IWICImagingFactory *imaging_factory = Renderer::GetImagingFactory(); IWICImagingFactory *imaging_factory = Graphics::GetImagingFactory();
ID2D1HwndRenderTarget* render_target = Renderer::GetInstance()->GetRenderTarget(); ID2D1HwndRenderTarget* render_target = Graphics::GetInstance()->GetRenderTarget();
IWICBitmapDecoder *decoder = nullptr; IWICBitmapDecoder *decoder = nullptr;
IWICBitmapFrameDecode *source = nullptr; IWICBitmapFrameDecode *source = nullptr;
IWICStream *stream = nullptr; IWICStream *stream = nullptr;

View File

@ -52,21 +52,18 @@ void e2d::Node::Visit()
if (!visible_) if (!visible_)
return; return;
if (!Game::GetInstance()->IsPaused()) UpdateActions();
{ UpdateTasks();
UpdateActions();
UpdateTasks();
auto updatable_node = dynamic_cast<Updatable*>(this); auto updatable_node = dynamic_cast<Updatable*>(this);
if (updatable_node) if (updatable_node)
{ {
updatable_node->Update(); updatable_node->Update();
}
} }
UpdateTransform(); UpdateTransform();
auto render_target = Renderer::GetInstance()->GetRenderTarget(); auto render_target = Graphics::Get()->GetRenderTarget();
if (clip_enabled_) if (clip_enabled_)
{ {
render_target->SetTransform(final_matrix_); render_target->SetTransform(final_matrix_);
@ -138,10 +135,10 @@ void e2d::Node::DrawBorder()
{ {
if (border_) if (border_)
{ {
auto renderer = Renderer::GetInstance(); auto graphics = Graphics::Get();
auto brush = renderer->GetSolidBrush(); auto brush = graphics->GetSolidBrush();
brush->SetColor(D2D1_COLOR_F(border_color_)); brush->SetColor(D2D1_COLOR_F(border_color_));
renderer->GetRenderTarget()->DrawGeometry( graphics->GetRenderTarget()->DrawGeometry(
border_, border_,
brush, brush,
1.5f 1.5f
@ -198,7 +195,7 @@ void e2d::Node::UpdateTransform()
// 重新构造轮廓 // 重新构造轮廓
SafeRelease(border_); SafeRelease(border_);
ID2D1Factory * factory = Renderer::GetFactory(); ID2D1Factory * factory = Graphics::GetFactory();
ID2D1RectangleGeometry * rectangle = nullptr; ID2D1RectangleGeometry * rectangle = nullptr;
ID2D1TransformedGeometry * transformed = nullptr; ID2D1TransformedGeometry * transformed = nullptr;
ThrowIfFailed( ThrowIfFailed(

View File

@ -3,16 +3,12 @@
e2d::Scene::Scene() e2d::Scene::Scene()
: root_(nullptr) : root_(nullptr)
, border_visible_(false)
, collider_visible_(false)
, transform_(D2D1::Matrix3x2F::Identity()) , transform_(D2D1::Matrix3x2F::Identity())
{ {
} }
e2d::Scene::Scene(Node * root) e2d::Scene::Scene(Node * root)
: root_(nullptr) : root_(nullptr)
, border_visible_(false)
, collider_visible_(false)
, transform_(D2D1::Matrix3x2F::Identity()) , transform_(D2D1::Matrix3x2F::Identity())
{ {
this->SetRoot(root); this->SetRoot(root);
@ -52,34 +48,11 @@ e2d::Node * e2d::Scene::GetRoot() const
return root_; return root_;
} }
void e2d::Scene::ShowBorder(bool visible)
{
border_visible_ = visible;
}
void e2d::Scene::ShowCollider(bool visible)
{
collider_visible_ = visible;
}
void e2d::Scene::Draw() void e2d::Scene::Draw()
{ {
if (root_) if (root_)
{ {
root_->Visit(); root_->Visit();
if (border_visible_)
{
Renderer::GetInstance()->GetRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity());
Renderer::GetInstance()->GetSolidBrush()->SetOpacity(1.f);
root_->DrawBorder();
}
if (collider_visible_)
{
Renderer::GetInstance()->GetRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity());
root_->DrawCollider();
}
} }
} }

View File

@ -93,6 +93,15 @@ bool e2d::Sprite::Open(const String & file_name)
return false; return false;
} }
void e2d::Sprite::Crop(const Rect& crop_rect)
{
image_->Crop(crop_rect);
Node::SetSize(
std::min(std::max(crop_rect.size.width, 0.f), image_->GetSourceWidth() - image_->GetCropX()),
std::min(std::max(crop_rect.size.height, 0.f), image_->GetSourceHeight() - image_->GetCropY())
);
}
e2d::Image * e2d::Sprite::GetImage() const e2d::Image * e2d::Sprite::GetImage() const
{ {
return image_; return image_;
@ -105,7 +114,7 @@ void e2d::Sprite::Draw() const
// »ñȡͼƬ²Ã¼ôλÖà // »ñȡͼƬ²Ã¼ôλÖÃ
auto crop_pos = image_->GetCropPos(); auto crop_pos = image_->GetCropPos();
// äÖȾͼƬ // äÖȾͼƬ
Renderer::GetInstance()->GetRenderTarget()->DrawBitmap( Graphics::Get()->GetRenderTarget()->DrawBitmap(
image_->GetBitmap(), image_->GetBitmap(),
D2D1::RectF(0, 0, transform_.size.width, transform_.size.height), D2D1::RectF(0, 0, transform_.size.width, transform_.size.height),
display_opacity_, display_opacity_,

View File

@ -292,13 +292,13 @@ void e2d::Text::Draw() const
{ {
if (text_layout_) if (text_layout_)
{ {
auto renderer = Renderer::GetInstance(); auto graphics = Graphics::GetInstance();
// 创建文本区域 // 创建文本区域
D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, transform_.size.width, transform_.size.height); D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, transform_.size.width, transform_.size.height);
// 设置画刷颜色和透明度 // 设置画刷颜色和透明度
renderer->GetSolidBrush()->SetOpacity(display_opacity_); graphics->GetSolidBrush()->SetOpacity(display_opacity_);
// 获取文本渲染器 // 获取文本渲染器
auto textRenderer = renderer->GetTextRenderer(); auto textRenderer = graphics->GetTextRenderer();
textRenderer->SetTextStyle( textRenderer->SetTextStyle(
(D2D1_COLOR_F)style_.color, (D2D1_COLOR_F)style_.color,
style_.outline, style_.outline,
@ -323,7 +323,7 @@ void e2d::Text::CreateFormat()
SafeRelease(text_format_); SafeRelease(text_format_);
ThrowIfFailed( ThrowIfFailed(
Renderer::GetWriteFactory()->CreateTextFormat( Graphics::GetWriteFactory()->CreateTextFormat(
(const wchar_t *)font_.family, (const wchar_t *)font_.family,
nullptr, nullptr,
DWRITE_FONT_WEIGHT(font_.weight), DWRITE_FONT_WEIGHT(font_.weight),
@ -381,7 +381,7 @@ void e2d::Text::CreateLayout()
} }
UINT32 length = (UINT32)text_.GetLength(); UINT32 length = (UINT32)text_.GetLength();
auto writeFactory = Renderer::GetWriteFactory(); auto writeFactory = Graphics::GetWriteFactory();
// 对文本自动换行情况下进行处理 // 对文本自动换行情况下进行处理
if (style_.wrap) if (style_.wrap)

View File

@ -42,18 +42,18 @@ void e2d::Transition::Init(Scene * prev, Scene * next)
if (in_scene_) if (in_scene_)
in_scene_->Retain(); in_scene_->Retain();
auto renderer = Renderer::GetInstance(); auto graphics = Graphics::GetInstance();
if (in_scene_) if (in_scene_)
{ {
ThrowIfFailed( ThrowIfFailed(
renderer->GetRenderTarget()->CreateLayer(&in_layer_) graphics->GetRenderTarget()->CreateLayer(&in_layer_)
); );
} }
if (out_scene_) if (out_scene_)
{ {
ThrowIfFailed( ThrowIfFailed(
renderer->GetRenderTarget()->CreateLayer(&out_layer_) graphics->GetRenderTarget()->CreateLayer(&out_layer_)
); );
} }
@ -69,7 +69,7 @@ void e2d::Transition::Init(Scene * prev, Scene * next)
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
D2D1::Matrix3x2F::Identity(), D2D1::Matrix3x2F::Identity(),
1.f, 1.f,
renderer->GetSolidBrush(), graphics->GetSolidBrush(),
D2D1_LAYER_OPTIONS_NONE D2D1_LAYER_OPTIONS_NONE
); );
} }
@ -94,7 +94,7 @@ void e2d::Transition::Update()
void e2d::Transition::Draw() void e2d::Transition::Draw()
{ {
auto render_target = Renderer::GetInstance()->GetRenderTarget(); auto render_target = Graphics::GetInstance()->GetRenderTarget();
if (out_scene_) if (out_scene_)
{ {

View File

@ -229,7 +229,7 @@
<ClCompile Include="..\..\core\modules\Game.cpp" /> <ClCompile Include="..\..\core\modules\Game.cpp" />
<ClCompile Include="..\..\core\modules\GC.cpp" /> <ClCompile Include="..\..\core\modules\GC.cpp" />
<ClCompile Include="..\..\core\modules\Input.cpp" /> <ClCompile Include="..\..\core\modules\Input.cpp" />
<ClCompile Include="..\..\core\modules\Renderer.cpp" /> <ClCompile Include="..\..\core\modules\Graphics.cpp" />
<ClCompile Include="..\..\core\modules\Window.cpp" /> <ClCompile Include="..\..\core\modules\Window.cpp" />
<ClCompile Include="..\..\core\objects\Canvas.cpp" /> <ClCompile Include="..\..\core\objects\Canvas.cpp" />
<ClCompile Include="..\..\core\objects\Collider.cpp" /> <ClCompile Include="..\..\core\objects\Collider.cpp" />

View File

@ -108,9 +108,6 @@
<ClCompile Include="..\..\core\modules\Input.cpp"> <ClCompile Include="..\..\core\modules\Input.cpp">
<Filter>modules</Filter> <Filter>modules</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\core\modules\Renderer.cpp">
<Filter>modules</Filter>
</ClCompile>
<ClCompile Include="..\..\core\modules\Window.cpp"> <ClCompile Include="..\..\core\modules\Window.cpp">
<Filter>modules</Filter> <Filter>modules</Filter>
</ClCompile> </ClCompile>
@ -234,6 +231,9 @@
<ClCompile Include="..\..\core\utils\Transform.cpp"> <ClCompile Include="..\..\core\utils\Transform.cpp">
<Filter>utils</Filter> <Filter>utils</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\core\modules\Graphics.cpp">
<Filter>modules</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\core\easy2d.h" /> <ClInclude Include="..\..\core\easy2d.h" />