update: modern singleton pattern

This commit is contained in:
Haibo 2018-11-12 20:46:54 +08:00 committed by Nomango
parent 2b366e42be
commit d2532c09db
57 changed files with 1200 additions and 976 deletions

View File

@ -38,6 +38,8 @@ namespace easy2d
friend class Sequence; friend class Sequence;
friend class Spawn; friend class Spawn;
E2D_DISABLE_COPY(Action);
public: public:
Action(); Action();
@ -92,9 +94,6 @@ namespace easy2d
// 获取动作结束状态 // 获取动作结束状态
virtual bool IsDone() const; virtual bool IsDone() const;
protected:
E2D_DISABLE_COPY(Action);
protected: protected:
String name_; String name_;
bool running_; bool running_;

View File

@ -27,7 +27,7 @@ namespace easy2d
// Loop // Loop
//------------------------------------------------------- //-------------------------------------------------------
Loop::Loop(Action * action, int times /* = -1 */) Loop::Loop(Action * action, int times)
: action_(action) : action_(action)
, times_(0) , times_(0)
, total_times_(times) , total_times_(times)

View File

@ -27,6 +27,8 @@ namespace easy2d
class Loop class Loop
: public Action : public Action
{ {
E2D_DISABLE_COPY(Loop);
public: public:
explicit Loop( explicit Loop(
Action * action, /* 执行循环的动作 */ Action * action, /* 执行循环的动作 */
@ -45,8 +47,6 @@ namespace easy2d
virtual void Reset() override; virtual void Reset() override;
protected: protected:
E2D_DISABLE_COPY(Loop);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;
@ -67,6 +67,8 @@ namespace easy2d
class Sequence class Sequence
: public Action : public Action
{ {
E2D_DISABLE_COPY(Sequence);
public: public:
typedef std::vector<Action*> Actions; typedef std::vector<Action*> Actions;
@ -98,8 +100,6 @@ namespace easy2d
virtual void Reset() override; virtual void Reset() override;
protected: protected:
E2D_DISABLE_COPY(Sequence);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;
@ -119,6 +119,8 @@ namespace easy2d
class Spawn class Spawn
: public Action : public Action
{ {
E2D_DISABLE_COPY(Spawn);
public: public:
typedef std::vector<Action*> Actions; typedef std::vector<Action*> Actions;
@ -150,8 +152,6 @@ namespace easy2d
virtual void Reset() override; virtual void Reset() override;
protected: protected:
E2D_DISABLE_COPY(Spawn);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;

View File

@ -27,6 +27,8 @@ namespace easy2d
class FiniteTimeAction class FiniteTimeAction
: public Action : public Action
{ {
E2D_DISABLE_COPY(FiniteTimeAction);
public: public:
// 创建特定时长的持续动作 // 创建特定时长的持续动作
explicit FiniteTimeAction( explicit FiniteTimeAction(
@ -37,8 +39,6 @@ namespace easy2d
virtual void Reset() override; virtual void Reset() override;
protected: protected:
E2D_DISABLE_COPY(FiniteTimeAction);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;
@ -58,6 +58,8 @@ namespace easy2d
class MoveBy class MoveBy
: public FiniteTimeAction : public FiniteTimeAction
{ {
E2D_DISABLE_COPY(MoveBy);
public: public:
explicit MoveBy( explicit MoveBy(
float duration, /* 持续时长 */ float duration, /* 持续时长 */
@ -71,8 +73,6 @@ namespace easy2d
virtual MoveBy * Reverse() const override; virtual MoveBy * Reverse() const override;
protected: protected:
E2D_DISABLE_COPY(MoveBy);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;
@ -90,6 +90,8 @@ namespace easy2d
class MoveTo class MoveTo
: public MoveBy : public MoveBy
{ {
E2D_DISABLE_COPY(MoveTo);
public: public:
explicit MoveTo( explicit MoveTo(
float duration, /* 持续时长 */ float duration, /* 持续时长 */
@ -107,8 +109,6 @@ namespace easy2d
} }
protected: protected:
E2D_DISABLE_COPY(MoveTo);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;
@ -121,6 +121,8 @@ namespace easy2d
class JumpBy class JumpBy
: public FiniteTimeAction : public FiniteTimeAction
{ {
E2D_DISABLE_COPY(JumpBy);
public: public:
explicit JumpBy( explicit JumpBy(
float duration, /* 持续时长 */ float duration, /* 持续时长 */
@ -136,8 +138,6 @@ namespace easy2d
virtual JumpBy * Reverse() const override; virtual JumpBy * Reverse() const override;
protected: protected:
E2D_DISABLE_COPY(JumpBy);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;
@ -157,6 +157,8 @@ namespace easy2d
class JumpTo class JumpTo
: public JumpBy : public JumpBy
{ {
E2D_DISABLE_COPY(JumpTo);
public: public:
explicit JumpTo( explicit JumpTo(
float duration, /* 持续时长 */ float duration, /* 持续时长 */
@ -176,8 +178,6 @@ namespace easy2d
} }
protected: protected:
E2D_DISABLE_COPY(JumpTo);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;
@ -190,6 +190,8 @@ namespace easy2d
class ScaleBy class ScaleBy
: public FiniteTimeAction : public FiniteTimeAction
{ {
E2D_DISABLE_COPY(ScaleBy);
public: public:
explicit ScaleBy( explicit ScaleBy(
float duration, /* 持续时长 */ float duration, /* 持续时长 */
@ -209,8 +211,6 @@ namespace easy2d
virtual ScaleBy * Reverse() const override; virtual ScaleBy * Reverse() const override;
protected: protected:
E2D_DISABLE_COPY(ScaleBy);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;
@ -229,6 +229,8 @@ namespace easy2d
class ScaleTo class ScaleTo
: public ScaleBy : public ScaleBy
{ {
E2D_DISABLE_COPY(ScaleTo);
public: public:
explicit ScaleTo( explicit ScaleTo(
float duration, /* 持续时长 */ float duration, /* 持续时长 */
@ -252,8 +254,6 @@ namespace easy2d
} }
protected: protected:
E2D_DISABLE_COPY(ScaleTo);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;
@ -267,6 +267,8 @@ namespace easy2d
class OpacityBy class OpacityBy
: public FiniteTimeAction : public FiniteTimeAction
{ {
E2D_DISABLE_COPY(OpacityBy);
public: public:
explicit OpacityBy( explicit OpacityBy(
float duration, /* 持续时长 */ float duration, /* 持续时长 */
@ -280,8 +282,6 @@ namespace easy2d
virtual OpacityBy * Reverse() const override; virtual OpacityBy * Reverse() const override;
protected: protected:
E2D_DISABLE_COPY(OpacityBy);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;
@ -298,6 +298,8 @@ namespace easy2d
class OpacityTo class OpacityTo
: public OpacityBy : public OpacityBy
{ {
E2D_DISABLE_COPY(OpacityTo);
public: public:
explicit OpacityTo( explicit OpacityTo(
float duration, /* 持续时长 */ float duration, /* 持续时长 */
@ -315,8 +317,6 @@ namespace easy2d
} }
protected: protected:
E2D_DISABLE_COPY(OpacityTo);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;
@ -329,14 +329,13 @@ namespace easy2d
class FadeIn class FadeIn
: public OpacityTo : public OpacityTo
{ {
E2D_DISABLE_COPY(FadeIn);
public: public:
// 创建淡入动作 // 创建淡入动作
explicit FadeIn( explicit FadeIn(
float duration /* 持续时长 */ float duration /* 持续时长 */
); );
protected:
E2D_DISABLE_COPY(FadeIn);
}; };
@ -344,14 +343,13 @@ namespace easy2d
class FadeOut class FadeOut
: public OpacityTo : public OpacityTo
{ {
E2D_DISABLE_COPY(FadeOut);
public: public:
// 创建淡出动作 // 创建淡出动作
explicit FadeOut( explicit FadeOut(
float duration /* 持续时长 */ float duration /* 持续时长 */
); );
protected:
E2D_DISABLE_COPY(FadeOut);
}; };
@ -359,6 +357,8 @@ namespace easy2d
class RotateBy class RotateBy
: public FiniteTimeAction : public FiniteTimeAction
{ {
E2D_DISABLE_COPY(RotateBy);
public: public:
explicit RotateBy( explicit RotateBy(
float duration, /* 持续时长 */ float duration, /* 持续时长 */
@ -372,8 +372,6 @@ namespace easy2d
virtual RotateBy * Reverse() const override; virtual RotateBy * Reverse() const override;
protected: protected:
E2D_DISABLE_COPY(RotateBy);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;
@ -390,6 +388,8 @@ namespace easy2d
class RotateTo class RotateTo
: public RotateBy : public RotateBy
{ {
E2D_DISABLE_COPY(RotateTo);
public: public:
explicit RotateTo( explicit RotateTo(
float duration, /* 持续时长 */ float duration, /* 持续时长 */
@ -407,8 +407,6 @@ namespace easy2d
} }
protected: protected:
E2D_DISABLE_COPY(RotateTo);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;
@ -421,6 +419,8 @@ namespace easy2d
class Delay class Delay
: public Action : public Action
{ {
E2D_DISABLE_COPY(Delay);
public: public:
explicit Delay( explicit Delay(
float duration /* 延迟时长(秒) */ float duration /* 延迟时长(秒) */
@ -436,8 +436,6 @@ namespace easy2d
virtual void Reset() override; virtual void Reset() override;
protected: protected:
E2D_DISABLE_COPY(Delay);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;

View File

@ -28,6 +28,8 @@ namespace easy2d
class Animation class Animation
: public RefCounter : public RefCounter
{ {
E2D_DISABLE_COPY(Animation);
public: public:
typedef std::vector<Image*> Images; typedef std::vector<Image*> Images;
@ -75,9 +77,6 @@ namespace easy2d
// 获取帧动画的倒转 // 获取帧动画的倒转
Animation * Reverse() const; Animation * Reverse() const;
protected:
E2D_DISABLE_COPY(Animation);
protected: protected:
float interval_; float interval_;
Images frames_; Images frames_;
@ -88,6 +87,8 @@ namespace easy2d
class Animate class Animate
: public Action : public Action
{ {
E2D_DISABLE_COPY(Animate);
public: public:
Animate(); Animate();
@ -115,8 +116,6 @@ namespace easy2d
virtual void Reset() override; virtual void Reset() override;
protected: protected:
E2D_DISABLE_COPY(Animate);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;

View File

@ -23,6 +23,7 @@
#include "../math/vector.hpp" #include "../math/vector.hpp"
#include "Color.h" #include "Color.h"
#include "Size.h" #include "Size.h"
#include "Rect.hpp"
namespace easy2d namespace easy2d
{ {
@ -33,9 +34,9 @@ namespace easy2d
// 计算两点间距离: float distance = p1.Distance(p2); // 计算两点间距离: float distance = p1.Distance(p2);
// 坐标可以相加减: Point p = Point(10, 10) + Point(20, 20); // p 的坐标是 (30, 30) // 坐标可以相加减: Point p = Point(10, 10) + Point(20, 20); // p 的坐标是 (30, 30)
// //
typedef math::Vector2 Point; using Point = math::Vector2;
typedef std::wstring String; using String = std::wstring;
// 方向 // 方向
enum class Direction : int enum class Direction : int
@ -138,4 +139,11 @@ namespace easy2d
Right = VK_RBUTTON, /* 鼠标右键 */ Right = VK_RBUTTON, /* 鼠标右键 */
Middle = VK_MBUTTON /* 鼠标中键 */ Middle = VK_MBUTTON /* 鼠标中键 */
}; };
// 图层属性
struct LayerProperties
{
Rect area;
float opacity;
};
} }

View File

@ -28,6 +28,8 @@ namespace easy2d
class CallFunc class CallFunc
: public Action : public Action
{ {
E2D_DISABLE_COPY(CallFunc);
typedef std::function<void()> Callback; typedef std::function<void()> Callback;
public: public:
@ -42,8 +44,6 @@ namespace easy2d
virtual CallFunc *Reverse() const override; virtual CallFunc *Reverse() const override;
protected: protected:
E2D_DISABLE_COPY(CallFunc);
// 初始化动作 // 初始化动作
virtual void Initialize() override; virtual void Initialize() override;

View File

@ -88,7 +88,7 @@ namespace easy2d
{ {
SafeRelease(stroke_style_); SafeRelease(stroke_style_);
stroke_style_ = render::instance.GetStrokeStyle(stroke); stroke_style_ = devices::Graphics::Instance().GetStrokeStyle(stroke);
if (stroke_style_) if (stroke_style_)
stroke_style_->AddRef(); stroke_style_->AddRef();

View File

@ -28,6 +28,8 @@ namespace easy2d
class Canvas class Canvas
: public Node : public Node
{ {
E2D_DISABLE_COPY(Canvas);
public: public:
Canvas( Canvas(
float width, float width,
@ -124,12 +126,9 @@ namespace easy2d
float radius_y float radius_y
); );
private:
E2D_DISABLE_COPY(Canvas);
private: private:
float stroke_width_; float stroke_width_;
StrokeStyle stroke_; StrokeStyle stroke_;
ID2D1RenderTarget* render_target_; ID2D1RenderTarget* render_target_;
ID2D1SolidColorBrush* fill_brush_; ID2D1SolidColorBrush* fill_brush_;
ID2D1SolidColorBrush* line_brush_; ID2D1SolidColorBrush* line_brush_;

View File

@ -34,16 +34,6 @@
namespace easy2d namespace easy2d
{ {
namespace
{
Game * instance = nullptr;
}
Game * Game::GetInstance()
{
return instance;
}
Game::Game() Game::Game()
: quit_(true) : quit_(true)
, curr_scene_(nullptr) , curr_scene_(nullptr)
@ -51,12 +41,6 @@ namespace easy2d
, transition_(nullptr) , transition_(nullptr)
, debug_mode_(false) , debug_mode_(false)
{ {
if (instance)
{
throw std::runtime_error("同时只能存在一个游戏实例");
}
instance = this;
::CoInitialize(nullptr); ::CoInitialize(nullptr);
} }
@ -66,25 +50,14 @@ namespace easy2d
SafeRelease(curr_scene_); SafeRelease(curr_scene_);
SafeRelease(next_scene_); SafeRelease(next_scene_);
Image::ClearCache();
Player::ClearCache();
render::instance.Uninitialize();
audio::instance.Uninitialize();
window::instance.Destroy();
modules::Uninitialize();
instance = nullptr;
::CoUninitialize(); ::CoUninitialize();
} }
void Game::Initialize(const window::Property& property) void Game::Initialize(const Options& options)
{ {
modules::Initialize(); Window::Instance().Initialize(options.title, options.width, options.height, options.icon, options.debug);
window::instance.Initialize(property); devices::Graphics::Instance().Initialize(Window::Instance().GetHandle());
render::instance.Initialize(window::instance.handle); devices::Audio::Instance().Initialize();
audio::instance.Initialize();
// 若开启了调试模式,打开控制台 // 若开启了调试模式,打开控制台
HWND console = ::GetConsoleWindow(); HWND console = ::GetConsoleWindow();
@ -117,7 +90,7 @@ namespace easy2d
} }
::SetWindowLongPtrW( ::SetWindowLongPtrW(
window::instance.handle, Window::Instance().GetHandle(),
GWLP_USERDATA, GWLP_USERDATA,
PtrToUlong(this) PtrToUlong(this)
); );
@ -134,8 +107,8 @@ namespace easy2d
next_scene_ = nullptr; next_scene_ = nullptr;
} }
::ShowWindow(window::instance.handle, SW_SHOWNORMAL); ::ShowWindow(Window::Instance().GetHandle(), SW_SHOWNORMAL);
::UpdateWindow(window::instance.handle); ::UpdateWindow(Window::Instance().GetHandle());
const int64_t min_interval = 5; const int64_t min_interval = 5;
auto last = time::Now(); auto last = time::Now();
@ -151,10 +124,10 @@ namespace easy2d
float dt = (now - last).Seconds(); float dt = (now - last).Seconds();
last = now; last = now;
input::instance.Update( devices::Input::Instance().Update(
window::instance.handle, Window::Instance().GetHandle(),
window::instance.xscale, Window::Instance().GetContentScaleX(),
window::instance.yscale Window::Instance().GetContentScaleY()
); );
OnUpdate(dt); OnUpdate(dt);
@ -277,7 +250,7 @@ namespace easy2d
void Game::DrawScene() void Game::DrawScene()
{ {
render::instance.BeginDraw(window::instance.handle); devices::Graphics::Instance().BeginDraw(Window::Instance().GetHandle());
if (transition_) if (transition_)
{ {
@ -292,21 +265,21 @@ namespace easy2d
{ {
if (curr_scene_ && curr_scene_->GetRoot()) if (curr_scene_ && curr_scene_->GetRoot())
{ {
render::instance.SetTransform(math::Matrix()); devices::Graphics::Instance().SetTransform(math::Matrix());
render::instance.SetBrushOpacity(1.f); devices::Graphics::Instance().SetBrushOpacity(1.f);
curr_scene_->GetRoot()->DrawBorder(); curr_scene_->GetRoot()->DrawBorder();
} }
if (next_scene_ && next_scene_->GetRoot()) if (next_scene_ && next_scene_->GetRoot())
{ {
render::instance.SetTransform(math::Matrix()); devices::Graphics::Instance().SetTransform(math::Matrix());
render::instance.SetBrushOpacity(1.f); devices::Graphics::Instance().SetBrushOpacity(1.f);
next_scene_->GetRoot()->DrawBorder(); next_scene_->GetRoot()->DrawBorder();
} }
render::instance.DrawDebugInfo(); devices::Graphics::Instance().DrawDebugInfo();
} }
render::instance.EndDraw(); devices::Graphics::Instance().EndDraw();
} }
void Game::SetDebugMode(bool enabled) void Game::SetDebugMode(bool enabled)

View File

@ -27,12 +27,32 @@ namespace easy2d
class Scene; class Scene;
class Transition; class Transition;
struct Options
{
String title; /* 标题 */
int width; /* 宽度 */
int height; /* 高度 */
LPCWSTR icon; /* 图标 */
bool debug; /* 调试模式 */
Options()
: title(L"Easy2D Game")
, width(640)
, height(480)
, icon(nullptr)
, debug(false)
{}
};
class Game class Game
{ {
E2D_DISABLE_COPY(Game);
public: public:
Game(); Game();
~Game(); virtual ~Game();
// 更新时 // 更新时
virtual void OnUpdate(float dt) {} virtual void OnUpdate(float dt) {}
@ -46,7 +66,7 @@ namespace easy2d
// 初始化 // 初始化
void Initialize( void Initialize(
const window::Property& property /* 窗口属性 */ const Options& options /* 属性 */
); );
// 运行 // 运行
@ -80,12 +100,6 @@ namespace easy2d
float dt float dt
); );
// 获取实例
static Game * GetInstance();
protected:
E2D_DISABLE_COPY(Game);
private: private:
bool debug_mode_; bool debug_mode_;
bool quit_; bool quit_;

View File

@ -25,11 +25,6 @@
namespace easy2d namespace easy2d
{ {
namespace
{
std::map<size_t, ID2D1Bitmap*> bitmap_cache_;
}
Image::Image() Image::Image()
: bitmap_(nullptr) : bitmap_(nullptr)
, crop_rect_() , crop_rect_()
@ -73,13 +68,12 @@ namespace easy2d
bool Image::Load(Resource& res) bool Image::Load(Resource& res)
{ {
if (!Image::CacheBitmap(res)) HRESULT hr = devices::Graphics::Instance().CreateBitmapFromResource(res, &bitmap_);
if (FAILED(hr))
{ {
E2D_WARNING("Load Image from file failed!"); logs::Trace(L"Load Image from resource failed!", hr);
return false; return false;
} }
this->SetBitmap(bitmap_cache_.at(res.GetHashCode()));
return true; return true;
} }
@ -87,16 +81,23 @@ namespace easy2d
{ {
E2D_WARNING_IF(file_name.empty(), "Image Load failed! Invalid file name."); E2D_WARNING_IF(file_name.empty(), "Image Load failed! Invalid file name.");
if (file_name.empty()) File image_file;
return false; if (!image_file.Open(file_name))
if (!Image::CacheBitmap(file_name))
{ {
E2D_WARNING("Load Image from file failed!"); E2D_WARNING("Image file not found!");
return false; return false;
} }
this->SetBitmap(bitmap_cache_.at(std::hash<String>{}(file_name))); // 用户输入的路径不一定是完整路径,因为用户可能通过 File::AddSearchPath 添加
// 默认搜索路径,所以需要通过 File::GetPath 获取完整路径
String image_file_path = image_file.GetPath();
HRESULT hr = devices::Graphics::Instance().CreateBitmapFromFile(image_file_path, &bitmap_);
if (FAILED(hr))
{
logs::Trace(L"Load Image from file failed!", hr);
return false;
}
return true; return true;
} }
@ -186,70 +187,6 @@ namespace easy2d
return bitmap_; return bitmap_;
} }
bool Image::CacheBitmap(Resource& res)
{
size_t hash_code = res.GetHashCode();
if (bitmap_cache_.find(hash_code) != bitmap_cache_.end())
{
return true;
}
ID2D1Bitmap* bitmap = nullptr;
HRESULT hr = render::instance.CreateBitmapFromResource(res, &bitmap);
if (SUCCEEDED(hr))
{
bitmap_cache_.insert(std::make_pair(hash_code, bitmap));
}
else
{
logs::Trace(L"CreateBitmapFromFile", hr);
}
return SUCCEEDED(hr);
}
bool Image::CacheBitmap(const String & file_name)
{
size_t hash_code = std::hash<String>{}(file_name);
if (bitmap_cache_.find(hash_code) != bitmap_cache_.end())
return true;
File image_file;
if (!image_file.Open(file_name))
return false;
// 用户输入的路径不一定是完整路径,因为用户可能通过 File::AddSearchPath 添加
// 默认搜索路径,所以需要通过 File::GetPath 获取完整路径
String image_file_path = image_file.GetPath();
ID2D1Bitmap* bitmap = nullptr;
HRESULT hr = render::instance.CreateBitmapFromFile(file_name, &bitmap);
if (SUCCEEDED(hr))
{
bitmap_cache_.insert(std::make_pair(hash_code, bitmap));
}
else
{
logs::Trace(L"CreateBitmapFromFile", hr);
}
return SUCCEEDED(hr);
}
void Image::ClearCache()
{
if (bitmap_cache_.empty())
return;
for (const auto& bitmap : bitmap_cache_)
{
bitmap.second->Release();
}
bitmap_cache_.clear();
}
void Image::SetBitmap(ID2D1Bitmap * bitmap) void Image::SetBitmap(ID2D1Bitmap * bitmap)
{ {
if (bitmap_ == bitmap) if (bitmap_ == bitmap)

View File

@ -29,6 +29,8 @@ namespace easy2d
class Image class Image
: public RefCounter : public RefCounter
{ {
E2D_DISABLE_COPY(Image);
public: public:
Image(); Image();
@ -100,22 +102,7 @@ namespace easy2d
// 获取 ID2D1Bitmap 对象 // 获取 ID2D1Bitmap 对象
ID2D1Bitmap * GetBitmap() const; ID2D1Bitmap * GetBitmap() const;
// 헌왕뻠닸
static void ClearCache();
private: private:
E2D_DISABLE_COPY(Image);
// 뻠닸 Bitmap 栗都
static bool CacheBitmap(
const String& file_name
);
// 뻠닸 Bitmap 栗都
static bool CacheBitmap(
Resource& res
);
// 设置 Bitmap // 设置 Bitmap
void SetBitmap( void SetBitmap(
ID2D1Bitmap * bitmap ID2D1Bitmap * bitmap

View File

@ -22,10 +22,8 @@
namespace easy2d namespace easy2d
{ {
namespace input namespace devices
{ {
InputDevice instance;
InputDevice::InputDevice() InputDevice::InputDevice()
{ {
ZeroMemory(keys_, sizeof(keys_)); ZeroMemory(keys_, sizeof(keys_));
@ -35,7 +33,7 @@ namespace easy2d
{ {
} }
void InputDevice::Update(HWND hwnd, float xscale, float yscale) void InputDevice::Update(HWND hwnd, float scale_x, float scale_y)
{ {
::GetKeyboardState(keys_); ::GetKeyboardState(keys_);
@ -43,7 +41,7 @@ namespace easy2d
::GetCursorPos(&client_cursor_pos); ::GetCursorPos(&client_cursor_pos);
::ScreenToClient(hwnd, &client_cursor_pos); ::ScreenToClient(hwnd, &client_cursor_pos);
mouse_pos_ = Point(client_cursor_pos.x * xscale, client_cursor_pos.y * yscale); mouse_pos_ = Point(client_cursor_pos.x * scale_x, client_cursor_pos.y * scale_y);
} }
bool InputDevice::IsDown(KeyCode code) bool InputDevice::IsDown(KeyCode code)

View File

@ -20,14 +20,18 @@
#pragma once #pragma once
#include "base.h" #include "base.h"
#include "Singleton.hpp"
namespace easy2d namespace easy2d
{ {
namespace input namespace devices
{ {
// 输入设备
class InputDevice class InputDevice
{ {
E2D_DECLARE_SINGLETON(InputDevice);
E2D_DISABLE_COPY(InputDevice);
public: public:
InputDevice(); InputDevice();
@ -55,8 +59,8 @@ namespace easy2d
// 刷新设备状态 // 刷新设备状态
void Update( void Update(
HWND hwnd, HWND hwnd,
float xscale, float scale_x,
float yscale float scale_y
); );
protected: protected:
@ -64,6 +68,6 @@ namespace easy2d
Point mouse_pos_; Point mouse_pos_;
}; };
extern InputDevice instance; E2D_DECLARE_SINGLETON_TYPE(InputDevice, Input);
} }
} }

View File

@ -32,19 +32,19 @@ namespace easy2d
float MouseEvent::GetX() const float MouseEvent::GetX() const
{ {
return ((float)(short)LOWORD(l_param_)) * window::instance.xscale; return ((float)(short)LOWORD(l_param_)) * Window::Instance().GetContentScaleX();
} }
float MouseEvent::GetY() const float MouseEvent::GetY() const
{ {
return ((float)(short)HIWORD(l_param_)) * window::instance.yscale; return ((float)(short)HIWORD(l_param_)) * Window::Instance().GetContentScaleY();
} }
Point MouseEvent::GetPosition() const Point MouseEvent::GetPosition() const
{ {
return Point( return Point(
((float)(short)LOWORD(l_param_)) * window::instance.xscale, ((float)(short)LOWORD(l_param_)) * Window::Instance().GetContentScaleX(),
((float)(short)HIWORD(l_param_)) * window::instance.yscale ((float)(short)HIWORD(l_param_)) * Window::Instance().GetContentScaleY()
); );
} }

View File

@ -19,11 +19,11 @@
// THE SOFTWARE. // THE SOFTWARE.
#include "Music.h" #include "Music.h"
#include "Transcoder.h" #include "../utils/Transcoder.h"
#include "File.h" #include "../utils/File.h"
#include "../base/modules.h" #include "modules.h"
#include "../base/audio.h" #include "audio.h"
#include "../base/logs.h" #include "logs.h"
namespace easy2d namespace easy2d
{ {
@ -71,7 +71,7 @@ namespace easy2d
File music_file; File music_file;
if (!music_file.Open(file_path)) if (!music_file.Open(file_path))
{ {
E2D_WARNING("Media file not found."); logs::Trace(L"Media file not found.");
return false; return false;
} }
@ -80,12 +80,14 @@ namespace easy2d
String music_file_path = music_file.GetPath(); String music_file_path = music_file.GetPath();
Transcoder transcoder; Transcoder transcoder;
if (!transcoder.LoadMediaFile(music_file_path.c_str(), &wave_data_, &size_)) HRESULT hr = transcoder.LoadMediaFile(music_file_path.c_str(), &wave_data_, &size_);
if (FAILED(hr))
{ {
logs::Trace(L"Load media from file failed.", hr);
return false; return false;
} }
HRESULT hr = audio::instance.CreateVoice(&voice_, transcoder.GetWaveFormatEx()); hr = devices::Audio::Instance().CreateVoice(&voice_, transcoder.GetWaveFormatEx());
if (FAILED(hr)) if (FAILED(hr))
{ {
if (wave_data_) if (wave_data_)
@ -109,12 +111,15 @@ namespace easy2d
} }
Transcoder transcoder; Transcoder transcoder;
if (!transcoder.LoadMediaResource(res, &wave_data_, &size_)) HRESULT hr = transcoder.LoadMediaResource(res, &wave_data_, &size_);
if (FAILED(hr))
{ {
logs::Trace(L"Load media from resource failed.", hr);
return false; return false;
} }
HRESULT hr = audio::instance.CreateVoice(&voice_, transcoder.GetWaveFormatEx()); hr = devices::Audio::Instance().CreateVoice(&voice_, transcoder.GetWaveFormatEx());
if (FAILED(hr)) if (FAILED(hr))
{ {
if (wave_data_) if (wave_data_)
@ -134,48 +139,26 @@ namespace easy2d
{ {
if (!opened_) if (!opened_)
{ {
E2D_WARNING("Music must be opened first!"); logs::Trace(L"Music must be opened first!");
return false; return false;
} }
if (voice_ == nullptr) UINT32 buffers_queued = 0;
{ voice_.GetBuffersQueued(&buffers_queued);
E2D_WARNING("IXAudio2SourceVoice Null pointer exception!"); if (buffers_queued)
return false;
}
XAUDIO2_VOICE_STATE state;
voice_->GetState(&state);
if (state.BuffersQueued)
{
Stop(); Stop();
}
if (loop_count < 0) if (loop_count < 0)
{
loop_count = XAUDIO2_LOOP_INFINITE; loop_count = XAUDIO2_LOOP_INFINITE;
}
else else
{
loop_count = std::min(loop_count, XAUDIO2_LOOP_INFINITE - 1); loop_count = std::min(loop_count, XAUDIO2_LOOP_INFINITE - 1);
}
// Ìá½» wave Ñù±¾Êý¾Ý HRESULT hr = voice_.Play(wave_data_, size_, static_cast<UINT32>(loop_count));
XAUDIO2_BUFFER buffer = { 0 }; if (FAILED(hr))
buffer.pAudioData = wave_data_;
buffer.Flags = XAUDIO2_END_OF_STREAM;
buffer.AudioBytes = size_;
buffer.LoopCount = loop_count;
HRESULT hr;
if (FAILED(hr = voice_->SubmitSourceBuffer(&buffer)))
{ {
logs::Trace(L"Submitting source buffer error", hr); logs::Trace(L"Submitting source buffer error", hr);
return false;
} }
hr = voice_->Start(0);
playing_ = SUCCEEDED(hr); playing_ = SUCCEEDED(hr);
return playing_; return playing_;
@ -183,48 +166,25 @@ namespace easy2d
void Music::Pause() void Music::Pause()
{ {
if (voice_) if (SUCCEEDED(voice_.Pause()))
{ playing_ = false;
if (SUCCEEDED(voice_->Stop()))
{
playing_ = false;
}
}
} }
void Music::Resume() void Music::Resume()
{ {
if (voice_) if (SUCCEEDED(voice_.Resume()))
{ playing_ = true;
if (SUCCEEDED(voice_->Start()))
{
playing_ = true;
}
}
} }
void Music::Stop() void Music::Stop()
{ {
if (voice_) if (SUCCEEDED(voice_.Stop()))
{ playing_ = false;
if (SUCCEEDED(voice_->Stop()))
{
voice_->ExitLoop();
voice_->FlushSourceBuffers();
playing_ = false;
}
}
} }
void Music::Close() void Music::Close()
{ {
if (voice_) voice_.Destroy();
{
voice_->Stop();
voice_->FlushSourceBuffers();
voice_->DestroyVoice();
voice_ = nullptr;
}
if (wave_data_) if (wave_data_)
{ {
@ -238,11 +198,11 @@ namespace easy2d
bool Music::IsPlaying() const bool Music::IsPlaying() const
{ {
if (opened_ && voice_) if (opened_)
{ {
XAUDIO2_VOICE_STATE state; UINT32 buffers_queued = 0;
voice_->GetState(&state); voice_.GetBuffersQueued(&buffers_queued);
if (state.BuffersQueued && playing_) if (buffers_queued && playing_)
return true; return true;
} }
return false; return false;
@ -250,27 +210,13 @@ namespace easy2d
float Music::GetVolume() const float Music::GetVolume() const
{ {
if (voice_) float volume = 0.f;
{ voice_.GetVolume(&volume);
float volume = 0.f; return volume;
voice_->GetVolume(&volume);
return volume;
}
return 0.f;
} }
bool Music::SetVolume(float volume) bool Music::SetVolume(float volume)
{ {
if (voice_) return SUCCEEDED(voice_.SetVolume(volume));
{
volume = std::min(std::max(volume, -224.f), 224.f);
return SUCCEEDED(voice_->SetVolume(volume));
}
return false;
}
IXAudio2SourceVoice * Music::GetSourceVoice() const
{
return voice_;
} }
} }

View File

@ -19,9 +19,10 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include "../base/base.h" #include "base.h"
#include "../base/RefCounter.h" #include "audio.h"
#include "../base/Resource.h" #include "RefCounter.h"
#include "Resource.h"
#include <xaudio2.h> #include <xaudio2.h>
namespace easy2d namespace easy2d
@ -30,6 +31,8 @@ namespace easy2d
class Music class Music
: public RefCounter : public RefCounter
{ {
E2D_DISABLE_COPY(Music);
public: public:
Music(); Music();
@ -81,17 +84,11 @@ namespace easy2d
float volume /* 1 为原始音量, 大于 1 为放大音量, 0 为最小音量 */ float volume /* 1 为原始音量, 大于 1 为放大音量, 0 为最小音量 */
); );
// 获取 IXAudio2SourceVoice 对象
IXAudio2SourceVoice * GetSourceVoice() const;
protected: protected:
E2D_DISABLE_COPY(Music); bool opened_;
bool playing_;
protected: UINT32 size_;
bool opened_; BYTE* wave_data_;
bool playing_; Voice voice_;
UINT32 size_;
BYTE* wave_data_;
IXAudio2SourceVoice* voice_;
}; };
} }

View File

@ -77,12 +77,12 @@ namespace easy2d
if (clip_enabled_) if (clip_enabled_)
{ {
render::instance.PushClip(final_matrix_, transform_.size); devices::Graphics::Instance().PushClip(final_matrix_, transform_.size);
} }
if (children_.empty()) if (children_.empty())
{ {
render::instance.SetTransform(final_matrix_); devices::Graphics::Instance().SetTransform(final_matrix_);
OnDraw(); OnDraw();
} }
else else
@ -114,7 +114,7 @@ namespace easy2d
} }
} }
render::instance.SetTransform(final_matrix_); devices::Graphics::Instance().SetTransform(final_matrix_);
OnDraw(); OnDraw();
// 访问剩余节点 // 访问剩余节点
@ -124,7 +124,7 @@ namespace easy2d
if (clip_enabled_) if (clip_enabled_)
{ {
render::instance.PopClip(); devices::Graphics::Instance().PopClip();
} }
} }
@ -171,7 +171,7 @@ namespace easy2d
{ {
if (border_) if (border_)
{ {
render::instance.DrawGeometry(border_, border_color_, 1.f, 1.5f); devices::Graphics::Instance().DrawGeometry(border_, border_color_, 1.f, 1.5f);
} }
for (const auto& child : children_) for (const auto& child : children_)
@ -212,7 +212,7 @@ namespace easy2d
SafeRelease(border_); SafeRelease(border_);
ThrowIfFailed( ThrowIfFailed(
render::instance.CreateRectGeometry(final_matrix_, transform_.size, &border_) devices::Graphics::Instance().CreateRectGeometry(final_matrix_, transform_.size, &border_)
); );
// 通知子节点进行转换 // 通知子节点进行转换

View File

@ -40,6 +40,8 @@ namespace easy2d
friend class Game; friend class Game;
friend class Scene; friend class Scene;
E2D_DISABLE_COPY(Node);
public: public:
typedef std::vector<Node*> Nodes; typedef std::vector<Node*> Nodes;
typedef std::vector<Action*> Actions; typedef std::vector<Action*> Actions;
@ -418,8 +420,6 @@ namespace easy2d
); );
private: private:
E2D_DISABLE_COPY(Node);
// 渲染节点边缘 // 渲染节点边缘
void DrawBorder(); void DrawBorder();

View File

@ -19,7 +19,8 @@
// THE SOFTWARE. // THE SOFTWARE.
#pragma once #pragma once
#include "BaseTypes.h" #include "../math/vector.hpp"
#include "Size.h"
#include <d2d1.h> #include <d2d1.h>
namespace easy2d namespace easy2d
@ -34,9 +35,11 @@ namespace easy2d
// //
class Rect class Rect
{ {
using Point = math::Vector2;
public: public:
Point origin; // 左上角坐标 Point origin; // 左上角坐标
Size size; // 宽度和高度 Size size; // 宽度和高度
public: public:
Rect() {} Rect() {}

View File

@ -32,6 +32,8 @@ namespace easy2d
class Scene class Scene
: public RefCounter : public RefCounter
{ {
E2D_DISABLE_COPY(Scene);
public: public:
Scene(); Scene();
@ -79,9 +81,6 @@ namespace easy2d
// »ñȡת»»¾ØÕó // »ñȡת»»¾ØÕó
const math::Matrix& GetTransform() const; const math::Matrix& GetTransform() const;
private:
E2D_DISABLE_COPY(Scene);
private: private:
Node* root_; Node* root_;
math::Matrix transform_; math::Matrix transform_;

77
core/base/Singleton.hpp Normal file
View File

@ -0,0 +1,77 @@
// Copyright (c) 2016-2018 Easy2D - Nomango
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma once
#include <memory>
namespace easy2d
{
template <typename T>
class ISingleton
{
public:
static inline T& Instance();
static inline void Destroy();
private:
ISingleton() {}
~ISingleton() {}
ISingleton(const ISingleton&) = delete;
ISingleton & operator= (const ISingleton &) = delete;
static std::unique_ptr<T> instance_;
};
template<typename T>
inline T & easy2d::ISingleton<T>::Instance()
{
if (!instance_)
instance_.reset(new (std::nothrow) T);
return *instance_;
}
template<typename T>
inline void easy2d::ISingleton<T>::Destroy()
{
if (instance_)
instance_.reset();
}
template<typename T>
std::unique_ptr<T> easy2d::ISingleton<T>::instance_;
}
// Class that will implement the singleton mode,
// must use the macro in it's delare file
#ifndef E2D_DECLARE_SINGLETON
#define E2D_DECLARE_SINGLETON( type ) \
friend class ::std::unique_ptr< type >; \
friend struct ::std::default_delete< type >;\
friend class ::easy2d::ISingleton< type >
#endif
#ifndef E2D_DECLARE_SINGLETON_TYPE
#define E2D_DECLARE_SINGLETON_TYPE( type, singleton_type ) using singleton_type = ::easy2d::ISingleton< type >
#endif

View File

@ -135,7 +135,7 @@ namespace easy2d
if (image_ && image_->GetBitmap()) if (image_ && image_->GetBitmap())
{ {
auto crop_pos = image_->GetCropPos(); auto crop_pos = image_->GetCropPos();
render::instance.DrawImage( devices::Graphics::Instance().DrawImage(
image_, image_,
GetDisplayOpacity(), GetDisplayOpacity(),
Rect(Point(), GetTransform().size), Rect(Point(), GetTransform().size),

View File

@ -28,6 +28,8 @@ namespace easy2d
class Sprite class Sprite
: public Node : public Node
{ {
E2D_DISABLE_COPY(Sprite);
public: public:
Sprite(); Sprite();
@ -81,9 +83,6 @@ namespace easy2d
// äÖČžžŤÁé // äÖČžžŤÁé
virtual void OnDraw() const override; virtual void OnDraw() const override;
private:
E2D_DISABLE_COPY(Sprite);
private: private:
Image* image_; Image* image_;
}; };

View File

@ -318,16 +318,16 @@ namespace easy2d
// 创建文本区域 // 创建文本区域
D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, GetTransform().size.width, GetTransform().size.height); D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, GetTransform().size.width, GetTransform().size.height);
// 设置画刷颜色和透明度 // 设置画刷颜色和透明度
render::instance.SetBrushOpacity(GetDisplayOpacity()); devices::Graphics::Instance().SetBrushOpacity(GetDisplayOpacity());
// 获取文本渲染器 // 获取文本渲染器
render::instance.SetTextStyle( devices::Graphics::Instance().SetTextStyle(
style_.color, style_.color,
style_.outline, style_.outline,
style_.outline_color, style_.outline_color,
style_.outline_width, style_.outline_width,
style_.outline_stroke style_.outline_stroke
); );
render::instance.DrawTextLayout(text_layout_); devices::Graphics::Instance().DrawTextLayout(text_layout_);
} }
} }
@ -344,7 +344,7 @@ namespace easy2d
SafeRelease(text_format_); SafeRelease(text_format_);
ThrowIfFailed( ThrowIfFailed(
render::instance.CreateTextFormat( devices::Graphics::Instance().CreateTextFormat(
&text_format_, &text_format_,
font_ font_
) )
@ -399,7 +399,7 @@ namespace easy2d
if (style_.wrap) if (style_.wrap)
{ {
ThrowIfFailed( ThrowIfFailed(
render::instance.CreateTextLayout( devices::Graphics::Instance().CreateTextLayout(
&text_layout_, &text_layout_,
text_, text_,
text_format_, text_format_,
@ -416,7 +416,7 @@ namespace easy2d
{ {
// 为防止文本对齐问题,根据先创建 layout 以获取宽度 // 为防止文本对齐问题,根据先创建 layout 以获取宽度
ThrowIfFailed( ThrowIfFailed(
render::instance.CreateTextLayout( devices::Graphics::Instance().CreateTextLayout(
&text_layout_, &text_layout_,
text_, text_,
text_format_, text_format_,
@ -433,7 +433,7 @@ namespace easy2d
// 重新创建 layout // 重新创建 layout
SafeRelease(text_layout_); SafeRelease(text_layout_);
ThrowIfFailed( ThrowIfFailed(
render::instance.CreateTextLayout( devices::Graphics::Instance().CreateTextLayout(
&text_layout_, &text_layout_,
text_, text_,
text_format_, text_format_,

View File

@ -28,6 +28,8 @@ namespace easy2d
class Text class Text
: public Node : public Node
{ {
E2D_DISABLE_COPY(Text);
public: public:
// 文本对齐方式 // 文本对齐方式
enum class Align enum class Align
@ -221,8 +223,6 @@ namespace easy2d
virtual void OnDraw() const override; virtual void OnDraw() const override;
private: private:
E2D_DISABLE_COPY(Text);
// 重新排版文字 // 重新排版文字
void Reset(); void Reset();

View File

@ -73,7 +73,7 @@ namespace easy2d
bShowOutline_ = outline; bShowOutline_ = outline;
sOutlineColor_ = outline_color; sOutlineColor_ = outline_color;
fOutlineWidth = 2 * outline_width; fOutlineWidth = 2 * outline_width;
pCurrStrokeStyle_ = render::instance.GetStrokeStyle(StrokeStyle(outlineJoin)); pCurrStrokeStyle_ = devices::Graphics::Instance().GetStrokeStyle(StrokeStyle(outlineJoin));
} }
STDMETHODIMP ITextRenderer::DrawGlyphRun( STDMETHODIMP ITextRenderer::DrawGlyphRun(

View File

@ -22,6 +22,7 @@
#include "Node.h" #include "Node.h"
#include "Scene.h" #include "Scene.h"
#include "window.h" #include "window.h"
#include "render.h"
#include "../math/Matrix.hpp" #include "../math/Matrix.hpp"
namespace easy2d namespace easy2d
@ -73,22 +74,19 @@ namespace easy2d
if (in_scene_) if (in_scene_)
{ {
ThrowIfFailed( ThrowIfFailed(
render::instance.CreateLayer(&in_layer_) devices::Graphics::Instance().CreateLayer(&in_layer_)
); );
} }
if (out_scene_) if (out_scene_)
{ {
ThrowIfFailed( ThrowIfFailed(
render::instance.CreateLayer(&out_layer_) devices::Graphics::Instance().CreateLayer(&out_layer_)
); );
} }
window_size_ = window::instance.GetSize(); window_size_ = Window::Instance().GetSize();
out_layer_prop_ = in_layer_prop_ = render::LayerProperties{ out_layer_prop_ = in_layer_prop_ = LayerProperties{ Rect(Point(), window_size_),1.f };
Rect(Point(), window_size_),
1.f
};
} }
void Transition::Update() void Transition::Update()
@ -113,30 +111,30 @@ namespace easy2d
{ {
if (out_scene_) if (out_scene_)
{ {
render::instance.PushClip( devices::Graphics::Instance().PushClip(
out_scene_->GetTransform(), out_scene_->GetTransform(),
window_size_ window_size_
); );
render::instance.PushLayer(out_layer_, out_layer_prop_); devices::Graphics::Instance().PushLayer(out_layer_, out_layer_prop_);
out_scene_->Draw(); out_scene_->Draw();
render::instance.PopLayer(); devices::Graphics::Instance().PopLayer();
render::instance.PopClip(); devices::Graphics::Instance().PopClip();
} }
if (in_scene_) if (in_scene_)
{ {
render::instance.PushClip( devices::Graphics::Instance().PushClip(
in_scene_->GetTransform(), in_scene_->GetTransform(),
window_size_ window_size_
); );
render::instance.PushLayer(in_layer_, in_layer_prop_); devices::Graphics::Instance().PushLayer(in_layer_, in_layer_prop_);
in_scene_->Draw(); in_scene_->Draw();
render::instance.PopLayer(); devices::Graphics::Instance().PopLayer();
render::instance.PopClip(); devices::Graphics::Instance().PopClip();
} }
} }

View File

@ -21,7 +21,6 @@
#pragma once #pragma once
#include "base.h" #include "base.h"
#include "time.h" #include "time.h"
#include "render.h"
#include "RefCounter.h" #include "RefCounter.h"
namespace easy2d namespace easy2d
@ -75,8 +74,8 @@ namespace easy2d
Scene* in_scene_; Scene* in_scene_;
ID2D1Layer* out_layer_; ID2D1Layer* out_layer_;
ID2D1Layer* in_layer_; ID2D1Layer* in_layer_;
render::LayerProperties out_layer_prop_; LayerProperties out_layer_prop_;
render::LayerProperties in_layer_prop_; LayerProperties in_layer_prop_;
}; };

View File

@ -27,18 +27,161 @@
namespace easy2d namespace easy2d
{ {
namespace audio //-------------------------------------------------------
// Voice
//-------------------------------------------------------
Voice::Voice()
: source_voice_(nullptr)
{ {
AudioDevice instance; }
Voice::Voice(IXAudio2SourceVoice * source_voice)
: source_voice_(source_voice)
{
}
Voice::~Voice()
{
Destroy();
devices::Audio::Instance().DeleteVoice(this);
}
HRESULT Voice::Play(const BYTE * wave_data, UINT32 data_size, UINT32 loop_count)
{
if (!source_voice_)
return E_UNEXPECTED;
XAUDIO2_BUFFER buffer = { 0 };
buffer.pAudioData = wave_data;
buffer.Flags = XAUDIO2_END_OF_STREAM;
buffer.AudioBytes = data_size;
buffer.LoopCount = loop_count;
HRESULT hr = source_voice_->SubmitSourceBuffer(&buffer);
if (SUCCEEDED(hr))
{
hr = source_voice_->Start();
}
return hr;
}
HRESULT Voice::Pause()
{
if (!source_voice_)
return E_UNEXPECTED;
return source_voice_->Stop();
}
HRESULT Voice::Resume()
{
if (!source_voice_)
return E_UNEXPECTED;
return source_voice_->Start();
}
HRESULT Voice::Stop()
{
if (!source_voice_)
return E_UNEXPECTED;
HRESULT hr = source_voice_->Stop();
if (SUCCEEDED(hr))
{
hr = source_voice_->ExitLoop();
}
if (SUCCEEDED(hr))
{
hr = source_voice_->FlushSourceBuffers();
}
return hr;
}
HRESULT Voice::GetVolume(float * volume) const
{
if (!source_voice_)
return E_UNEXPECTED;
if (volume == nullptr)
return E_POINTER;
source_voice_->GetVolume(volume);
return S_OK;
}
HRESULT Voice::SetVolume(float volume)
{
if (!source_voice_)
return E_UNEXPECTED;
volume = std::min(std::max(volume, -224.f), 224.f);
return source_voice_->SetVolume(volume);
}
HRESULT Voice::GetBuffersQueued(UINT32 * queued) const
{
if (!source_voice_)
return E_UNEXPECTED;
if (queued == nullptr)
return E_POINTER;
XAUDIO2_VOICE_STATE state;
source_voice_->GetState(&state);
*queued = state.BuffersQueued;
return S_OK;
}
void Voice::Destroy()
{
if (source_voice_)
{
source_voice_->Stop();
source_voice_->FlushSourceBuffers();
source_voice_->DestroyVoice();
source_voice_ = nullptr;
}
}
void Voice::SetSourceVoice(IXAudio2SourceVoice * source_voice)
{
Destroy();
source_voice_ = source_voice;
}
namespace devices
{
//-------------------------------------------------------
// AudioDevice
//-------------------------------------------------------
AudioDevice::AudioDevice() AudioDevice::AudioDevice()
: x_audio2_(nullptr) : x_audio2_(nullptr)
, mastering_voice_(nullptr) , mastering_voice_(nullptr)
{ {
modules::Initialize();
} }
AudioDevice::~AudioDevice() AudioDevice::~AudioDevice()
{ {
ClearVoiceCache();
if (mastering_voice_)
{
mastering_voice_->DestroyVoice();
mastering_voice_ = nullptr;
}
SafeRelease(x_audio2_);
modules::MediaFoundation.MFShutdown();
modules::Destroy();
} }
void AudioDevice::Initialize() void AudioDevice::Initialize()
@ -56,22 +199,42 @@ namespace easy2d
); );
} }
void AudioDevice::Uninitialize() HRESULT AudioDevice::CreateVoice(Voice* voice, WAVEFORMATEX * wfx)
{ {
if (mastering_voice_) HRESULT hr;
IXAudio2SourceVoice* source_voice;
if (!voice)
return E_POINTER;
hr = x_audio2_->CreateSourceVoice(&source_voice, wfx, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
if (SUCCEEDED(hr))
{ {
mastering_voice_->DestroyVoice(); voice->SetSourceVoice(source_voice);
mastering_voice_ = nullptr; voice_cache_.push_back(voice);
} }
return hr;
SafeRelease(x_audio2_);
modules::MediaFoundation.MFShutdown();
} }
HRESULT AudioDevice::CreateVoice(IXAudio2SourceVoice ** voice, WAVEFORMATEX * wfx) void AudioDevice::DeleteVoice(Voice * voice)
{ {
return x_audio2_->CreateSourceVoice(voice, wfx, 0, XAUDIO2_DEFAULT_FREQ_RATIO); for (auto iter = voice_cache_.begin(); iter != voice_cache_.end(); ++iter)
{
if (*iter == voice)
{
voice_cache_.erase(iter);
break;
}
}
}
void AudioDevice::ClearVoiceCache()
{
for (auto voice : voice_cache_)
{
voice->Destroy();
}
voice_cache_.clear();
} }
void AudioDevice::Open() void AudioDevice::Open()

View File

@ -20,41 +20,97 @@
#pragma once #pragma once
#include "macros.h" #include "macros.h"
#include "Singleton.hpp"
#include <xaudio2.h> #include <xaudio2.h>
namespace easy2d namespace easy2d
{ {
namespace audio class Voice
{
E2D_DISABLE_COPY(Voice);
public:
Voice();
Voice(
IXAudio2SourceVoice* source_voice
);
~Voice();
HRESULT Play(
const BYTE* wave_data,
UINT32 data_size,
UINT32 loop_count
);
HRESULT Pause();
HRESULT Resume();
HRESULT Stop();
HRESULT GetVolume(
float* volume
) const;
HRESULT SetVolume(
float volume
);
HRESULT GetBuffersQueued(
UINT32* queued
) const;
void Destroy();
void SetSourceVoice(
IXAudio2SourceVoice* source_voice
);
protected:
IXAudio2SourceVoice* source_voice_;
};
namespace devices
{ {
// 音频设备
class AudioDevice class AudioDevice
{ {
E2D_DECLARE_SINGLETON(AudioDevice);
E2D_DISABLE_COPY(AudioDevice);
public: public:
AudioDevice();
~AudioDevice();
void Initialize(); void Initialize();
void Uninitialize();
// 开启设备 // 开启设备
void Open(); void Open();
// 关闭设备 // 关闭设备
void Close(); void Close();
// 创建音源
HRESULT CreateVoice( HRESULT CreateVoice(
IXAudio2SourceVoice ** voice, Voice* voice,
WAVEFORMATEX * wfx WAVEFORMATEX * wfx
); );
void DeleteVoice(
Voice* voice
);
void ClearVoiceCache();
protected:
AudioDevice();
~AudioDevice();
protected: protected:
IXAudio2 * x_audio2_; IXAudio2 * x_audio2_;
IXAudio2MasteringVoice* mastering_voice_; IXAudio2MasteringVoice* mastering_voice_;
std::list<Voice*> voice_cache_;
}; };
extern AudioDevice instance; E2D_DECLARE_SINGLETON_TYPE(AudioDevice, Audio);
} }
} }

View File

@ -20,7 +20,6 @@
#pragma once #pragma once
#include "BaseTypes.h" #include "BaseTypes.h"
#include "Rect.hpp"
#include <stdexcept> #include <stdexcept>
namespace easy2d namespace easy2d

View File

@ -80,6 +80,7 @@
#include <list> #include <list>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include <memory>
#if VS_VER >= VS_2015 #if VS_VER >= VS_2015
@ -89,9 +90,10 @@
#endif #endif
#define E2D_DISABLE_COPY(Class) \ #define E2D_DISABLE_COPY(Class) \
Class(const Class &) = delete; \ private: \
Class & operator= (const Class &) = delete Class(const Class &) = delete; \
Class & operator= (const Class &) = delete
#if defined( DEBUG ) || defined( _DEBUG ) #if defined( DEBUG ) || defined( _DEBUG )

View File

@ -26,6 +26,8 @@ namespace easy2d
{ {
namespace namespace
{ {
int initialize_count = 0;
inline void SafeFreeLibrary(HMODULE instance) inline void SafeFreeLibrary(HMODULE instance)
{ {
if (instance) if (instance)
@ -38,6 +40,10 @@ namespace easy2d
void Initialize() void Initialize()
{ {
initialize_count++;
if (initialize_count > 1)
return;
const auto xaudio2_dll_names = const auto xaudio2_dll_names =
{ {
L"xaudio2_9.dll", L"xaudio2_9.dll",
@ -86,8 +92,12 @@ namespace easy2d
} }
} }
void Uninitialize() void Destroy()
{ {
initialize_count--;
if (initialize_count > 0)
return;
SafeFreeLibrary(XAudio2.instance); SafeFreeLibrary(XAudio2.instance);
SafeFreeLibrary(MediaFoundation.mfplat); SafeFreeLibrary(MediaFoundation.mfplat);
SafeFreeLibrary(MediaFoundation.mfreadwrite); SafeFreeLibrary(MediaFoundation.mfreadwrite);

View File

@ -29,6 +29,12 @@ namespace easy2d
{ {
namespace modules namespace modules
{ {
// modules can be initialized multiple times,
// but it needs to be destroyed every time
void Initialize();
void Destroy();
// XAudio2 functions // XAudio2 functions
typedef HRESULT(WINAPI *PFN_XAudio2Create)(IXAudio2**, UINT32, XAUDIO2_PROCESSOR); typedef HRESULT(WINAPI *PFN_XAudio2Create)(IXAudio2**, UINT32, XAUDIO2_PROCESSOR);
@ -66,13 +72,5 @@ namespace easy2d
}; };
extern Module_MediaFoundation MediaFoundation; extern Module_MediaFoundation MediaFoundation;
//
// Functions
//
void Initialize();
void Uninitialize();
} }
} }

View File

@ -21,6 +21,7 @@
#include "render.h" #include "render.h"
#include "time.h" #include "time.h"
#include "base.h" #include "base.h"
#include "modules.h"
#pragma comment(lib, "d2d1.lib") #pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "dwrite.lib") #pragma comment(lib, "dwrite.lib")
@ -28,33 +29,49 @@
namespace easy2d namespace easy2d
{ {
namespace render namespace devices
{ {
GraphicsDevice instance;
GraphicsDevice::GraphicsDevice() GraphicsDevice::GraphicsDevice()
: fps_text_format_(nullptr) : fps_text_format_(nullptr)
, fps_text_layout_(nullptr) , fps_text_layout_(nullptr)
, clear_color_(D2D1::ColorF(D2D1::ColorF::Black)) , clear_color_(D2D1::ColorF(D2D1::ColorF::Black))
{ {
ZeroMemory(&d2d, sizeof(D2DResources)); ZeroMemory(&d2d, sizeof(D2DResources));
modules::Initialize();
} }
GraphicsDevice::~GraphicsDevice() GraphicsDevice::~GraphicsDevice()
{ {
ClearImageCache();
SafeRelease(fps_text_format_); SafeRelease(fps_text_format_);
SafeRelease(fps_text_layout_); SafeRelease(fps_text_layout_);
SafeRelease(d2d.text_renderer);
SafeRelease(d2d.solid_brush);
SafeRelease(d2d.render_target);
SafeRelease(d2d.miter_stroke_style);
SafeRelease(d2d.bevel_stroke_style);
SafeRelease(d2d.round_stroke_style);
SafeRelease(d2d.imaging_factory);
SafeRelease(d2d.write_factory);
SafeRelease(d2d.factory);
modules::Destroy();
} }
void GraphicsDevice::Initialize(HWND hwnd) void GraphicsDevice::Initialize(HWND hwnd)
{ {
if (d2d.Factory) if (d2d.factory)
return; return;
ThrowIfFailed( ThrowIfFailed(
D2D1CreateFactory( D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED, D2D1_FACTORY_TYPE_SINGLE_THREADED,
&d2d.Factory &d2d.factory
) )
); );
@ -64,7 +81,7 @@ namespace easy2d
nullptr, nullptr,
CLSCTX_INPROC_SERVER, CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory, IID_IWICImagingFactory,
reinterpret_cast<void**>(&d2d.WICImagingFactory) reinterpret_cast<void**>(&d2d.imaging_factory)
) )
); );
@ -72,7 +89,7 @@ namespace easy2d
DWriteCreateFactory( DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED, DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory), __uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&d2d.DWriteFactory) reinterpret_cast<IUnknown**>(&d2d.write_factory)
) )
); );
@ -87,65 +104,50 @@ namespace easy2d
); );
ThrowIfFailed( ThrowIfFailed(
d2d.Factory->CreateStrokeStyle( d2d.factory->CreateStrokeStyle(
stroke_style, stroke_style,
nullptr, nullptr,
0, 0,
&d2d.MiterStrokeStyle &d2d.miter_stroke_style
) )
); );
stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL; stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL;
ThrowIfFailed( ThrowIfFailed(
d2d.Factory->CreateStrokeStyle( d2d.factory->CreateStrokeStyle(
stroke_style, stroke_style,
nullptr, nullptr,
0, 0,
&d2d.BevelStrokeStyle &d2d.bevel_stroke_style
) )
); );
stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND; stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND;
ThrowIfFailed( ThrowIfFailed(
d2d.Factory->CreateStrokeStyle( d2d.factory->CreateStrokeStyle(
stroke_style, stroke_style,
nullptr, nullptr,
0, 0,
&d2d.RoundStrokeStyle &d2d.round_stroke_style
) )
); );
CreateDeviceResources(hwnd); CreateDeviceResources(hwnd);
} }
void GraphicsDevice::Uninitialize()
{
SafeRelease(d2d.TextRenderer);
SafeRelease(d2d.SolidColorBrush);
SafeRelease(d2d.HwndRenderTarget);
SafeRelease(d2d.MiterStrokeStyle);
SafeRelease(d2d.BevelStrokeStyle);
SafeRelease(d2d.RoundStrokeStyle);
SafeRelease(d2d.WICImagingFactory);
SafeRelease(d2d.DWriteFactory);
SafeRelease(d2d.Factory);
}
void GraphicsDevice::BeginDraw(HWND hwnd) void GraphicsDevice::BeginDraw(HWND hwnd)
{ {
CreateDeviceResources(hwnd); CreateDeviceResources(hwnd);
d2d.HwndRenderTarget->BeginDraw(); d2d.render_target->BeginDraw();
d2d.HwndRenderTarget->Clear(clear_color_); d2d.render_target->Clear(clear_color_);
} }
void GraphicsDevice::EndDraw() void GraphicsDevice::EndDraw()
{ {
HRESULT hr = d2d.HwndRenderTarget->EndDraw(); HRESULT hr = d2d.render_target->EndDraw();
if (hr == D2DERR_RECREATE_TARGET) if (hr == D2DERR_RECREATE_TARGET)
{ {
@ -155,36 +157,48 @@ namespace easy2d
SafeRelease(fps_text_format_); SafeRelease(fps_text_format_);
SafeRelease(fps_text_layout_); SafeRelease(fps_text_layout_);
SafeRelease(d2d.TextRenderer); SafeRelease(d2d.text_renderer);
SafeRelease(d2d.SolidColorBrush); SafeRelease(d2d.solid_brush);
SafeRelease(d2d.HwndRenderTarget); SafeRelease(d2d.render_target);
} }
ThrowIfFailed(hr); ThrowIfFailed(hr);
} }
void GraphicsDevice::ClearImageCache()
{
if (bitmap_cache_.empty())
return;
for (const auto& bitmap : bitmap_cache_)
{
bitmap.second->Release();
}
bitmap_cache_.clear();
}
HRESULT GraphicsDevice::CreateRectGeometry( HRESULT GraphicsDevice::CreateRectGeometry(
const math::Matrix& matrix, const math::Matrix& matrix,
const Size& size, const Size& size,
ID2D1Geometry** geometry ID2D1Geometry** geometry
) const ) const
{ {
if (!d2d.Factory) if (!d2d.factory)
return E_UNEXPECTED; return E_UNEXPECTED;
HRESULT hr; HRESULT hr;
ID2D1RectangleGeometry * rectangle = nullptr; ID2D1RectangleGeometry * rectangle = nullptr;
ID2D1TransformedGeometry * transformed = nullptr; ID2D1TransformedGeometry * transformed = nullptr;
hr = d2d.Factory->CreateRectangleGeometry( hr = d2d.factory->CreateRectangleGeometry(
D2D1::RectF(0, 0, size.width, size.height), D2D1::RectF(0, 0, size.width, size.height),
&rectangle &rectangle
); );
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = d2d.Factory->CreateTransformedGeometry( hr = d2d.factory->CreateTransformedGeometry(
rectangle, rectangle,
matrix, matrix,
&transformed &transformed
@ -202,10 +216,10 @@ namespace easy2d
HRESULT GraphicsDevice::CreateTextFormat(IDWriteTextFormat ** text_format, const Font & font) const HRESULT GraphicsDevice::CreateTextFormat(IDWriteTextFormat ** text_format, const Font & font) const
{ {
if (!d2d.DWriteFactory) if (!d2d.write_factory)
return E_UNEXPECTED; return E_UNEXPECTED;
return d2d.DWriteFactory->CreateTextFormat( return d2d.write_factory->CreateTextFormat(
font.family.c_str(), font.family.c_str(),
nullptr, nullptr,
DWRITE_FONT_WEIGHT(font.weight), DWRITE_FONT_WEIGHT(font.weight),
@ -219,11 +233,11 @@ namespace easy2d
HRESULT GraphicsDevice::CreateTextLayout(IDWriteTextLayout ** text_layout, const String & text, IDWriteTextFormat * text_format, float wrap_width) const HRESULT GraphicsDevice::CreateTextLayout(IDWriteTextLayout ** text_layout, const String & text, IDWriteTextFormat * text_format, float wrap_width) const
{ {
if (!d2d.DWriteFactory) if (!d2d.write_factory)
return E_UNEXPECTED; return E_UNEXPECTED;
UINT32 length = static_cast<UINT32>(text.length()); UINT32 length = static_cast<UINT32>(text.length());
return d2d.DWriteFactory->CreateTextLayout( return d2d.write_factory->CreateTextLayout(
text.c_str(), text.c_str(),
length, length,
text_format, text_format,
@ -235,10 +249,10 @@ namespace easy2d
HRESULT GraphicsDevice::CreateLayer(ID2D1Layer ** layer) HRESULT GraphicsDevice::CreateLayer(ID2D1Layer ** layer)
{ {
if (!d2d.HwndRenderTarget) if (!d2d.render_target)
return E_UNEXPECTED; return E_UNEXPECTED;
return d2d.HwndRenderTarget->CreateLayer(layer); return d2d.render_target->CreateLayer(layer);
} }
HRESULT GraphicsDevice::DrawGeometry( HRESULT GraphicsDevice::DrawGeometry(
@ -249,15 +263,15 @@ namespace easy2d
StrokeStyle stroke StrokeStyle stroke
) )
{ {
if (!d2d.SolidColorBrush || if (!d2d.solid_brush ||
!d2d.HwndRenderTarget) !d2d.render_target)
return E_UNEXPECTED; return E_UNEXPECTED;
d2d.SolidColorBrush->SetColor(border_color); d2d.solid_brush->SetColor(border_color);
d2d.SolidColorBrush->SetOpacity(opacity); d2d.solid_brush->SetOpacity(opacity);
d2d.HwndRenderTarget->DrawGeometry( d2d.render_target->DrawGeometry(
geometry, geometry,
d2d.SolidColorBrush, d2d.solid_brush,
stroke_width, stroke_width,
GetStrokeStyle(stroke) GetStrokeStyle(stroke)
); );
@ -270,13 +284,13 @@ namespace easy2d
switch (stroke) switch (stroke)
{ {
case StrokeStyle::Miter: case StrokeStyle::Miter:
stroke_style = d2d.MiterStrokeStyle; stroke_style = d2d.miter_stroke_style;
break; break;
case StrokeStyle::Bevel: case StrokeStyle::Bevel:
stroke_style = d2d.BevelStrokeStyle; stroke_style = d2d.bevel_stroke_style;
break; break;
case StrokeStyle::Round: case StrokeStyle::Round:
stroke_style = d2d.RoundStrokeStyle; stroke_style = d2d.round_stroke_style;
break; break;
} }
return stroke_style; return stroke_style;
@ -289,10 +303,10 @@ namespace easy2d
const Rect & source_rect const Rect & source_rect
) )
{ {
if (!d2d.HwndRenderTarget) if (!d2d.render_target)
return E_UNEXPECTED; return E_UNEXPECTED;
d2d.HwndRenderTarget->DrawBitmap( d2d.render_target->DrawBitmap(
image->GetBitmap(), image->GetBitmap(),
dest_rect, dest_rect,
opacity, opacity,
@ -304,19 +318,19 @@ namespace easy2d
HRESULT GraphicsDevice::DrawTextLayout(IDWriteTextLayout * text_layout) HRESULT GraphicsDevice::DrawTextLayout(IDWriteTextLayout * text_layout)
{ {
if (!d2d.TextRenderer) if (!d2d.text_renderer)
return E_UNEXPECTED; return E_UNEXPECTED;
return text_layout->Draw(nullptr, d2d.TextRenderer, 0, 0); return text_layout->Draw(nullptr, d2d.text_renderer, 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 (!d2d.HwndRenderTarget) if (!d2d.render_target)
return E_UNEXPECTED; return E_UNEXPECTED;
d2d.HwndRenderTarget->SetTransform(clip_matrix); d2d.render_target->SetTransform(clip_matrix);
d2d.HwndRenderTarget->PushAxisAlignedClip( d2d.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
); );
@ -325,27 +339,27 @@ namespace easy2d
HRESULT GraphicsDevice::PopClip() HRESULT GraphicsDevice::PopClip()
{ {
if (!d2d.HwndRenderTarget) if (!d2d.render_target)
return E_UNEXPECTED; return E_UNEXPECTED;
d2d.HwndRenderTarget->PopAxisAlignedClip(); d2d.render_target->PopAxisAlignedClip();
return S_OK; return S_OK;
} }
HRESULT GraphicsDevice::PushLayer(ID2D1Layer * layer, LayerProperties properties) HRESULT GraphicsDevice::PushLayer(ID2D1Layer * layer, LayerProperties properties)
{ {
if (!d2d.HwndRenderTarget || if (!d2d.render_target ||
!d2d.SolidColorBrush) !d2d.solid_brush)
return E_UNEXPECTED; return E_UNEXPECTED;
d2d.HwndRenderTarget->PushLayer( d2d.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,
d2d.SolidColorBrush, d2d.solid_brush,
D2D1_LAYER_OPTIONS_NONE D2D1_LAYER_OPTIONS_NONE
), ),
layer layer
@ -355,17 +369,17 @@ namespace easy2d
HRESULT GraphicsDevice::PopLayer() HRESULT GraphicsDevice::PopLayer()
{ {
if (!d2d.HwndRenderTarget) if (!d2d.render_target)
return E_UNEXPECTED; return E_UNEXPECTED;
d2d.HwndRenderTarget->PopLayer(); d2d.render_target->PopLayer();
return S_OK; return S_OK;
} }
HRESULT GraphicsDevice::CreateBitmapFromFile(const String & file_path, ID2D1Bitmap ** bitmap) HRESULT GraphicsDevice::CreateBitmapFromFile(const String & file_path, ID2D1Bitmap ** bitmap)
{ {
if (d2d.WICImagingFactory == nullptr || if (d2d.imaging_factory == nullptr ||
d2d.HwndRenderTarget == nullptr) d2d.render_target == nullptr)
{ {
return E_UNEXPECTED; return E_UNEXPECTED;
} }
@ -375,13 +389,20 @@ namespace easy2d
return E_POINTER; return E_POINTER;
} }
size_t hash_code = std::hash<String>{}(file_path);
if (bitmap_cache_.find(hash_code) != bitmap_cache_.end())
{
*bitmap = bitmap_cache_[hash_code];
return S_OK;
}
IWICBitmapDecoder* decoder = nullptr; IWICBitmapDecoder* decoder = nullptr;
IWICBitmapFrameDecode* source = nullptr; IWICBitmapFrameDecode* source = nullptr;
IWICStream* stream = nullptr; IWICStream* stream = nullptr;
IWICFormatConverter* converter = nullptr; IWICFormatConverter* converter = nullptr;
// 创建解码器 // 创建解码器
HRESULT hr = d2d.WICImagingFactory->CreateDecoderFromFilename( HRESULT hr = d2d.imaging_factory->CreateDecoderFromFilename(
file_path.c_str(), file_path.c_str(),
nullptr, nullptr,
GENERIC_READ, GENERIC_READ,
@ -398,7 +419,7 @@ namespace easy2d
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
// 创建图片格式转换器 // 创建图片格式转换器
hr = d2d.WICImagingFactory->CreateFormatConverter(&converter); hr = d2d.imaging_factory->CreateFormatConverter(&converter);
} }
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
@ -417,13 +438,18 @@ namespace easy2d
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
// 从 WIC 位图创建一个 Direct2D 位图 // 从 WIC 位图创建一个 Direct2D 位图
hr = d2d.HwndRenderTarget->CreateBitmapFromWicBitmap( hr = d2d.render_target->CreateBitmapFromWicBitmap(
converter, converter,
nullptr, nullptr,
bitmap bitmap
); );
} }
if (SUCCEEDED(hr))
{
bitmap_cache_.insert(std::make_pair(hash_code, *bitmap));
}
// 释放相关资源 // 释放相关资源
SafeRelease(decoder); SafeRelease(decoder);
SafeRelease(source); SafeRelease(source);
@ -435,8 +461,8 @@ namespace easy2d
HRESULT GraphicsDevice::CreateBitmapFromResource(Resource & res, ID2D1Bitmap ** bitmap) HRESULT GraphicsDevice::CreateBitmapFromResource(Resource & res, ID2D1Bitmap ** bitmap)
{ {
if (d2d.WICImagingFactory == nullptr || if (d2d.imaging_factory == nullptr ||
d2d.HwndRenderTarget == nullptr) d2d.render_target == nullptr)
{ {
return E_UNEXPECTED; return E_UNEXPECTED;
} }
@ -446,6 +472,13 @@ namespace easy2d
return E_POINTER; return E_POINTER;
} }
size_t hash_code = res.GetHashCode();
if (bitmap_cache_.find(hash_code) != bitmap_cache_.end())
{
*bitmap = bitmap_cache_[hash_code];
return S_OK;
}
HRESULT hr; HRESULT hr;
HINSTANCE hinstance = GetModuleHandle(nullptr); HINSTANCE hinstance = GetModuleHandle(nullptr);
@ -453,14 +486,14 @@ namespace easy2d
IWICBitmapFrameDecode* source = nullptr; IWICBitmapFrameDecode* source = nullptr;
IWICStream* stream = nullptr; IWICStream* stream = nullptr;
IWICFormatConverter* converter = nullptr; IWICFormatConverter* converter = nullptr;
// 加载资源 // 加载资源
hr = res.Load() ? S_OK : E_FAIL; hr = res.Load() ? S_OK : E_FAIL;
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
// 创建 WIC 流 // 创建 WIC 流
hr = d2d.WICImagingFactory->CreateStream(&stream); hr = d2d.imaging_factory->CreateStream(&stream);
} }
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
@ -475,7 +508,7 @@ namespace easy2d
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
// 创建流的解码器 // 创建流的解码器
hr = d2d.WICImagingFactory->CreateDecoderFromStream( hr = d2d.imaging_factory->CreateDecoderFromStream(
stream, stream,
nullptr, nullptr,
WICDecodeMetadataCacheOnLoad, WICDecodeMetadataCacheOnLoad,
@ -492,7 +525,7 @@ namespace easy2d
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
// 创建图片格式转换器 // 创建图片格式转换器
hr = d2d.WICImagingFactory->CreateFormatConverter(&converter); hr = d2d.imaging_factory->CreateFormatConverter(&converter);
} }
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
@ -511,13 +544,18 @@ namespace easy2d
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
// 从 WIC 位图创建一个 Direct2D 位图 // 从 WIC 位图创建一个 Direct2D 位图
hr = d2d.HwndRenderTarget->CreateBitmapFromWicBitmap( hr = d2d.render_target->CreateBitmapFromWicBitmap(
converter, converter,
nullptr, nullptr,
bitmap bitmap
); );
} }
if (SUCCEEDED(hr))
{
bitmap_cache_.insert(std::make_pair(hash_code, *bitmap));
}
// 释放相关资源 // 释放相关资源
SafeRelease(decoder); SafeRelease(decoder);
SafeRelease(source); SafeRelease(source);
@ -529,28 +567,28 @@ namespace easy2d
HRESULT GraphicsDevice::Resize(UINT32 width, UINT32 height) HRESULT GraphicsDevice::Resize(UINT32 width, UINT32 height)
{ {
if (!d2d.HwndRenderTarget) if (!d2d.render_target)
return E_UNEXPECTED; return E_UNEXPECTED;
d2d.HwndRenderTarget->Resize(D2D1::SizeU(width, height)); d2d.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 (!d2d.HwndRenderTarget) if (!d2d.render_target)
return E_UNEXPECTED; return E_UNEXPECTED;
d2d.HwndRenderTarget->SetTransform(matrix); d2d.render_target->SetTransform(matrix);
return S_OK; return S_OK;
} }
HRESULT GraphicsDevice::SetBrushOpacity(float opacity) HRESULT GraphicsDevice::SetBrushOpacity(float opacity)
{ {
if (!d2d.HwndRenderTarget) if (!d2d.render_target)
return E_UNEXPECTED; return E_UNEXPECTED;
d2d.SolidColorBrush->SetOpacity(opacity); d2d.solid_brush->SetOpacity(opacity);
return S_OK; return S_OK;
} }
@ -562,10 +600,10 @@ namespace easy2d
StrokeStyle outline_stroke StrokeStyle outline_stroke
) )
{ {
if (!d2d.TextRenderer) if (!d2d.text_renderer)
return E_UNEXPECTED; return E_UNEXPECTED;
d2d.TextRenderer->SetTextStyle( d2d.text_renderer->SetTextStyle(
color, color,
has_outline, has_outline,
outline_color, outline_color,
@ -590,7 +628,7 @@ namespace easy2d
if (!fps_text_format_) if (!fps_text_format_)
{ {
ThrowIfFailed( ThrowIfFailed(
d2d.DWriteFactory->CreateTextFormat( d2d.write_factory->CreateTextFormat(
L"", L"",
nullptr, nullptr,
DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_WEIGHT_NORMAL,
@ -621,7 +659,7 @@ namespace easy2d
SafeRelease(fps_text_layout_); SafeRelease(fps_text_layout_);
ThrowIfFailed( ThrowIfFailed(
d2d.DWriteFactory->CreateTextLayout( d2d.write_factory->CreateTextLayout(
fps_text, fps_text,
static_cast<UINT32>(len), static_cast<UINT32>(len),
fps_text_format_, fps_text_format_,
@ -634,9 +672,9 @@ namespace easy2d
if (fps_text_layout_) if (fps_text_layout_)
{ {
d2d.HwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); d2d.render_target->SetTransform(D2D1::Matrix3x2F::Identity());
d2d.SolidColorBrush->SetOpacity(1.0f); d2d.solid_brush->SetOpacity(1.0f);
d2d.TextRenderer->SetTextStyle( d2d.text_renderer->SetTextStyle(
D2D1::ColorF(D2D1::ColorF::White), D2D1::ColorF(D2D1::ColorF::White),
TRUE, TRUE,
D2D1::ColorF(D2D1::ColorF::Black, 0.4f), D2D1::ColorF(D2D1::ColorF::Black, 0.4f),
@ -644,13 +682,13 @@ namespace easy2d
D2D1_LINE_JOIN_ROUND D2D1_LINE_JOIN_ROUND
); );
fps_text_layout_->Draw(nullptr, d2d.TextRenderer, 10, 0); fps_text_layout_->Draw(nullptr, d2d.text_renderer, 10, 0);
} }
} }
void GraphicsDevice::CreateDeviceResources(HWND hwnd) void GraphicsDevice::CreateDeviceResources(HWND hwnd)
{ {
if (!d2d.HwndRenderTarget) if (!d2d.render_target)
{ {
RECT rc; RECT rc;
::GetClientRect(hwnd, &rc); ::GetClientRect(hwnd, &rc);
@ -663,35 +701,35 @@ namespace easy2d
// 创建设备相关资源。这些资源应在 Direct2D 设备消失时重建 // 创建设备相关资源。这些资源应在 Direct2D 设备消失时重建
// 创建一个 Direct2D 渲染目标 // 创建一个 Direct2D 渲染目标
ThrowIfFailed( ThrowIfFailed(
d2d.Factory->CreateHwndRenderTarget( d2d.factory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(), D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties( D2D1::HwndRenderTargetProperties(
hwnd, hwnd,
size, size,
D2D1_PRESENT_OPTIONS_NONE), D2D1_PRESENT_OPTIONS_NONE),
&d2d.HwndRenderTarget &d2d.render_target
) )
); );
} }
if (!d2d.SolidColorBrush) if (!d2d.solid_brush)
{ {
ThrowIfFailed( ThrowIfFailed(
d2d.HwndRenderTarget->CreateSolidColorBrush( d2d.render_target->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::White), D2D1::ColorF(D2D1::ColorF::White),
&d2d.SolidColorBrush &d2d.solid_brush
) )
); );
} }
if (!d2d.TextRenderer) if (!d2d.text_renderer)
{ {
ThrowIfFailed( ThrowIfFailed(
ITextRenderer::Create( ITextRenderer::Create(
&d2d.TextRenderer, &d2d.text_renderer,
d2d.Factory, d2d.factory,
d2d.HwndRenderTarget, d2d.render_target,
d2d.SolidColorBrush d2d.solid_brush
) )
); );
} }

View File

@ -20,6 +20,7 @@
#pragma once #pragma once
#include "base.h" #include "base.h"
#include "Singleton.hpp"
#include "Font.h" #include "Font.h"
#include "Resource.h" #include "Resource.h"
#include "Image.h" #include "Image.h"
@ -28,38 +29,31 @@
namespace easy2d namespace easy2d
{ {
namespace render namespace devices
{ {
typedef struct struct D2DResources
{ {
ID2D1Factory* Factory; ID2D1Factory* factory;
IWICImagingFactory* WICImagingFactory; IWICImagingFactory* imaging_factory;
IDWriteFactory* DWriteFactory; IDWriteFactory* write_factory;
ITextRenderer* TextRenderer; ITextRenderer* text_renderer;
ID2D1SolidColorBrush* SolidColorBrush; ID2D1SolidColorBrush* solid_brush;
ID2D1HwndRenderTarget* HwndRenderTarget; ID2D1HwndRenderTarget* render_target;
ID2D1StrokeStyle* MiterStrokeStyle; ID2D1StrokeStyle* miter_stroke_style;
ID2D1StrokeStyle* BevelStrokeStyle; ID2D1StrokeStyle* bevel_stroke_style;
ID2D1StrokeStyle* RoundStrokeStyle; ID2D1StrokeStyle* round_stroke_style;
} D2DResources; };
typedef struct
{
Rect area;
float opacity;
} LayerProperties;
class GraphicsDevice class GraphicsDevice
{ {
E2D_DECLARE_SINGLETON(GraphicsDevice);
E2D_DISABLE_COPY(GraphicsDevice);
public: public:
GraphicsDevice();
~GraphicsDevice();
void Initialize(HWND hwnd); void Initialize(HWND hwnd);
void Uninitialize();
// ¿ªÊ¼äÖȾ // ¿ªÊ¼äÖȾ
void BeginDraw(HWND hwnd); void BeginDraw(HWND hwnd);
@ -166,13 +160,21 @@ namespace easy2d
UINT32 height UINT32 height
); );
void ClearImageCache();
protected: protected:
D2D1_COLOR_F clear_color_; GraphicsDevice();
IDWriteTextFormat* fps_text_format_;
IDWriteTextLayout* fps_text_layout_; ~GraphicsDevice();
D2DResources d2d;
protected:
D2DResources d2d;
D2D1_COLOR_F clear_color_;
IDWriteTextFormat* fps_text_format_;
IDWriteTextLayout* fps_text_layout_;
std::map<size_t, ID2D1Bitmap*> bitmap_cache_;
}; };
extern GraphicsDevice instance; E2D_DECLARE_SINGLETON_TYPE(GraphicsDevice, Graphics);
} }
} }

View File

@ -33,332 +33,342 @@
namespace easy2d namespace easy2d
{ {
namespace window namespace
{ {
namespace void GetContentScale(float* scale_x, float* scale_y);
Rect LocateWindow(int width, int height, float scale_x, float scale_y);
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param);
}
WindowInfo::WindowInfo()
: handle(nullptr)
, scale_x(1.f)
, scale_y(1.f)
{
}
WindowInfo::~WindowInfo()
{
if (handle)
::DestroyWindow(handle);
}
void WindowInfo::Initialize(String title, int width, int height, LPCWSTR icon, bool debug)
{
HINSTANCE hinstance = GetModuleHandle(nullptr);
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpszClassName = REGISTER_CLASS;
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcex.lpfnWndProc = WndProc;
wcex.hIcon = nullptr;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = hinstance;
wcex.hbrBackground = nullptr;
wcex.lpszMenuName = nullptr;
wcex.hCursor = ::LoadCursor(nullptr, IDC_ARROW);
if (icon)
{ {
void GetContentScale(float* xscale, float* yscale); wcex.hIcon = (HICON)::LoadImage(
Rect LocateWindow(int width, int height);
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param);
}
WindowInfo instance;
WindowInfo::WindowInfo()
: handle(nullptr)
, xscale(1.f)
, yscale(1.f)
{
}
void WindowInfo::Initialize(const Property& property)
{
HINSTANCE hinstance = GetModuleHandle(nullptr);
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpszClassName = REGISTER_CLASS;
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcex.lpfnWndProc = WndProc;
wcex.hIcon = nullptr;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = hinstance;
wcex.hbrBackground = nullptr;
wcex.lpszMenuName = nullptr;
wcex.hCursor = ::LoadCursor(nullptr, IDC_ARROW);
if (property.icon)
{
wcex.hIcon = (HICON)::LoadImage(
hinstance,
property.icon,
IMAGE_ICON,
0,
0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE
);
}
::RegisterClassEx(&wcex);
GetContentScale(&xscale, &yscale);
// 计算窗口大小
Rect client_rect = LocateWindow(property.width, property.height);
// 创建窗口
handle = ::CreateWindowEx(
NULL,
REGISTER_CLASS,
property.title.c_str(),
WINDOW_STYLE,
static_cast<int>(client_rect.origin.x),
static_cast<int>(client_rect.origin.y),
static_cast<int>(client_rect.size.width),
static_cast<int>(client_rect.size.height),
nullptr,
nullptr,
hinstance, hinstance,
this icon,
IMAGE_ICON,
0,
0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE
); );
if (handle == nullptr)
{
::UnregisterClass(REGISTER_CLASS, hinstance);
throw std::runtime_error("Create window failed");
}
// 禁用输入法
::ImmAssociateContext(handle, nullptr);
} }
void WindowInfo::Destroy() ::RegisterClassEx(&wcex);
GetContentScale(&scale_x, &scale_y);
// 计算窗口大小
Rect client_rect = LocateWindow(width, height, scale_x, scale_y);
// 创建窗口
handle = ::CreateWindowEx(
NULL,
REGISTER_CLASS,
title.c_str(),
WINDOW_STYLE,
static_cast<int>(client_rect.origin.x),
static_cast<int>(client_rect.origin.y),
static_cast<int>(client_rect.size.width),
static_cast<int>(client_rect.size.height),
nullptr,
nullptr,
hinstance,
this
);
if (handle == nullptr)
{ {
if (handle) ::UnregisterClass(REGISTER_CLASS, hinstance);
::DestroyWindow(handle); throw std::runtime_error("Create window failed");
} }
String WindowInfo::GetTitle() const // 禁用输入法
::ImmAssociateContext(handle, nullptr);
}
String WindowInfo::GetTitle() const
{
if (handle)
{ {
if (handle) wchar_t title[256];
{ GetWindowTextW(handle, title, 256);
wchar_t title[256]; return title;
GetWindowTextW(handle, title, 256);
return title;
}
return String();
} }
return String();
}
void WindowInfo::SetTitle(const String& title) void WindowInfo::SetTitle(const String& title)
{
if (handle)
::SetWindowText(handle, title.c_str());
}
Size WindowInfo::GetSize() const
{
if (handle)
{ {
if (handle) RECT rect;
::SetWindowText(handle, title.c_str()); GetClientRect(handle, &rect);
return Size(
static_cast<float>(rect.right - rect.left),
static_cast<float>(rect.bottom - rect.top)
);
} }
return Size();
}
Size WindowInfo::GetSize() const float WindowInfo::GetWidth() const
{
return GetSize().width;
}
float WindowInfo::GetHeight() const
{
return GetSize().height;
}
void WindowInfo::SetSize(int width, int height)
{
if (handle)
{ {
if (handle) Rect rect = LocateWindow(width, height, scale_x, scale_y);
{ ::MoveWindow(
RECT rect; handle,
GetClientRect(handle, &rect); static_cast<int>(rect.origin.x),
return Size( static_cast<int>(rect.origin.y),
static_cast<float>(rect.right - rect.left), static_cast<int>(rect.size.width),
static_cast<float>(rect.bottom - rect.top) static_cast<int>(rect.size.height),
); TRUE
} );
return Size();
}
float WindowInfo::GetWidth() const
{
return GetSize().width;
}
float WindowInfo::GetHeight() const
{
return GetSize().height;
}
void WindowInfo::SetSize(int width, int height)
{
if (handle)
{
Rect rect = LocateWindow(width, height);
::MoveWindow(
handle,
static_cast<int>(rect.origin.x),
static_cast<int>(rect.origin.y),
static_cast<int>(rect.size.width),
static_cast<int>(rect.size.height),
TRUE
);
}
}
void WindowInfo::SetIcon(LPCWSTR icon_resource)
{
if (handle)
{
HINSTANCE hinstance = GetModuleHandle(nullptr);
HICON icon = (HICON)::LoadImage(
hinstance,
icon_resource,
IMAGE_ICON,
0,
0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE
);
::SendMessage(handle, WM_SETICON, ICON_BIG, (LPARAM)icon);
::SendMessage(handle, WM_SETICON, ICON_SMALL, (LPARAM)icon);
}
}
namespace
{
void GetContentScale(float* xscale, float* yscale)
{
const float DEFAULT_SCREEN_DPI = 96.f;
const HDC dc = GetDC(NULL);
float xdpi = static_cast<float>(GetDeviceCaps(dc, LOGPIXELSX));
float ydpi = static_cast<float>(GetDeviceCaps(dc, LOGPIXELSY));
ReleaseDC(NULL, dc);
if (xscale)
*xscale = xdpi / DEFAULT_SCREEN_DPI;
if (yscale)
*yscale = ydpi / DEFAULT_SCREEN_DPI;
}
Rect LocateWindow(int width, int height)
{
int max_width = ::GetSystemMetrics(SM_CXSCREEN);
int max_height = ::GetSystemMetrics(SM_CYSCREEN);
RECT rect =
{
0,
0,
static_cast<LONG>(math::Ceil(width * instance.xscale)),
static_cast<LONG>(math::Ceil(height * instance.yscale))
};
// 计算合适的窗口大小
::AdjustWindowRectEx(&rect, WINDOW_STYLE, FALSE, NULL);
width = static_cast<int>(rect.right - rect.left);
height = static_cast<int>(rect.bottom - rect.top);
// 当输入的窗口大小比分辨率大时,给出警告
E2D_WARNING_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);
return Rect(
static_cast<float>((max_width - width) / 2),
static_cast<float>((max_height - height) / 2),
static_cast<float>(width),
static_cast<float>(height)
);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param)
{
LRESULT result = 0;
bool was_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;
was_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;
was_handled = true;
break;
// 处理窗口大小变化消息
case WM_SIZE:
{
UINT width = LOWORD(l_param);
UINT height = HIWORD(l_param);
// 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染
// 目标的大小。它可能会调用失败,但是这里可以忽略有可能的
// 错误,因为这个错误将在下一次调用 EndDraw 时产生
render::instance.Resize(width, height);
}
break;
// 处理分辨率变化消息
case WM_DISPLAYCHANGE:
{
// 重绘客户区
::InvalidateRect(hwnd, nullptr, FALSE);
}
result = 0;
was_handled = true;
break;
// 重绘窗口
case WM_PAINT:
{
game->DrawScene();
::ValidateRect(hwnd, nullptr);
}
result = 0;
was_handled = true;
break;
// 窗口关闭消息
case WM_CLOSE:
{
if (game->OnClose())
{
game->Quit();
}
}
result = 0;
was_handled = true;
break;
// 窗口销毁消息
case WM_DESTROY:
{
::PostQuitMessage(0);
}
result = 1;
was_handled = true;
break;
}
if (!was_handled)
{
result = ::DefWindowProc(hwnd, msg, w_param, l_param);
}
return result;
}
} }
} }
}
void WindowInfo::SetIcon(LPCWSTR icon_resource)
{
if (handle)
{
HINSTANCE hinstance = GetModuleHandle(nullptr);
HICON icon = (HICON)::LoadImage(
hinstance,
icon_resource,
IMAGE_ICON,
0,
0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE
);
::SendMessage(handle, WM_SETICON, ICON_BIG, (LPARAM)icon);
::SendMessage(handle, WM_SETICON, ICON_SMALL, (LPARAM)icon);
}
}
HWND WindowInfo::GetHandle() const
{
return handle;
}
float WindowInfo::GetContentScaleX() const
{
return scale_x;
}
float WindowInfo::GetContentScaleY() const
{
return scale_y;
}
namespace
{
void GetContentScale(float* scale_x, float* scale_y)
{
const float DEFAULT_SCREEN_DPI = 96.f;
const HDC dc = GetDC(NULL);
float xdpi = static_cast<float>(GetDeviceCaps(dc, LOGPIXELSX));
float ydpi = static_cast<float>(GetDeviceCaps(dc, LOGPIXELSY));
ReleaseDC(NULL, dc);
if (scale_x)
*scale_x = xdpi / DEFAULT_SCREEN_DPI;
if (scale_y)
*scale_y = ydpi / DEFAULT_SCREEN_DPI;
}
Rect LocateWindow(int width, int height, float scale_x, float scale_y)
{
int max_width = ::GetSystemMetrics(SM_CXSCREEN);
int max_height = ::GetSystemMetrics(SM_CYSCREEN);
RECT rect =
{
0,
0,
static_cast<LONG>(math::Ceil(width * scale_x)),
static_cast<LONG>(math::Ceil(height * scale_y))
};
// 计算合适的窗口大小
::AdjustWindowRectEx(&rect, WINDOW_STYLE, FALSE, NULL);
width = static_cast<int>(rect.right - rect.left);
height = static_cast<int>(rect.bottom - rect.top);
// 当输入的窗口大小比分辨率大时,给出警告
E2D_WARNING_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);
return Rect(
static_cast<float>((max_width - width) / 2),
static_cast<float>((max_height - height) / 2),
static_cast<float>(width),
static_cast<float>(height)
);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param)
{
LRESULT result = 0;
bool was_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;
was_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;
was_handled = true;
break;
// 处理窗口大小变化消息
case WM_SIZE:
{
UINT width = LOWORD(l_param);
UINT height = HIWORD(l_param);
// 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染
// 目标的大小。它可能会调用失败,但是这里可以忽略有可能的
// 错误,因为这个错误将在下一次调用 EndDraw 时产生
devices::Graphics::Instance().Resize(width, height);
}
break;
// 处理分辨率变化消息
case WM_DISPLAYCHANGE:
{
// 重绘客户区
::InvalidateRect(hwnd, nullptr, FALSE);
}
result = 0;
was_handled = true;
break;
// 重绘窗口
case WM_PAINT:
{
game->DrawScene();
::ValidateRect(hwnd, nullptr);
}
result = 0;
was_handled = true;
break;
// 窗口关闭消息
case WM_CLOSE:
{
if (game->OnClose())
{
game->Quit();
}
}
result = 0;
was_handled = true;
break;
// 窗口销毁消息
case WM_DESTROY:
{
::PostQuitMessage(0);
}
result = 1;
was_handled = true;
break;
}
if (!was_handled)
{
result = ::DefWindowProc(hwnd, msg, w_param, l_param);
}
return result;
}
}
}

View File

@ -20,64 +20,64 @@
#pragma once #pragma once
#include "base.h" #include "base.h"
#include "Singleton.hpp"
namespace easy2d namespace easy2d
{ {
namespace window
class WindowInfo
{ {
typedef struct Property E2D_DECLARE_SINGLETON(WindowInfo);
{
String title; /* 标题 */
int width; /* 宽度 */
int height; /* 高度 */
LPCWSTR icon; /* 图标 */
Property() E2D_DISABLE_COPY(WindowInfo);
: title(L"Easy2D Game")
, width(640)
, height(480)
, icon(nullptr)
{}
} Property;
class WindowInfo public:
{ void Initialize(
public: String title,
HWND handle; int width,
float xscale; int height,
float yscale; LPCWSTR icon,
bool debug
);
public: // 获取标题
WindowInfo(); String GetTitle() const;
void Initialize( // 设置标题
const Property& property void SetTitle(const String& title);
);
void Destroy(); // 获取窗口大小
Size GetSize() const;
// 获取标题 // 获取窗口宽度
String GetTitle() const; float GetWidth() const;
// 设置标题 // 获取窗口高度
void SetTitle(const String& title); float GetHeight() const;
// 获取窗口大小 // 重设窗口大小
Size GetSize() const; void SetSize(int width, int height);
// 获取窗口宽度 // 设置窗口图标
float GetWidth() const; void SetIcon(LPCWSTR icon_resource);
// 获取窗口高度 HWND GetHandle() const;
float GetHeight() const;
// 重设窗口大小 float GetContentScaleX() const;
void SetSize(int width, int height);
// 设置窗口图标 float GetContentScaleY() const;
void SetIcon(LPCWSTR icon_resource);
};
extern WindowInfo instance; protected:
} WindowInfo();
~WindowInfo();
private:
HWND handle;
float scale_x;
float scale_y;
};
E2D_DECLARE_SINGLETON_TYPE(WindowInfo, Window);
} }

View File

@ -60,6 +60,7 @@
#include "base/CallFunc.h" #include "base/CallFunc.h"
#include "base/Canvas.h" #include "base/Canvas.h"
#include "base/Transition.h" #include "base/Transition.h"
#include "base/Music.h"
#include "base/KeyEvent.h" #include "base/KeyEvent.h"
#include "base/MouseEvent.h" #include "base/MouseEvent.h"
@ -85,9 +86,8 @@
#include "utils/Path.h" #include "utils/Path.h"
#include "utils/Data.h" #include "utils/Data.h"
#include "utils/File.h" #include "utils/File.h"
#include "utils/Transcoder.h"
#include "utils/Music.h"
#include "utils/Player.h" #include "utils/Player.h"
#include "utils/Transcoder.h"
// //

View File

@ -112,9 +112,9 @@ namespace easy2d
return *this; return *this;
} }
inline Matrix& Scale(float xscale, float yscale, const Vector2& center) inline Matrix& Scale(float scale_x, float scale_y, const Vector2& center)
{ {
*this = *this * Matrix::Scaling(xscale, yscale, center); *this = *this * Matrix::Scaling(scale_x, scale_y, center);
return *this; return *this;
} }

View File

@ -50,6 +50,16 @@ namespace easy2d
, y(other.y) , y(other.y)
{} {}
inline float Length() const
{
return math::Sqrt(x * x + y * y);
}
inline float Distance(const Vector2& v)
{
return Vector2(x - v.x, y - v.y).Length();
}
inline Vector2 operator + (const Vector2 & other) const inline Vector2 operator + (const Vector2 & other) const
{ {
return Vector2(x + other.x, y + other.y); return Vector2(x + other.x, y + other.y);
@ -80,13 +90,6 @@ namespace easy2d
return (x == other.x) && (y == other.y); return (x == other.x) && (y == other.y);
} }
inline float Length() const { return math::Sqrt(x * x + y * y); }
inline float Distance(const Vector2& v)
{
return Vector2(x - v.x, y - v.y).Length();
}
inline operator D2D1_POINT_2F () const inline operator D2D1_POINT_2F () const
{ {
return D2D1_POINT_2F{ x, y }; return D2D1_POINT_2F{ x, y };

View File

@ -223,7 +223,7 @@ namespace easy2d
if (IsVisible() && if (IsVisible() &&
!enabled_ && !enabled_ &&
normal_ && normal_ &&
normal_->ContainsPoint(input::instance.GetMousePos())) normal_->ContainsPoint(devices::Input::Instance().GetMousePos()))
{ {
HCURSOR hcursor = ::LoadCursor(nullptr, IDC_NO); HCURSOR hcursor = ::LoadCursor(nullptr, IDC_NO);
if (hcursor) if (hcursor)

View File

@ -29,6 +29,8 @@ namespace easy2d
class Button class Button
: public Node : public Node
{ {
E2D_DISABLE_COPY(Button);
typedef std::function<void()> Callback; typedef std::function<void()> Callback;
public: public:
@ -101,8 +103,6 @@ namespace easy2d
) override; ) override;
private: private:
E2D_DISABLE_COPY(Button);
// °´Å¥×´Ì¬Ã¶¾Ù // °´Å¥×´Ì¬Ã¶¾Ù
enum class Status { Normal, Mouseover, Selected }; enum class Status { Normal, Mouseover, Selected };

View File

@ -30,6 +30,8 @@ namespace easy2d
class Menu class Menu
: public Node : public Node
{ {
E2D_DISABLE_COPY(Menu);
public: public:
Menu(); Menu();
@ -61,9 +63,6 @@ namespace easy2d
// 获取所有按钮 // 获取所有按钮
const std::vector<Button*>& GetAllButtons() const; const std::vector<Button*>& GetAllButtons() const;
private:
E2D_DISABLE_COPY(Menu);
private: private:
bool enabled_; bool enabled_;
std::vector<Button*> buttons_; std::vector<Button*> buttons_;

View File

@ -62,7 +62,7 @@ namespace easy2d
{ {
// 设置数据的保存路径 // 设置数据的保存路径
String local_app_data_path = Path::GetLocalAppDataPath(); String local_app_data_path = Path::GetLocalAppDataPath();
String title = window::instance.GetTitle(); String title = Window::Instance().GetTitle();
String folder_name = std::to_wstring(std::hash<String>{}(title)); String folder_name = std::to_wstring(std::hash<String>{}(title));
if (!local_app_data_path.empty()) if (!local_app_data_path.empty())
@ -90,7 +90,7 @@ namespace easy2d
{ {
// 设置临时文件保存路径 // 设置临时文件保存路径
wchar_t path[_MAX_PATH]; wchar_t path[_MAX_PATH];
String title = window::instance.GetTitle(); String title = Window::Instance().GetTitle();
String folder_name = std::to_wstring(std::hash<String>{}(title)); String folder_name = std::to_wstring(std::hash<String>{}(title));
if (0 != ::GetTempPath(_MAX_PATH, path)) if (0 != ::GetTempPath(_MAX_PATH, path))

View File

@ -19,15 +19,10 @@
// THE SOFTWARE. // THE SOFTWARE.
#include "Player.h" #include "Player.h"
#include "Music.h" #include "../base/Music.h"
namespace easy2d namespace easy2d
{ {
namespace
{
std::map<size_t, Music*> musics_;
}
Player::Player() Player::Player()
: volume_(1.f) : volume_(1.f)
{ {
@ -35,6 +30,7 @@ namespace easy2d
Player::~Player() Player::~Player()
{ {
ClearCache();
} }
bool Player::Load(const String & file_path) bool Player::Load(const String & file_path)
@ -51,7 +47,7 @@ namespace easy2d
music->SetVolume(volume_); music->SetVolume(volume_);
size_t hash_code = std::hash<String>{}(file_path); size_t hash_code = std::hash<String>{}(file_path);
musics_.insert(std::make_pair(hash_code, music)); musics_cache_.insert(std::make_pair(hash_code, music));
return true; return true;
} }
else else
@ -69,7 +65,7 @@ namespace easy2d
if (Load(file_path)) if (Load(file_path))
{ {
auto music = musics_[std::hash<String>{}(file_path)]; auto music = musics_cache_[std::hash<String>{}(file_path)];
if (music->Play(loop_count)) if (music->Play(loop_count))
{ {
return true; return true;
@ -84,8 +80,8 @@ namespace easy2d
return; return;
size_t hash_code = std::hash<String>{}(file_path); size_t hash_code = std::hash<String>{}(file_path);
if (musics_.end() != musics_.find(hash_code)) if (musics_cache_.end() != musics_cache_.find(hash_code))
musics_[hash_code]->Pause(); musics_cache_[hash_code]->Pause();
} }
void Player::Resume(const String & file_path) void Player::Resume(const String & file_path)
@ -94,8 +90,8 @@ namespace easy2d
return; return;
size_t hash_code = std::hash<String>{}(file_path); size_t hash_code = std::hash<String>{}(file_path);
if (musics_.end() != musics_.find(hash_code)) if (musics_cache_.end() != musics_cache_.find(hash_code))
musics_[hash_code]->Resume(); musics_cache_[hash_code]->Resume();
} }
void Player::Stop(const String & file_path) void Player::Stop(const String & file_path)
@ -104,8 +100,8 @@ namespace easy2d
return; return;
size_t hash_code = std::hash<String>{}(file_path); size_t hash_code = std::hash<String>{}(file_path);
if (musics_.end() != musics_.find(hash_code)) if (musics_cache_.end() != musics_cache_.find(hash_code))
musics_[hash_code]->Stop(); musics_cache_[hash_code]->Stop();
} }
bool Player::IsPlaying(const String & file_path) bool Player::IsPlaying(const String & file_path)
@ -114,15 +110,15 @@ namespace easy2d
return false; return false;
size_t hash_code = std::hash<String>{}(file_path); size_t hash_code = std::hash<String>{}(file_path);
if (musics_.end() != musics_.find(hash_code)) if (musics_cache_.end() != musics_cache_.find(hash_code))
return musics_[hash_code]->IsPlaying(); return musics_cache_[hash_code]->IsPlaying();
return false; return false;
} }
bool Player::Load(Resource& res) bool Player::Load(Resource& res)
{ {
size_t hash_code = res.GetHashCode(); size_t hash_code = res.GetHashCode();
if (musics_.end() != musics_.find(hash_code)) if (musics_cache_.end() != musics_cache_.find(hash_code))
return true; return true;
Music * music = new (std::nothrow) Music(); Music * music = new (std::nothrow) Music();
@ -132,7 +128,7 @@ namespace easy2d
if (music->Load(res)) if (music->Load(res))
{ {
music->SetVolume(volume_); music->SetVolume(volume_);
musics_.insert(std::make_pair(hash_code, music)); musics_cache_.insert(std::make_pair(hash_code, music));
return true; return true;
} }
else else
@ -148,7 +144,7 @@ namespace easy2d
if (Load(res)) if (Load(res))
{ {
size_t hash_code = res.GetHashCode(); size_t hash_code = res.GetHashCode();
auto music = musics_[hash_code]; auto music = musics_cache_[hash_code];
if (music->Play(loop_count)) if (music->Play(loop_count))
{ {
return true; return true;
@ -160,29 +156,29 @@ namespace easy2d
void Player::Pause(Resource& res) void Player::Pause(Resource& res)
{ {
size_t hash_code = res.GetHashCode(); size_t hash_code = res.GetHashCode();
if (musics_.end() != musics_.find(hash_code)) if (musics_cache_.end() != musics_cache_.find(hash_code))
musics_[hash_code]->Pause(); musics_cache_[hash_code]->Pause();
} }
void Player::Resume(Resource& res) void Player::Resume(Resource& res)
{ {
size_t hash_code = res.GetHashCode(); size_t hash_code = res.GetHashCode();
if (musics_.end() != musics_.find(hash_code)) if (musics_cache_.end() != musics_cache_.find(hash_code))
musics_[hash_code]->Resume(); musics_cache_[hash_code]->Resume();
} }
void Player::Stop(Resource& res) void Player::Stop(Resource& res)
{ {
size_t hash_code = res.GetHashCode(); size_t hash_code = res.GetHashCode();
if (musics_.end() != musics_.find(hash_code)) if (musics_cache_.end() != musics_cache_.find(hash_code))
musics_[hash_code]->Stop(); musics_cache_[hash_code]->Stop();
} }
bool Player::IsPlaying(Resource& res) bool Player::IsPlaying(Resource& res)
{ {
size_t hash_code = res.GetHashCode(); size_t hash_code = res.GetHashCode();
if (musics_.end() != musics_.find(hash_code)) if (musics_cache_.end() != musics_cache_.find(hash_code))
return musics_[hash_code]->IsPlaying(); return musics_cache_[hash_code]->IsPlaying();
return false; return false;
} }
@ -194,7 +190,7 @@ namespace easy2d
void Player::SetVolume(float volume) void Player::SetVolume(float volume)
{ {
volume_ = std::min(std::max(volume, -224.f), 224.f); volume_ = std::min(std::max(volume, -224.f), 224.f);
for (const auto& pair : musics_) for (const auto& pair : musics_cache_)
{ {
pair.second->SetVolume(volume_); pair.second->SetVolume(volume_);
} }
@ -202,7 +198,7 @@ namespace easy2d
void Player::PauseAll() void Player::PauseAll()
{ {
for (const auto& pair : musics_) for (const auto& pair : musics_cache_)
{ {
pair.second->Pause(); pair.second->Pause();
} }
@ -210,7 +206,7 @@ namespace easy2d
void Player::ResumeAll() void Player::ResumeAll()
{ {
for (const auto& pair : musics_) for (const auto& pair : musics_cache_)
{ {
pair.second->Resume(); pair.second->Resume();
} }
@ -218,7 +214,7 @@ namespace easy2d
void Player::StopAll() void Player::StopAll()
{ {
for (const auto& pair : musics_) for (const auto& pair : musics_cache_)
{ {
pair.second->Stop(); pair.second->Stop();
} }
@ -226,13 +222,13 @@ namespace easy2d
void Player::ClearCache() void Player::ClearCache()
{ {
if (musics_.empty()) if (musics_cache_.empty())
return; return;
for (const auto& pair : musics_) for (const auto& pair : musics_cache_)
{ {
pair.second->Release(); pair.second->Release();
} }
musics_.clear(); musics_cache_.clear();
} }
} }

View File

@ -24,9 +24,13 @@
namespace easy2d namespace easy2d
{ {
class Music;
// 稜있꺄렴포 // 稜있꺄렴포
class Player class Player
{ {
E2D_DISABLE_COPY(Player);
public: public:
Player(); Player();
@ -112,12 +116,10 @@ namespace easy2d
void StopAll(); void StopAll();
// 헌뇜뻠닸 // 헌뇜뻠닸
static void ClearCache(); void ClearCache();
protected:
E2D_DISABLE_COPY(Player);
protected: protected:
float volume_; float volume_;
std::map<size_t, Music*> musics_cache_;
}; };
} }

View File

@ -45,7 +45,7 @@ namespace easy2d
return wave_format_; return wave_format_;
} }
bool Transcoder::LoadMediaFile(LPCWSTR file_path, BYTE** wave_data, UINT32* wave_data_size) HRESULT Transcoder::LoadMediaFile(LPCWSTR file_path, BYTE** wave_data, UINT32* wave_data_size)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
@ -64,10 +64,10 @@ namespace easy2d
SafeRelease(reader); SafeRelease(reader);
return SUCCEEDED(hr); return hr;
} }
bool Transcoder::LoadMediaResource(Resource& res, BYTE** wave_data, UINT32* wave_data_size) HRESULT Transcoder::LoadMediaResource(Resource& res, BYTE** wave_data, UINT32* wave_data_size)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
@ -86,7 +86,7 @@ namespace easy2d
if (stream == nullptr) if (stream == nullptr)
{ {
logs::Trace(L"SHCreateMemStream"); logs::Trace(L"SHCreateMemStream");
return false; return E_OUTOFMEMORY;
} }
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
@ -112,7 +112,7 @@ namespace easy2d
SafeRelease(byte_stream); SafeRelease(byte_stream);
SafeRelease(reader); SafeRelease(reader);
return SUCCEEDED(hr); return hr;
} }
HRESULT Transcoder::ReadSource(IMFSourceReader* reader, BYTE** wave_data, UINT32* wave_data_size) HRESULT Transcoder::ReadSource(IMFSourceReader* reader, BYTE** wave_data, UINT32* wave_data_size)

View File

@ -38,13 +38,13 @@ namespace easy2d
WAVEFORMATEX* GetWaveFormatEx() const; WAVEFORMATEX* GetWaveFormatEx() const;
bool LoadMediaFile( HRESULT LoadMediaFile(
LPCWSTR file_path, LPCWSTR file_path,
BYTE** wave_data, BYTE** wave_data,
UINT32* wave_data_size UINT32* wave_data_size
); );
bool LoadMediaResource( HRESULT LoadMediaResource(
Resource& res, Resource& res,
BYTE** wave_data, BYTE** wave_data,
UINT32* wave_data_size UINT32* wave_data_size

View File

@ -38,12 +38,14 @@
<ClInclude Include="..\..\core\base\macros.h" /> <ClInclude Include="..\..\core\base\macros.h" />
<ClInclude Include="..\..\core\base\modules.h" /> <ClInclude Include="..\..\core\base\modules.h" />
<ClInclude Include="..\..\core\base\MouseEvent.h" /> <ClInclude Include="..\..\core\base\MouseEvent.h" />
<ClInclude Include="..\..\core\base\Music.h" />
<ClInclude Include="..\..\core\base\Node.h" /> <ClInclude Include="..\..\core\base\Node.h" />
<ClInclude Include="..\..\core\base\Rect.hpp" /> <ClInclude Include="..\..\core\base\Rect.hpp" />
<ClInclude Include="..\..\core\base\RefCounter.h" /> <ClInclude Include="..\..\core\base\RefCounter.h" />
<ClInclude Include="..\..\core\base\render.h" /> <ClInclude Include="..\..\core\base\render.h" />
<ClInclude Include="..\..\core\base\Resource.h" /> <ClInclude Include="..\..\core\base\Resource.h" />
<ClInclude Include="..\..\core\base\Scene.h" /> <ClInclude Include="..\..\core\base\Scene.h" />
<ClInclude Include="..\..\core\base\Singleton.hpp" />
<ClInclude Include="..\..\core\base\Size.h" /> <ClInclude Include="..\..\core\base\Size.h" />
<ClInclude Include="..\..\core\base\Sprite.h" /> <ClInclude Include="..\..\core\base\Sprite.h" />
<ClInclude Include="..\..\core\base\Task.h" /> <ClInclude Include="..\..\core\base\Task.h" />
@ -62,7 +64,6 @@
<ClInclude Include="..\..\core\ui\Menu.h" /> <ClInclude Include="..\..\core\ui\Menu.h" />
<ClInclude Include="..\..\core\utils\Data.h" /> <ClInclude Include="..\..\core\utils\Data.h" />
<ClInclude Include="..\..\core\utils\File.h" /> <ClInclude Include="..\..\core\utils\File.h" />
<ClInclude Include="..\..\core\utils\Music.h" />
<ClInclude Include="..\..\core\utils\Path.h" /> <ClInclude Include="..\..\core\utils\Path.h" />
<ClInclude Include="..\..\core\utils\Player.h" /> <ClInclude Include="..\..\core\utils\Player.h" />
<ClInclude Include="..\..\core\utils\Transcoder.h" /> <ClInclude Include="..\..\core\utils\Transcoder.h" />
@ -83,6 +84,7 @@
<ClCompile Include="..\..\core\base\KeyEvent.cpp" /> <ClCompile Include="..\..\core\base\KeyEvent.cpp" />
<ClCompile Include="..\..\core\base\modules.cpp" /> <ClCompile Include="..\..\core\base\modules.cpp" />
<ClCompile Include="..\..\core\base\MouseEvent.cpp" /> <ClCompile Include="..\..\core\base\MouseEvent.cpp" />
<ClCompile Include="..\..\core\base\Music.cpp" />
<ClCompile Include="..\..\core\base\Node.cpp" /> <ClCompile Include="..\..\core\base\Node.cpp" />
<ClCompile Include="..\..\core\base\RefCounter.cpp" /> <ClCompile Include="..\..\core\base\RefCounter.cpp" />
<ClCompile Include="..\..\core\base\render.cpp" /> <ClCompile Include="..\..\core\base\render.cpp" />
@ -102,7 +104,6 @@
<ClCompile Include="..\..\core\ui\Menu.cpp" /> <ClCompile Include="..\..\core\ui\Menu.cpp" />
<ClCompile Include="..\..\core\utils\Data.cpp" /> <ClCompile Include="..\..\core\utils\Data.cpp" />
<ClCompile Include="..\..\core\utils\File.cpp" /> <ClCompile Include="..\..\core\utils\File.cpp" />
<ClCompile Include="..\..\core\utils\Music.cpp" />
<ClCompile Include="..\..\core\utils\Path.cpp" /> <ClCompile Include="..\..\core\utils\Path.cpp" />
<ClCompile Include="..\..\core\utils\Player.cpp" /> <ClCompile Include="..\..\core\utils\Player.cpp" />
<ClCompile Include="..\..\core\utils\Transcoder.cpp" /> <ClCompile Include="..\..\core\utils\Transcoder.cpp" />

View File

@ -122,9 +122,6 @@
<ClInclude Include="..\..\core\utils\File.h"> <ClInclude Include="..\..\core\utils\File.h">
<Filter>utils</Filter> <Filter>utils</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\core\utils\Music.h">
<Filter>utils</Filter>
</ClInclude>
<ClInclude Include="..\..\core\utils\Path.h"> <ClInclude Include="..\..\core\utils\Path.h">
<Filter>utils</Filter> <Filter>utils</Filter>
</ClInclude> </ClInclude>
@ -140,6 +137,12 @@
<ClInclude Include="..\..\core\ui\Menu.h"> <ClInclude Include="..\..\core\ui\Menu.h">
<Filter>ui</Filter> <Filter>ui</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\core\base\Music.h">
<Filter>base</Filter>
</ClInclude>
<ClInclude Include="..\..\core\base\Singleton.hpp">
<Filter>base</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="base"> <Filter Include="base">
@ -252,9 +255,6 @@
<ClCompile Include="..\..\core\utils\File.cpp"> <ClCompile Include="..\..\core\utils\File.cpp">
<Filter>utils</Filter> <Filter>utils</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\core\utils\Music.cpp">
<Filter>utils</Filter>
</ClCompile>
<ClCompile Include="..\..\core\utils\Path.cpp"> <ClCompile Include="..\..\core\utils\Path.cpp">
<Filter>utils</Filter> <Filter>utils</Filter>
</ClCompile> </ClCompile>
@ -270,5 +270,8 @@
<ClCompile Include="..\..\core\ui\Menu.cpp"> <ClCompile Include="..\..\core\ui\Menu.cpp">
<Filter>ui</Filter> <Filter>ui</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\core\base\Music.cpp">
<Filter>base</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -38,12 +38,14 @@
<ClInclude Include="..\..\core\base\macros.h" /> <ClInclude Include="..\..\core\base\macros.h" />
<ClInclude Include="..\..\core\base\modules.h" /> <ClInclude Include="..\..\core\base\modules.h" />
<ClInclude Include="..\..\core\base\MouseEvent.h" /> <ClInclude Include="..\..\core\base\MouseEvent.h" />
<ClInclude Include="..\..\core\base\Music.h" />
<ClInclude Include="..\..\core\base\Node.h" /> <ClInclude Include="..\..\core\base\Node.h" />
<ClInclude Include="..\..\core\base\Rect.hpp" /> <ClInclude Include="..\..\core\base\Rect.hpp" />
<ClInclude Include="..\..\core\base\RefCounter.h" /> <ClInclude Include="..\..\core\base\RefCounter.h" />
<ClInclude Include="..\..\core\base\render.h" /> <ClInclude Include="..\..\core\base\render.h" />
<ClInclude Include="..\..\core\base\Resource.h" /> <ClInclude Include="..\..\core\base\Resource.h" />
<ClInclude Include="..\..\core\base\Scene.h" /> <ClInclude Include="..\..\core\base\Scene.h" />
<ClInclude Include="..\..\core\base\Singleton.hpp" />
<ClInclude Include="..\..\core\base\Size.h" /> <ClInclude Include="..\..\core\base\Size.h" />
<ClInclude Include="..\..\core\base\Sprite.h" /> <ClInclude Include="..\..\core\base\Sprite.h" />
<ClInclude Include="..\..\core\base\Task.h" /> <ClInclude Include="..\..\core\base\Task.h" />
@ -62,7 +64,6 @@
<ClInclude Include="..\..\core\ui\Menu.h" /> <ClInclude Include="..\..\core\ui\Menu.h" />
<ClInclude Include="..\..\core\utils\Data.h" /> <ClInclude Include="..\..\core\utils\Data.h" />
<ClInclude Include="..\..\core\utils\File.h" /> <ClInclude Include="..\..\core\utils\File.h" />
<ClInclude Include="..\..\core\utils\Music.h" />
<ClInclude Include="..\..\core\utils\Path.h" /> <ClInclude Include="..\..\core\utils\Path.h" />
<ClInclude Include="..\..\core\utils\Player.h" /> <ClInclude Include="..\..\core\utils\Player.h" />
<ClInclude Include="..\..\core\utils\Transcoder.h" /> <ClInclude Include="..\..\core\utils\Transcoder.h" />
@ -83,6 +84,7 @@
<ClCompile Include="..\..\core\base\KeyEvent.cpp" /> <ClCompile Include="..\..\core\base\KeyEvent.cpp" />
<ClCompile Include="..\..\core\base\modules.cpp" /> <ClCompile Include="..\..\core\base\modules.cpp" />
<ClCompile Include="..\..\core\base\MouseEvent.cpp" /> <ClCompile Include="..\..\core\base\MouseEvent.cpp" />
<ClCompile Include="..\..\core\base\Music.cpp" />
<ClCompile Include="..\..\core\base\Node.cpp" /> <ClCompile Include="..\..\core\base\Node.cpp" />
<ClCompile Include="..\..\core\base\RefCounter.cpp" /> <ClCompile Include="..\..\core\base\RefCounter.cpp" />
<ClCompile Include="..\..\core\base\render.cpp" /> <ClCompile Include="..\..\core\base\render.cpp" />
@ -102,7 +104,6 @@
<ClCompile Include="..\..\core\ui\Menu.cpp" /> <ClCompile Include="..\..\core\ui\Menu.cpp" />
<ClCompile Include="..\..\core\utils\Data.cpp" /> <ClCompile Include="..\..\core\utils\Data.cpp" />
<ClCompile Include="..\..\core\utils\File.cpp" /> <ClCompile Include="..\..\core\utils\File.cpp" />
<ClCompile Include="..\..\core\utils\Music.cpp" />
<ClCompile Include="..\..\core\utils\Path.cpp" /> <ClCompile Include="..\..\core\utils\Path.cpp" />
<ClCompile Include="..\..\core\utils\Player.cpp" /> <ClCompile Include="..\..\core\utils\Player.cpp" />
<ClCompile Include="..\..\core\utils\Transcoder.cpp" /> <ClCompile Include="..\..\core\utils\Transcoder.cpp" />

View File

@ -122,9 +122,6 @@
<ClInclude Include="..\..\core\utils\File.h"> <ClInclude Include="..\..\core\utils\File.h">
<Filter>utils</Filter> <Filter>utils</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\core\utils\Music.h">
<Filter>utils</Filter>
</ClInclude>
<ClInclude Include="..\..\core\utils\Path.h"> <ClInclude Include="..\..\core\utils\Path.h">
<Filter>utils</Filter> <Filter>utils</Filter>
</ClInclude> </ClInclude>
@ -140,6 +137,12 @@
<ClInclude Include="..\..\core\ui\Menu.h"> <ClInclude Include="..\..\core\ui\Menu.h">
<Filter>ui</Filter> <Filter>ui</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\core\base\Music.h">
<Filter>base</Filter>
</ClInclude>
<ClInclude Include="..\..\core\base\Singleton.hpp">
<Filter>base</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="base"> <Filter Include="base">
@ -252,9 +255,6 @@
<ClCompile Include="..\..\core\utils\File.cpp"> <ClCompile Include="..\..\core\utils\File.cpp">
<Filter>utils</Filter> <Filter>utils</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\core\utils\Music.cpp">
<Filter>utils</Filter>
</ClCompile>
<ClCompile Include="..\..\core\utils\Path.cpp"> <ClCompile Include="..\..\core\utils\Path.cpp">
<Filter>utils</Filter> <Filter>utils</Filter>
</ClCompile> </ClCompile>
@ -270,5 +270,8 @@
<ClCompile Include="..\..\core\ui\Menu.cpp"> <ClCompile Include="..\..\core\ui\Menu.cpp">
<Filter>ui</Filter> <Filter>ui</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\core\base\Music.cpp">
<Filter>base</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -38,12 +38,14 @@
<ClInclude Include="..\..\core\base\macros.h" /> <ClInclude Include="..\..\core\base\macros.h" />
<ClInclude Include="..\..\core\base\modules.h" /> <ClInclude Include="..\..\core\base\modules.h" />
<ClInclude Include="..\..\core\base\MouseEvent.h" /> <ClInclude Include="..\..\core\base\MouseEvent.h" />
<ClInclude Include="..\..\core\base\Music.h" />
<ClInclude Include="..\..\core\base\Node.h" /> <ClInclude Include="..\..\core\base\Node.h" />
<ClInclude Include="..\..\core\base\Rect.hpp" /> <ClInclude Include="..\..\core\base\Rect.hpp" />
<ClInclude Include="..\..\core\base\RefCounter.h" /> <ClInclude Include="..\..\core\base\RefCounter.h" />
<ClInclude Include="..\..\core\base\render.h" /> <ClInclude Include="..\..\core\base\render.h" />
<ClInclude Include="..\..\core\base\Resource.h" /> <ClInclude Include="..\..\core\base\Resource.h" />
<ClInclude Include="..\..\core\base\Scene.h" /> <ClInclude Include="..\..\core\base\Scene.h" />
<ClInclude Include="..\..\core\base\Singleton.hpp" />
<ClInclude Include="..\..\core\base\Size.h" /> <ClInclude Include="..\..\core\base\Size.h" />
<ClInclude Include="..\..\core\base\Sprite.h" /> <ClInclude Include="..\..\core\base\Sprite.h" />
<ClInclude Include="..\..\core\base\Task.h" /> <ClInclude Include="..\..\core\base\Task.h" />
@ -62,7 +64,6 @@
<ClInclude Include="..\..\core\ui\Menu.h" /> <ClInclude Include="..\..\core\ui\Menu.h" />
<ClInclude Include="..\..\core\utils\Data.h" /> <ClInclude Include="..\..\core\utils\Data.h" />
<ClInclude Include="..\..\core\utils\File.h" /> <ClInclude Include="..\..\core\utils\File.h" />
<ClInclude Include="..\..\core\utils\Music.h" />
<ClInclude Include="..\..\core\utils\Path.h" /> <ClInclude Include="..\..\core\utils\Path.h" />
<ClInclude Include="..\..\core\utils\Player.h" /> <ClInclude Include="..\..\core\utils\Player.h" />
<ClInclude Include="..\..\core\utils\Transcoder.h" /> <ClInclude Include="..\..\core\utils\Transcoder.h" />
@ -83,6 +84,7 @@
<ClCompile Include="..\..\core\base\KeyEvent.cpp" /> <ClCompile Include="..\..\core\base\KeyEvent.cpp" />
<ClCompile Include="..\..\core\base\modules.cpp" /> <ClCompile Include="..\..\core\base\modules.cpp" />
<ClCompile Include="..\..\core\base\MouseEvent.cpp" /> <ClCompile Include="..\..\core\base\MouseEvent.cpp" />
<ClCompile Include="..\..\core\base\Music.cpp" />
<ClCompile Include="..\..\core\base\Node.cpp" /> <ClCompile Include="..\..\core\base\Node.cpp" />
<ClCompile Include="..\..\core\base\RefCounter.cpp" /> <ClCompile Include="..\..\core\base\RefCounter.cpp" />
<ClCompile Include="..\..\core\base\render.cpp" /> <ClCompile Include="..\..\core\base\render.cpp" />
@ -102,7 +104,6 @@
<ClCompile Include="..\..\core\ui\Menu.cpp" /> <ClCompile Include="..\..\core\ui\Menu.cpp" />
<ClCompile Include="..\..\core\utils\Data.cpp" /> <ClCompile Include="..\..\core\utils\Data.cpp" />
<ClCompile Include="..\..\core\utils\File.cpp" /> <ClCompile Include="..\..\core\utils\File.cpp" />
<ClCompile Include="..\..\core\utils\Music.cpp" />
<ClCompile Include="..\..\core\utils\Path.cpp" /> <ClCompile Include="..\..\core\utils\Path.cpp" />
<ClCompile Include="..\..\core\utils\Player.cpp" /> <ClCompile Include="..\..\core\utils\Player.cpp" />
<ClCompile Include="..\..\core\utils\Transcoder.cpp" /> <ClCompile Include="..\..\core\utils\Transcoder.cpp" />

View File

@ -122,9 +122,6 @@
<ClInclude Include="..\..\core\utils\File.h"> <ClInclude Include="..\..\core\utils\File.h">
<Filter>utils</Filter> <Filter>utils</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\core\utils\Music.h">
<Filter>utils</Filter>
</ClInclude>
<ClInclude Include="..\..\core\utils\Path.h"> <ClInclude Include="..\..\core\utils\Path.h">
<Filter>utils</Filter> <Filter>utils</Filter>
</ClInclude> </ClInclude>
@ -140,6 +137,12 @@
<ClInclude Include="..\..\core\ui\Menu.h"> <ClInclude Include="..\..\core\ui\Menu.h">
<Filter>ui</Filter> <Filter>ui</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\core\base\Music.h">
<Filter>base</Filter>
</ClInclude>
<ClInclude Include="..\..\core\base\Singleton.hpp">
<Filter>base</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="base"> <Filter Include="base">
@ -252,9 +255,6 @@
<ClCompile Include="..\..\core\utils\File.cpp"> <ClCompile Include="..\..\core\utils\File.cpp">
<Filter>utils</Filter> <Filter>utils</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\core\utils\Music.cpp">
<Filter>utils</Filter>
</ClCompile>
<ClCompile Include="..\..\core\utils\Path.cpp"> <ClCompile Include="..\..\core\utils\Path.cpp">
<Filter>utils</Filter> <Filter>utils</Filter>
</ClCompile> </ClCompile>
@ -270,5 +270,8 @@
<ClCompile Include="..\..\core\ui\Menu.cpp"> <ClCompile Include="..\..\core\ui\Menu.cpp">
<Filter>ui</Filter> <Filter>ui</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\core\base\Music.cpp">
<Filter>base</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>