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 Spawn;
E2D_DISABLE_COPY(Action);
public:
Action();
@ -92,9 +94,6 @@ namespace easy2d
// 获取动作结束状态
virtual bool IsDone() const;
protected:
E2D_DISABLE_COPY(Action);
protected:
String name_;
bool running_;

View File

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

View File

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

View File

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

View File

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

View File

@ -23,6 +23,7 @@
#include "../math/vector.hpp"
#include "Color.h"
#include "Size.h"
#include "Rect.hpp"
namespace easy2d
{
@ -33,9 +34,9 @@ namespace easy2d
// 计算两点间距离: float distance = p1.Distance(p2);
// 坐标可以相加减: 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
@ -138,4 +139,11 @@ namespace easy2d
Right = VK_RBUTTON, /* 鼠标右键 */
Middle = VK_MBUTTON /* 鼠标中键 */
};
// 图层属性
struct LayerProperties
{
Rect area;
float opacity;
};
}

View File

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

View File

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

View File

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

View File

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

View File

@ -27,12 +27,32 @@ namespace easy2d
class Scene;
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
{
E2D_DISABLE_COPY(Game);
public:
Game();
~Game();
virtual ~Game();
// 更新时
virtual void OnUpdate(float dt) {}
@ -46,7 +66,7 @@ namespace easy2d
// 初始化
void Initialize(
const window::Property& property /* 窗口属性 */
const Options& options /* 属性 */
);
// 运行
@ -80,12 +100,6 @@ namespace easy2d
float dt
);
// 获取实例
static Game * GetInstance();
protected:
E2D_DISABLE_COPY(Game);
private:
bool debug_mode_;
bool quit_;

View File

@ -25,11 +25,6 @@
namespace easy2d
{
namespace
{
std::map<size_t, ID2D1Bitmap*> bitmap_cache_;
}
Image::Image()
: bitmap_(nullptr)
, crop_rect_()
@ -73,13 +68,12 @@ namespace easy2d
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;
}
this->SetBitmap(bitmap_cache_.at(res.GetHashCode()));
return true;
}
@ -87,16 +81,23 @@ namespace easy2d
{
E2D_WARNING_IF(file_name.empty(), "Image Load failed! Invalid file name.");
if (file_name.empty())
return false;
if (!Image::CacheBitmap(file_name))
File image_file;
if (!image_file.Open(file_name))
{
E2D_WARNING("Load Image from file failed!");
E2D_WARNING("Image file not found!");
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;
}
@ -186,70 +187,6 @@ namespace easy2d
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)
{
if (bitmap_ == bitmap)

View File

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

View File

@ -22,10 +22,8 @@
namespace easy2d
{
namespace input
namespace devices
{
InputDevice instance;
InputDevice::InputDevice()
{
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_);
@ -43,7 +41,7 @@ namespace easy2d
::GetCursorPos(&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)

View File

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

View File

@ -32,19 +32,19 @@ namespace easy2d
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
{
return ((float)(short)HIWORD(l_param_)) * window::instance.yscale;
return ((float)(short)HIWORD(l_param_)) * Window::Instance().GetContentScaleY();
}
Point MouseEvent::GetPosition() const
{
return Point(
((float)(short)LOWORD(l_param_)) * window::instance.xscale,
((float)(short)HIWORD(l_param_)) * window::instance.yscale
((float)(short)LOWORD(l_param_)) * Window::Instance().GetContentScaleX(),
((float)(short)HIWORD(l_param_)) * Window::Instance().GetContentScaleY()
);
}

View File

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

View File

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

View File

@ -77,12 +77,12 @@ namespace easy2d
if (clip_enabled_)
{
render::instance.PushClip(final_matrix_, transform_.size);
devices::Graphics::Instance().PushClip(final_matrix_, transform_.size);
}
if (children_.empty())
{
render::instance.SetTransform(final_matrix_);
devices::Graphics::Instance().SetTransform(final_matrix_);
OnDraw();
}
else
@ -114,7 +114,7 @@ namespace easy2d
}
}
render::instance.SetTransform(final_matrix_);
devices::Graphics::Instance().SetTransform(final_matrix_);
OnDraw();
// 访问剩余节点
@ -124,7 +124,7 @@ namespace easy2d
if (clip_enabled_)
{
render::instance.PopClip();
devices::Graphics::Instance().PopClip();
}
}
@ -171,7 +171,7 @@ namespace easy2d
{
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_)
@ -212,7 +212,7 @@ namespace easy2d
SafeRelease(border_);
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 Scene;
E2D_DISABLE_COPY(Node);
public:
typedef std::vector<Node*> Nodes;
typedef std::vector<Action*> Actions;
@ -418,8 +420,6 @@ namespace easy2d
);
private:
E2D_DISABLE_COPY(Node);
// 渲染节点边缘
void DrawBorder();

View File

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

View File

@ -32,6 +32,8 @@ namespace easy2d
class Scene
: public RefCounter
{
E2D_DISABLE_COPY(Scene);
public:
Scene();
@ -79,9 +81,6 @@ namespace easy2d
// »ñȡת»»¾ØÕó
const math::Matrix& GetTransform() const;
private:
E2D_DISABLE_COPY(Scene);
private:
Node* root_;
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())
{
auto crop_pos = image_->GetCropPos();
render::instance.DrawImage(
devices::Graphics::Instance().DrawImage(
image_,
GetDisplayOpacity(),
Rect(Point(), GetTransform().size),

View File

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

View File

@ -318,16 +318,16 @@ namespace easy2d
// 创建文本区域
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_.outline,
style_.outline_color,
style_.outline_width,
style_.outline_stroke
);
render::instance.DrawTextLayout(text_layout_);
devices::Graphics::Instance().DrawTextLayout(text_layout_);
}
}
@ -344,7 +344,7 @@ namespace easy2d
SafeRelease(text_format_);
ThrowIfFailed(
render::instance.CreateTextFormat(
devices::Graphics::Instance().CreateTextFormat(
&text_format_,
font_
)
@ -399,7 +399,7 @@ namespace easy2d
if (style_.wrap)
{
ThrowIfFailed(
render::instance.CreateTextLayout(
devices::Graphics::Instance().CreateTextLayout(
&text_layout_,
text_,
text_format_,
@ -416,7 +416,7 @@ namespace easy2d
{
// 为防止文本对齐问题,根据先创建 layout 以获取宽度
ThrowIfFailed(
render::instance.CreateTextLayout(
devices::Graphics::Instance().CreateTextLayout(
&text_layout_,
text_,
text_format_,
@ -433,7 +433,7 @@ namespace easy2d
// 重新创建 layout
SafeRelease(text_layout_);
ThrowIfFailed(
render::instance.CreateTextLayout(
devices::Graphics::Instance().CreateTextLayout(
&text_layout_,
text_,
text_format_,

View File

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

View File

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

View File

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

View File

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

View File

@ -27,18 +27,161 @@
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()
: x_audio2_(nullptr)
, mastering_voice_(nullptr)
{
modules::Initialize();
}
AudioDevice::~AudioDevice()
{
ClearVoiceCache();
if (mastering_voice_)
{
mastering_voice_->DestroyVoice();
mastering_voice_ = nullptr;
}
SafeRelease(x_audio2_);
modules::MediaFoundation.MFShutdown();
modules::Destroy();
}
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();
mastering_voice_ = nullptr;
voice->SetSourceVoice(source_voice);
voice_cache_.push_back(voice);
}
SafeRelease(x_audio2_);
modules::MediaFoundation.MFShutdown();
return hr;
}
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()

View File

@ -20,41 +20,97 @@
#pragma once
#include "macros.h"
#include "Singleton.hpp"
#include <xaudio2.h>
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
{
E2D_DECLARE_SINGLETON(AudioDevice);
E2D_DISABLE_COPY(AudioDevice);
public:
AudioDevice();
~AudioDevice();
void Initialize();
void Uninitialize();
// 开启设备
void Open();
// 关闭设备
void Close();
// 创建音源
HRESULT CreateVoice(
IXAudio2SourceVoice ** voice,
Voice* voice,
WAVEFORMATEX * wfx
);
void DeleteVoice(
Voice* voice
);
void ClearVoiceCache();
protected:
AudioDevice();
~AudioDevice();
protected:
IXAudio2 * x_audio2_;
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
#include "BaseTypes.h"
#include "Rect.hpp"
#include <stdexcept>
namespace easy2d

View File

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

View File

@ -26,6 +26,8 @@ namespace easy2d
{
namespace
{
int initialize_count = 0;
inline void SafeFreeLibrary(HMODULE instance)
{
if (instance)
@ -38,6 +40,10 @@ namespace easy2d
void Initialize()
{
initialize_count++;
if (initialize_count > 1)
return;
const auto xaudio2_dll_names =
{
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(MediaFoundation.mfplat);
SafeFreeLibrary(MediaFoundation.mfreadwrite);

View File

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

View File

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

View File

@ -20,6 +20,7 @@
#pragma once
#include "base.h"
#include "Singleton.hpp"
#include "Font.h"
#include "Resource.h"
#include "Image.h"
@ -28,38 +29,31 @@
namespace easy2d
{
namespace render
namespace devices
{
typedef struct
struct D2DResources
{
ID2D1Factory* Factory;
IWICImagingFactory* WICImagingFactory;
IDWriteFactory* DWriteFactory;
ITextRenderer* TextRenderer;
ID2D1SolidColorBrush* SolidColorBrush;
ID2D1HwndRenderTarget* HwndRenderTarget;
ID2D1StrokeStyle* MiterStrokeStyle;
ID2D1StrokeStyle* BevelStrokeStyle;
ID2D1StrokeStyle* RoundStrokeStyle;
} D2DResources;
ID2D1Factory* factory;
IWICImagingFactory* imaging_factory;
IDWriteFactory* write_factory;
ITextRenderer* text_renderer;
ID2D1SolidColorBrush* solid_brush;
ID2D1HwndRenderTarget* render_target;
ID2D1StrokeStyle* miter_stroke_style;
ID2D1StrokeStyle* bevel_stroke_style;
ID2D1StrokeStyle* round_stroke_style;
};
typedef struct
{
Rect area;
float opacity;
} LayerProperties;
class GraphicsDevice
{
E2D_DECLARE_SINGLETON(GraphicsDevice);
E2D_DISABLE_COPY(GraphicsDevice);
public:
GraphicsDevice();
~GraphicsDevice();
void Initialize(HWND hwnd);
void Uninitialize();
// ¿ªÊ¼äÖȾ
void BeginDraw(HWND hwnd);
@ -166,13 +160,21 @@ namespace easy2d
UINT32 height
);
void ClearImageCache();
protected:
D2D1_COLOR_F clear_color_;
IDWriteTextFormat* fps_text_format_;
IDWriteTextLayout* fps_text_layout_;
D2DResources d2d;
GraphicsDevice();
~GraphicsDevice();
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 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);
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,
wcex.hIcon = (HICON)::LoadImage(
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)
::DestroyWindow(handle);
::UnregisterClass(REGISTER_CLASS, hinstance);
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);
return title;
}
return String();
wchar_t title[256];
GetWindowTextW(handle, title, 256);
return title;
}
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)
::SetWindowText(handle, title.c_str());
RECT rect;
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;
GetClientRect(handle, &rect);
return Size(
static_cast<float>(rect.right - rect.left),
static_cast<float>(rect.bottom - rect.top)
);
}
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;
}
Rect rect = LocateWindow(width, height, scale_x, scale_y);
::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);
}
}
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
#include "base.h"
#include "Singleton.hpp"
namespace easy2d
{
namespace window
class WindowInfo
{
typedef struct Property
{
String title; /* 标题 */
int width; /* 宽度 */
int height; /* 高度 */
LPCWSTR icon; /* 图标 */
E2D_DECLARE_SINGLETON(WindowInfo);
Property()
: title(L"Easy2D Game")
, width(640)
, height(480)
, icon(nullptr)
{}
} Property;
E2D_DISABLE_COPY(WindowInfo);
class WindowInfo
{
public:
HWND handle;
float xscale;
float yscale;
public:
void Initialize(
String title,
int width,
int height,
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);
// 获取窗口高度
float GetHeight() const;
HWND GetHandle() const;
// 重设窗口大小
void SetSize(int width, int height);
float GetContentScaleX() const;
// 设置窗口图标
void SetIcon(LPCWSTR icon_resource);
};
float GetContentScaleY() const;
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/Canvas.h"
#include "base/Transition.h"
#include "base/Music.h"
#include "base/KeyEvent.h"
#include "base/MouseEvent.h"
@ -85,9 +86,8 @@
#include "utils/Path.h"
#include "utils/Data.h"
#include "utils/File.h"
#include "utils/Transcoder.h"
#include "utils/Music.h"
#include "utils/Player.h"
#include "utils/Transcoder.h"
//

View File

@ -112,9 +112,9 @@ namespace easy2d
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;
}

View File

@ -50,6 +50,16 @@ namespace easy2d
, 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
{
return Vector2(x + other.x, y + other.y);
@ -80,13 +90,6 @@ namespace easy2d
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
{
return D2D1_POINT_2F{ x, y };

View File

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

View File

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

View File

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

View File

@ -62,7 +62,7 @@ namespace easy2d
{
// 设置数据的保存路径
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));
if (!local_app_data_path.empty())
@ -90,7 +90,7 @@ namespace easy2d
{
// 设置临时文件保存路径
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));
if (0 != ::GetTempPath(_MAX_PATH, path))

View File

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

View File

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

View File

@ -45,7 +45,7 @@ namespace easy2d
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;
@ -64,10 +64,10 @@ namespace easy2d
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;
@ -86,7 +86,7 @@ namespace easy2d
if (stream == nullptr)
{
logs::Trace(L"SHCreateMemStream");
return false;
return E_OUTOFMEMORY;
}
if (SUCCEEDED(hr))
@ -112,7 +112,7 @@ namespace easy2d
SafeRelease(byte_stream);
SafeRelease(reader);
return SUCCEEDED(hr);
return hr;
}
HRESULT Transcoder::ReadSource(IMFSourceReader* reader, BYTE** wave_data, UINT32* wave_data_size)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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