change: add namespace modules & load libraries from dll

refactoring: time package

refactoring: the whole project has been changed
This commit is contained in:
Haibo 2018-11-08 21:39:26 +08:00 committed by Nomango
parent b129a1bf18
commit f4cadddce4
114 changed files with 9723 additions and 8905 deletions

View File

@ -1,138 +0,0 @@
// 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.
#include "..\e2daction.h"
#include "..\e2dobject.h"
namespace easy2d
{
Animate::Animate()
: frame_index_(0)
, animation_(nullptr)
{
}
Animate::Animate(Animation * animation)
: frame_index_(0)
, animation_(nullptr)
{
this->SetAnimation(animation);
}
Animate::~Animate()
{
SafeRelease(animation_);
}
Animation * Animate::GetAnimation() const
{
return animation_;
}
void Animate::SetAnimation(Animation * animation)
{
if (animation && animation != animation_)
{
if (animation_)
{
animation_->Release();
}
animation_ = animation;
animation_->Retain();
frame_index_ = 0;
}
}
void Animate::Init()
{
Action::Init();
auto target = dynamic_cast<Sprite*>(target_);
if (target && animation_)
{
target->Load(animation_->GetFrames()[frame_index_]);
++frame_index_;
}
}
void Animate::Update()
{
Action::Update();
if (!animation_)
{
this->Stop();
return;
}
while ((Time::Now() - started_).Seconds() >= animation_->GetInterval())
{
auto& frames = animation_->GetFrames();
auto target = dynamic_cast<Sprite*>(target_);
if (target)
{
target->Load(frames[frame_index_]);
}
started_ += Duration::Second * animation_->GetInterval();
++frame_index_;
if (frame_index_ == frames.size())
{
this->Stop();
break;
}
}
}
void Animate::ResetTime()
{
Action::ResetTime();
}
void Animate::Reset()
{
Action::Reset();
frame_index_ = 0;
}
Animate * Animate::Clone() const
{
if (animation_)
{
return new Animate(animation_);
}
return nullptr;
}
Animate * Animate::Reverse() const
{
if (animation_)
{
auto animation = animation_->Reverse();
if (animation)
{
return new Animate(animation);
}
}
return nullptr;
}
}

View File

@ -1,29 +0,0 @@
// 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.
#include "..\e2daction.h"
namespace easy2d
{
FadeIn::FadeIn(float duration)
: OpacityTo(duration, 1)
{
}
}

View File

@ -1,42 +0,0 @@
// 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.
#include "..\e2daction.h"
#include "..\e2dobject.h"
namespace easy2d
{
MoveTo::MoveTo(float duration, Point pos)
: MoveBy(duration, Point())
{
end_pos_ = pos;
}
MoveTo * MoveTo::Clone() const
{
return new MoveTo(duration_, end_pos_);
}
void MoveTo::Init()
{
MoveBy::Init();
delta_pos_ = end_pos_ - start_pos_;
}
}

View File

@ -1,143 +0,0 @@
// 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.
#include "..\e2daction.h"
namespace easy2d
{
Sequence::Sequence()
: action_index_(0)
{
}
Sequence::Sequence(const Actions& actions)
: action_index_(0)
{
this->Add(actions);
}
Sequence::~Sequence()
{
for (auto action : actions_)
{
SafeRelease(action);
}
}
void Sequence::Init()
{
Action::Init();
// 将所有动作与目标绑定
if (target_)
{
for (const auto& action : actions_)
{
action->target_ = target_;
}
}
// 初始化第一个动作
actions_[0]->Init();
}
void Sequence::Update()
{
Action::Update();
auto &action = actions_[action_index_];
action->Update();
if (action->IsDone())
{
++action_index_;
if (action_index_ == actions_.size())
{
this->Stop();
}
else
{
actions_[action_index_]->Init();
}
}
}
void Sequence::Reset()
{
Action::Reset();
for (const auto& action : actions_)
{
action->Reset();
}
action_index_ = 0;
}
void Sequence::ResetTime()
{
for (const auto& action : actions_)
{
action->ResetTime();
}
}
void Sequence::Add(Action * action)
{
if (action)
{
actions_.push_back(action);
action->Retain();
}
}
void Sequence::Add(const Actions& actions)
{
for (const auto &action : actions)
{
this->Add(action);
}
}
Sequence * Sequence::Clone() const
{
auto sequence = new Sequence();
for (const auto& action : actions_)
{
if (action)
{
sequence->Add(action->Clone());
}
}
return sequence;
}
Sequence * Sequence::Reverse() const
{
auto sequence = new Sequence();
if (sequence && !actions_.empty())
{
std::vector<Action*> newActions(actions_.size());
for (auto iter = actions_.crbegin(), iterCrend = actions_.crend(); iter != iterCrend; ++iter)
{
newActions.push_back((*iter)->Reverse());
}
sequence->Add(newActions);
}
return sequence;
}
}

View File

@ -1,141 +0,0 @@
// 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.
#include "..\e2daction.h"
namespace easy2d
{
Spawn::Spawn()
{
}
Spawn::Spawn(const Actions& actions)
{
this->Add(actions);
}
Spawn::~Spawn()
{
for (auto action : actions_)
{
SafeRelease(action);
}
}
void Spawn::Init()
{
Action::Init();
if (target_)
{
for (const auto& action : actions_)
{
action->target_ = target_;
action->Init();
}
}
}
void Spawn::Update()
{
Action::Update();
size_t done_num = 0;
for (const auto& action : actions_)
{
if (action->IsDone())
{
++done_num;
}
else
{
action->Update();
}
}
if (done_num == actions_.size())
{
this->Stop();
}
}
void Spawn::Reset()
{
Action::Reset();
for (const auto& action : actions_)
{
action->Reset();
}
}
void Spawn::ResetTime()
{
for (const auto& action : actions_)
{
action->ResetTime();
}
}
void Spawn::Add(Action * action)
{
if (action)
{
actions_.push_back(action);
action->Retain();
}
}
void Spawn::Add(const Actions& actions)
{
for (const auto &action : actions)
{
this->Add(action);
}
}
Spawn * Spawn::Clone() const
{
auto spawn = new Spawn();
for (const auto& action : actions_)
{
if (action)
{
spawn->Add(action->Clone());
}
}
return spawn;
}
Spawn * Spawn::Reverse() const
{
auto spawn = new Spawn();
if (spawn && !actions_.empty())
{
std::vector<Action*> newActions(actions_.size());
for (auto iter = actions_.crbegin(), iterCrend = actions_.crend(); iter != iterCrend; ++iter)
{
newActions.push_back((*iter)->Reverse());
}
spawn->Add(newActions);
}
return spawn;
}
}

View File

@ -18,16 +18,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2daction.h"
#include "Action.h"
#include "base.h"
namespace easy2d
{
Action::Action()
: running_(false)
, done_(false)
, initialized_(false)
, target_(nullptr)
: running_(false), done_(false), initialized_(false), target_(nullptr)
{
}
@ -55,12 +52,12 @@ namespace easy2d
done_ = true;
}
const std::wstring& Action::GetName() const
const String& Action::GetName() const
{
return name_;
}
void Action::SetName(const std::wstring& name)
void Action::SetName(const String& name)
{
name_ = name;
}
@ -74,7 +71,7 @@ namespace easy2d
{
initialized_ = false;
done_ = false;
started_ = Time::Now();
started_ = time::Now();
}
bool Action::IsDone() const
@ -89,21 +86,21 @@ namespace easy2d
this->Reset();
}
void Action::Init()
void Action::Initialize()
{
initialized_ = true;
started_ = Time::Now();
started_ = time::Now();
}
void Action::Update()
{
if (!initialized_)
{
Init();
Initialize();
}
}
void Action::ResetTime()
{
}
}
}

106
core/base/Action.h Normal file
View File

@ -0,0 +1,106 @@
// 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 "base.h"
#include "time.h"
#include "RefCounter.h"
namespace easy2d
{
class Node;
class Loop;
class Sequence;
class Spawn;
// 基础动作
class Action
: public RefCounter
{
friend class Loop;
friend class Sequence;
friend class Spawn;
public:
Action();
virtual ~Action();
// 获取动作运行状态
virtual bool IsRunning();
// 继续动作
virtual void Resume();
// 暂停动作
virtual void Pause();
// 停止动作
virtual void Stop();
// 获取动作名称
virtual const String& GetName() const;
// 设置动作名称
virtual void SetName(
const String& name
);
// 获取动作的拷贝
virtual Action * Clone() const = 0;
// 获取动作的倒转
virtual Action * Reverse() const = 0;
// 重置动作
virtual void Reset();
// 获取该动作的执行目标
virtual Node * GetTarget();
// 开始动作
virtual void StartWithTarget(
Node* target
);
// 初始化动作
virtual void Initialize();
// 更新动作
virtual void Update();
// 重置动作时间
virtual void ResetTime();
// 获取动作结束状态
virtual bool IsDone() const;
protected:
E2D_DISABLE_COPY(Action);
protected:
String name_;
bool running_;
bool done_;
bool initialized_;
Node* target_;
time::TimePoint started_;
};
}

View File

@ -0,0 +1,368 @@
// 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.
#include "ActionCombined.h"
#include "base.h"
namespace easy2d
{
//-------------------------------------------------------
// Loop
//-------------------------------------------------------
Loop::Loop(Action * action, int times /* = -1 */)
: action_(action)
, times_(0)
, total_times_(times)
{
E2D_WARNING_IF(action == nullptr, "Loop NULL pointer exception!");
if (action)
{
action_ = action;
action_->Retain();
}
}
Loop::~Loop()
{
SafeRelease(action_);
}
Loop * Loop::Clone() const
{
if (action_)
{
return new Loop(action_->Clone());
}
else
{
return nullptr;
}
}
Loop * Loop::Reverse() const
{
if (action_)
{
return new Loop(action_->Clone());
}
else
{
return nullptr;
}
}
void Loop::Initialize()
{
Action::Initialize();
if (action_)
{
action_->target_ = target_;
action_->Initialize();
}
}
void Loop::Update()
{
Action::Update();
if (times_ == total_times_)
{
this->Stop();
return;
}
if (action_)
{
action_->Update();
if (action_->IsDone())
{
++times_;
Action::Reset();
action_->Reset();
}
}
else
{
this->Stop();
}
}
void Loop::Reset()
{
Action::Reset();
if (action_) action_->Reset();
times_ = 0;
}
void Loop::ResetTime()
{
if (action_) action_->ResetTime();
}
//-------------------------------------------------------
// Sequence
//-------------------------------------------------------
Sequence::Sequence()
: action_index_(0)
{
}
Sequence::Sequence(const Actions& actions)
: action_index_(0)
{
this->Add(actions);
}
Sequence::~Sequence()
{
for (auto action : actions_)
{
SafeRelease(action);
}
}
void Sequence::Initialize()
{
Action::Initialize();
// 将所有动作与目标绑定
if (target_)
{
for (const auto& action : actions_)
{
action->target_ = target_;
}
}
// 初始化第一个动作
actions_[0]->Initialize();
}
void Sequence::Update()
{
Action::Update();
auto &action = actions_[action_index_];
action->Update();
if (action->IsDone())
{
++action_index_;
if (action_index_ == actions_.size())
{
this->Stop();
}
else
{
actions_[action_index_]->Initialize();
}
}
}
void Sequence::Reset()
{
Action::Reset();
for (const auto& action : actions_)
{
action->Reset();
}
action_index_ = 0;
}
void Sequence::ResetTime()
{
for (const auto& action : actions_)
{
action->ResetTime();
}
}
void Sequence::Add(Action * action)
{
if (action)
{
actions_.push_back(action);
action->Retain();
}
}
void Sequence::Add(const Actions& actions)
{
for (const auto &action : actions)
{
this->Add(action);
}
}
Sequence * Sequence::Clone() const
{
auto sequence = new Sequence();
for (const auto& action : actions_)
{
if (action)
{
sequence->Add(action->Clone());
}
}
return sequence;
}
Sequence * Sequence::Reverse() const
{
auto sequence = new Sequence();
if (sequence && !actions_.empty())
{
std::vector<Action*> newActions(actions_.size());
for (auto iter = actions_.crbegin(), iterCrend = actions_.crend(); iter != iterCrend; ++iter)
{
newActions.push_back((*iter)->Reverse());
}
sequence->Add(newActions);
}
return sequence;
}
//-------------------------------------------------------
// Spawn
//-------------------------------------------------------
Spawn::Spawn()
{
}
Spawn::Spawn(const Actions& actions)
{
this->Add(actions);
}
Spawn::~Spawn()
{
for (auto action : actions_)
{
SafeRelease(action);
}
}
void Spawn::Initialize()
{
Action::Initialize();
if (target_)
{
for (const auto& action : actions_)
{
action->target_ = target_;
action->Initialize();
}
}
}
void Spawn::Update()
{
Action::Update();
size_t done_num = 0;
for (const auto& action : actions_)
{
if (action->IsDone())
{
++done_num;
}
else
{
action->Update();
}
}
if (done_num == actions_.size())
{
this->Stop();
}
}
void Spawn::Reset()
{
Action::Reset();
for (const auto& action : actions_)
{
action->Reset();
}
}
void Spawn::ResetTime()
{
for (const auto& action : actions_)
{
action->ResetTime();
}
}
void Spawn::Add(Action * action)
{
if (action)
{
actions_.push_back(action);
action->Retain();
}
}
void Spawn::Add(const Actions& actions)
{
for (const auto &action : actions)
{
this->Add(action);
}
}
Spawn * Spawn::Clone() const
{
auto spawn = new Spawn();
for (const auto& action : actions_)
{
if (action)
{
spawn->Add(action->Clone());
}
}
return spawn;
}
Spawn * Spawn::Reverse() const
{
auto spawn = new Spawn();
if (spawn && !actions_.empty())
{
std::vector<Action*> newActions(actions_.size());
for (auto iter = actions_.crbegin(), iterCrend = actions_.crend(); iter != iterCrend; ++iter)
{
newActions.push_back((*iter)->Reverse());
}
spawn->Add(newActions);
}
return spawn;
}
}

167
core/base/ActionCombined.h Normal file
View File

@ -0,0 +1,167 @@
// 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 "Action.h"
namespace easy2d
{
// 循环动作
class Loop
: public Action
{
public:
explicit Loop(
Action * action, /* 执行循环的动作 */
int times = -1 /* 循环次数 */
);
virtual ~Loop();
// 获取该动作的拷贝对象
virtual Loop * Clone() const override;
// 获取该动作的倒转
virtual Loop * Reverse() const override;
// 重置动作
virtual void Reset() override;
protected:
E2D_DISABLE_COPY(Loop);
// 初始化动作
virtual void Initialize() override;
// 更新动作
virtual void Update() override;
// 重置动作时间
virtual void ResetTime() override;
protected:
Action * action_;
int times_;
int total_times_;
};
// 顺序动作
class Sequence
: public Action
{
public:
typedef std::vector<Action*> Actions;
Sequence();
explicit Sequence(
const Actions& actions /* 动作列表 */
);
virtual ~Sequence();
// 在结尾添加动作
void Add(
Action * action
);
// 在结尾添加多个动作
void Add(
const Actions& actions /* 动作列表 */
);
// 获取该动作的拷贝对象
virtual Sequence * Clone() const override;
// 获取该动作的倒转
virtual Sequence * Reverse() const;
// 重置动作
virtual void Reset() override;
protected:
E2D_DISABLE_COPY(Sequence);
// 初始化动作
virtual void Initialize() override;
// 更新动作
virtual void Update() override;
// 重置动作时间
virtual void ResetTime() override;
protected:
UINT action_index_;
Actions actions_;
};
// 同步动作
class Spawn
: public Action
{
public:
typedef std::vector<Action*> Actions;
Spawn();
explicit Spawn(
const Actions& actions /* 动作列表 */
);
virtual ~Spawn();
// 在结尾添加动作
void Add(
Action * action
);
// 在结尾添加多个动作
void Add(
const Actions& actions /* 动作列表 */
);
// 获取该动作的拷贝对象
virtual Spawn * Clone() const override;
// 获取该动作的倒转
virtual Spawn * Reverse() const;
// 重置动作
virtual void Reset() override;
protected:
E2D_DISABLE_COPY(Spawn);
// 初始化动作
virtual void Initialize() override;
// 更新动作
virtual void Update() override;
// 重置动作时间
virtual void ResetTime() override;
protected:
Actions actions_;
};
}

View File

@ -0,0 +1,464 @@
// 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.
#include "ActionFiniteTime.h"
#include "base.h"
#include "Node.h"
#include <algorithm>
namespace easy2d
{
//-------------------------------------------------------
// FiniteTimeAction
//-------------------------------------------------------
FiniteTimeAction::FiniteTimeAction(float duration)
: delta_(0)
, duration_(std::max(duration, 0.f))
{
}
void FiniteTimeAction::Reset()
{
Action::Reset();
delta_ = 0;
}
void FiniteTimeAction::Initialize()
{
Action::Initialize();
}
void FiniteTimeAction::Update()
{
Action::Update();
if (duration_ == 0)
{
delta_ = 1;
this->Stop();
}
else
{
delta_ = std::min((time::Now() - started_).Seconds() / duration_, 1.f);
if (delta_ >= 1)
{
this->Stop();
}
}
}
void FiniteTimeAction::ResetTime()
{
Action::ResetTime();
started_ = time::Now() - time::Second * (delta_ * duration_);
}
//-------------------------------------------------------
// Move Action
//-------------------------------------------------------
MoveBy::MoveBy(float duration, Point vector)
: FiniteTimeAction(duration)
{
delta_pos_ = vector;
}
void MoveBy::Initialize()
{
FiniteTimeAction::Initialize();
if (target_)
{
prev_pos_ = start_pos_ = target_->GetPosition();
}
}
void MoveBy::Update()
{
FiniteTimeAction::Update();
if (target_)
{
Point currentPos = target_->GetPosition();
Point diff = currentPos - prev_pos_;
start_pos_ = start_pos_ + diff;
Point newPos = start_pos_ + (delta_pos_ * delta_);
target_->SetPosition(newPos);
prev_pos_ = newPos;
}
}
MoveBy * MoveBy::Clone() const
{
return new MoveBy(duration_, delta_pos_);
}
MoveBy * MoveBy::Reverse() const
{
return new MoveBy(duration_, -delta_pos_);
}
MoveTo::MoveTo(float duration, Point pos)
: MoveBy(duration, Point())
{
end_pos_ = pos;
}
MoveTo * MoveTo::Clone() const
{
return new MoveTo(duration_, end_pos_);
}
void MoveTo::Initialize()
{
MoveBy::Initialize();
delta_pos_ = end_pos_ - start_pos_;
}
//-------------------------------------------------------
// Jump Action
//-------------------------------------------------------
JumpBy::JumpBy(float duration, const Point & vec, float height, int jumps)
: FiniteTimeAction(duration)
, delta_pos_(vec)
, height_(height)
, jumps_(jumps)
{
}
JumpBy * JumpBy::Clone() const
{
return new JumpBy(duration_, delta_pos_, height_, jumps_);
}
JumpBy * JumpBy::Reverse() const
{
return new JumpBy(duration_, -delta_pos_, height_, jumps_);
}
void JumpBy::Initialize()
{
FiniteTimeAction::Initialize();
if (target_)
{
prev_pos_ = start_pos_ = target_->GetPosition();
}
}
void JumpBy::Update()
{
FiniteTimeAction::Update();
if (target_)
{
float frac = fmod(delta_ * jumps_, 1.f);
float x = delta_pos_.x * delta_;
float y = height_ * 4 * frac * (1 - frac);
y += delta_pos_.y * delta_;
Point currentPos = target_->GetPosition();
Point diff = currentPos - prev_pos_;
start_pos_ = diff + start_pos_;
Point newPos = start_pos_ + Point(x, y);
target_->SetPosition(newPos);
prev_pos_ = newPos;
}
}
JumpTo::JumpTo(float duration, const Point & pos, float height, int jumps)
: JumpBy(duration, Point(), height, jumps)
, end_pos_(pos)
{
}
JumpTo * JumpTo::Clone() const
{
return new JumpTo(duration_, end_pos_, height_, jumps_);
}
void JumpTo::Initialize()
{
JumpBy::Initialize();
delta_pos_ = end_pos_ - start_pos_;
}
//-------------------------------------------------------
// Scale Action
//-------------------------------------------------------
ScaleBy::ScaleBy(float duration, float scale)
: FiniteTimeAction(duration)
{
delta_x_ = scale;
delta_y_ = scale;
}
ScaleBy::ScaleBy(float duration, float scale_x, float scale_y)
: FiniteTimeAction(duration)
{
delta_x_ = scale_x;
delta_y_ = scale_y;
}
void ScaleBy::Initialize()
{
FiniteTimeAction::Initialize();
if (target_)
{
start_scale_x_ = target_->GetScaleX();
start_scale_y_ = target_->GetScaleY();
}
}
void ScaleBy::Update()
{
FiniteTimeAction::Update();
if (target_)
{
target_->SetScale(start_scale_x_ + delta_x_ * delta_, start_scale_y_ + delta_y_ * delta_);
}
}
ScaleBy * ScaleBy::Clone() const
{
return new ScaleBy(duration_, delta_x_, delta_y_);
}
ScaleBy * ScaleBy::Reverse() const
{
return new ScaleBy(duration_, -delta_x_, -delta_y_);
}
ScaleTo::ScaleTo(float duration, float scale)
: ScaleBy(duration, 0, 0)
{
end_scale_x_ = scale;
end_scale_y_ = scale;
}
ScaleTo::ScaleTo(float duration, float scale_x, float scale_y)
: ScaleBy(duration, 0, 0)
{
end_scale_x_ = scale_x;
end_scale_y_ = scale_y;
}
ScaleTo * ScaleTo::Clone() const
{
return new ScaleTo(duration_, end_scale_x_, end_scale_y_);
}
void ScaleTo::Initialize()
{
ScaleBy::Initialize();
delta_x_ = end_scale_x_ - start_scale_x_;
delta_y_ = end_scale_y_ - start_scale_y_;
}
//-------------------------------------------------------
// Opacity Action
//-------------------------------------------------------
OpacityBy::OpacityBy(float duration, float opacity)
: FiniteTimeAction(duration)
{
delta_val_ = opacity;
}
void OpacityBy::Initialize()
{
FiniteTimeAction::Initialize();
if (target_)
{
start_val_ = target_->GetOpacity();
}
}
void OpacityBy::Update()
{
FiniteTimeAction::Update();
if (target_)
{
target_->SetOpacity(start_val_ + delta_val_ * delta_);
}
}
OpacityBy * OpacityBy::Clone() const
{
return new OpacityBy(duration_, delta_val_);
}
OpacityBy * OpacityBy::Reverse() const
{
return new OpacityBy(duration_, -delta_val_);
}
OpacityTo::OpacityTo(float duration, float opacity)
: OpacityBy(duration, 0)
{
end_val_ = opacity;
}
OpacityTo * OpacityTo::Clone() const
{
return new OpacityTo(duration_, end_val_);
}
void OpacityTo::Initialize()
{
OpacityBy::Initialize();
delta_val_ = end_val_ - start_val_;
}
FadeIn::FadeIn(float duration)
: OpacityTo(duration, 1)
{
}
FadeOut::FadeOut(float duration)
: OpacityTo(duration, 0)
{
}
//-------------------------------------------------------
// Rotate Action
//-------------------------------------------------------
RotateBy::RotateBy(float duration, float rotation)
: FiniteTimeAction(duration)
{
delta_val_ = rotation;
}
void RotateBy::Initialize()
{
FiniteTimeAction::Initialize();
if (target_)
{
start_val_ = target_->GetRotation();
}
}
void RotateBy::Update()
{
FiniteTimeAction::Update();
if (target_)
{
target_->SetRotation(start_val_ + delta_val_ * delta_);
}
}
RotateBy * RotateBy::Clone() const
{
return new RotateBy(duration_, delta_val_);
}
RotateBy * RotateBy::Reverse() const
{
return new RotateBy(duration_, -delta_val_);
}
RotateTo::RotateTo(float duration, float rotation)
: RotateBy(duration, 0)
{
end_val_ = rotation;
}
RotateTo * RotateTo::Clone() const
{
return new RotateTo(duration_, end_val_);
}
void RotateTo::Initialize()
{
RotateBy::Initialize();
delta_val_ = end_val_ - start_val_;
}
//-------------------------------------------------------
// Delay
//-------------------------------------------------------
Delay::Delay(float duration)
: delta_(0)
, delay_(std::max(duration, 0.f))
{
}
void Delay::Reset()
{
Action::Reset();
delta_ = 0;
}
void Delay::Initialize()
{
Action::Initialize();
}
void Delay::Update()
{
Action::Update();
delta_ = (time::Now() - started_).Seconds();
if (delta_ >= delay_)
{
this->Stop();
}
}
void Delay::ResetTime()
{
Action::ResetTime();
started_ = time::Now() - time::Second * delta_;
}
Delay * Delay::Clone() const
{
return new Delay(delay_);
}
Delay * Delay::Reverse() const
{
return new Delay(delay_);
}
}

View File

@ -18,98 +18,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef __E2D_ACTION_H__
#define __E2D_ACTION_H__
#include "e2dutil.h"
#include "e2dobject.h"
#pragma once
#include "Action.h"
namespace easy2d
{
class Node;
class Loop;
class Sequence;
class Spawn;
// 基础动作
class Action
: public Ref
{
friend class Loop;
friend class Sequence;
friend class Spawn;
public:
Action();
virtual ~Action();
// 获取动作运行状态
virtual bool IsRunning();
// 继续动作
virtual void Resume();
// 暂停动作
virtual void Pause();
// 停止动作
virtual void Stop();
// 获取动作名称
virtual const std::wstring& GetName() const;
// 设置动作名称
virtual void SetName(
const std::wstring& name
);
// 获取动作的拷贝
virtual Action * Clone() const = 0;
// 获取动作的倒转
virtual Action * Reverse() const = 0;
// 重置动作
virtual void Reset();
// 获取该动作的执行目标
virtual Node * GetTarget();
// 开始动作
virtual void StartWithTarget(
Node* target
);
// 初始化动作
virtual void Init();
// 更新动作
virtual void Update();
// 重置动作时间
virtual void ResetTime();
// 获取动作结束状态
virtual bool IsDone() const;
protected:
E2D_DISABLE_COPY(Action);
protected:
std::wstring name_;
bool running_;
bool done_;
bool initialized_;
Node* target_;
Time started_;
};
// 持续动作
// ³ÖÐø¶¯×÷
class FiniteTimeAction
: public Action
{
@ -126,7 +40,7 @@ namespace easy2d
E2D_DISABLE_COPY(FiniteTimeAction);
// 初始化动作
virtual void Init() override;
virtual void Initialize() override;
// 更新动作
virtual void Update() override;
@ -160,7 +74,7 @@ namespace easy2d
E2D_DISABLE_COPY(MoveBy);
// 初始化动作
virtual void Init() override;
virtual void Initialize() override;
// 更新动作
virtual void Update() override;
@ -196,7 +110,7 @@ namespace easy2d
E2D_DISABLE_COPY(MoveTo);
// 初始化动作
virtual void Init() override;
virtual void Initialize() override;
protected:
Point end_pos_;
@ -225,7 +139,7 @@ namespace easy2d
E2D_DISABLE_COPY(JumpBy);
// 初始化动作
virtual void Init() override;
virtual void Initialize() override;
// 更新动作
virtual void Update() override;
@ -265,7 +179,7 @@ namespace easy2d
E2D_DISABLE_COPY(JumpTo);
// 初始化动作
virtual void Init() override;
virtual void Initialize() override;
protected:
Point end_pos_;
@ -298,7 +212,7 @@ namespace easy2d
E2D_DISABLE_COPY(ScaleBy);
// 初始化动作
virtual void Init() override;
virtual void Initialize() override;
// 更新动作
virtual void Update() override;
@ -341,7 +255,7 @@ namespace easy2d
E2D_DISABLE_COPY(ScaleTo);
// 初始化动作
virtual void Init() override;
virtual void Initialize() override;
protected:
float end_scale_x_;
@ -369,7 +283,7 @@ namespace easy2d
E2D_DISABLE_COPY(OpacityBy);
// 初始化动作
virtual void Init() override;
virtual void Initialize() override;
// 更新动作
virtual void Update() override;
@ -404,7 +318,7 @@ namespace easy2d
E2D_DISABLE_COPY(OpacityTo);
// 初始化动作
virtual void Init() override;
virtual void Initialize() override;
protected:
float end_val_;
@ -461,7 +375,7 @@ namespace easy2d
E2D_DISABLE_COPY(RotateBy);
// 初始化动作
virtual void Init() override;
virtual void Initialize() override;
// 更新动作
virtual void Update() override;
@ -496,7 +410,7 @@ namespace easy2d
E2D_DISABLE_COPY(RotateTo);
// 初始化动作
virtual void Init() override;
virtual void Initialize() override;
protected:
float end_val_;
@ -525,7 +439,7 @@ namespace easy2d
E2D_DISABLE_COPY(Delay);
// 初始化动作
virtual void Init() override;
virtual void Initialize() override;
// 更新动作
virtual void Update() override;
@ -537,290 +451,4 @@ namespace easy2d
float delay_;
float delta_;
};
// 循环动作
class Loop
: public Action
{
public:
explicit Loop(
Action * action, /* 执行循环的动作 */
int times = -1 /* 循环次数 */
);
virtual ~Loop();
// 获取该动作的拷贝对象
virtual Loop * Clone() const override;
// 获取该动作的倒转
virtual Loop * Reverse() const override;
// 重置动作
virtual void Reset() override;
protected:
E2D_DISABLE_COPY(Loop);
// 初始化动作
virtual void Init() override;
// 更新动作
virtual void Update() override;
// 重置动作时间
virtual void ResetTime() override;
protected:
Action * action_;
int times_;
int total_times_;
};
// 回调动作
class CallFunc
: public Action
{
typedef std::function<void()> Callback;
public:
explicit CallFunc(
const Callback& func /* 函数对象 */
);
// 获取该动作的拷贝对象
virtual CallFunc * Clone() const override;
// 获取该动作的倒转
virtual CallFunc * Reverse() const override;
protected:
E2D_DISABLE_COPY(CallFunc);
// 初始化动作
virtual void Init() override;
// 更新动作
virtual void Update() override;
protected:
Callback callback_;
};
// 顺序动作
class Sequence
: public Action
{
public:
typedef std::vector<Action*> Actions;
Sequence();
explicit Sequence(
const Actions& actions /* 动作列表 */
);
virtual ~Sequence();
// 在结尾添加动作
void Add(
Action * action
);
// 在结尾添加多个动作
void Add(
const Actions& actions /* 动作列表 */
);
// 获取该动作的拷贝对象
virtual Sequence * Clone() const override;
// 获取该动作的倒转
virtual Sequence * Reverse() const;
// 重置动作
virtual void Reset() override;
protected:
E2D_DISABLE_COPY(Sequence);
// 初始化动作
virtual void Init() override;
// 更新动作
virtual void Update() override;
// 重置动作时间
virtual void ResetTime() override;
protected:
UINT action_index_;
Actions actions_;
};
// 同步动作
class Spawn
: public Action
{
public:
typedef std::vector<Action*> Actions;
Spawn();
explicit Spawn(
const Actions& actions /* 动作列表 */
);
virtual ~Spawn();
// 在结尾添加动作
void Add(
Action * action
);
// 在结尾添加多个动作
void Add(
const Actions& actions /* 动作列表 */
);
// 获取该动作的拷贝对象
virtual Spawn * Clone() const override;
// 获取该动作的倒转
virtual Spawn * Reverse() const;
// 重置动作
virtual void Reset() override;
protected:
E2D_DISABLE_COPY(Spawn);
// 初始化动作
virtual void Init() override;
// 更新动作
virtual void Update() override;
// 重置动作时间
virtual void ResetTime() override;
protected:
Actions actions_;
};
// 帧动画
class Animation
: public Ref
{
public:
typedef std::vector<Image*> Images;
Animation();
explicit Animation(
const Images& frames /* 关键帧数组 */
);
explicit Animation(
float interval /* 帧间隔(秒) */
);
explicit Animation(
float interval, /* 帧间隔(秒) */
const Images& frames /* 关键帧数组 */
);
virtual ~Animation();
// 添加关键帧
void Add(
Image * frame /* 关键帧 */
);
// 添加多个关键帧
void Add(
const Images& frames /* 关键帧数组 */
);
// 获取帧间隔
float GetInterval() const;
// 获取关键帧
const Images& GetFrames() const;
// 设置每一帧的时间间隔
void SetInterval(
float interval /* 帧间隔(秒) */
);
// 获取帧动画的拷贝对象
Animation * Clone() const;
// 获取帧动画的倒转
Animation * Reverse() const;
protected:
E2D_DISABLE_COPY(Animation);
protected:
float interval_;
Images frames_;
};
// 精灵动作
class Animate
: public Action
{
public:
Animate();
explicit Animate(
Animation * animation
);
virtual ~Animate();
// 获取动画
virtual Animation * GetAnimation() const;
// 设置动画
virtual void SetAnimation(
Animation * animation
);
// 获取该动作的拷贝对象
virtual Animate * Clone() const override;
// 获取该动作的倒转
virtual Animate * Reverse() const override;
// 重置动作
virtual void Reset() override;
protected:
E2D_DISABLE_COPY(Animate);
// 初始化动作
virtual void Init() override;
// 更新动作
virtual void Update() override;
// 重置动作时间
virtual void ResetTime() override;
protected:
UINT frame_index_;
Animation * animation_;
};
} // end of easy2d namespace
#endif // __E2D_ACTION_H__
}

View File

@ -18,10 +18,133 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2daction.h"
#include "Animation.h"
#include "Sprite.h"
namespace easy2d
{
//-------------------------------------------------------
// Animate
//-------------------------------------------------------
Animate::Animate()
: frame_index_(0)
, animation_(nullptr)
{
}
Animate::Animate(Animation * animation)
: frame_index_(0)
, animation_(nullptr)
{
this->SetAnimation(animation);
}
Animate::~Animate()
{
SafeRelease(animation_);
}
Animation * Animate::GetAnimation() const
{
return animation_;
}
void Animate::SetAnimation(Animation * animation)
{
if (animation && animation != animation_)
{
if (animation_)
{
animation_->Release();
}
animation_ = animation;
animation_->Retain();
frame_index_ = 0;
}
}
void Animate::Initialize()
{
Action::Initialize();
auto target = dynamic_cast<Sprite*>(target_);
if (target && animation_)
{
target->Load(animation_->GetFrames()[frame_index_]);
++frame_index_;
}
}
void Animate::Update()
{
Action::Update();
if (!animation_)
{
this->Stop();
return;
}
while ((time::Now() - started_).Seconds() >= animation_->GetInterval())
{
auto& frames = animation_->GetFrames();
auto target = dynamic_cast<Sprite*>(target_);
if (target)
{
target->Load(frames[frame_index_]);
}
started_ += time::Second * animation_->GetInterval();
++frame_index_;
if (frame_index_ == frames.size())
{
this->Stop();
break;
}
}
}
void Animate::ResetTime()
{
Action::ResetTime();
}
void Animate::Reset()
{
Action::Reset();
frame_index_ = 0;
}
Animate * Animate::Clone() const
{
if (animation_)
{
return new Animate(animation_);
}
return nullptr;
}
Animate * Animate::Reverse() const
{
if (animation_)
{
auto animation = animation_->Reverse();
if (animation)
{
return new Animate(animation);
}
}
return nullptr;
}
//-------------------------------------------------------
// Animation
//-------------------------------------------------------
Animation::Animation()
: interval_(1)
{

133
core/base/Animation.h Normal file
View File

@ -0,0 +1,133 @@
// 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 "Action.h"
#include "Image.h"
namespace easy2d
{
// 帧动画
class Animation
: public RefCounter
{
public:
typedef std::vector<Image*> Images;
Animation();
explicit Animation(
const Images& frames /* 关键帧数组 */
);
explicit Animation(
float interval /* 帧间隔(秒) */
);
explicit Animation(
float interval, /* 帧间隔(秒) */
const Images& frames /* 关键帧数组 */
);
virtual ~Animation();
// 添加关键帧
void Add(
Image * frame /* 关键帧 */
);
// 添加多个关键帧
void Add(
const Images& frames /* 关键帧数组 */
);
// 获取帧间隔
float GetInterval() const;
// 获取关键帧
const Images& GetFrames() const;
// 设置每一帧的时间间隔
void SetInterval(
float interval /* 帧间隔(秒) */
);
// 获取帧动画的拷贝对象
Animation * Clone() const;
// 获取帧动画的倒转
Animation * Reverse() const;
protected:
E2D_DISABLE_COPY(Animation);
protected:
float interval_;
Images frames_;
};
// 精灵动作
class Animate
: public Action
{
public:
Animate();
explicit Animate(
Animation * animation
);
virtual ~Animate();
// 获取动画
virtual Animation * GetAnimation() const;
// 设置动画
virtual void SetAnimation(
Animation * animation
);
// 获取该动作的拷贝对象
virtual Animate * Clone() const override;
// 获取该动作的倒转
virtual Animate * Reverse() const override;
// 重置动作
virtual void Reset() override;
protected:
E2D_DISABLE_COPY(Animate);
// 初始化动作
virtual void Initialize() override;
// 更新动作
virtual void Update() override;
// 重置动作时间
virtual void ResetTime() override;
protected:
UINT frame_index_;
Animation * animation_;
};
}

141
core/base/BaseTypes.h Normal file
View File

@ -0,0 +1,141 @@
// 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 "macros.h"
#include "../math/vector.hpp"
#include "Color.h"
#include "Size.h"
namespace easy2d
{
// 坐标
//
// Usage:
// 表示一个二维空间的坐标: Point origin(0, 0);
// 计算两点间距离: float distance = p1.Distance(p2);
// 坐标可以相加减: Point p = Point(10, 10) + Point(20, 20); // p 的坐标是 (30, 30)
//
typedef math::Vector2 Point;
typedef std::wstring String;
// 方向
enum class Direction : int
{
Up, /* 上 */
Down, /* 下 */
Left, /* 左 */
Right /* 右 */
};
// 线条相交样式
enum class Stroke : int
{
Miter = 0, /* 斜切 */
Bevel = 1, /* 斜角 */
Round = 2 /* 圆角 */
};
// 键盘键值
enum class KeyCode : int
{
Unknown = 0,
Up = VK_UP,
Left = VK_LEFT,
Right = VK_RIGHT,
Down = VK_DOWN,
Enter = VK_RETURN,
Space = VK_SPACE,
Esc = VK_ESCAPE,
Ctrl = VK_CONTROL,
Shift = VK_SHIFT,
A = 0x41,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
Num0 = 0x30,
Num1,
Num2,
Num3,
Num4,
Num5,
Num6,
Num7,
Num8,
Num9,
Numpad0 = VK_NUMPAD0,
Numpad1,
Numpad2,
Numpad3,
Numpad4,
Numpad5,
Numpad6,
Numpad7,
Numpad8,
Numpad9,
F1 = VK_F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
};
// 鼠标键值
enum class MouseCode : int
{
Left = VK_LBUTTON, /* 鼠标左键 */
Right = VK_RBUTTON, /* 鼠标右键 */
Middle = VK_MBUTTON /* 鼠标中键 */
};
}

View File

@ -18,7 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2daction.h"
#include "CallFunc.h"
namespace easy2d
{
@ -37,7 +37,7 @@ namespace easy2d
return new CallFunc(callback_);
}
void CallFunc::Init()
void CallFunc::Initialize()
{
}
@ -46,4 +46,4 @@ namespace easy2d
callback_();
this->Stop();
}
}
}

56
core/base/CallFunc.h Normal file
View File

@ -0,0 +1,56 @@
// 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 "Action.h"
#include <functional>
namespace easy2d
{
// 回调动作
class CallFunc
: public Action
{
typedef std::function<void()> Callback;
public:
explicit CallFunc(
const Callback &func /* 函数对象 */
);
// 获取该动作的拷贝对象
virtual CallFunc *Clone() const override;
// 获取该动作的倒转
virtual CallFunc *Reverse() const override;
protected:
E2D_DISABLE_COPY(CallFunc);
// 初始化动作
virtual void Initialize() override;
// 更新动作
virtual void Update() override;
protected:
Callback callback_;
};
}

View File

@ -18,8 +18,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dobject.h"
#include "..\e2dmodule.h"
#include "base.h"
#include "Canvas.h"
#include "render.h"
namespace easy2d
{
@ -31,7 +32,7 @@ namespace easy2d
, stroke_width_(1.0f)
, stroke_(Stroke::Miter)
{
render_target_ = Device::GetGraphics()->GetRenderTarget();
render_target_ = render::D2D.HwndRenderTarget;
render_target_->AddRef();
ThrowIfFailed(
@ -56,6 +57,7 @@ namespace easy2d
Canvas::~Canvas()
{
SafeRelease(stroke_style_);
SafeRelease(line_brush_);
SafeRelease(fill_brush_);
SafeRelease(render_target_);
@ -78,18 +80,23 @@ namespace easy2d
void Canvas::SetStrokeStyle(Stroke strokeStyle)
{
SafeRelease(stroke_style_);
switch (strokeStyle)
{
case Stroke::Miter:
stroke_style_ = Device::GetGraphics()->GetMiterStrokeStyle();
stroke_style_ = render::D2D.MiterStrokeStyle;
break;
case Stroke::Bevel:
stroke_style_ = Device::GetGraphics()->GetBevelStrokeStyle();
stroke_style_ = render::D2D.BevelStrokeStyle;
break;
case Stroke::Round:
stroke_style_ = Device::GetGraphics()->GetRoundStrokeStyle();
stroke_style_ = render::D2D.RoundStrokeStyle;
break;
}
if (stroke_style_)
stroke_style_->AddRef();
}
Color Canvas::GetLineColor() const

138
core/base/Canvas.h Normal file
View File

@ -0,0 +1,138 @@
// 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 "Node.h"
#include <d2d1.h>
namespace easy2d
{
// »­²¼
class Canvas
: public Node
{
public:
Canvas(
float width,
float height
);
virtual ~Canvas();
// ÉèÖÃÏßÌõÑÕÉ«
void SetLineColor(
const Color& color
);
// ÉèÖÃÌî³äÑÕÉ«
void SetFillColor(
const Color& color
);
// ÉèÖÃÏßÌõ¿í¶È
void SetStrokeWidth(
float width
);
// ÉèÖÃÏßÌõÏཻÑùʽ
void SetStrokeStyle(
Stroke strokeStyle
);
// »ñÈ¡ÏßÌõÑÕÉ«
Color GetLineColor() const;
// »ñÈ¡Ìî³äÑÕÉ«
Color GetFillColor() const;
// »ñÈ¡ÏßÌõ¿í¶È
float GetStrokeWidth() const;
// »ñÈ¡ÏßÌõÏཻÑùʽ
Stroke GetStrokeStyle() const;
// »­Ö±Ïß
void DrawLine(
const Point& begin,
const Point& end
);
// »­Ô²Ðα߿ò
void DrawCircle(
const Point& center,
float radius
);
// »­ÍÖÔ²Ðα߿ò
void DrawEllipse(
const Point& center,
float radius_x,
float radius_y
);
// »­¾ØÐα߿ò
void DrawRect(
const Rect& rect
);
// »­Ô²½Ç¾ØÐα߿ò
void DrawRoundedRect(
const Rect& rect,
float radius_x,
float radius_y
);
// Ìî³äÔ²ÐÎ
void FillCircle(
const Point& center,
float radius
);
// Ìî³äÍÖÔ²ÐÎ
void FillEllipse(
const Point& center,
float radius_x,
float radius_y
);
// Ìî³ä¾ØÐÎ
void FillRect(
const Rect& rect
);
// Ìî³äÔ²½Ç¾ØÐÎ
void FillRoundedRect(
const Rect& rect,
float radius_x,
float radius_y
);
private:
E2D_DISABLE_COPY(Canvas);
private:
float stroke_width_;
Stroke stroke_;
ID2D1RenderTarget* render_target_;
ID2D1SolidColorBrush* fill_brush_;
ID2D1SolidColorBrush* line_brush_;
ID2D1StrokeStyle* stroke_style_;
};
}

View File

@ -18,19 +18,19 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dutil.h"
#include "Color.h"
namespace easy2d
{
namespace
{
const UINT RED_SHIFT = 16;
const UINT GREEN_SHIFT = 8;
const UINT BLUE_SHIFT = 0;
const unsigned int RED_SHIFT = 16;
const unsigned int GREEN_SHIFT = 8;
const unsigned int BLUE_SHIFT = 0;
const UINT RED_MASK = 0xff << RED_SHIFT;
const UINT GREEN_MASK = 0xff << GREEN_SHIFT;
const UINT BLUE_MASK = 0xff << BLUE_SHIFT;
const unsigned int RED_MASK = 0xff << RED_SHIFT;
const unsigned int GREEN_MASK = 0xff << GREEN_SHIFT;
const unsigned int BLUE_MASK = 0xff << BLUE_SHIFT;
}
Color::Color()
@ -57,7 +57,7 @@ namespace easy2d
{
}
Color::Color(UINT rgb)
Color::Color(unsigned int rgb)
: r(((rgb & RED_MASK) >> RED_SHIFT) / 255.f)
, g(((rgb & GREEN_MASK) >> GREEN_SHIFT) / 255.f)
, b(((rgb & BLUE_MASK) >> BLUE_SHIFT) / 255.f)
@ -65,7 +65,7 @@ namespace easy2d
{
}
Color::Color(UINT rgb, float alpha)
Color::Color(unsigned int rgb, float alpha)
: r(((rgb & RED_MASK) >> RED_SHIFT) / 255.f)
, g(((rgb & GREEN_MASK) >> GREEN_SHIFT) / 255.f)
, b(((rgb & BLUE_MASK) >> BLUE_SHIFT) / 255.f)

118
core/base/Color.h Normal file
View File

@ -0,0 +1,118 @@
// 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 "macros.h"
#include <d2d1.h>
namespace easy2d
{
// 颜色
//
// Usage:
// 使用枚举表示颜色: Color blue = Color::Blue;
// 使用 RGB 表示一个颜色: Color red(1.0f, 0.0f, 0.0f);
// 使用 RGBA 表示一个带透明度的颜色: Color not_black(1.0f, 1.0f, 1.0f, 0.5f);
// 使用一个 unsigned int 类型的值表示 RGB: Color black(0x000000);
//
class Color
{
public:
Color();
Color(
float r,
float g,
float b
);
Color(
float r,
float g,
float b,
float alpha
);
Color(
unsigned int rgb
);
Color(
unsigned int rgb,
float alpha
);
Color(
const D2D1_COLOR_F& color
);
operator D2D1_COLOR_F() const;
public:
enum Value : unsigned int
{
Black = 0x000000,
Blue = 0x0000FF,
BlueViolet = 0x8A2BE2,
Brown = 0xA52A2A,
Chocolate = 0xD2691E,
DarkBlue = 0x00008B,
DarkGray = 0xA9A9A9,
DarkGreen = 0x006400,
DarkOrange = 0xFF8C00,
DarkRed = 0x8B0000,
DarkViolet = 0x9400D3,
ForestGreen = 0x228B22,
Gold = 0xFFD700,
Gray = 0x808080,
Green = 0x008000,
GreenYellow = 0xADFF2F,
LightBlue = 0xADD8E6,
LightCyan = 0xE0FFFF,
LightGreen = 0x90EE90,
LightGray = 0xD3D3D3,
LightPink = 0xFFB6C1,
LightSeaGreen = 0x20B2AA,
LightSkyBlue = 0x87CEFA,
LightYellow = 0xFFFFE0,
Orange = 0xFFA500,
OrangeRed = 0xFF4500,
Pink = 0xFFC0CB,
Purple = 0x800080,
Red = 0xFF0000,
Silver = 0xC0C0C0,
SkyBlue = 0x87CEEB,
Snow = 0xFFFAFA,
Violet = 0xEE82EE,
Wheat = 0xF5DEB3,
White = 0xFFFFFF,
WhiteSmoke = 0xF5F5F5,
Wood = 0xDEB887,
Yellow = 0xFFFF00,
YellowGreen = 0x9ACD32
};
public:
float r;
float g;
float b;
float a;
};
}

View File

@ -18,16 +18,15 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dutil.h"
#include "Font.h"
namespace easy2d
{
Font::Font(const std::wstring & family, float size, UINT weight, bool italic)
Font::Font(const std::wstring & family, float size, unsigned int weight, bool italic)
: family(family)
, size(size)
, weight(weight)
, italic(italic)
{
}
}
}

View File

@ -18,37 +18,41 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dtransition.h"
#include "..\e2dobject.h"
#pragma once
#include <string>
namespace easy2d
{
FadeTransition::FadeTransition(float duration)
: Transition(duration)
// 字体
class Font
{
}
public:
std::wstring family; // 字体族
float size; // 字号
unsigned int weight; // 粗细值
bool italic; // 是否斜体
void FadeTransition::Init(Scene * prev, Scene * next, Game * game)
{
Transition::Init(prev, next, game);
out_layer_param_.opacity = 1;
in_layer_param_.opacity = 0;
}
void FadeTransition::Update()
{
Transition::Update();
if (process_ < 0.5)
public:
// 字体粗细值
enum Weight : unsigned int
{
out_layer_param_.opacity = 1 - process_ * 2;
in_layer_param_.opacity = 0;
}
else
{
out_layer_param_.opacity = 0;
in_layer_param_.opacity = (process_ - 0.5f) * 2;
}
}
}
Thin = 100,
ExtraLight = 200,
Light = 300,
Normal = 400,
Medium = 500,
Bold = 700,
ExtraBold = 800,
Black = 900,
ExtraBlack = 950
};
public:
explicit Font(
const std::wstring& family = L"",
float size = 22,
unsigned int weight = Font::Weight::Normal,
bool italic = false
);
};
}

315
core/base/Game.cpp Normal file
View File

@ -0,0 +1,315 @@
// 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.
#include "Game.h"
#include "Node.h"
#include "Scene.h"
#include "Transition.h"
#include "Image.h"
#include "../utils/Player.h"
#include "time.h"
#include "render.h"
#include "input.h"
#include "audio.h"
#include "modules.h"
#include <thread>
namespace easy2d
{
namespace
{
Game * instance = nullptr;
}
Game * Game::GetInstance()
{
return instance;
}
Game::Game()
: quit_(true)
, curr_scene_(nullptr)
, next_scene_(nullptr)
, transition_(nullptr)
, debug_mode_(false)
{
if (instance)
{
throw std::runtime_error("同时只能存在一个游戏实例");
}
instance = this;
::CoInitialize(nullptr);
}
Game::~Game()
{
SafeRelease(transition_);
SafeRelease(curr_scene_);
SafeRelease(next_scene_);
Image::ClearCache();
Player::ClearCache();
render::Uninitialize();
audio::instance.Uninitialize();
window::instance.Destroy();
modules::Uninitialize();
instance = nullptr;
::CoUninitialize();
}
void Game::Initialize(const window::Property& property)
{
modules::Initialize();
window::instance.Initialize(property);
audio::instance.Initialize();
render::Initialize(window::instance.handle);
// 若开启了调试模式,打开控制台
HWND console = ::GetConsoleWindow();
// 关闭控制台
if (debug_mode_)
{
if (console == nullptr)
{
// 显示一个新控制台
if (::AllocConsole())
{
console = ::GetConsoleWindow();
// 重定向输入输出
FILE * stdoutStream, *stdinStream, *stderrStream;
freopen_s(&stdoutStream, "conout$", "w+t", stdout);
freopen_s(&stdinStream, "conin$", "r+t", stdin);
freopen_s(&stderrStream, "conout$", "w+t", stderr);
// 禁用控制台关闭按钮
HMENU hmenu = ::GetSystemMenu(console, FALSE);
::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND);
}
}
}
else
{
if (console)
{
::ShowWindow(console, SW_HIDE);
}
}
::SetWindowLongPtrW(
window::instance.handle,
GWLP_USERDATA,
PtrToUlong(this)
);
}
void Game::Run()
{
quit_ = false;
if (next_scene_)
{
next_scene_->OnEnter();
curr_scene_ = next_scene_;
next_scene_ = nullptr;
}
::ShowWindow(window::instance.handle, SW_SHOWNORMAL);
::UpdateWindow(window::instance.handle);
const int min_interval = 5;
auto last = time::Now();
MSG msg = { 0 };
while (!quit_)
{
auto now = time::Now();
auto dur = now - last;
if (dur.Milliseconds() > min_interval)
{
float dt = (now - last).Seconds();
last = now;
input::instance.Update(
window::instance.handle,
window::instance.xscale,
window::instance.yscale
);
OnUpdate(dt);
UpdateScene(dt);
DrawScene();
while (::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
else
{
// ID2D1HwndRenderTarget 开启了垂直同步,在渲染时会等待显示器刷新,
// 它起到了非常稳定的延时作用,所以大部分时候不需要手动挂起线程进行延时。
// 下面的代码仅在一些情况下(例如窗口最小化时)挂起线程,防止占用过高 CPU 。
int wait = min_interval - dur.Milliseconds();
if (wait > 1)
{
std::this_thread::sleep_for(std::chrono::milliseconds(wait));
}
}
}
}
void Game::Quit()
{
quit_ = true;
}
void Game::EnterScene(Scene * scene, Transition * transition)
{
if (scene == nullptr)
{
E2D_WARNING("Next scene is null pointer!");
return;
}
if (curr_scene_ == scene) { return; }
if (next_scene_)
{
next_scene_->Release();
}
next_scene_ = scene;
next_scene_->Retain();
if (transition)
{
if (transition_)
{
transition_->Stop();
transition_->Release();
}
transition_ = transition;
transition_->Retain();
transition_->Initialize(curr_scene_, next_scene_, this);
}
}
Scene * Game::GetCurrentScene()
{
return curr_scene_;
}
bool Game::IsTransitioning() const
{
return transition_ != nullptr;
}
void Game::UpdateScene(float dt)
{
auto update = [&](Scene * scene) -> void
{
if (scene)
{
scene->OnUpdate(dt);
Node * root = scene->GetRoot();
if (root)
{
root->UpdateChildren(dt);
}
}
};
update(curr_scene_);
update(next_scene_);
if (transition_)
{
transition_->Update();
if (transition_->IsDone())
{
transition_->Release();
transition_ = nullptr;
}
else
{
return;
}
}
if (next_scene_)
{
if (curr_scene_)
{
curr_scene_->OnExit();
curr_scene_->Release();
}
next_scene_->OnEnter();
curr_scene_ = next_scene_;
next_scene_ = nullptr;
}
}
void Game::DrawScene()
{
render::instance.BeginDraw(window::instance.handle);
if (transition_)
{
transition_->Draw();
}
else if (curr_scene_)
{
curr_scene_->Draw();
}
if (debug_mode_)
{
if (curr_scene_ && curr_scene_->GetRoot())
{
render::D2D.HwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
render::D2D.SolidColorBrush->SetOpacity(1.f);
curr_scene_->GetRoot()->DrawBorder();
}
if (next_scene_ && next_scene_->GetRoot())
{
render::D2D.HwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
render::D2D.SolidColorBrush->SetOpacity(1.f);
next_scene_->GetRoot()->DrawBorder();
}
render::instance.DrawDebugInfo();
}
render::instance.EndDraw();
}
void Game::SetDebugMode(bool enabled)
{
debug_mode_ = enabled;
}
}

96
core/base/Game.h Normal file
View File

@ -0,0 +1,96 @@
// 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 "base.h"
#include "window.h"
namespace easy2d
{
class Scene;
class Transition;
class Game
{
public:
Game();
~Game();
// 更新时
virtual void OnUpdate(float dt) {}
// 退出时
virtual void OnExit() {}
// 窗口关闭时
// 返回值:返回 false 将阻止窗口关闭
virtual bool OnClose() { return true; }
// 初始化
void Initialize(
const window::Property& property /* 窗口属性 */
);
// 运行
void Run();
// 结束
void Quit();
// 调试模式
void SetDebugMode(
bool enabled
);
// 切换场景
void EnterScene(
Scene * scene, /* 场景 */
Transition * transition = nullptr /* 场景动画 */
);
// 获取当前场景
Scene * GetCurrentScene();
// 是否正在进行场景过渡
bool IsTransitioning() const;
// 渲染场景画面
void DrawScene();
// 更新场景
void UpdateScene(
float dt
);
// 获取实例
static Game * GetInstance();
protected:
E2D_DISABLE_COPY(Game);
private:
bool debug_mode_;
bool quit_;
Scene* curr_scene_;
Scene* next_scene_;
Transition* transition_;
};
}

View File

@ -18,13 +18,16 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dobject.h"
#include "..\e2dmodule.h"
#include "..\e2dtool.h"
#include "Image.h"
#include "render.h"
#include "../utils/File.h"
namespace easy2d
{
std::map<size_t, ID2D1Bitmap*> Image::bitmap_cache_;
namespace
{
std::map<size_t, ID2D1Bitmap*> bitmap_cache_;
}
Image::Image()
: bitmap_(nullptr)
@ -47,14 +50,14 @@ namespace easy2d
this->Crop(crop_rect);
}
Image::Image(const std::wstring & file_name)
Image::Image(const String & file_name)
: bitmap_(nullptr)
, crop_rect_()
{
this->Load(file_name);
}
Image::Image(const std::wstring & file_name, const Rect & crop_rect)
Image::Image(const String & file_name, const Rect & crop_rect)
: bitmap_(nullptr)
, crop_rect_()
{
@ -79,7 +82,7 @@ namespace easy2d
return true;
}
bool Image::Load(const std::wstring & file_name)
bool Image::Load(const String & file_name)
{
E2D_WARNING_IF(file_name.empty(), "Image Load failed! Invalid file name.");
@ -92,7 +95,7 @@ namespace easy2d
return false;
}
this->SetBitmap(bitmap_cache_.at(std::hash<std::wstring>{}(file_name)));
this->SetBitmap(bitmap_cache_.at(std::hash<String>{}(file_name)));
return true;
}
@ -193,8 +196,8 @@ namespace easy2d
HRESULT hr;
HINSTANCE hinstance = GetModuleHandle(nullptr);
IWICImagingFactory* imaging_factory = Device::GetGraphics()->GetImagingFactory();
ID2D1HwndRenderTarget* render_target = Device::GetGraphics()->GetRenderTarget();
IWICImagingFactory* imaging_factory = render::D2D.WICImagingFactory;
ID2D1HwndRenderTarget* render_target = render::D2D.HwndRenderTarget;
IWICBitmapDecoder* decoder = nullptr;
IWICBitmapFrameDecode* source = nullptr;
IWICStream* stream = nullptr;
@ -279,9 +282,9 @@ namespace easy2d
return SUCCEEDED(hr);
}
bool Image::CacheBitmap(const std::wstring & file_name)
bool Image::CacheBitmap(const String & file_name)
{
size_t hash_code = std::hash<std::wstring>{}(file_name);
size_t hash_code = std::hash<String>{}(file_name);
if (bitmap_cache_.find(hash_code) != bitmap_cache_.end())
return true;
@ -291,11 +294,10 @@ namespace easy2d
// 用户输入的路径不一定是完整路径,因为用户可能通过 File::AddSearchPath 添加
// 默认搜索路径,所以需要通过 File::GetPath 获取完整路径
std::wstring image_file_path = image_file.GetPath();
String image_file_path = image_file.GetPath();
Graphics* graphics_device = Device::GetGraphics();
IWICImagingFactory* imaging_factory = graphics_device->GetImagingFactory();
ID2D1HwndRenderTarget* render_target = graphics_device->GetRenderTarget();
IWICImagingFactory* imaging_factory = render::D2D.WICImagingFactory;
ID2D1HwndRenderTarget* render_target = render::D2D.HwndRenderTarget;
IWICBitmapDecoder* decoder = nullptr;
IWICBitmapFrameDecode* source = nullptr;
IWICStream* stream = nullptr;

128
core/base/Image.h Normal file
View File

@ -0,0 +1,128 @@
// 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 "base.h"
#include "Resource.h"
#include "RefCounter.h"
namespace easy2d
{
// 图片
class Image
: public RefCounter
{
public:
Image();
explicit Image(
Resource& res
);
explicit Image(
Resource& res,
const Rect& crop_rect /* 裁剪矩形 */
);
explicit Image(
const String& file_name
);
explicit Image(
const String& file_name,
const Rect& crop_rect /* 裁剪矩形 */
);
virtual ~Image();
// 加载图片资源
bool Load(
Resource& res
);
// 加载图片资源
bool Load(
const String& file_name
);
// 将图片裁剪为矩形
void Crop(
const Rect& crop_rect /* 裁剪矩形 */
);
// 获取宽度
float GetWidth() const;
// 获取高度
float GetHeight() const;
// 获取大小
Size GetSize() const;
// 获取源图片宽度
float GetSourceWidth() const;
// 获取源图片高度
float GetSourceHeight() const;
// 获取源图片大小
Size GetSourceSize() const;
// 获取裁剪位置 X 坐标
float GetCropX() const;
// 获取裁剪位置 Y 坐标
float GetCropY() const;
// 获取裁剪位置
Point GetCropPos() const;
// 获取裁剪矩形
const Rect& GetCropRect() const;
// 获取 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
);
private:
Rect crop_rect_;
ID2D1Bitmap* bitmap_;
};
}

View File

@ -18,58 +18,61 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dmodule.h"
#include "input.h"
namespace easy2d
{
namespace
namespace input
{
Graphics * graphics_device = nullptr;
Input * input_device = nullptr;
Audio * audio_device = nullptr;
}
InputDevice instance;
Graphics * Device::GetGraphics()
{
return graphics_device;
}
Input * Device::GetInput()
{
return input_device;
}
Audio * Device::GetAudio()
{
return audio_device;
}
void Device::Init(HWND hwnd)
{
graphics_device = new (std::nothrow) Graphics(hwnd);
input_device = new (std::nothrow) Input(hwnd);
audio_device = new (std::nothrow) Audio();
}
void Device::Destroy()
{
if (audio_device)
InputDevice::InputDevice()
{
delete audio_device;
audio_device = nullptr;
ZeroMemory(keys_, sizeof(keys_));
}
if (input_device)
InputDevice::~InputDevice()
{
delete input_device;
input_device = nullptr;
}
if (graphics_device)
void InputDevice::Update(HWND hwnd, float xscale, float yscale)
{
delete graphics_device;
graphics_device = nullptr;
::GetKeyboardState(keys_);
POINT client_cursor_pos;
::GetCursorPos(&client_cursor_pos);
::ScreenToClient(hwnd, &client_cursor_pos);
mouse_pos_ = Point(client_cursor_pos.x * xscale, client_cursor_pos.y * yscale);
}
bool InputDevice::IsDown(KeyCode code)
{
if (keys_[static_cast<int>(code)] & 0x80)
return true;
return false;
}
bool InputDevice::IsDown(MouseCode code)
{
if (keys_[static_cast<int>(code)] & 0x80)
return true;
return false;
}
float InputDevice::GetMouseX()
{
return mouse_pos_.x;
}
float InputDevice::GetMouseY()
{
return mouse_pos_.y;
}
Point InputDevice::GetMousePos()
{
return mouse_pos_;
}
}
}

View File

@ -18,52 +18,52 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2daction.h"
#pragma once
#include "base.h"
namespace easy2d
{
Delay::Delay(float duration)
: delta_(0)
, delay_(std::max(duration, 0.f))
namespace input
{
}
Delay * Delay::Clone() const
{
return new Delay(delay_);
}
Delay * Delay::Reverse() const
{
return new Delay(delay_);
}
void Delay::Reset()
{
Action::Reset();
delta_ = 0;
}
void Delay::Init()
{
Action::Init();
}
void Delay::Update()
{
Action::Update();
delta_ = (Time::Now() - started_).Seconds();
if (delta_ >= delay_)
// 输入设备
class InputDevice
{
this->Stop();
}
}
public:
InputDevice();
void Delay::ResetTime()
{
Action::ResetTime();
started_ = Time::Now() - Duration::Second * delta_;
~InputDevice();
// 检测键盘某按键是否正被按下
bool IsDown(
KeyCode code
);
// 检测鼠标按键是否正被按下
bool IsDown(
MouseCode code
);
// 获得鼠标X轴坐标值
float GetMouseX();
// 获得鼠标Y轴坐标值
float GetMouseY();
// 获得鼠标坐标值
Point GetMousePos();
// 刷新设备状态
void Update(
HWND hwnd,
float xscale,
float yscale
);
protected:
BYTE keys_[256];
Point mouse_pos_;
};
extern InputDevice instance;
}
}
}

View File

@ -18,26 +18,29 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2daction.h"
#include "..\e2dobject.h"
#include "KeyEvent.h"
namespace easy2d
{
OpacityTo::OpacityTo(float duration, float opacity)
: OpacityBy(duration, 0)
KeyEvent::KeyEvent(UINT message, WPARAM w_param, LPARAM l_param)
: message_(message)
, w_param_(w_param)
, l_param_(l_param)
{
end_val_ = opacity;
}
OpacityTo * OpacityTo::Clone() const
KeyCode KeyEvent::GetCode() const
{
return new OpacityTo(duration_, end_val_);
return static_cast<KeyCode>(w_param_);
}
void OpacityTo::Init()
int KeyEvent::GetCount() const
{
OpacityBy::Init();
delta_val_ = end_val_ - start_val_;
return static_cast<int>((DWORD)l_param_ & 0x0000FFFF);
}
}
KeyEvent::Type KeyEvent::GetType() const
{
return Type(message_);
}
}

View File

@ -18,45 +18,51 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2daction.h"
#include "..\e2dobject.h"
#pragma once
#include "macros.h"
#include "BaseTypes.h"
namespace easy2d
{
RotateBy::RotateBy(float duration, float rotation)
: FiniteTimeAction(duration)
// 按键消息
class KeyEvent
{
delta_val_ = rotation;
}
void RotateBy::Init()
{
FiniteTimeAction::Init();
if (target_)
public:
// 按键消息类型
enum class Type : int
{
start_val_ = target_->GetRotation();
}
}
Down = 0x0100, // 按下
Up // 抬起
};
void RotateBy::Update()
public:
explicit KeyEvent(
UINT message,
WPARAM w_param,
LPARAM l_param
);
// 获取事件类型
KeyEvent::Type GetType() const;
// 获取按键键值
KeyCode GetCode() const;
// 获取按键次数
int GetCount() const;
protected:
UINT message_;
WPARAM w_param_;
LPARAM l_param_;
};
// 按键消息处理接口
class KeyEventHandler
{
FiniteTimeAction::Update();
if (target_)
{
target_->SetRotation(start_val_ + delta_val_ * delta_);
}
}
RotateBy * RotateBy::Clone() const
{
return new RotateBy(duration_, delta_val_);
}
RotateBy * RotateBy::Reverse() const
{
return new RotateBy(duration_, -delta_val_);
}
}
public:
// 处理按键消息
virtual void Handle(KeyEvent e) = 0;
};
}

View File

@ -18,8 +18,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2devent.h"
#include "..\e2dmodule.h"
#include "MouseEvent.h"
#include "window.h"
namespace easy2d
{
@ -32,22 +32,19 @@ namespace easy2d
float MouseEvent::GetX() const
{
float dpi = Graphics::GetDpi();
return ((float)(short)LOWORD(l_param_)) * 96.f / dpi;
return ((float)(short)LOWORD(l_param_)) * window::instance.xscale;
}
float MouseEvent::GetY() const
{
float dpi = Graphics::GetDpi();
return ((float)(short)HIWORD(l_param_)) * 96.f / dpi;
return ((float)(short)HIWORD(l_param_)) * window::instance.yscale;
}
Point MouseEvent::GetPosition() const
{
float dpi = Graphics::GetDpi();
return Point(
((float)(short)LOWORD(l_param_)) * 96.f / dpi,
((float)(short)HIWORD(l_param_)) * 96.f / dpi
((float)(short)LOWORD(l_param_)) * window::instance.xscale,
((float)(short)HIWORD(l_param_)) * window::instance.yscale
);
}

View File

@ -18,48 +18,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef __E2D_EVENT_H__
#define __E2D_EVENT_H__
#include "e2dutil.h"
#pragma once
#include "macros.h"
#include "BaseTypes.h"
namespace easy2d
{
// 按键消息
class KeyEvent
{
public:
// 按键消息类型
enum class Type : int
{
Down = 0x0100, // 按下
Up // 抬起
};
public:
explicit KeyEvent(
UINT message,
WPARAM w_param,
LPARAM l_param
);
// 获取事件类型
KeyEvent::Type GetType() const;
// 获取按键键值
KeyCode GetCode() const;
// 获取按键次数
int GetCount() const;
protected:
UINT message_;
WPARAM w_param_;
LPARAM l_param_;
};
// 報炎<E5A0B1>
class MouseEvent
{
@ -122,7 +86,12 @@ namespace easy2d
LPARAM l_param_;
};
} // end of easy2d namespace
#endif // __E2D_EVENT_H__
// 鼠标消息处理接口
class MouseEventHandler
{
public:
// 处理鼠标消息
virtual void Handle(MouseEvent e) = 0;
};
}

View File

@ -18,13 +18,14 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dobject.h"
#include "..\e2devent.h"
#include "..\e2daction.h"
#include "..\e2dmodule.h"
#include "Node.h"
#include "Scene.h"
#include "Task.h"
#include "Action.h"
#include "time.h"
#include "render.h"
#include <iterator>
namespace easy2d
{
Node::Node()
@ -74,7 +75,7 @@ namespace easy2d
if (!visible_)
return;
auto render_target = Device::GetGraphics()->GetRenderTarget();
auto render_target = render::D2D.HwndRenderTarget;
if (clip_enabled_)
{
render_target->SetTransform(final_matrix_);
@ -175,12 +176,10 @@ namespace easy2d
{
if (border_)
{
auto graphics = Device::GetGraphics();
auto brush = graphics->GetSolidBrush();
brush->SetColor(D2D1_COLOR_F(border_color_));
graphics->GetRenderTarget()->DrawGeometry(
render::D2D.SolidColorBrush->SetColor(D2D1_COLOR_F(border_color_));
render::D2D.HwndRenderTarget->DrawGeometry(
border_,
brush,
render::D2D.SolidColorBrush,
1.5f
);
}
@ -222,7 +221,7 @@ namespace easy2d
// 重新构造轮廓
SafeRelease(border_);
ID2D1Factory * factory = Device::GetGraphics()->GetFactory();
ID2D1Factory * factory = render::D2D.Factory;
ID2D1RectangleGeometry * rectangle = nullptr;
ID2D1TransformedGeometry * transformed = nullptr;
ThrowIfFailed(
@ -329,7 +328,7 @@ namespace easy2d
return visible_;
}
const std::wstring& Node::GetName() const
const String& Node::GetName() const
{
return name_;
}
@ -409,7 +408,7 @@ namespace easy2d
return transform_.rotation;
}
const Transform & Node::GetTransform() const
const math::Transform & Node::GetTransform() const
{
return transform_;
}
@ -585,7 +584,7 @@ namespace easy2d
this->SetSize(size.width, size.height);
}
void Node::SetTransform(const Transform & transform)
void Node::SetTransform(const math::Transform & transform)
{
transform_ = transform;
dirty_transform_ = true;
@ -656,10 +655,10 @@ namespace easy2d
return parent_scene_;
}
Node::Nodes Node::GetChildren(const std::wstring& name) const
Node::Nodes Node::GetChildren(const String& name) const
{
Nodes children;
size_t hash_code = std::hash<std::wstring>{}(name);
size_t hash_code = std::hash<String>{}(name);
for (const auto& child : children_)
{
@ -672,9 +671,9 @@ namespace easy2d
return children;
}
Node * Node::GetChild(const std::wstring& name) const
Node * Node::GetChild(const String& name) const
{
size_t hash_code = std::hash<std::wstring>{}(name);
size_t hash_code = std::hash<String>{}(name);
for (const auto& child : children_)
{
@ -734,14 +733,14 @@ namespace easy2d
return false;
}
void Node::RemoveChildren(const std::wstring& child_name)
void Node::RemoveChildren(const String& child_name)
{
if (children_.empty())
{
return;
}
size_t hash_code = std::hash<std::wstring>{}(child_name);
size_t hash_code = std::hash<String>{}(child_name);
for (auto iter = children_.begin(); iter != children_.end();)
{
if ((*iter)->hash_name_ == hash_code && (*iter)->name_ == child_name)
@ -795,7 +794,7 @@ namespace easy2d
}
}
void Node::ResumeAction(const std::wstring& name)
void Node::ResumeAction(const String& name)
{
if (actions_.empty())
return;
@ -809,7 +808,7 @@ namespace easy2d
}
}
void Node::PauseAction(const std::wstring& name)
void Node::PauseAction(const String& name)
{
if (actions_.empty())
return;
@ -823,7 +822,7 @@ namespace easy2d
}
}
void Node::StopAction(const std::wstring& name)
void Node::StopAction(const String& name)
{
if (actions_.empty())
return;
@ -923,13 +922,13 @@ namespace easy2d
if (iter == tasks_.end())
{
task->Retain();
task->last_time_ = Time::Now();
task->last_time_ = time::Now();
tasks_.push_back(task);
}
}
}
void Node::StopTasks(const std::wstring& name)
void Node::StopTasks(const String& name)
{
for (const auto& task : tasks_)
{
@ -940,7 +939,7 @@ namespace easy2d
}
}
void Node::StartTasks(const std::wstring& name)
void Node::StartTasks(const String& name)
{
for (const auto& task : tasks_)
{
@ -951,7 +950,7 @@ namespace easy2d
}
}
void Node::RemoveTasks(const std::wstring& name)
void Node::RemoveTasks(const String& name)
{
for (const auto& task : tasks_)
{
@ -1047,14 +1046,14 @@ namespace easy2d
visible_ = value;
}
void Node::SetName(const std::wstring& name)
void Node::SetName(const String& name)
{
if (name_ != name)
{
// 保存节点名
name_ = name;
// 保存节点 Hash 名
hash_name_ = std::hash<std::wstring>{}(name);
hash_name_ = std::hash<String>{}(name);
}
}

469
core/base/Node.h Normal file
View File

@ -0,0 +1,469 @@
// 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 "base.h"
#include "RefCounter.h"
#include "../math/Transform.h"
#include "KeyEvent.h"
#include "MouseEvent.h"
namespace easy2d
{
class Game;
class Scene;
class Action;
class Task;
// 节点
class Node
: public RefCounter
{
friend class Game;
friend class Scene;
public:
typedef std::vector<Node*> Nodes;
typedef std::vector<Action*> Actions;
typedef std::vector<Task*> Tasks;
Node();
virtual ~Node();
// 渲染节点
virtual void OnDraw() const {}
// 更新节点
virtual void OnUpdate(float dt) {}
// 获取节点显示状态
bool IsVisible() const;
// 获取节点名称
const String& GetName() const;
// 获取节点名称的 Hash 值
size_t GetHashName() const;
// 获取节点绘图顺序
int GetOrder() const;
// 获取节点坐标
const Point& GetPosition() const;
// 获取节点宽度
float GetWidth() const;
// 获取节点高度
float GetHeight() const;
// 获取节点宽度(不考虑缩放)
float GetRealWidth() const;
// 获取节点高度(不考虑缩放)
float GetRealHeight() const;
// 获取节点大小(不考虑缩放)
const Size& GetRealSize() const;
// 获取节点的支点
float GetPivotX() const;
// 获取节点的支点
float GetPivotY() const;
// 获取节点大小
Size GetSize() const;
// 获取节点横向缩放比例
float GetScaleX() const;
// 获取节点纵向缩放比例
float GetScaleY() const;
// 获取节点横向倾斜角度
float GetSkewX() const;
// 获取节点纵向倾斜角度
float GetSkewY() const;
// 获取节点旋转角度
float GetRotation() const;
// 获取二维转换矩阵
const math::Transform& GetTransform() const;
// 获取节点透明度
float GetOpacity() const;
// 获取显示透明度
float GetDisplayOpacity() const;
// 获取父节点
Node * GetParent() const;
// 获取节点所在场景
Scene * GetParentScene() const;
// 设置节点是否显示
void SetVisible(
bool value
);
// 设置节点名称
void SetName(
const String& name
);
// 设置节点横坐标
virtual void SetPositionX(
float x
);
// 设置节点纵坐标
virtual void SetPositionY(
float y
);
// 设置节点坐标
virtual void SetPosition(
const Point & point
);
// 设置节点坐标
virtual void SetPosition(
float x,
float y
);
// 移动节点
virtual void MoveBy(
float x,
float y
);
// 移动节点
virtual void MoveBy(
const Point & vector
);
// 设置节点绘图顺序
// 默认为 0
virtual void SetOrder(
int order
);
// 设置横向缩放比例
// 默认为 1.0
virtual void SetScaleX(
float scale_x
);
// 设置纵向缩放比例
// 默认为 1.0
virtual void SetScaleY(
float scale_y
);
// 设置缩放比例
// 默认为 (1.0, 1.0)
virtual void SetScale(
float scale_x,
float scale_y
);
// 设置缩放比例
// 默认为 1.0
virtual void SetScale(
float scale
);
// 设置横向倾斜角度
// 默认为 0
virtual void SetSkewX(
float skew_x
);
// 设置纵向倾斜角度
// 默认为 0
virtual void SetSkewY(
float skew_y
);
// 设置倾斜角度
// 默认为 (0, 0)
virtual void SetSkew(
float skew_x,
float skew_y
);
// 设置旋转角度
// 默认为 0
virtual void SetRotation(
float rotation
);
// 设置透明度
// 默认为 1.0, 范围 [0, 1]
virtual void SetOpacity(
float opacity
);
// 设置支点的横向位置
// 默认为 0, 范围 [0, 1]
virtual void SetPivotX(
float pivot_x
);
// 设置支点的纵向位置
// 默认为 0, 范围 [0, 1]
virtual void SetPivotY(
float pivot_y
);
// 设置支点位置
// 默认为 (0, 0), 范围 [0, 1]
virtual void SetPivot(
float pivot_x,
float pivot_y
);
// 修改节点宽度
virtual void SetWidth(
float width
);
// 修改节点高度
virtual void SetHeight(
float height
);
// 修改节点大小
virtual void SetSize(
float width,
float height
);
// 修改节点大小
virtual void SetSize(
const Size & size
);
// 设置二维转换
virtual void SetTransform(
const math::Transform& transform
);
// 启用或关闭渲染区域裁剪
virtual void SetClipEnabled(
bool enabled
);
// 设置节点边缘颜色
virtual void SetBorderColor(
const Color& color
);
// 判断点是否在节点内
bool ContainsPoint(
const Point& point
);
// 判断两物体是否相交
bool Intersects(
Node * node
);
// 添加子节点
void AddChild(
Node * child,
int order = 0 /* 渲染顺序 */
);
// 添加多个子节点
void AddChild(
const Nodes& nodes, /* 节点数组 */
int order = 0 /* 渲染顺序 */
);
// 获取所有名称相同的子节点
Nodes GetChildren(
const String& name
) const;
// 获取名称相同的子节点
Node* GetChild(
const String& name
) const;
// 获取所有子节点
const Nodes& GetAllChildren() const;
// 获取子节点数量
int GetChildrenCount() const;
// 移除子节点
bool RemoveChild(
Node * child
);
// 移除所有名称相同的子节点
void RemoveChildren(
const String& child_name
);
// 移除所有节点
void RemoveAllChildren();
// 从父节点移除
void RemoveFromParent();
// 执行动作
void RunAction(
Action * action
);
// 继续动作
void ResumeAction(
const String& name
);
// 暂停动作
void PauseAction(
const String& name
);
// 停止动作
void StopAction(
const String& name
);
// 继续所有暂停动作
void ResumeAllActions();
// 暂停所有动作
void PauseAllActions();
// 停止所有动作
void StopAllActions();
// 获取所有动作
const Actions& GetAllActions() const;
// 添加任务
void AddTask(
Task * task
);
// 启动任务
void StartTasks(
const String& task_name
);
// 停止任务
void StopTasks(
const String& task_name
);
// 移除任务
void RemoveTasks(
const String& task_name
);
// 启动所有任务
void StartAllTasks();
// 停止所有任务
void StopAllTasks();
// 移除所有任务
void RemoveAllTasks();
// 获取所有任务
const Tasks& GetAllTasks() const;
protected:
// 遍历节点
virtual void Visit();
// 分发鼠标消息
virtual bool Dispatch(
const MouseEvent& e,
bool handled
);
// 分发按键消息
virtual bool Dispatch(
const KeyEvent& e,
bool handled
);
private:
E2D_DISABLE_COPY(Node);
// 渲染节点边缘
void DrawBorder();
// 设置节点所在场景
void SetParentScene(
Scene * scene
);
// 更新子节点
void UpdateChildren(float dt);
// 更新转换矩阵
void UpdateTransform();
// 更新节点透明度
void UpdateOpacity();
// 更新动作
void UpdateActions();
// 更新任务
void UpdateTasks();
// 更新节点时间
void UpdateTime();
private:
String name_;
size_t hash_name_;
math::Transform transform_;
float display_opacity_;
float real_opacity_;
int order_;
bool visible_;
bool clip_enabled_;
bool dirty_sort_;
bool dirty_transform_;
Scene* parent_scene_;
Node* parent_;
Color border_color_;
Actions actions_;
Tasks tasks_;
Nodes children_;
ID2D1Geometry* border_;
D2D1::Matrix3x2F initial_matrix_;
D2D1::Matrix3x2F final_matrix_;
};
}

100
core/base/Rect.hpp Normal file
View File

@ -0,0 +1,100 @@
// 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 "BaseTypes.h"
namespace easy2d
{
// 矩形
//
// Usage:
// 表示一个二维矩形: Rect rect = Rect(10, 20, 30, 40); // 左上角坐标为 (10, 20), 宽为 30, 高为 40
// 矩形可以通过 Point + Size 定义, Point 表示矩形左上角坐标, Size 表示矩形宽高
// 判断一个点是否在矩形内: bool contains = rect.ContainsPoint(p);
// 判断两矩形是否相交: bool intersects = rect1.Intersects(rect2);
//
class Rect
{
public:
Point origin; // 左上角坐标
Size size; // 宽度和高度
public:
Rect() {}
Rect(
float x,
float y,
float width,
float height
)
: origin(x, y)
, size(width, height)
{}
Rect(
const Point& pos,
const Size& size
)
: origin(pos.x, pos.y)
, size(size.width, size.height)
{}
Rect(
const Rect& other
)
: origin(other.origin.x, other.origin.y)
, size(other.size.width, other.size.height)
{}
Rect& operator= (const Rect& other)
{
origin = other.origin;
size = other.size;
return *this;
}
inline bool operator== (const Rect& rect) const
{
return (origin == rect.origin) && (size == rect.size);
}
// 判断点是否在矩形内
inline bool ContainsPoint(
const Point& point
) const
{
return point.x >= origin.x && point.x <= (origin.y + size.height) &&
point.y >= origin.y && point.y <= (origin.y + size.height);
}
// 判断两矩形是否相交
inline bool Intersects(
const Rect& rect
) const
{
return !((origin.x + size.width) < rect.origin.x ||
(rect.origin.x + rect.size.width) < origin.x ||
(origin.y + size.height) < rect.origin.y ||
(rect.origin.y + rect.size.height) < origin.y);
}
};
}

View File

@ -18,28 +18,27 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dobject.h"
#include "RefCounter.h"
namespace easy2d
{
Ref::Ref()
RefCounter::RefCounter()
{
// 当对象被创建时,意味着它已经被引用了一次
ref_count_ = 1;
ref_count_ = 0;
}
Ref::~Ref()
RefCounter::~RefCounter()
{
}
LONG Ref::Retain()
long RefCounter::Retain()
{
return ::InterlockedIncrement(&ref_count_);
}
LONG Ref::Release()
long RefCounter::Release()
{
LONG new_count = ::InterlockedDecrement(&ref_count_);
long new_count = ::InterlockedDecrement(&ref_count_);
if (new_count <= 0)
{
@ -50,7 +49,7 @@ namespace easy2d
return new_count;
}
LONG Ref::GetRefCount() const
long RefCounter::GetRefCount() const
{
return ref_count_;
}

View File

@ -18,14 +18,29 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dutil.h"
#pragma once
#include "macros.h"
namespace easy2d
{
std::default_random_engine &Random::GetEngine()
// 引用计数
class RefCounter
{
static std::random_device device;
static std::default_random_engine engine(device());
return engine;
}
}
public:
RefCounter();
virtual ~RefCounter();
// 增加引用计数
long Retain();
// 减少引用计数
long Release();
// 获取引用计数
long GetRefCount() const;
private:
long ref_count_;
};
}

View File

@ -18,8 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dtool.h"
#include "Resource.h"
namespace easy2d
{

67
core/base/Resource.h Normal file
View File

@ -0,0 +1,67 @@
// 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 "macros.h"
namespace easy2d
{
// 资源
//
// Usage:
// Resource 用于获取可执行文件 (exe) 中的资源, 必须在构造函数中指定它的
// 资源类型和名称标识符。
// 例如, 一份音频资源的类型为 L"WAVE", 名称标识符为 IDR_WAVE_1, 那么可以这样指定该资源:
// Resource res(MAKEINTRESOURCE(IDR_WAVE_1), L"WAVE");
// 如果需要手动加载这份资源, 可以通过 Load 方法获取资源内容
// if (res.Load()) {
// LPVOID data = res.GetData();
// DWORD size = res.GetDataSize();
// }
// 了解资源的更多信息: https://docs.microsoft.com/en-us/windows/desktop/menurc/resources
//
class Resource
{
public:
Resource(
LPCWSTR name, /* 资源名称 */
LPCWSTR type /* 资源类型 */
);
bool Load();
LPCWSTR GetName() const;
LPCWSTR GetType() const;
LPVOID GetData() const;
DWORD GetDataSize() const;
size_t GetHashCode() const;
private:
bool loaded_;
LPCWSTR name_;
LPCWSTR type_;
LPVOID data_;
DWORD data_size_;
};
}

View File

@ -18,8 +18,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dmodule.h"
#include "..\e2dobject.h"
#include "Scene.h"
#include "Node.h"
namespace easy2d
{
@ -120,4 +120,4 @@ namespace easy2d
{
return transform_;
}
}
}

View File

@ -18,54 +18,72 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2daction.h"
#include "..\e2dobject.h"
#pragma once
#include "RefCounter.h"
#include "KeyEvent.h"
#include "MouseEvent.h"
#include <d2d1.h>
namespace easy2d
{
ScaleBy::ScaleBy(float duration, float scale)
: FiniteTimeAction(duration)
class Node;
// 场景
class Scene
: public RefCounter
{
delta_x_ = scale;
delta_y_ = scale;
}
public:
Scene();
ScaleBy::ScaleBy(float duration, float scale_x, float scale_y)
: FiniteTimeAction(duration)
{
delta_x_ = scale_x;
delta_y_ = scale_y;
}
explicit Scene(
Node * root
);
void ScaleBy::Init()
{
FiniteTimeAction::Init();
virtual ~Scene();
if (target_)
{
start_scale_x_ = target_->GetScaleX();
start_scale_y_ = target_->GetScaleY();
}
}
// 进入场景
virtual void OnEnter() {}
void ScaleBy::Update()
{
FiniteTimeAction::Update();
// 退出场景
virtual void OnExit() {}
if (target_)
{
target_->SetScale(start_scale_x_ + delta_x_ * delta_, start_scale_y_ + delta_y_ * delta_);
}
}
// 更新场景
virtual void OnUpdate(float dt) {}
ScaleBy * ScaleBy::Clone() const
{
return new ScaleBy(duration_, delta_x_, delta_y_);
}
// 设置根节点
void SetRoot(
Node * root
);
ScaleBy * ScaleBy::Reverse() const
{
return new ScaleBy(duration_, -delta_x_, -delta_y_);
}
}
// 获取根节点
Node* GetRoot() const;
// 渲染场景
void Draw();
// 分发鼠标消息
virtual void Dispatch(
const MouseEvent& e
);
// 分发按键消息
virtual void Dispatch(
const KeyEvent& e
);
// 设置转换矩阵
void SetTransform(
const D2D1::Matrix3x2F& matrix
);
// 获取转换矩阵
const D2D1::Matrix3x2F& GetTransform() const;
private:
E2D_DISABLE_COPY(Scene);
private:
Node* root_;
D2D1::Matrix3x2F transform_;
};
}

View File

@ -18,7 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dutil.h"
#include "Size.h"
namespace easy2d
{
@ -60,11 +60,6 @@ namespace easy2d
return Size(width / value, height / value);
}
Size::operator Point() const
{
return Point(width, height);
}
Size Size::operator-() const
{
return Size(-width, -height);
@ -74,4 +69,4 @@ namespace easy2d
{
return (width == other.width) && (height == other.height);
}
}
}

View File

@ -18,45 +18,39 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2daction.h"
#include "..\e2dobject.h"
#pragma once
namespace easy2d
{
OpacityBy::OpacityBy(float duration, float opacity)
: FiniteTimeAction(duration)
// 大小
//
// Usage:
// 表示一个二维矩形区域的大小: Size s(10, 5); // 宽为 10, 高为 5
// 大小可以相加减: Size s = Size(10, 10) + Size(20, 20); // s 的大小是宽高均为 30
//
class Size
{
delta_val_ = opacity;
}
public:
float width; // 宽度
float height; // 高度
void OpacityBy::Init()
{
FiniteTimeAction::Init();
public:
Size();
if (target_)
{
start_val_ = target_->GetOpacity();
}
}
Size(
float width,
float height
);
void OpacityBy::Update()
{
FiniteTimeAction::Update();
Size(
const Size& other
);
if (target_)
{
target_->SetOpacity(start_val_ + delta_val_ * delta_);
}
}
OpacityBy * OpacityBy::Clone() const
{
return new OpacityBy(duration_, delta_val_);
}
OpacityBy * OpacityBy::Reverse() const
{
return new OpacityBy(duration_, -delta_val_);
}
}
Size operator + (const Size & other) const;
Size operator - (const Size & other) const;
Size operator * (float value) const;
Size operator / (float value) const;
Size operator - () const;
bool operator== (const Size& other) const;
};
}

View File

@ -18,8 +18,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dobject.h"
#include "..\e2dmodule.h"
#include "Sprite.h"
#include "render.h"
#include <algorithm>
namespace easy2d
{
@ -47,13 +48,13 @@ namespace easy2d
Crop(crop_rect);
}
Sprite::Sprite(const std::wstring & file_name)
Sprite::Sprite(const String & file_name)
: image_(nullptr)
{
Load(file_name);
}
Sprite::Sprite(const std::wstring & file_name, const Rect & crop_rect)
Sprite::Sprite(const String & file_name, const Rect & crop_rect)
: image_(nullptr)
{
Load(file_name);
@ -99,7 +100,7 @@ namespace easy2d
return false;
}
bool Sprite::Load(const std::wstring & file_name)
bool Sprite::Load(const String & file_name)
{
if (!image_)
{
@ -134,7 +135,7 @@ namespace easy2d
if (image_ && image_->GetBitmap())
{
auto crop_pos = image_->GetCropPos();
Device::GetGraphics()->GetRenderTarget()->DrawBitmap(
render::D2D.HwndRenderTarget->DrawBitmap(
image_->GetBitmap(),
D2D1::RectF(0, 0, GetTransform().size.width, GetTransform().size.height),
GetDisplayOpacity(),

View File

@ -18,53 +18,73 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dmodule.h"
#pragma once
#include "Node.h"
#include "Image.h"
namespace easy2d
{
Audio::Audio()
: x_audio2_(nullptr)
, mastering_voice_(nullptr)
// 精灵
class Sprite
: public Node
{
ThrowIfFailed(
MFStartup(MF_VERSION)
public:
Sprite();
explicit Sprite(
Image * image
);
ThrowIfFailed(
XAudio2Create(&x_audio2_)
explicit Sprite(
Resource& res
);
ThrowIfFailed(
x_audio2_->CreateMasteringVoice(&mastering_voice_)
explicit Sprite(
Resource& res,
const Rect& crop_rect /* 裁剪矩形 */
);
}
Audio::~Audio()
{
if (mastering_voice_)
{
mastering_voice_->DestroyVoice();
mastering_voice_ = nullptr;
}
explicit Sprite(
const String& file_name
);
SafeRelease(x_audio2_);
explicit Sprite(
const String& file_name,
const Rect& crop_rect /* 裁剪矩形 */
);
MFShutdown();
}
virtual ~Sprite();
HRESULT Audio::CreateVoice(IXAudio2SourceVoice ** voice, WAVEFORMATEX * wfx)
{
return x_audio2_->CreateSourceVoice(voice, wfx, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
}
// 加载图片文件
bool Load(
Resource& res
);
void Audio::Open()
{
x_audio2_->StartEngine();
}
// 加载图片文件
bool Load(
const String& file_name
);
void Audio::Close()
{
x_audio2_->StopEngine();
}
}
// 加载图片
bool Load(
Image * image
);
// 将图片裁剪为矩形
void Crop(
const Rect& crop_rect /* 裁剪矩形 */
);
// 获取 Image 对象
Image * GetImage() const;
// 渲染精灵
virtual void OnDraw() const override;
private:
E2D_DISABLE_COPY(Sprite);
private:
Image* image_;
};
}

View File

@ -18,12 +18,11 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dobject.h"
#include "Task.h"
namespace easy2d
{
Task::Task(const Callback & func, const std::wstring & name)
Task::Task(const Callback & func, const String & name)
: running_(true)
, stopped_(false)
, run_times_(0)
@ -34,11 +33,11 @@ namespace easy2d
{
}
Task::Task(const Callback & func, float delay, int times, const std::wstring & name)
Task::Task(const Callback & func, float delay, int times, const String & name)
: running_(true)
, stopped_(false)
, run_times_(0)
, delay_(Duration::Second * std::max(delay, 0.f))
, delay_(time::Second * std::max(delay, 0.f))
, total_times_(times)
, callback_(func)
, name_(name)
@ -48,7 +47,7 @@ namespace easy2d
void Task::Start()
{
running_ = true;
last_time_ = Time::Now();
last_time_ = time::Now();
}
void Task::Stop()
@ -81,7 +80,7 @@ namespace easy2d
void Task::ResetTime()
{
last_time_ = Time::Now();
last_time_ = time::Now();
}
bool Task::IsReady() const
@ -92,7 +91,7 @@ namespace easy2d
{
return true;
}
if (Time::Now() - last_time_ >= delay_)
if (time::Now() - last_time_ >= delay_)
{
return true;
}
@ -105,7 +104,7 @@ namespace easy2d
return running_;
}
const std::wstring& Task::GetName() const
const String& Task::GetName() const
{
return name_;
}

84
core/base/Task.h Normal file
View File

@ -0,0 +1,84 @@
// 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 "base.h"
#include "time.h"
#include "RefCounter.h"
#include <functional>
namespace easy2d
{
class Node;
// 定时任务
class Task
: public RefCounter
{
friend class Node;
typedef std::function<void()> Callback;
public:
explicit Task(
const Callback& func, /* 执行函数 */
const String& name = L"" /* 任务名称 */
);
explicit Task(
const Callback& func, /* 执行函数 */
float delay, /* 时间间隔(秒) */
int times = -1, /* 执行次数(设 -1 为永久执行) */
const String& name = L"" /* 任务名称 */
);
// 启动任务
void Start();
// 停止任务
void Stop();
// 任务是否正在执行
bool IsRunning() const;
// 获取任务名称
const String& GetName() const;
// 任务是否就绪
bool IsReady() const;
// 执行任务
void Update();
// 重置计时
void ResetTime();
private:
bool running_;
bool stopped_;
int run_times_;
int total_times_;
String name_;
time::Duration delay_;
time::TimePoint last_time_;
Callback callback_;
Node * target_;
};
}

View File

@ -18,9 +18,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dobject.h"
#include "..\e2dmodule.h"
#include "Text.h"
#include "render.h"
#include "base.h"
namespace easy2d
{
@ -82,7 +82,7 @@ namespace easy2d
{
}
Text::Text(const std::wstring & text, const Font & font, const Style & style)
Text::Text(const String & text, const Font & font, const Style & style)
: font_(font)
, style_(style)
, text_layout_(nullptr)
@ -98,7 +98,7 @@ namespace easy2d
SafeRelease(text_layout_);
}
const std::wstring& Text::GetText() const
const String& Text::GetText() const
{
return text_;
}
@ -113,7 +113,7 @@ namespace easy2d
return style_;
}
const std::wstring& Text::GetFontFamily() const
const String& Text::GetFontFamily() const
{
return font_.family;
}
@ -182,7 +182,7 @@ namespace easy2d
return style_.outline;
}
void Text::SetText(const std::wstring& text)
void Text::SetText(const String& text)
{
text_ = text;
Reset();
@ -200,7 +200,7 @@ namespace easy2d
Reset();
}
void Text::SetFontFamily(const std::wstring& family)
void Text::SetFontFamily(const String& family)
{
font_.family = family;
Reset();
@ -315,21 +315,19 @@ namespace easy2d
{
if (text_layout_)
{
auto graphics = Device::GetGraphics();
// 创建文本区域
D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, GetTransform().size.width, GetTransform().size.height);
// 设置画刷颜色和透明度
graphics->GetSolidBrush()->SetOpacity(GetDisplayOpacity());
render::D2D.SolidColorBrush->SetOpacity(GetDisplayOpacity());
// 获取文本渲染器
auto text_renderer = graphics->GetTextRender();
graphics->SetTextRendererStyle(
render::D2D.TextRenderer->SetTextStyle(
style_.color,
style_.outline,
style_.outline_color,
style_.outline_width,
style_.outline_stroke
static_cast<D2D1_LINE_JOIN>(style_.outline_stroke)
);
text_layout_->Draw(nullptr, text_renderer, 0, 0);
text_layout_->Draw(nullptr, render::D2D.TextRenderer, 0, 0);
}
}
@ -346,7 +344,7 @@ namespace easy2d
SafeRelease(text_format_);
ThrowIfFailed(
Device::GetGraphics()->GetWriteFactory()->CreateTextFormat(
render::D2D.DWriteFactory->CreateTextFormat(
font_.family.c_str(),
nullptr,
DWRITE_FONT_WEIGHT(font_.weight),
@ -404,13 +402,12 @@ namespace easy2d
}
UINT32 length = static_cast<UINT32>(text_.size());
auto writeFactory = Device::GetGraphics()->GetWriteFactory();
// 对文本自动换行情况下进行处理
if (style_.wrap)
{
ThrowIfFailed(
writeFactory->CreateTextLayout(
render::D2D.DWriteFactory->CreateTextLayout(
text_.c_str(),
length,
text_format_,
@ -429,7 +426,7 @@ namespace easy2d
{
// 为防止文本对齐问题,根据先创建 layout 以获取宽度
ThrowIfFailed(
writeFactory->CreateTextLayout(
render::D2D.DWriteFactory->CreateTextLayout(
text_.c_str(),
length,
text_format_,
@ -448,7 +445,7 @@ namespace easy2d
// 重新创建 layout
SafeRelease(text_layout_);
ThrowIfFailed(
writeFactory->CreateTextLayout(
render::D2D.DWriteFactory->CreateTextLayout(
text_.c_str(),
length,
text_format_,
@ -460,14 +457,14 @@ namespace easy2d
}
// 添加下划线和删除线
DWRITE_TEXT_RANGE Range = { 0, length };
DWRITE_TEXT_RANGE range = { 0, length };
if (style_.underline)
{
text_layout_->SetUnderline(true, Range);
text_layout_->SetUnderline(true, range);
}
if (style_.strikethrough)
{
text_layout_->SetStrikethrough(true, Range);
text_layout_->SetStrikethrough(true, range);
}
}
}
}

242
core/base/Text.h Normal file
View File

@ -0,0 +1,242 @@
// 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 "Node.h"
#include "Font.h"
namespace easy2d
{
// 文本
class Text
: public Node
{
public:
// 文本对齐方式
enum class Align
{
Left, /* 左对齐 */
Right, /* 右对齐 */
Center /* 居中对齐 */
};
// 文本样式
class Style
{
public:
Color color; // 颜色
Align alignment; // 对齐方式
bool wrap; // 打开自动换行
float wrap_width; // 自动换行宽度
float line_spacing; // 行间距
bool underline; // 下划线
bool strikethrough; // 删除线
bool outline; // 显示描边
Color outline_color; // 描边颜色
float outline_width; // 描边线宽
Stroke outline_stroke; // 描边线相交样式
public:
Style();
Style(
Color color,
Align alignment = Align::Left,
bool wrap = false,
float wrap_width = 0.f,
float line_spacing = 0.f,
bool underline = false,
bool strikethrough = false,
bool outline = true,
Color outline_color = Color(Color::Black, 0.5),
float outline_width = 1.f,
Stroke outline_stroke = Stroke::Round
);
};
public:
Text();
explicit Text(
const String& text, /* 文字内容 */
const Font& font = Font(), /* 字体 */
const Style& style = Style() /* 文本样式 */
);
virtual ~Text();
// 获取文本
const String& GetText() const;
// 获取字体
const Font& GetFont() const;
// 获取文本样式
const Style& GetStyle() const;
// 获取字体族
const String& GetFontFamily() const;
// 获取当前字号
float GetFontSize() const;
// 获取当前字体粗细值
UINT GetFontWeight() const;
// 获取文字颜色
const Color& GetColor() const;
// 获取描边颜色
const Color& GetOutlineColor() const;
// 获取描边线宽
float GetOutlineWidth() const;
// 获取描边线相交样式
Stroke GetOutlineStroke() const;
// 获取文本显示行数
int GetLineCount() const;
// 是否是斜体
bool IsItalic() const;
// 是否显示删除线
bool strikethrough() const;
// 是否显示下划线
bool underline() const;
// 是否显示描边
bool outline() const;
// 设置文本
void SetText(
const String& text
);
// 设置文本样式
void SetStyle(
const Style& style
);
// 设置字体
void SetFont(
const Font& font
);
// 设置字体族
void SetFontFamily(
const String& family
);
// 设置字号(默认值为 22
void SetFontSize(
float size
);
// 设置字体粗细值(默认值为 Text::Font::Weight::Normal
void SetFontWeight(
UINT weight
);
// 设置文字颜色(默认值为 Color::WHITE
void SetColor(
Color color
);
// 设置文字斜体(默认值为 false
void SetItalic(
bool value
);
// 打开或关闭文本自动换行(默认为关闭)
void SetWrapEnabled(
bool wrap
);
// 设置文本自动换行的宽度(默认为 0
void SetWrapWidth(
float wrap_width
);
// 设置行间距(默认为 0
void SetLineSpacing(
float line_spacing
);
// 设置对齐方式(默认为 Align::Left
void SetAlignment(
Align align
);
// 设置下划线(默认值为 false
void SetUnderline(
bool underline
);
// 设置删除线(默认值为 false
void SetStrikethrough(
bool strikethrough
);
// 设置是否显示描边
void SetOutline(
bool outline
);
// 设置描边颜色
void SetOutlineColor(
Color outline_color
);
// 设置描边线宽
void SetOutlineWidth(
float outline_width
);
// 设置描边线相交样式
void SetOutlineStroke(
Stroke outline_stroke
);
// 渲染文字
virtual void OnDraw() const override;
private:
E2D_DISABLE_COPY(Text);
// 重新排版文字
void Reset();
// 创建文字格式化
void CreateFormat();
// 创建文字布局
void CreateLayout();
private:
String text_;
Font font_;
Style style_;
IDWriteTextFormat* text_format_;
IDWriteTextLayout* text_layout_;
};
}

398
core/base/TextRenderer.cpp Normal file
View File

@ -0,0 +1,398 @@
// 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.
#include "TextRenderer.h"
#include "base.h"
#include "render.h"
namespace easy2d
{
ITextRenderer::ITextRenderer(ID2D1Factory* pD2DFactory, ID2D1HwndRenderTarget* pRT, ID2D1SolidColorBrush* pBrush)
: cRefCount_(0)
, pD2DFactory_(pD2DFactory)
, pRT_(pRT)
, pBrush_(pBrush)
, sFillColor_()
, sOutlineColor_()
, fOutlineWidth(1)
, bShowOutline_(TRUE)
, pCurrStrokeStyle_(nullptr)
{
pD2DFactory->AddRef();
pRT->AddRef();
pBrush->AddRef();
}
ITextRenderer::~ITextRenderer()
{
SafeRelease(pD2DFactory_);
SafeRelease(pRT_);
SafeRelease(pBrush_);
}
HRESULT ITextRenderer::Create(
ITextRenderer** ppTextRenderer,
ID2D1Factory* pD2DFactory,
ID2D1HwndRenderTarget* pRT,
ID2D1SolidColorBrush* pBrush)
{
*ppTextRenderer = new (std::nothrow) ITextRenderer(pD2DFactory, pRT, pBrush);
if (*ppTextRenderer)
{
(*ppTextRenderer)->AddRef();
return S_OK;
}
return E_FAIL;
}
STDMETHODIMP_(void) ITextRenderer::SetTextStyle(
CONST D2D1_COLOR_F &fillColor,
BOOL outline,
CONST D2D1_COLOR_F &outline_color,
FLOAT outline_width,
D2D1_LINE_JOIN outlineJoin)
{
sFillColor_ = fillColor;
bShowOutline_ = outline;
sOutlineColor_ = outline_color;
fOutlineWidth = 2 * outline_width;
switch (outlineJoin)
{
case D2D1_LINE_JOIN_MITER:
pCurrStrokeStyle_ = render::D2D.MiterStrokeStyle;
break;
case D2D1_LINE_JOIN_BEVEL:
pCurrStrokeStyle_ = render::D2D.BevelStrokeStyle;
break;
case D2D1_LINE_JOIN_ROUND:
pCurrStrokeStyle_ = render::D2D.RoundStrokeStyle;
break;
default:
pCurrStrokeStyle_ = nullptr;
break;
}
}
STDMETHODIMP ITextRenderer::DrawGlyphRun(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
DWRITE_MEASURING_MODE measuringMode,
__in DWRITE_GLYPH_RUN const* glyphRun,
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
IUnknown* clientDrawingEffect)
{
HRESULT hr = S_OK;
ID2D1PathGeometry* pPathGeometry = nullptr;
hr = pD2DFactory_->CreatePathGeometry(
&pPathGeometry
);
ID2D1GeometrySink* pSink = nullptr;
if (SUCCEEDED(hr))
{
hr = pPathGeometry->Open(
&pSink
);
}
if (SUCCEEDED(hr))
{
hr = glyphRun->fontFace->GetGlyphRunOutline(
glyphRun->fontEmSize,
glyphRun->glyphIndices,
glyphRun->glyphAdvances,
glyphRun->glyphOffsets,
glyphRun->glyphCount,
glyphRun->isSideways,
glyphRun->bidiLevel % 2,
pSink
);
}
if (SUCCEEDED(hr))
{
hr = pSink->Close();
}
D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F(
1.0f, 0.0f,
0.0f, 1.0f,
baselineOriginX, baselineOriginY
);
ID2D1TransformedGeometry* pTransformedGeometry = nullptr;
if (SUCCEEDED(hr))
{
hr = pD2DFactory_->CreateTransformedGeometry(
pPathGeometry,
&matrix,
&pTransformedGeometry
);
}
if (SUCCEEDED(hr) && bShowOutline_)
{
pBrush_->SetColor(sOutlineColor_);
pRT_->DrawGeometry(
pTransformedGeometry,
pBrush_,
fOutlineWidth,
pCurrStrokeStyle_
);
}
if (SUCCEEDED(hr))
{
pBrush_->SetColor(sFillColor_);
pRT_->FillGeometry(
pTransformedGeometry,
pBrush_
);
}
SafeRelease(pPathGeometry);
SafeRelease(pSink);
SafeRelease(pTransformedGeometry);
return hr;
}
STDMETHODIMP ITextRenderer::DrawUnderline(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
__in DWRITE_UNDERLINE const* underline,
IUnknown* clientDrawingEffect)
{
HRESULT hr;
D2D1_RECT_F rect = D2D1::RectF(
0,
underline->offset,
underline->width,
underline->offset + underline->thickness
);
ID2D1RectangleGeometry* pRectangleGeometry = nullptr;
hr = pD2DFactory_->CreateRectangleGeometry(
&rect,
&pRectangleGeometry
);
D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F(
1.0f, 0.0f,
0.0f, 1.0f,
baselineOriginX, baselineOriginY
);
ID2D1TransformedGeometry* pTransformedGeometry = nullptr;
if (SUCCEEDED(hr))
{
hr = pD2DFactory_->CreateTransformedGeometry(
pRectangleGeometry,
&matrix,
&pTransformedGeometry
);
}
if (SUCCEEDED(hr) && bShowOutline_)
{
pBrush_->SetColor(sOutlineColor_);
pRT_->DrawGeometry(
pTransformedGeometry,
pBrush_,
fOutlineWidth,
pCurrStrokeStyle_
);
}
if (SUCCEEDED(hr))
{
pBrush_->SetColor(sFillColor_);
pRT_->FillGeometry(
pTransformedGeometry,
pBrush_
);
}
SafeRelease(pRectangleGeometry);
SafeRelease(pTransformedGeometry);
return S_OK;
}
STDMETHODIMP ITextRenderer::DrawStrikethrough(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
__in DWRITE_STRIKETHROUGH const* strikethrough,
IUnknown* clientDrawingEffect)
{
HRESULT hr;
D2D1_RECT_F rect = D2D1::RectF(
0,
strikethrough->offset,
strikethrough->width,
strikethrough->offset + strikethrough->thickness
);
ID2D1RectangleGeometry* pRectangleGeometry = nullptr;
hr = pD2DFactory_->CreateRectangleGeometry(
&rect,
&pRectangleGeometry
);
D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F(
1.0f, 0.0f,
0.0f, 1.0f,
baselineOriginX, baselineOriginY
);
ID2D1TransformedGeometry* pTransformedGeometry = nullptr;
if (SUCCEEDED(hr))
{
hr = pD2DFactory_->CreateTransformedGeometry(
pRectangleGeometry,
&matrix,
&pTransformedGeometry
);
}
if (SUCCEEDED(hr) && bShowOutline_)
{
pBrush_->SetColor(sOutlineColor_);
pRT_->DrawGeometry(
pTransformedGeometry,
pBrush_,
fOutlineWidth,
pCurrStrokeStyle_
);
}
if (SUCCEEDED(hr))
{
pBrush_->SetColor(sFillColor_);
pRT_->FillGeometry(
pTransformedGeometry,
pBrush_
);
}
SafeRelease(pRectangleGeometry);
SafeRelease(pTransformedGeometry);
return S_OK;
}
STDMETHODIMP ITextRenderer::DrawInlineObject(
__maybenull void* clientDrawingContext,
FLOAT originX,
FLOAT originY,
IDWriteInlineObject* inlineObject,
BOOL IsSideways,
BOOL IsRightToLeft,
IUnknown* clientDrawingEffect)
{
return E_NOTIMPL;
}
STDMETHODIMP_(unsigned long) ITextRenderer::AddRef()
{
return InterlockedIncrement(&cRefCount_);
}
STDMETHODIMP_(unsigned long) ITextRenderer::Release()
{
unsigned long newCount = InterlockedDecrement(&cRefCount_);
if (newCount == 0)
{
delete this;
return 0;
}
return newCount;
}
STDMETHODIMP ITextRenderer::IsPixelSnappingDisabled(
__maybenull void* clientDrawingContext,
__out BOOL* isDisabled)
{
*isDisabled = FALSE;
return S_OK;
}
STDMETHODIMP ITextRenderer::GetCurrentTransform(
__maybenull void* clientDrawingContext,
__out DWRITE_MATRIX* transform)
{
pRT_->GetTransform(reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
return S_OK;
}
STDMETHODIMP ITextRenderer::GetPixelsPerDip(
__maybenull void* clientDrawingContext,
__out FLOAT* pixelsPerDip)
{
float x, yUnused;
pRT_->GetDpi(&x, &yUnused);
*pixelsPerDip = x / 96;
return S_OK;
}
STDMETHODIMP ITextRenderer::QueryInterface(
IID const& riid,
void** ppvObject)
{
if (__uuidof(IDWriteTextRenderer) == riid)
{
*ppvObject = this;
}
else if (__uuidof(IDWritePixelSnapping) == riid)
{
*ppvObject = this;
}
else if (__uuidof(IUnknown) == riid)
{
*ppvObject = this;
}
else
{
*ppvObject = nullptr;
return E_FAIL;
}
AddRef();
return S_OK;
}
}

126
core/base/TextRenderer.h Normal file
View File

@ -0,0 +1,126 @@
// 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 "macros.h"
#include <d2d1.h>
#include <dwrite.h>
namespace easy2d
{
class ITextRenderer
: public IDWriteTextRenderer
{
public:
static HRESULT Create(
ITextRenderer** ppTextRenderer,
ID2D1Factory* pD2DFactory,
ID2D1HwndRenderTarget* pRT,
ID2D1SolidColorBrush* pBrush
);
STDMETHOD_(void, SetTextStyle)(
CONST D2D1_COLOR_F &fillColor,
BOOL outline,
CONST D2D1_COLOR_F &outline_color,
FLOAT outline_width,
D2D1_LINE_JOIN outlineJoin
);
STDMETHOD(DrawGlyphRun)(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
DWRITE_MEASURING_MODE measuringMode,
__in DWRITE_GLYPH_RUN const* glyphRun,
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
IUnknown* clientDrawingEffect
);
STDMETHOD(DrawUnderline)(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
__in DWRITE_UNDERLINE const* underline,
IUnknown* clientDrawingEffect
);
STDMETHOD(DrawStrikethrough)(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
__in DWRITE_STRIKETHROUGH const* strikethrough,
IUnknown* clientDrawingEffect
);
STDMETHOD(DrawInlineObject)(
__maybenull void* clientDrawingContext,
FLOAT originX,
FLOAT originY,
IDWriteInlineObject* inlineObject,
BOOL IsSideways,
BOOL IsRightToLeft,
IUnknown* clientDrawingEffect
);
STDMETHOD(IsPixelSnappingDisabled)(
__maybenull void* clientDrawingContext,
__out BOOL* isDisabled
);
STDMETHOD(GetCurrentTransform)(
__maybenull void* clientDrawingContext,
__out DWRITE_MATRIX* transform
);
STDMETHOD(GetPixelsPerDip)(
__maybenull void* clientDrawingContext,
__out FLOAT* pixelsPerDip
);
public:
unsigned long STDMETHODCALLTYPE AddRef();
unsigned long STDMETHODCALLTYPE Release();
HRESULT STDMETHODCALLTYPE QueryInterface(
IID const& riid,
void** ppvObject
);
private:
ITextRenderer(
ID2D1Factory* pD2DFactory,
ID2D1HwndRenderTarget* pRT,
ID2D1SolidColorBrush* pBrush
);
~ITextRenderer();
private:
unsigned long cRefCount_;
D2D1_COLOR_F sFillColor_;
D2D1_COLOR_F sOutlineColor_;
FLOAT fOutlineWidth;
BOOL bShowOutline_;
ID2D1Factory* pD2DFactory_;
ID2D1HwndRenderTarget* pRT_;
ID2D1SolidColorBrush* pBrush_;
ID2D1StrokeStyle* pCurrStrokeStyle_;
};
}

448
core/base/Transition.cpp Normal file
View File

@ -0,0 +1,448 @@
// 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.
#include "Transition.h"
#include "Node.h"
#include "Scene.h"
#include "render.h"
#include "window.h"
namespace easy2d
{
//-------------------------------------------------------
// Transition
//-------------------------------------------------------
Transition::Transition(float duration)
: done_(false)
, started_()
, process_(0)
, window_size_()
, out_scene_(nullptr)
, in_scene_(nullptr)
, out_layer_(nullptr)
, in_layer_(nullptr)
, out_layer_param_()
, in_layer_param_()
{
duration_ = std::max(duration, 0.f);
}
Transition::~Transition()
{
SafeRelease(out_layer_);
SafeRelease(in_layer_);
SafeRelease(out_scene_);
SafeRelease(in_scene_);
}
bool Transition::IsDone()
{
return done_;
}
void Transition::Initialize(Scene * prev, Scene * next, Game * game)
{
started_ = time::Now();
out_scene_ = prev;
in_scene_ = next;
if (out_scene_)
out_scene_->Retain();
if (in_scene_)
in_scene_->Retain();
if (in_scene_)
{
ThrowIfFailed(
render::D2D.HwndRenderTarget->CreateLayer(&in_layer_)
);
}
if (out_scene_)
{
ThrowIfFailed(
render::D2D.HwndRenderTarget->CreateLayer(&out_layer_)
);
}
window_size_ = window::instance.GetSize();
out_layer_param_ = in_layer_param_ = D2D1::LayerParameters(
D2D1::RectF(
0.f,
0.f,
window_size_.width,
window_size_.height
),
nullptr,
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
D2D1::Matrix3x2F::Identity(),
1.f,
render::D2D.SolidColorBrush,
D2D1_LAYER_OPTIONS_NONE
);
}
void Transition::Update()
{
if (duration_ == 0)
{
process_ = 1;
}
else
{
process_ = (time::Now() - started_).Seconds() / duration_;
process_ = std::min(process_, 1.f);
}
if (process_ >= 1)
{
this->Stop();
}
}
void Transition::Draw()
{
auto render_target = render::D2D.HwndRenderTarget;
if (out_scene_)
{
render_target->SetTransform(out_scene_->GetTransform());
render_target->PushAxisAlignedClip(
D2D1::RectF(
0.f,
0.f,
window_size_.width,
window_size_.height
),
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
);
render_target->PushLayer(out_layer_param_, out_layer_);
out_scene_->Draw();
render_target->PopLayer();
render_target->PopAxisAlignedClip();
}
if (in_scene_)
{
render_target->SetTransform(in_scene_->GetTransform());
render_target->PushAxisAlignedClip(
D2D1::RectF(
0.f,
0.f,
window_size_.width,
window_size_.height
),
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
);
render_target->PushLayer(in_layer_param_, in_layer_);
in_scene_->Draw();
render_target->PopLayer();
render_target->PopAxisAlignedClip();
}
}
void Transition::Stop()
{
done_ = true;
Reset();
}
//-------------------------------------------------------
// BoxTransition
//-------------------------------------------------------
BoxTransition::BoxTransition(float duration)
: Transition(duration)
{
}
void BoxTransition::Initialize(Scene * prev, Scene * next, Game * game)
{
Transition::Initialize(prev, next, game);
in_layer_param_.opacity = 0;
}
void BoxTransition::Update()
{
Transition::Update();
if (process_ < .5f)
{
out_layer_param_.contentBounds = D2D1::RectF(
window_size_.width * process_,
window_size_.height * process_,
window_size_.width * (1 - process_),
window_size_.height * (1 - process_)
);
}
else
{
out_layer_param_.opacity = 0;
in_layer_param_.opacity = 1;
in_layer_param_.contentBounds = D2D1::RectF(
window_size_.width * (1 - process_),
window_size_.height * (1 - process_),
window_size_.width * process_,
window_size_.height * process_
);
}
}
//-------------------------------------------------------
// EmergeTransition
//-------------------------------------------------------
EmergeTransition::EmergeTransition(float duration)
: Transition(duration)
{
}
void EmergeTransition::Initialize(Scene * prev, Scene * next, Game * game)
{
Transition::Initialize(prev, next, game);
out_layer_param_.opacity = 1;
in_layer_param_.opacity = 0;
}
void EmergeTransition::Update()
{
Transition::Update();
out_layer_param_.opacity = 1 - process_;
in_layer_param_.opacity = process_;
}
//-------------------------------------------------------
// FadeTransition
//-------------------------------------------------------
FadeTransition::FadeTransition(float duration)
: Transition(duration)
{
}
void FadeTransition::Initialize(Scene * prev, Scene * next, Game * game)
{
Transition::Initialize(prev, next, game);
out_layer_param_.opacity = 1;
in_layer_param_.opacity = 0;
}
void FadeTransition::Update()
{
Transition::Update();
if (process_ < 0.5)
{
out_layer_param_.opacity = 1 - process_ * 2;
in_layer_param_.opacity = 0;
}
else
{
out_layer_param_.opacity = 0;
in_layer_param_.opacity = (process_ - 0.5f) * 2;
}
}
//-------------------------------------------------------
// MoveTransition
//-------------------------------------------------------
MoveTransition::MoveTransition(float duration, Direction direction)
: Transition(duration)
, direction_(direction)
{
}
void MoveTransition::Initialize(Scene * prev, Scene * next, Game * game)
{
Transition::Initialize(prev, next, game);
switch (direction_)
{
case Direction::Up:
pos_delta_ = Point(0, -window_size_.height);
start_pos_ = Point(0, window_size_.height);
break;
case Direction::Down:
pos_delta_ = Point(0, window_size_.height);
start_pos_ = Point(0, -window_size_.height);
break;
case Direction::Left:
pos_delta_ = Point(-window_size_.width, 0);
start_pos_ = Point(window_size_.width, 0);
break;
case Direction::Right:
pos_delta_ = Point(window_size_.width, 0);
start_pos_ = Point(-window_size_.width, 0);
break;
}
if (out_scene_)
{
out_scene_->SetTransform(D2D1::Matrix3x2F::Identity());
}
if (in_scene_)
{
in_scene_->SetTransform(
D2D1::Matrix3x2F::Translation(
start_pos_.x,
start_pos_.y
)
);
}
}
void MoveTransition::Update()
{
Transition::Update();
if (out_scene_)
{
auto translation = pos_delta_ * process_;
out_scene_->SetTransform(
D2D1::Matrix3x2F::Translation(
translation.x,
translation.y
)
);
}
if (in_scene_)
{
auto translation = start_pos_ + pos_delta_ * process_;
in_scene_->SetTransform(
D2D1::Matrix3x2F::Translation(
translation.x,
translation.y
)
);
}
}
void MoveTransition::Reset()
{
if (out_scene_)
{
out_scene_->SetTransform(D2D1::Matrix3x2F::Identity());
}
if (in_scene_)
{
in_scene_->SetTransform(D2D1::Matrix3x2F::Identity());
}
}
//-------------------------------------------------------
// RotationTransition
//-------------------------------------------------------
RotationTransition::RotationTransition(float duration, float rotation)
: Transition(duration)
, rotation_(rotation)
{
}
void RotationTransition::Initialize(Scene * prev, Scene * next, Game * game)
{
Transition::Initialize(prev, next, game);
if (out_scene_)
{
out_scene_->SetTransform(D2D1::Matrix3x2F::Identity());
}
if (in_scene_)
{
in_scene_->SetTransform(D2D1::Matrix3x2F::Identity());
}
in_layer_param_.opacity = 0;
}
void RotationTransition::Update()
{
Transition::Update();
auto center_pos = D2D1::Point2F(
window_size_.width / 2,
window_size_.height / 2
);
if (process_ < .5f)
{
if (out_scene_)
{
out_scene_->SetTransform(
D2D1::Matrix3x2F::Scale(
(.5f - process_) * 2,
(.5f - process_) * 2,
center_pos
) * D2D1::Matrix3x2F::Rotation(
rotation_ * (.5f - process_) * 2,
center_pos
)
);
}
}
else
{
if (in_scene_)
{
out_layer_param_.opacity = 0;
in_layer_param_.opacity = 1;
in_scene_->SetTransform(
D2D1::Matrix3x2F::Scale(
(process_ - .5f) * 2,
(process_ - .5f) * 2,
center_pos
) * D2D1::Matrix3x2F::Rotation(
rotation_ * (process_ - .5f) * 2,
center_pos
)
);
}
}
}
void RotationTransition::Reset()
{
if (out_scene_)
{
out_scene_->SetTransform(D2D1::Matrix3x2F::Identity());
}
if (in_scene_)
{
in_scene_->SetTransform(D2D1::Matrix3x2F::Identity());
}
}
}

View File

@ -18,21 +18,19 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef __E2D_TRANSITION_H__
#define __E2D_TRANSITION_H__
#include "e2dutil.h"
#pragma once
#include "base.h"
#include "time.h"
#include "RefCounter.h"
namespace easy2d
{
class Game;
class Scene;
// 场景过渡
class Transition
: public Ref
: public RefCounter
{
friend class Game;
@ -48,7 +46,7 @@ namespace easy2d
protected:
// 初始化场景过渡动画
virtual void Init(
virtual void Initialize(
Scene * prev,
Scene * next,
Game * game
@ -70,7 +68,7 @@ namespace easy2d
bool done_;
float duration_;
float process_;
Time started_;
time::TimePoint started_;
Size window_size_;
Scene* out_scene_;
Scene* in_scene_;
@ -94,7 +92,7 @@ namespace easy2d
// 更新动画
virtual void Update() override;
virtual void Init(
virtual void Initialize(
Scene * prev,
Scene * next,
Game * game
@ -114,7 +112,7 @@ namespace easy2d
protected:
virtual void Update() override;
virtual void Init(
virtual void Initialize(
Scene * prev,
Scene * next,
Game * game
@ -134,7 +132,7 @@ namespace easy2d
protected:
virtual void Update() override;
virtual void Init(
virtual void Initialize(
Scene * prev,
Scene * next,
Game * game
@ -155,7 +153,7 @@ namespace easy2d
protected:
virtual void Update() override;
virtual void Init(
virtual void Initialize(
Scene * prev,
Scene * next,
Game * game
@ -183,7 +181,7 @@ namespace easy2d
protected:
virtual void Update() override;
virtual void Init(
virtual void Initialize(
Scene * prev,
Scene * next,
Game * game
@ -194,8 +192,4 @@ namespace easy2d
protected:
float rotation_;
};
} // end of easy2d namespace
#endif // __E2D_TRANSITION_H__
}

View File

@ -18,102 +18,70 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2daction.h"
#include "audio.h"
#include "base.h"
#include "modules.h"
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
namespace easy2d
{
Loop::Loop(Action * action, int times /* = -1 */)
: action_(action)
, times_(0)
, total_times_(times)
namespace audio
{
E2D_WARNING_IF(action == nullptr, "Loop NULL pointer exception!");
AudioDevice instance;
if (action)
AudioDevice::AudioDevice()
: x_audio2_(nullptr)
, mastering_voice_(nullptr)
{
action_ = action;
action_->Retain();
}
}
Loop::~Loop()
{
SafeRelease(action_);
}
Loop * Loop::Clone() const
{
if (action_)
{
return new Loop(action_->Clone());
}
else
{
return nullptr;
}
}
Loop * Loop::Reverse() const
{
if (action_)
{
return new Loop(action_->Clone());
}
else
{
return nullptr;
}
}
void Loop::Init()
{
Action::Init();
if (action_)
{
action_->target_ = target_;
action_->Init();
}
}
void Loop::Update()
{
Action::Update();
if (times_ == total_times_)
{
this->Stop();
return;
}
if (action_)
AudioDevice::~AudioDevice()
{
action_->Update();
}
if (action_->IsDone())
void AudioDevice::Initialize()
{
ThrowIfFailed(
modules::MediaFoundation.MFStartup(MF_VERSION, MFSTARTUP_FULL)
);
ThrowIfFailed(
modules::XAudio2.XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR)
);
ThrowIfFailed(
x_audio2_->CreateMasteringVoice(&mastering_voice_)
);
}
void AudioDevice::Uninitialize()
{
if (mastering_voice_)
{
++times_;
Action::Reset();
action_->Reset();
mastering_voice_->DestroyVoice();
mastering_voice_ = nullptr;
}
SafeRelease(x_audio2_);
modules::MediaFoundation.MFShutdown();
}
else
HRESULT AudioDevice::CreateVoice(IXAudio2SourceVoice ** voice, WAVEFORMATEX * wfx)
{
this->Stop();
return x_audio2_->CreateSourceVoice(voice, wfx, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
}
}
void Loop::Reset()
{
Action::Reset();
void AudioDevice::Open()
{
x_audio2_->StartEngine();
}
if (action_) action_->Reset();
times_ = 0;
}
void Loop::ResetTime()
{
if (action_) action_->ResetTime();
void AudioDevice::Close()
{
x_audio2_->StopEngine();
}
}
}

View File

@ -18,29 +18,43 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dtransition.h"
#include "..\e2dobject.h"
#pragma once
#include "macros.h"
#include <xaudio2.h>
namespace easy2d
{
EmergeTransition::EmergeTransition(float duration)
: Transition(duration)
namespace audio
{
// 音频设备
class AudioDevice
{
public:
AudioDevice();
~AudioDevice();
void Initialize();
void Uninitialize();
// 开启设备
void Open();
// 关闭设备
void Close();
// 创建音源
HRESULT CreateVoice(
IXAudio2SourceVoice ** voice,
WAVEFORMATEX * wfx
);
protected:
IXAudio2 * x_audio2_;
IXAudio2MasteringVoice* mastering_voice_;
};
extern AudioDevice instance;
}
void EmergeTransition::Init(Scene * prev, Scene * next, Game * game)
{
Transition::Init(prev, next, game);
out_layer_param_.opacity = 1;
in_layer_param_.opacity = 0;
}
void EmergeTransition::Update()
{
Transition::Update();
out_layer_param_.opacity = 1 - process_;
in_layer_param_.opacity = process_;
}
}
}

View File

@ -18,25 +18,31 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2daction.h"
#include "..\e2dobject.h"
#pragma once
#include "BaseTypes.h"
#include "Rect.hpp"
#include <stdexcept>
namespace easy2d
{
JumpTo::JumpTo(float duration, const Point & pos, float height, int jumps)
: JumpBy(duration, Point(), height, jumps)
, end_pos_(pos)
template<class Interface>
inline void SafeRelease(Interface*& p)
{
if (p != nullptr)
{
p->Release();
p = nullptr;
}
}
JumpTo * JumpTo::Clone() const
inline void ThrowIfFailed(HRESULT hr)
{
return new JumpTo(duration_, end_pos_, height_, jumps_);
if (FAILED(hr))
{
static char s_str[64] = {};
::sprintf_s(s_str, "[easy2d] Failure with HRESULT of %08X", static_cast<unsigned int>(hr));
::OutputDebugStringA(s_str);
throw std::runtime_error(s_str);
}
}
void JumpTo::Init()
{
JumpBy::Init();
delta_pos_ = end_pos_ - start_pos_;
}
}
}

View File

@ -18,50 +18,39 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2daction.h"
#pragma once
#include "macros.h"
namespace easy2d
{
FiniteTimeAction::FiniteTimeAction(float duration)
: delta_(0)
, duration_(std::max(duration, 0.f))
namespace logs
{
}
void FiniteTimeAction::Reset()
{
Action::Reset();
delta_ = 0;
}
void FiniteTimeAction::Init()
{
Action::Init();
}
void FiniteTimeAction::Update()
{
Action::Update();
if (duration_ == 0)
namespace
{
delta_ = 1;
this->Stop();
}
else
{
delta_ = std::min((Time::Now() - started_).Seconds() / duration_, 1.f);
if (delta_ >= 1)
inline void OutputDebugStringExW(LPCWSTR pszOutput, ...)
{
this->Stop();
va_list args = NULL;
va_start(args, pszOutput);
size_t nLen = ::_vscwprintf(pszOutput, args) + 1;
wchar_t* psBuffer = new wchar_t[nLen];
::_vsnwprintf_s(psBuffer, nLen, nLen, pszOutput, args);
va_end(args);
::OutputDebugStringW(psBuffer);
delete[] psBuffer;
}
}
}
void FiniteTimeAction::ResetTime()
{
Action::ResetTime();
started_ = Time::Now() - Duration::Second * (delta_ * duration_);
inline void Trace(LPCWSTR output)
{
OutputDebugStringExW(L"[easy2d] Error: %s\r\n", output);
}
inline void Trace(LPCWSTR output, HRESULT hr)
{
OutputDebugStringExW(L"[easy2d] Failure with HRESULT of %08X: %s\r\n", output, static_cast<unsigned int>(hr));
}
}
}
}

View File

@ -18,9 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef __E2D_MACROS_H__
#define __E2D_MACROS_H__
#pragma once
#ifndef WINVER
# define WINVER 0x0700 // Allow use of features specific to Windows 7 or later
@ -47,10 +45,6 @@
# define NOMINMAX
#endif
#ifndef DIRECTINPUT_VERSION
# define DIRECTINPUT_VERSION 0x0800
#endif
#ifndef INITGUID
# define INITGUID
#endif
@ -59,40 +53,14 @@
// Windows Header Files
#include <windows.h>
#include <wincodec.h>
#include <mmsystem.h>
#include <d2d1.h>
#include <dwrite.h>
#include <dinput.h>
#include <xaudio2.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <shlwapi.h>
// C++ RunTime Header Files
#include <string>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <random>
#include <utility>
#include <chrono>
#include <sstream>
#include <functional>
#include <algorithm>
#include <stdexcept>
// Import Libraries
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "dwrite.lib")
#pragma comment(lib, "windowscodecs.lib")
#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "xaudio2.lib")
#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "mfreadwrite.lib")
#pragma comment(lib, "shlwapi.lib")
#if _MSC_VER >= 1900
@ -119,6 +87,3 @@
#else
# define E2D_WARNING_IF(exp, msg) ((void)0)
#endif
#endif // __E2D_MACROS_H__

96
core/base/modules.cpp Normal file
View File

@ -0,0 +1,96 @@
// 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.
#include "modules.h"
namespace easy2d
{
namespace modules
{
namespace
{
inline void SafeFreeLibrary(HMODULE instance)
{
if (instance)
FreeLibrary(instance);
}
}
Module_XAudio2 XAudio2;
Module_MediaFoundation MediaFoundation;
void Initialize()
{
const auto xaudio2_dll_names =
{
L"xaudio2_9.dll",
L"xaudio2_8.dll",
L"xaudio2_7.dll"
};
for (const auto& name : xaudio2_dll_names)
{
XAudio2.instance = LoadLibraryW(name);
if (XAudio2.instance)
{
XAudio2.XAudio2Create = (PFN_XAudio2Create)
GetProcAddress(XAudio2.instance, "XAudio2Create");
break;
}
}
MediaFoundation.mfplat = LoadLibraryW(L"Mfplat.dll");
if (MediaFoundation.mfplat)
{
MediaFoundation.MFStartup = (PFN_MFStartup)
GetProcAddress(MediaFoundation.mfplat, "MFStartup");
MediaFoundation.MFShutdown = (PFN_MFShutdown)
GetProcAddress(MediaFoundation.mfplat, "MFShutdown");
MediaFoundation.MFCreateMediaType = (PFN_MFCreateMediaType)
GetProcAddress(MediaFoundation.mfplat, "MFCreateMediaType");
MediaFoundation.MFCreateWaveFormatExFromMFMediaType = (PFN_MFCreateWaveFormatExFromMFMediaType)
GetProcAddress(MediaFoundation.mfplat, "MFCreateWaveFormatExFromMFMediaType");
MediaFoundation.MFCreateMFByteStreamOnStream = (PFN_MFCreateMFByteStreamOnStream)
GetProcAddress(MediaFoundation.mfplat, "MFCreateMFByteStreamOnStream");
}
MediaFoundation.mfreadwrite = LoadLibraryW(L"Mfreadwrite.dll");
if (MediaFoundation.mfreadwrite)
{
MediaFoundation.MFCreateSourceReaderFromURL = (PFN_MFCreateSourceReaderFromURL)
GetProcAddress(MediaFoundation.mfreadwrite, "MFCreateSourceReaderFromURL");
MediaFoundation.MFCreateSourceReaderFromByteStream = (PFN_MFCreateSourceReaderFromByteStream)
GetProcAddress(MediaFoundation.mfreadwrite, "MFCreateSourceReaderFromByteStream");
}
}
void Uninitialize()
{
SafeFreeLibrary(XAudio2.instance);
SafeFreeLibrary(MediaFoundation.mfplat);
SafeFreeLibrary(MediaFoundation.mfreadwrite);
}
}
}

78
core/base/modules.h Normal file
View File

@ -0,0 +1,78 @@
// 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 "macros.h"
#include <xaudio2.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
namespace easy2d
{
namespace modules
{
// XAudio2 functions
typedef HRESULT(WINAPI *PFN_XAudio2Create)(IXAudio2**, UINT32, XAUDIO2_PROCESSOR);
struct Module_XAudio2
{
HMODULE instance;
PFN_XAudio2Create XAudio2Create;
};
extern Module_XAudio2 XAudio2;
// MediaFoundation functions
typedef HRESULT(WINAPI *PFN_MFStartup)(ULONG, DWORD);
typedef HRESULT(WINAPI *PFN_MFShutdown)();
typedef HRESULT(WINAPI *PFN_MFCreateMediaType)(IMFMediaType**);
typedef HRESULT(WINAPI *PFN_MFCreateWaveFormatExFromMFMediaType)(IMFMediaType*, WAVEFORMATEX**, UINT32*, UINT32);
typedef HRESULT(WINAPI *PFN_MFCreateSourceReaderFromURL)(LPCWSTR, IMFAttributes*, IMFSourceReader**);
typedef HRESULT(WINAPI *PFN_MFCreateSourceReaderFromByteStream)(IMFByteStream*, IMFAttributes*, IMFSourceReader**);
typedef HRESULT(WINAPI *PFN_MFCreateMFByteStreamOnStream)(IStream*, IMFByteStream**);
struct Module_MediaFoundation
{
HMODULE mfplat;
HMODULE mfreadwrite;
PFN_MFStartup MFStartup;
PFN_MFShutdown MFShutdown;
PFN_MFCreateMediaType MFCreateMediaType;
PFN_MFCreateWaveFormatExFromMFMediaType MFCreateWaveFormatExFromMFMediaType;
PFN_MFCreateSourceReaderFromURL MFCreateSourceReaderFromURL;
PFN_MFCreateSourceReaderFromByteStream MFCreateSourceReaderFromByteStream;
PFN_MFCreateMFByteStreamOnStream MFCreateMFByteStreamOnStream;
};
extern Module_MediaFoundation MediaFoundation;
//
// Functions
//
void Initialize();
void Uninitialize();
}
}

291
core/base/render.cpp Normal file
View File

@ -0,0 +1,291 @@
// 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.
#include "render.h"
#include "time.h"
#include "base.h"
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "dwrite.lib")
#pragma comment(lib, "windowscodecs.lib")
namespace easy2d
{
namespace render
{
_D2D_Resource D2D = { 0 };
void Initialize(HWND hwnd)
{
if (D2D.Factory)
return;
ThrowIfFailed(
D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&D2D.Factory
)
);
ThrowIfFailed(
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<void**>(&D2D.WICImagingFactory)
)
);
ThrowIfFailed(
DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&D2D.DWriteFactory)
)
);
auto stroke_style = D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_LINE_JOIN_MITER,
2.0f,
D2D1_DASH_STYLE_SOLID,
0.0f
);
ThrowIfFailed(
D2D.Factory->CreateStrokeStyle(
stroke_style,
nullptr,
0,
&D2D.MiterStrokeStyle
)
);
stroke_style.lineJoin = D2D1_LINE_JOIN_BEVEL;
ThrowIfFailed(
D2D.Factory->CreateStrokeStyle(
stroke_style,
nullptr,
0,
&D2D.BevelStrokeStyle
)
);
stroke_style.lineJoin = D2D1_LINE_JOIN_ROUND;
ThrowIfFailed(
D2D.Factory->CreateStrokeStyle(
stroke_style,
nullptr,
0,
&D2D.RoundStrokeStyle
)
);
CreateDeviceResources(hwnd);
}
void CreateDeviceResources(HWND hwnd)
{
if (!D2D.HwndRenderTarget)
{
RECT rc;
::GetClientRect(hwnd, &rc);
D2D1_SIZE_U size = D2D1::SizeU(
rc.right - rc.left,
rc.bottom - rc.top
);
// 创建设备相关资源。这些资源应在 Direct2D 设备消失时重建
// 创建一个 Direct2D 渲染目标
ThrowIfFailed(
D2D.Factory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
hwnd,
size,
D2D1_PRESENT_OPTIONS_NONE),
&D2D.HwndRenderTarget
)
);
}
if (!D2D.SolidColorBrush)
{
ThrowIfFailed(
D2D.HwndRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::White),
&D2D.SolidColorBrush
)
);
}
if (!D2D.TextRenderer)
{
ThrowIfFailed(
ITextRenderer::Create(
&D2D.TextRenderer,
D2D.Factory,
D2D.HwndRenderTarget,
D2D.SolidColorBrush
)
);
}
}
void 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);
}
//-------------------------------------------------------
// GraphicsDevice
//-------------------------------------------------------
GraphicsDevice instance;
GraphicsDevice::GraphicsDevice()
: fps_text_format_(nullptr)
, fps_text_layout_(nullptr)
, clear_color_(D2D1::ColorF(D2D1::ColorF::Black))
{
}
GraphicsDevice::~GraphicsDevice()
{
SafeRelease(fps_text_format_);
SafeRelease(fps_text_layout_);
}
void GraphicsDevice::BeginDraw(HWND hwnd)
{
render::CreateDeviceResources(hwnd);
render::D2D.HwndRenderTarget->BeginDraw();
render::D2D.HwndRenderTarget->Clear(clear_color_);
}
void GraphicsDevice::EndDraw()
{
HRESULT hr = render::D2D.HwndRenderTarget->EndDraw();
if (hr == D2DERR_RECREATE_TARGET)
{
// 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源
// 并在下一次调用时重建资源
hr = S_OK;
SafeRelease(fps_text_format_);
SafeRelease(fps_text_layout_);
SafeRelease(render::D2D.TextRenderer);
SafeRelease(render::D2D.SolidColorBrush);
SafeRelease(render::D2D.HwndRenderTarget);
}
ThrowIfFailed(hr);
}
void GraphicsDevice::SetBackgroundColor(const Color& color)
{
clear_color_ = color;
}
void GraphicsDevice::DrawDebugInfo()
{
static int render_times_ = 0;
static time::TimePoint last_render_time_ = time::Now();
int duration = (time::Now() - last_render_time_).Milliseconds();
if (!fps_text_format_)
{
ThrowIfFailed(
render::D2D.DWriteFactory->CreateTextFormat(
L"",
nullptr,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
20,
L"",
&fps_text_format_
)
);
ThrowIfFailed(
fps_text_format_->SetWordWrapping(
DWRITE_WORD_WRAPPING_NO_WRAP
)
);
}
++render_times_;
if (duration >= 100)
{
wchar_t fps_text[12] = {};
int len = swprintf_s(fps_text, L"FPS: %.1f", 1000.f / duration * render_times_);
last_render_time_ = time::Now();
render_times_ = 0;
SafeRelease(fps_text_layout_);
ThrowIfFailed(
render::D2D.DWriteFactory->CreateTextLayout(
fps_text,
static_cast<UINT32>(len),
fps_text_format_,
0,
0,
&fps_text_layout_
)
);
}
if (fps_text_layout_)
{
render::D2D.HwndRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
render::D2D.SolidColorBrush->SetOpacity(1.0f);
render::D2D.TextRenderer->SetTextStyle(
D2D1::ColorF(D2D1::ColorF::White),
TRUE,
D2D1::ColorF(D2D1::ColorF::Black, 0.4f),
1.5f,
D2D1_LINE_JOIN_ROUND
);
fps_text_layout_->Draw(nullptr, render::D2D.TextRenderer, 10, 0);
}
}
}
}

View File

@ -18,59 +18,62 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2daction.h"
#include "..\e2dobject.h"
#pragma once
#include "base.h"
#include "TextRenderer.h"
namespace easy2d
{
JumpBy::JumpBy(float duration, const Point & vec, float height, int jumps)
: FiniteTimeAction(duration)
, delta_pos_(vec)
, height_(height)
, jumps_(jumps)
namespace render
{
}
JumpBy * JumpBy::Clone() const
{
return new JumpBy(duration_, delta_pos_, height_, jumps_);
}
JumpBy * JumpBy::Reverse() const
{
return new JumpBy(duration_, -delta_pos_, height_, jumps_);
}
void JumpBy::Init()
{
FiniteTimeAction::Init();
if (target_)
typedef struct
{
prev_pos_ = start_pos_ = target_->GetPosition();
}
}
ID2D1Factory* Factory;
IWICImagingFactory* WICImagingFactory;
IDWriteFactory* DWriteFactory;
ITextRenderer* TextRenderer;
ID2D1SolidColorBrush* SolidColorBrush;
ID2D1HwndRenderTarget* HwndRenderTarget;
ID2D1StrokeStyle* MiterStrokeStyle;
ID2D1StrokeStyle* BevelStrokeStyle;
ID2D1StrokeStyle* RoundStrokeStyle;
} _D2D_Resource;
void JumpBy::Update()
{
FiniteTimeAction::Update();
extern _D2D_Resource D2D;
if (target_)
void Initialize(HWND hwnd);
void CreateDeviceResources(HWND hwnd);
void Uninitialize();
class GraphicsDevice
{
float frac = fmod(delta_ * jumps_, 1.f);
float x = delta_pos_.x * delta_;
float y = height_ * 4 * frac * (1 - frac);
y += delta_pos_.y * delta_;
public:
GraphicsDevice();
Point currentPos = target_->GetPosition();
~GraphicsDevice();
Point diff = currentPos - prev_pos_;
start_pos_ = diff + start_pos_;
// 开始渲染
void BeginDraw(HWND hwnd);
Point newPos = start_pos_ + Point(x, y);
target_->SetPosition(newPos);
// 结束渲染
void EndDraw();
prev_pos_ = newPos;
}
// 渲染调试信息
void DrawDebugInfo();
// 设置背景色
void SetBackgroundColor(
const Color& color
);
protected:
D2D1_COLOR_F clear_color_;
IDWriteTextFormat* fps_text_format_;
IDWriteTextLayout* fps_text_layout_;
};
extern GraphicsDevice instance;
}
}
}

408
core/base/time.cpp Normal file
View File

@ -0,0 +1,408 @@
// 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.
#include "time.h"
#include <regex>
namespace easy2d
{
namespace time
{
using namespace std::chrono;
//-------------------------------------------------------
// TimePoint
//-------------------------------------------------------
TimePoint::TimePoint()
{
}
TimePoint::TimePoint(std::chrono::steady_clock::time_point time)
: time_(time)
{
}
TimePoint::TimePoint(const TimePoint & other)
: time_(other.time_)
{
}
TimePoint::TimePoint(TimePoint && other)
: time_(std::move(other.time_))
{
}
time_t TimePoint::GetTimeStamp() const
{
auto& duration = time_point_cast<milliseconds>(time_).time_since_epoch();
return static_cast<time_t>(duration.count());
}
bool TimePoint::IsZero() const
{
return time_.time_since_epoch().count() == 0LL;
}
TimePoint TimePoint::operator+(const Duration & other) const
{
return TimePoint(time_ + milliseconds(other.Milliseconds()));
}
TimePoint TimePoint::operator-(const Duration & other) const
{
return TimePoint(time_ - milliseconds(other.Milliseconds()));
}
TimePoint & TimePoint::operator+=(const Duration & other)
{
time_ += milliseconds(other.Milliseconds());
return (*this);
}
TimePoint & TimePoint::operator-=(const Duration &other)
{
time_ -= milliseconds(other.Milliseconds());
return (*this);
}
Duration TimePoint::operator-(const TimePoint & other) const
{
auto ms = duration_cast<milliseconds>(time_ - other.time_).count();
return Duration(static_cast<int>(ms));
}
TimePoint& TimePoint::operator=(const TimePoint & other) E2D_NOEXCEPT
{
if (this == &other)
return *this;
time_ = other.time_;
return *this;
}
TimePoint& TimePoint::operator=(TimePoint && other) E2D_NOEXCEPT
{
if (this == &other)
return *this;
time_ = std::move(other.time_);
return *this;
}
//-------------------------------------------------------
// Duration
//-------------------------------------------------------
const Duration Millisecond = Duration(1);
const Duration Second = 1000 * Millisecond;
const Duration Minute = 60 * Second;
const Duration Hour = 60 * Minute;
namespace
{
const auto duration_regex = std::wregex(L"[-+]?([0-9]*(\\.[0-9]*)?[a-z]+)+");
typedef std::map<std::wstring, Duration> UnitMap;
const auto unit_map = UnitMap
{
{L"ms", Millisecond},
{L"s", Second},
{L"m", Minute},
{L"h", Hour}
};
}
Duration::Duration()
: milliseconds_(0)
{
}
Duration::Duration(int milliseconds)
: milliseconds_(milliseconds)
{
}
int Duration::Milliseconds() const
{
return milliseconds_;
}
float Duration::Seconds() const
{
int64_t sec = milliseconds_ / Second.milliseconds_;
int64_t ms = milliseconds_ % Second.milliseconds_;
return static_cast<float>(sec) + static_cast<float>(ms) / 1000.f;
}
float Duration::Minutes() const
{
int64_t min = milliseconds_ / Minute.milliseconds_;
int64_t ms = milliseconds_ % Minute.milliseconds_;
return static_cast<float>(min) + static_cast<float>(ms) / (60 * 1000.f);
}
float Duration::Hours() const
{
int64_t hour = milliseconds_ / Hour.milliseconds_;
int64_t ms = milliseconds_ % Hour.milliseconds_;
return static_cast<float>(hour) + static_cast<float>(ms) / (60 * 60 * 1000.f);
}
bool Duration::operator==(const Duration & other) const
{
return milliseconds_ == other.milliseconds_;
}
bool Duration::operator!=(const Duration & other) const
{
return milliseconds_ != other.milliseconds_;
}
bool Duration::operator>(const Duration & other) const
{
return milliseconds_ > other.milliseconds_;
}
bool Duration::operator>=(const Duration & other) const
{
return milliseconds_ >= other.milliseconds_;
}
bool Duration::operator<(const Duration & other) const
{
return milliseconds_ < other.milliseconds_;
}
bool Duration::operator<=(const Duration & other) const
{
return milliseconds_ <= other.milliseconds_;
}
Duration Duration::operator+(const Duration & other) const
{
return Duration(milliseconds_ + other.milliseconds_);
}
Duration Duration::operator-(const Duration & other) const
{
return Duration(milliseconds_ - other.milliseconds_);
}
Duration Duration::operator-() const
{
return Duration(-milliseconds_);
}
Duration Duration::operator*(int value) const
{
return Duration(milliseconds_ * value);
}
Duration Duration::operator/(int value) const
{
return Duration(milliseconds_ / value);
}
Duration Duration::operator*(float value) const
{
return Duration(static_cast<int>(milliseconds_ * value));
}
Duration Duration::operator/(float value) const
{
return Duration(static_cast<int>(milliseconds_ / value));
}
Duration Duration::operator*(double value) const
{
return Duration(static_cast<int>(milliseconds_ * value));
}
Duration Duration::operator/(double value) const
{
return Duration(static_cast<int>(milliseconds_ / value));
}
Duration & Duration::operator+=(const Duration &other)
{
milliseconds_ += other.milliseconds_;
return (*this);
}
Duration & Duration::operator-=(const Duration &other)
{
milliseconds_ -= other.milliseconds_;
return (*this);
}
Duration & Duration::operator*=(int value)
{
milliseconds_ *= value;
return (*this);
}
Duration & Duration::operator/=(int value)
{
milliseconds_ /= value;
return (*this);
}
Duration & Duration::operator*=(float value)
{
milliseconds_ = static_cast<int>(milliseconds_ * value);
return (*this);
}
Duration & Duration::operator/=(float value)
{
milliseconds_ = static_cast<int>(milliseconds_ / value);
return (*this);
}
Duration & Duration::operator*=(double value)
{
milliseconds_ = static_cast<int>(milliseconds_ * value);
return (*this);
}
Duration & Duration::operator/=(double value)
{
milliseconds_ = static_cast<int>(milliseconds_ / value);
return (*this);
}
Duration operator*(int value, const Duration & dur)
{
return dur * value;
}
Duration operator/(int value, const Duration & dur)
{
return dur / value;
}
Duration operator*(float value, const Duration & dur)
{
return dur * value;
}
Duration operator/(float value, const Duration & dur)
{
return dur / value;
}
Duration operator*(double value, const Duration & dur)
{
return dur * value;
}
Duration operator/(double value, const Duration & dur)
{
return dur / value;
}
//-------------------------------------------------------
// Functions
//-------------------------------------------------------
TimePoint Now()
{
return TimePoint(steady_clock::now());
}
Duration ParseDuration(const std::wstring & str)
{
size_t len = str.length();
size_t pos = 0;
bool negative = false;
Duration d;
if (!std::regex_match(str, duration_regex))
{
E2D_WARNING("Time::Duration::Parse: invalid duration");
return Duration();
}
if (str.empty() || str == L"0") { return d; }
// ·ûºÅλ
if (str[0] == L'-' || str[0] == L'+')
{
negative = (str[0] == L'-');
pos++;
}
while (pos < len)
{
// ÊýÖµ
size_t i = pos;
for (; i < len; ++i)
{
wchar_t ch = str[i];
if (!(ch == L'.' || L'0' <= ch && ch <= L'9'))
{
break;
}
}
std::wstring num_str = str.substr(pos, i - pos);
pos = i;
if (num_str.empty() || num_str == L".")
{
E2D_WARNING("Time::Duration::Parse: invalid duration");
return Duration();
}
// µ¥Î»
for (; i < len; ++i)
{
wchar_t ch = str[i];
if (ch == L'.' || L'0' <= ch && ch <= L'9')
{
break;
}
}
std::wstring unit_str = str.substr(pos, i - pos);
pos = i;
if (unit_map.find(unit_str) == unit_map.end())
{
E2D_WARNING("Time::Duration::Parse: invalid duration");
return Duration();
}
double num = std::stod(num_str);
Duration unit = unit_map.at(unit_str);
d += unit * num;
}
if (negative)
{
d = -d;
}
return d;
}
}
}

162
core/base/time.h Normal file
View File

@ -0,0 +1,162 @@
// 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 "macros.h"
#include <chrono>
namespace easy2d
{
namespace time
{
// 时间段
//
// Usage:
// 时间段表示法:
// 5 秒: time::Second * 5
// 1.5 小时: time::Hour * 1.5
// 3 小时 45 分 15 秒: time::Hour * 3 + time::Minute * 45 + time::Second * 15
// 时间段格式化: auto d = time::ParseDuration(L"1h35m"); // 1小时35分钟
//
class Duration
{
public:
Duration();
explicit Duration(
int milliseconds
);
// 转化为毫秒
int Milliseconds() const;
// 转化为秒
float Seconds() const;
// 转化为分钟
float Minutes() const;
// 转化为小时
float Hours() const;
bool operator== (const Duration &) const;
bool operator!= (const Duration &) const;
bool operator> (const Duration &) const;
bool operator>= (const Duration &) const;
bool operator< (const Duration &) const;
bool operator<= (const Duration &) const;
Duration operator + (const Duration &) const;
Duration operator - (const Duration &) const;
Duration operator - () const;
Duration operator * (int) const;
Duration operator * (float) const;
Duration operator * (double) const;
Duration operator / (int) const;
Duration operator / (float) const;
Duration operator / (double) const;
Duration& operator += (const Duration &);
Duration& operator -= (const Duration &);
Duration& operator *= (int);
Duration& operator *= (float);
Duration& operator *= (double);
Duration& operator /= (int);
Duration& operator /= (float);
Duration& operator /= (double);
friend Duration operator* (int, const Duration &);
friend Duration operator* (float, const Duration &);
friend Duration operator* (double, const Duration &);
friend Duration operator/ (int, const Duration &);
friend Duration operator/ (float, const Duration &);
friend Duration operator/ (double, const Duration &);
private:
int milliseconds_;
};
extern const Duration Millisecond; // 毫秒
extern const Duration Second; // 秒
extern const Duration Minute; // 分钟
extern const Duration Hour; // 小时
// 时间
//
// Usage:
// 获取当前时间: Time now = time::Now();
// 时间操作:
// 两时间相减, 得到一个 Duration 对象, 例如:
// Time t1 = time::Now();
// ... // 做些什么
// Time t2 = time::Now();
// auto duration = t2 - t1;
// 获取两时间相差的毫秒数:
// int ms = duration.Milliseconds();
//
class TimePoint
{
public:
TimePoint();
explicit TimePoint(
std::chrono::steady_clock::time_point
);
TimePoint(
const TimePoint& other
);
TimePoint(
TimePoint&& other
);
// 获取时间戳
time_t GetTimeStamp() const;
// 是否是零时
bool IsZero() const;
TimePoint operator + (const Duration &) const;
TimePoint operator - (const Duration &) const;
TimePoint& operator += (const Duration &);
TimePoint& operator -= (const Duration &);
Duration operator - (const TimePoint &) const;
TimePoint& operator = (const TimePoint &) E2D_NOEXCEPT;
TimePoint& operator = (TimePoint &&) E2D_NOEXCEPT;
private:
std::chrono::steady_clock::time_point time_;
};
// 获取当前时间
TimePoint Now();
// 时间段格式化
// 时间段字符串允许是有符号的浮点数, 并且带有时间单位后缀
// 例如: "300ms", "-1.5h", "2h45m"
// 允许的时间单位有 "ms", "s", "m", "h"
Duration ParseDuration(const std::wstring& parse_str);
}
}

368
core/base/window.cpp Normal file
View File

@ -0,0 +1,368 @@
// 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.
#include "window.h"
#include "render.h"
#include "Game.h"
#include "Scene.h"
#include "KeyEvent.h"
#include "MouseEvent.h"
#include "../math/scalar.hpp"
#include <imm.h>
#pragma comment (lib ,"imm32.lib")
#define WINDOW_STYLE WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME
#define REGISTER_CLASS L"Easy2DApp"
namespace easy2d
{
namespace window
{
namespace
{
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,
hinstance,
this
);
if (handle == nullptr)
{
::UnregisterClass(REGISTER_CLASS, hinstance);
throw std::runtime_error("Create window failed");
}
// 禁用输入法
::ImmAssociateContext(handle, nullptr);
}
void WindowInfo::Destroy()
{
if (handle)
::DestroyWindow(handle);
}
String WindowInfo::GetTitle() const
{
if (handle)
{
wchar_t title[256];
GetWindowTextW(handle, title, 256);
return title;
}
return String();
}
void WindowInfo::SetTitle(const String& title)
{
if (handle)
::SetWindowText(handle, title.c_str());
}
Size WindowInfo::GetSize() const
{
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 时产生
auto render_target = render::D2D.HwndRenderTarget;
if (render_target)
{
render_target->Resize(D2D1::SizeU(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

@ -18,46 +18,66 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dtransition.h"
#include "..\e2dobject.h"
#pragma once
#include "base.h"
namespace easy2d
{
BoxTransition::BoxTransition(float duration)
: Transition(duration)
namespace window
{
}
void BoxTransition::Init(Scene * prev, Scene * next, Game * game)
{
Transition::Init(prev, next, game);
in_layer_param_.opacity = 0;
}
void BoxTransition::Update()
{
Transition::Update();
if (process_ < .5f)
typedef struct Property
{
out_layer_param_.contentBounds = D2D1::RectF(
window_size_.width * process_,
window_size_.height * process_,
window_size_.width * (1 - process_),
window_size_.height * (1 - process_)
);
}
else
String title; /* 标题 */
int width; /* 宽度 */
int height; /* 高度 */
LPCWSTR icon; /* 图标 */
Property()
: title(L"Easy2D Game")
, width(640)
, height(480)
, icon(nullptr)
{}
} Property;
class WindowInfo
{
out_layer_param_.opacity = 0;
in_layer_param_.opacity = 1;
in_layer_param_.contentBounds = D2D1::RectF(
window_size_.width * (1 - process_),
window_size_.height * (1 - process_),
window_size_.width * process_,
window_size_.height * process_
public:
HWND handle;
float xscale;
float yscale;
public:
WindowInfo();
void Initialize(
const Property& property
);
}
void Destroy();
// 获取标题
String GetTitle() const;
// 设置标题
void SetTitle(const String& title);
// 获取窗口大小
Size GetSize() const;
// 获取窗口宽度
float GetWidth() const;
// 获取窗口高度
float GetHeight() const;
// 重设窗口大小
void SetSize(int width, int height);
// 设置窗口图标
void SetIcon(LPCWSTR icon_resource);
};
extern WindowInfo instance;
}
}
}

View File

@ -1,285 +0,0 @@
// 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.
#include "..\e2dcomponent.h"
#include "..\e2dmodule.h"
#define SAFE_SET(pointer, func, ...) if (pointer) { pointer->##func(__VA_ARGS__); }
#define SET_BUTTON_NODE(Old, New) \
if (New != Old) \
{ \
if (Old) this->RemoveChild(Old); \
if (New) \
{ \
New->SetPivot(GetPivotX(), GetPivotY()); \
this->AddChild(New); \
} \
Old = New; \
UpdateVisible(); \
} \
namespace easy2d
{
Button::Button()
: callback_(nullptr)
, status_(Status::Normal)
, enabled_(true)
, is_selected_(false)
, normal_(nullptr)
, mouseover_(nullptr)
, selected_(nullptr)
, disabled_(nullptr)
{
}
Button::Button(Node * normal, const Callback& func)
: callback_(nullptr)
, status_(Status::Normal)
, enabled_(true)
, is_selected_(false)
, normal_(nullptr)
, mouseover_(nullptr)
, selected_(nullptr)
, disabled_(nullptr)
{
this->SetNormal(normal);
this->SetCallbackOnClick(func);
}
Button::Button(Node * normal, Node * selected, const Callback& func)
: callback_(nullptr)
, status_(Status::Normal)
, enabled_(true)
, is_selected_(false)
, normal_(nullptr)
, mouseover_(nullptr)
, selected_(nullptr)
, disabled_(nullptr)
{
this->SetNormal(normal);
this->SetSelected(selected);
this->SetCallbackOnClick(func);
}
Button::Button(Node * normal, Node * mouseover, Node * selected, const Callback& func)
: callback_(nullptr)
, status_(Status::Normal)
, enabled_(true)
, is_selected_(false)
, normal_(nullptr)
, mouseover_(nullptr)
, selected_(nullptr)
, disabled_(nullptr)
{
this->SetNormal(normal);
this->SetMouseOver(mouseover);
this->SetSelected(selected);
this->SetCallbackOnClick(func);
}
Button::Button(Node * normal, Node * mouseover, Node * selected, Node * disabled, const Callback& func)
: callback_(nullptr)
, status_(Status::Normal)
, enabled_(true)
, is_selected_(false)
, normal_(nullptr)
, mouseover_(nullptr)
, selected_(nullptr)
, disabled_(nullptr)
{
this->SetNormal(normal);
this->SetMouseOver(mouseover);
this->SetSelected(selected);
this->SetDisabled(disabled);
this->SetCallbackOnClick(func);
}
bool Button::IsEnable() const
{
return enabled_;
}
void Button::SetNormal(Node * normal)
{
SET_BUTTON_NODE(normal_, normal);
if (normal)
{
this->SetSize(normal->GetWidth(), normal->GetHeight());
}
}
void Button::SetMouseOver(Node * mouseover)
{
SET_BUTTON_NODE(mouseover_, mouseover);
}
void Button::SetSelected(Node * selected)
{
SET_BUTTON_NODE(selected_, selected);
}
void Button::SetDisabled(Node * disabled)
{
SET_BUTTON_NODE(disabled_, disabled);
}
void Button::SetEnabled(bool enabled)
{
if (enabled_ != enabled)
{
enabled_ = enabled;
UpdateVisible();
}
}
void Button::SetCallbackOnClick(const Callback& func)
{
callback_ = func;
}
void Button::SetPivot(float pivot_x, float pivot_y)
{
Node::SetPivot(pivot_x, pivot_y);
SAFE_SET(normal_, SetPivot, pivot_x, pivot_y);
SAFE_SET(mouseover_, SetPivot, pivot_x, pivot_y);
SAFE_SET(selected_, SetPivot, pivot_x, pivot_y);
SAFE_SET(disabled_, SetPivot, pivot_x, pivot_y);
}
bool Button::Dispatch(const MouseEvent & e, bool handled)
{
if (!handled && enabled_ && IsVisible() && normal_)
{
bool contains = normal_->ContainsPoint(e.GetPosition());
if (e.GetType() == MouseEvent::Type::LeftUp && is_selected_ && contains)
{
if (callback_)
{
callback_();
}
is_selected_ = false;
SetStatus(Status::Normal);
return true;
}
else if (e.GetType() == MouseEvent::Type::LeftDown)
{
is_selected_ = contains;
SetStatus(contains ? Status::Selected : Status::Normal);
if (contains)
return true;
}
else if (e.GetType() == MouseEvent::Type::LeftUp)
{
is_selected_ = false;
}
else if (e.GetType() == MouseEvent::Type::MoveBy && is_selected_ && contains)
{
SetStatus(Status::Selected);
return true;
}
else
{
if (!e.IsLButtonDown() && is_selected_)
{
is_selected_ = false;
}
SetStatus(contains ? Status::Mouseover : Status::Normal);
if (contains)
return true;
}
}
return Node::Dispatch(e, handled);
}
void Button::Visit()
{
Node::Visit();
if (IsVisible() &&
!enabled_ &&
normal_ &&
normal_->ContainsPoint(Device::GetInput()->GetMousePos()))
{
HCURSOR hcursor = ::LoadCursor(nullptr, IDC_NO);
if (hcursor)
{
::SetCursor(hcursor);
}
}
else if (status_ == Status::Mouseover || status_ == Status::Selected)
{
HCURSOR hcursor = ::LoadCursor(nullptr, IDC_HAND);
if (hcursor)
{
::SetCursor(hcursor);
}
}
}
void Button::SetStatus(Status status)
{
if (status_ != status)
{
status_ = status;
UpdateVisible();
}
}
void Button::UpdateVisible()
{
SAFE_SET(normal_, SetVisible, false);
SAFE_SET(mouseover_, SetVisible, false);
SAFE_SET(selected_, SetVisible, false);
SAFE_SET(disabled_, SetVisible, false);
if (enabled_)
{
if (status_ == Status::Selected && selected_)
{
selected_->SetVisible(true);
}
else if (status_ == Status::Mouseover && mouseover_)
{
mouseover_->SetVisible(true);
}
else
{
if (normal_) normal_->SetVisible(true);
}
}
else
{
if (disabled_)
{
disabled_->SetVisible(true);
}
else
{
if (normal_) normal_->SetVisible(true);
}
}
}
}

View File

@ -1,185 +0,0 @@
// 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.
#ifndef __E2D_COMPONENT_H__
#define __E2D_COMPONENT_H__
#include "e2dobject.h"
namespace easy2d
{
class Button
: public Node
{
typedef std::function<void()> Callback;
public:
Button();
explicit Button(
Node * normal, /* 普通状态 */
const Callback& func = nullptr /* 按钮点击后的回调函数 */
);
explicit Button(
Node * normal, /* 普通状态 */
Node * selected, /* 鼠标按下状态 */
const Callback& func = nullptr /* 按钮点击后的回调函数 */
);
explicit Button(
Node * normal, /* 普通状态 */
Node * mouseover, /* 鼠标移入状态 */
Node * selected, /* 鼠标按下状态 */
const Callback& func = nullptr /* 按钮点击后的回调函数 */
);
explicit Button(
Node * normal, /* 普通状态 */
Node * mouseover, /* 鼠标移入状态 */
Node * selected, /* 鼠标移入状态 */
Node * disabled, /* 按钮禁用状态 */
const Callback& func = nullptr /* 按钮点击后的回调函数 */
);
// 获取按钮状态是启用还是禁用
bool IsEnable() const;
// 设置按钮启用或禁用
void SetEnabled(
bool enabled
);
// 设置一般情况下显示的按钮
virtual void SetNormal(
Node * normal
);
// 设置鼠标移入按钮时显示的按钮
virtual void SetMouseOver(
Node * mouseover
);
// 设置鼠标按下按钮时显示的按钮
virtual void SetSelected(
Node * selected
);
// 设置按钮被禁用时显示的按钮
virtual void SetDisabled(
Node * disabled
);
// 设置按钮点击后的回调函数
void SetCallbackOnClick(
const Callback& func
);
// 设置支点位置
// 默认为 (0, 0), 范围 [0, 1]
virtual void SetPivot(
float pivot_x,
float pivot_y
) override;
private:
E2D_DISABLE_COPY(Button);
// 按钮状态枚举
enum class Status { Normal, Mouseover, Selected };
// 设置按钮状态
virtual void SetStatus(
Status status
);
// 刷新按钮显示
virtual void UpdateVisible();
// 分发鼠标消息
virtual bool Dispatch(
const MouseEvent& e,
bool handled
) override;
// 遍历节点
virtual void Visit() override;
private:
Node * normal_;
Node * mouseover_;
Node * selected_;
Node * disabled_;
bool enabled_;
bool is_selected_;
Status status_;
Callback callback_;
};
// 菜单
class Menu
: public Node
{
public:
Menu();
explicit Menu(
const std::vector<Button*>& buttons /* 按钮数组 */
);
// 获取菜单是否禁用
bool IsEnable() const;
// 获取菜单中的按钮数量
size_t GetButtonCount() const;
// 设置菜单启用或禁用
void SetEnabled(
bool enabled
);
// 添加按钮
void AddButton(
Button * button
);
// 移除按钮
bool RemoveButton(
Button * button
);
// 获取所有按钮
const std::vector<Button*>& GetAllButtons() const;
private:
E2D_DISABLE_COPY(Menu);
private:
bool enabled_;
std::vector<Button*> buttons_;
};
} // end of easy2d namespace
#endif // !__E2D_COMPONENT_H__

View File

@ -1,327 +0,0 @@
// 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.
#ifndef __E2D_MODULE_H__
#define __E2D_MODULE_H__
#include "e2dobject.h"
#include "e2dtransition.h"
namespace easy2d
{
// 图形设备
class Graphics
{
public:
Graphics(
HWND hwnd
);
~Graphics();
// 开始渲染
void BeginDraw();
// 结束渲染
void EndDraw();
// 渲染调试信息
void DrawDebugInfo();
// 获取 ID2D1Factory 对象
ID2D1Factory* GetFactory() const;
// 获取 IWICImagingFactory 对象
IWICImagingFactory* GetImagingFactory() const;
// 获取 IDWriteFactory 对象
IDWriteFactory* GetWriteFactory() const;
// 获取 ID2D1HwndRenderTarget 对象
ID2D1HwndRenderTarget* GetRenderTarget() const;
// 获取 ID2D1SolidColorBrush 对象
ID2D1SolidColorBrush* GetSolidBrush() const;
// 获取文字渲染工具
IDWriteTextRenderer* GetTextRender() const;
// 获取 Miter 样式的 ID2D1StrokeStyle
ID2D1StrokeStyle* GetMiterStrokeStyle();
// 获取 Bevel 样式的 ID2D1StrokeStyle
ID2D1StrokeStyle* GetBevelStrokeStyle();
// 获取 Round 样式的 ID2D1StrokeStyle
ID2D1StrokeStyle* GetRoundStrokeStyle();
// 设置文字渲染样式
void SetTextRendererStyle(
const Color& fill_color,
bool has_outline,
const Color& outline_color,
float outline_width,
Stroke outline_stroke
);
// 获取 DPI
static float GetDpi();
protected:
D2D1_COLOR_F clear_color_;
ID2D1Factory* factory_;
IWICImagingFactory* imaging_factory_;
IDWriteFactory* write_factory_;
ID2D1StrokeStyle* miter_stroke_style_;
ID2D1StrokeStyle* bevel_stroke_style_;
ID2D1StrokeStyle* round_stroke_style_;
IDWriteTextRenderer* text_renderer_;
IDWriteTextFormat* fps_text_format_;
IDWriteTextLayout* fps_text_layout_;
ID2D1SolidColorBrush* solid_brush_;
ID2D1HwndRenderTarget* render_target_;
};
// 输入设备
class Input
{
public:
Input(
HWND hwnd
);
~Input();
// 检测键盘某按键是否正被按下
bool IsDown(
KeyCode key
);
// 检测鼠标按键是否正被按下
bool IsDown(
MouseCode code
);
// 获得鼠标X轴坐标值
float GetMouseX();
// 获得鼠标Y轴坐标值
float GetMouseY();
// 获得鼠标坐标值
Point GetMousePos();
// 获得鼠标X轴坐标增量
float GetMouseDeltaX();
// 获得鼠标Y轴坐标增量
float GetMouseDeltaY();
// 获得鼠标Z轴鼠标滚轮坐标增量
float GetMouseDeltaZ();
// 刷新设备状态
void Flush();
protected:
IDirectInput8W * direct_input_;
IDirectInputDevice8W* keyboard_device_;
IDirectInputDevice8W* mouse_device_;
DIMOUSESTATE mouse_state_;
char key_buffer_[256];
};
// 音频设备
class Audio
{
public:
Audio();
~Audio();
// 开启设备
void Open();
// 关闭设备
void Close();
// 创建音源
HRESULT CreateVoice(
IXAudio2SourceVoice ** voice,
WAVEFORMATEX * wfx
);
protected:
IXAudio2 * x_audio2_;
IXAudio2MasteringVoice* mastering_voice_;
};
// 设备
class Device
{
public:
// 获取图形设备
static Graphics * GetGraphics();
// 获取输入设备
static Input * GetInput();
// 获取音频设备
static Audio * GetAudio();
// 初始化
static void Init(
HWND hwnd
);
// 销毁资源
static void Destroy();
};
// 游戏控制器
class Game
{
public:
// 开始时
virtual void OnStart() = 0;
// 更新时
virtual void OnUpdate(float dt) {}
// 退出时
virtual void OnExit() {}
// 窗口关闭时
// 返回值:返回 false 将阻止窗口关闭
virtual bool OnClose() { return true; }
// 运行
void Run();
// 结束
void Quit();
// 设置窗口大小
void SetSize(
int width, /* 窗口宽度 */
int height /* 窗口高度 */
);
// 设置窗体标题
void SetTitle(
const std::wstring& title /* 窗体标题 */
);
// 设置窗体图标
void SetIcon(
int resource_id /* 图标资源 ID */
);
// 调试模式
void SetDebugMode(
bool enabled
);
// 获取窗体标题
const std::wstring& GetTitle() const;
// 获取窗体宽度
int GetWidth() const;
// 获取窗体高度
int GetHeight() const;
// 获取窗体大小
Size GetSize() const;
// 获取窗口句柄
HWND GetHWnd() const;
// 切换场景
void EnterScene(
Scene * scene, /* 场景 */
Transition * transition = nullptr /* 场景动画 */
);
// 获取当前场景
Scene * GetCurrentScene();
// 获取实例
static Game * GetInstance();
protected:
Game();
~Game();
E2D_DISABLE_COPY(Game);
private:
// 初始化
void Init();
// 根据客户区大小定位窗口
Rect Locate(
int width,
int height
);
// 是否正在进行场景过渡
bool IsTransitioning() const;
// 更新场景内容
void UpdateScene(
float dt
);
// 渲染场景画面
void DrawScene();
// Win32 窗口消息回调程序
static LRESULT CALLBACK WndProc(
HWND hwnd,
UINT msg,
WPARAM w_param,
LPARAM l_param
);
private:
HWND hwnd_;
std::wstring title_;
int width_;
int height_;
int icon_;
bool debug_mode_;
bool quit_;
Scene* curr_scene_;
Scene* next_scene_;
Transition* transition_;
};
} // end of easy2d namespace
#endif // __E2D_MODULE_H__

File diff suppressed because it is too large Load Diff

View File

@ -1,339 +0,0 @@
// 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.
#ifndef __E2D_TOOL_H__
#define __E2D_TOOL_H__
#include "e2dutil.h"
namespace easy2d
{
// 音乐
class Music
: public Ref
{
public:
Music();
Music(
const std::wstring& file_path /* 音乐文件路径 */
);
Music(
Resource& res /* 音乐资源 */
);
virtual ~Music();
// 打开音乐文件
bool Load(
const std::wstring& file_path /* 音乐文件路径 */
);
// 打开音乐资源
bool Load(
Resource& res /* 音乐资源 */
);
// 播放
bool Play(
int loop_count = 0 /* 播放循环次数 (-1 为循环播放) */
);
// 暂停
void Pause();
// 继续
void Resume();
// 停止
void Stop();
// 关闭并回收资源
void Close();
// 是否正在播放
bool IsPlaying() const;
// 获取音量
float GetVolume() const;
// 设置音量
bool SetVolume(
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_;
};
// 音乐播放器
class Player
{
public:
Player();
~Player();
// 预加载音乐资源
bool Load(
const std::wstring& file_path /* 音乐文件路径 */
);
// 播放音乐
bool Play(
const std::wstring& file_path, /* 音乐文件路径 */
int loop_count = 0 /* 播放循环次数 (-1 为循环播放) */
);
// 暂停音乐
void Pause(
const std::wstring& file_path /* 音乐文件路径 */
);
// 继续播放音乐
void Resume(
const std::wstring& file_path /* 音乐文件路径 */
);
// 停止音乐
void Stop(
const std::wstring& file_path /* 音乐文件路径 */
);
// 获取音乐播放状态
bool IsPlaying(
const std::wstring& file_path /* 音乐文件路径 */
);
// 预加载音乐资源
bool Load(
Resource& res /* 音乐资源 */
);
// 播放音乐
bool Play(
Resource& res, /* 音乐资源 */
int loop_count = 0 /* 播放循环次数 (-1 为循环播放) */
);
// 暂停音乐
void Pause(
Resource& res /* 音乐资源 */
);
// 继续播放音乐
void Resume(
Resource& res /* 音乐资源 */
);
// 停止音乐
void Stop(
Resource& res /* 音乐资源 */
);
// 获取音乐播放状态
bool IsPlaying(
Resource& res /* 音乐资源 */
);
// 获取音量
float GetVolume() const;
// 设置音量
void SetVolume(
float volume /* 1.0 为原始音量 */
);
// 暂停所有音乐
void PauseAll();
// 继续播放所有音乐
void ResumeAll();
// 停止所有音乐
void StopAll();
// 清除缓存
static void ClearCache();
protected:
E2D_DISABLE_COPY(Player);
protected:
float volume_;
static std::map<size_t, Music*> musics_;
};
// 数据管理工具
class Data
{
public:
Data(
const std::wstring& key, /* 键值 */
const std::wstring& field = L"Defalut" /* 字段名称 */
);
// 该数据是否存在
bool Exists() const;
// 保存 int 类型的值
bool SaveInt(
int value
);
// 保存 float 类型的值
bool SaveFloat(
float value
);
// 保存 double 类型的值
bool SaveDouble(
double value
);
// 保存 bool 类型的值
bool SaveBool(
bool value
);
// 保存 std::wstring 类型的值
bool SaveString(
const std::wstring& value
);
// 获取 int 类型的值
int GetInt() const;
// 获取 float 类型的值
float GetFloat() const;
// 获取 double 类型的值
double GetDouble() const;
// 获取 bool 类型的值
bool GetBool() const;
// 获取 字符串 类型的值
std::wstring GetString();
protected:
std::wstring key_;
std::wstring field_;
const std::wstring& data_path_;
};
// 文件
class File
{
public:
File();
File(
const std::wstring& file_name
);
virtual ~File();
// 打开文件
bool Open(
const std::wstring& file_name
);
// 文件是否存在
bool Exists() const;
// 删除文件
bool Delete();
// 获取文件路径
const std::wstring& GetPath() const;
// 获取文件扩展名
std::wstring GetExtension() const;
// 释放资源到临时文件目录
static File Extract(
Resource& res, /* 资源 */
const std::wstring& dest_file_name /* 目标文件名 */
);
// 添加文件搜索路径
static void AddSearchPath(
const std::wstring& path
);
// 弹出打开文件对话框
static File ShowOpenDialog(
const std::wstring& title = L"打开", /* 对话框标题 */
const std::wstring& filter = L"" /* 筛选扩展名,例如 "*.jpg;*.jpeg" */
);
// 弹出保存文件对话框
static File ShowSaveDialog(
const std::wstring& title = L"保存", /* 对话框标题 */
const std::wstring& def_file = L"", /* 默认保存的文件名 */
const std::wstring& def_ext = L"" /* 默认追加的扩展名,例如 "txt" */
);
protected:
std::wstring file_path_;
static std::list<std::wstring> search_paths_;
};
// 路径
class Path
{
public:
// 获取数据的默认保存路径
static const std::wstring& GetDataPath();
// 获取临时文件目录
static const std::wstring& GetTemporaryPath();
// 获取 LocalAppData 目录
static const std::wstring& GetLocalAppDataPath();
// 获取当前程序的运行路径
static const std::wstring& GetExeFilePath();
};
} // end of easy2d namespace
#endif // __E2D_TOOL_H__

View File

@ -1,668 +0,0 @@
// 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.
#ifndef __E2D_UTIL_H__
#define __E2D_UTIL_H__
#include "e2dmacros.h"
namespace easy2d
{
class Size;
// 坐标
//
// Usage:
// 表示一个二维空间的坐标: Point origin(0, 0);
// 计算两点间距离: float distance = Point::Distance(p1, p2);
// 坐标可以相加减: Point p = Point(10, 10) + Point(20, 20); // p 的坐标是 (30, 30)
//
class Point
{
public:
float x; // X 坐标
float y; // Y 坐标
public:
Point();
Point(
float x,
float y
);
Point(
const Point& other
);
Point operator + (const Point & other) const;
Point operator - (const Point & other) const;
Point operator * (float value) const;
Point operator / (float value) const;
Point operator - () const;
bool operator== (const Point& other) const;
explicit operator Size() const;
// 判断两点间距离
static float Distance(
const Point& p1,
const Point& p2
);
};
// 大小
//
// Usage:
// 表示一个二维矩形区域的大小: Size s(10, 5); // 宽为 10, 高为 5
// 大小可以相加减: Size s = Size(10, 10) + Size(20, 20); // s 的大小是宽高均为 30
//
class Size
{
public:
float width; // 宽度
float height; // 高度
public:
Size();
Size(
float width,
float height
);
Size(
const Size& other
);
Size operator + (const Size & other) const;
Size operator - (const Size & other) const;
Size operator * (float value) const;
Size operator / (float value) const;
Size operator - () const;
bool operator== (const Size& other) const;
explicit operator Point() const;
};
// 矩形
//
// Usage:
// 表示一个二维矩形: Rect rect = Rect(10, 20, 30, 40); // 左上角坐标为 (10, 20), 宽为 30, 高为 40
// 矩形可以通过 Point + Size 定义, Point 表示矩形左上角坐标, Size 表示矩形宽高
// 判断一个点是否在矩形内: bool contains = rect.ContainsPoint(p);
// 判断两矩形是否相交: bool intersects = rect1.Intersects(rect2);
//
class Rect
{
public:
Point origin; // 左上角坐标
Size size; // 宽度和高度
public:
Rect();
Rect(
float x,
float y,
float width,
float height
);
Rect(
const Point& pos,
const Size& size
);
Rect(
const Rect& other
);
Rect& operator= (const Rect& other);
bool operator== (const Rect& rect) const;
// 判断点是否在矩形内
bool ContainsPoint(
const Point& point
) const;
// 判断两矩形是否相交
bool Intersects(
const Rect& rect
) const;
};
// 颜色
//
// Usage:
// 使用枚举表示颜色: Color blue = Color::Blue;
// 使用 RGB 表示一个颜色: Color red(1.0f, 0.0f, 0.0f);
// 使用 RGBA 表示一个带透明度的颜色: Color not_black(1.0f, 1.0f, 1.0f, 0.5f);
// 使用一个 UINT 类型的值表示 RGB: Color black(0x000000);
//
class Color
{
public:
Color();
Color(
float r,
float g,
float b
);
Color(
float r,
float g,
float b,
float alpha
);
Color(
UINT rgb
);
Color(
UINT rgb,
float alpha
);
Color(
const D2D1_COLOR_F& color
);
explicit operator D2D1_COLOR_F() const;
public:
enum Value : UINT
{
Black = 0x000000,
Blue = 0x0000FF,
BlueViolet = 0x8A2BE2,
Brown = 0xA52A2A,
Chocolate = 0xD2691E,
DarkBlue = 0x00008B,
DarkGray = 0xA9A9A9,
DarkGreen = 0x006400,
DarkOrange = 0xFF8C00,
DarkRed = 0x8B0000,
DarkViolet = 0x9400D3,
ForestGreen = 0x228B22,
Gold = 0xFFD700,
Gray = 0x808080,
Green = 0x008000,
GreenYellow = 0xADFF2F,
LightBlue = 0xADD8E6,
LightCyan = 0xE0FFFF,
LightGreen = 0x90EE90,
LightGray = 0xD3D3D3,
LightPink = 0xFFB6C1,
LightSeaGreen = 0x20B2AA,
LightSkyBlue = 0x87CEFA,
LightYellow = 0xFFFFE0,
Orange = 0xFFA500,
OrangeRed = 0xFF4500,
Pink = 0xFFC0CB,
Purple = 0x800080,
Red = 0xFF0000,
Silver = 0xC0C0C0,
SkyBlue = 0x87CEEB,
Snow = 0xFFFAFA,
Violet = 0xEE82EE,
Wheat = 0xF5DEB3,
White = 0xFFFFFF,
WhiteSmoke = 0xF5F5F5,
Wood = 0xDEB887,
Yellow = 0xFFFF00,
YellowGreen = 0x9ACD32
};
public:
float r;
float g;
float b;
float a;
};
// 方向
enum class Direction : int
{
Up, /* 上 */
Down, /* 下 */
Left, /* 左 */
Right /* 右 */
};
// 线条相交样式
enum class Stroke : int
{
Miter = 0, /* 斜切 */
Bevel = 1, /* 斜角 */
Round = 2 /* 圆角 */
};
// 键盘键值
enum class KeyCode : int
{
Unknown = 0,
Up = 0xC8,
Left = 0xCB,
Right = 0xCD,
Down = 0xD0,
Enter = 0x1C,
Space = 0x39,
Esc = 0x01,
Q = 0x10,
W = 0x11,
E = 0x12,
R = 0x13,
T = 0x14,
Y = 0x15,
U = 0x16,
I = 0x17,
O = 0x18,
P = 0x19,
A = 0x1E,
S = 0x1F,
D = 0x20,
F = 0x21,
G = 0x22,
H = 0x23,
J = 0x24,
K = 0x25,
L = 0x26,
Z = 0x2C,
X = 0x2D,
C = 0x2E,
V = 0x2F,
B = 0x30,
N = 0x31,
M = 0x32,
Num1 = 0x02,
Num2 = 0x03,
Num3 = 0x04,
Num4 = 0x05,
Num5 = 0x06,
Num6 = 0x07,
Num7 = 0x08,
Num8 = 0x09,
Num9 = 0x0A,
Num0 = 0x0B,
Numpad7 = 0x47,
Numpad8 = 0x48,
Numpad9 = 0x49,
Numpad4 = 0x4B,
Numpad5 = 0x4C,
Numpad6 = 0x4D,
Numpad1 = 0x4F,
Numpad2 = 0x50,
Numpad3 = 0x51,
Numpad0 = 0x52,
};
// 鼠标键值
enum class MouseCode : int
{
Left, /* 鼠标左键 */
Right, /* 鼠标右键 */
Middle /* 鼠标中键 */
};
// 时间段
//
// Usage:
// 5 秒: Duration::Second * 5
// 1.5 小时: Duration::Hour * 1.5
// 3 小时 45 分 15 秒: Duration::Hour * 3 + Duration::Minute * 45 + Duration::Second * 15
// 时间段转化为秒: float s = duration.Seconds();
// 时间段格式化: Duration d = Duration::Parse(L"1h35m"); // 1小时35分钟
//
class Duration
{
public:
static const Duration Millisecond; // 毫秒
static const Duration Second; // 秒
static const Duration Minute; // 分钟
static const Duration Hour; // 小时
public:
Duration();
explicit Duration(
int milliseconds
);
// 转化为毫秒
int Milliseconds() const;
// 转化为秒
float Seconds() const;
// 转化为分钟
float Minutes() const;
// 转化为小时
float Hours() const;
// 时间段格式化
// 时间段字符串允许是有符号的浮点数, 并且带有时间单位后缀
// 例如: "300ms", "-1.5h", "2h45m"
// 允许的时间单位有 "ms", "s", "m", "h"
static Duration Parse(const std::wstring& str);
bool operator== (const Duration &) const;
bool operator!= (const Duration &) const;
bool operator> (const Duration &) const;
bool operator>= (const Duration &) const;
bool operator< (const Duration &) const;
bool operator<= (const Duration &) const;
Duration operator + (const Duration &) const;
Duration operator - (const Duration &) const;
Duration operator - () const;
Duration operator * (int) const;
Duration operator * (float) const;
Duration operator * (double) const;
Duration operator / (int) const;
Duration operator / (float) const;
Duration operator / (double) const;
Duration& operator += (const Duration &);
Duration& operator -= (const Duration &);
Duration& operator *= (int);
Duration& operator *= (float);
Duration& operator *= (double);
Duration& operator /= (int);
Duration& operator /= (float);
Duration& operator /= (double);
friend Duration operator* (int, const Duration &);
friend Duration operator* (float, const Duration &);
friend Duration operator* (double, const Duration &);
friend Duration operator/ (int, const Duration &);
friend Duration operator/ (float, const Duration &);
friend Duration operator/ (double, const Duration &);
private:
int milliseconds_;
};
// 时间点
//
// Usage:
// 使用 Time::Now 方法获取当前时间: Time now = Time::Now();
// 两时间相减, 得到的结果是一个 Duration 对象, 例如:
// Time t1 = Time::Now();
// ... // 做些什么
// Time t2 = Time::Now();
// 然后获取两时间相差的毫秒数:
// int ms = (t2 - t1).Milliseconds();
//
class Time
{
public:
Time();
explicit Time(
std::chrono::steady_clock::time_point
);
Time(
const Time& other
);
Time(
Time&& other
);
// 获取时间戳
time_t GetTimeStamp() const;
// 是否是零时
bool IsZero() const;
Time operator + (const Duration &) const;
Time operator - (const Duration &) const;
Time& operator += (const Duration &);
Time& operator -= (const Duration &);
Duration operator - (const Time &) const;
Time& operator = (const Time &) E2D_NOEXCEPT;
Time& operator = (Time &&) E2D_NOEXCEPT;
// 获取当前时间
static Time Now();
private:
std::chrono::steady_clock::time_point time_;
};
// 字体
class Font
{
public:
std::wstring family; // 字体族
float size; // 字号
UINT weight; // 粗细值
bool italic; // 是否斜体
public:
// 字体粗细值
enum Weight : UINT
{
Thin = 100,
ExtraLight = 200,
Light = 300,
Normal = 400,
Medium = 500,
Bold = 700,
ExtraBold = 800,
Black = 900,
ExtraBlack = 950
};
public:
explicit Font(
const std::wstring& family = L"",
float size = 22,
UINT weight = Font::Weight::Normal,
bool italic = false
);
};
// 资源
//
// Usage:
// Resource 用于获取可执行文件 (exe) 中的资源, 必须在构造函数中指定它的
// 资源类型和名称标识符。
// 例如, 一份音频资源的类型为 L"WAVE", 名称标识符为 IDR_WAVE_1, 那么可以这样指定该资源:
// Resource res(MAKEINTRESOURCE(IDR_WAVE_1), L"WAVE");
// 如果需要手动加载这份资源, 可以通过 Load 方法获取资源内容
// if (res.Load()) {
// LPVOID data = res.GetData();
// DWORD size = res.GetDataSize();
// }
// 了解资源的更多信息: https://docs.microsoft.com/en-us/windows/desktop/menurc/resources
//
class Resource
{
public:
Resource(
LPCWSTR name, /* 资源名称 */
LPCWSTR type /* 资源类型 */
);
bool Load();
LPCWSTR GetName() const;
LPCWSTR GetType() const;
LPVOID GetData() const;
DWORD GetDataSize() const;
size_t GetHashCode() const;
private:
bool loaded_;
LPCWSTR name_;
LPCWSTR type_;
LPVOID data_;
DWORD data_size_;
};
// 二维转换
class Transform
{
public:
Point position; // 坐标
Size size; // 大小
float scale_x; // 横向缩放
float scale_y; // 纵向缩放
float rotation; // 旋转
float skew_x; // 横向倾斜角度
float skew_y; // 纵向倾斜角度
float pivot_x; // 支点横坐标
float pivot_y; // 支点纵坐标
public:
Transform();
explicit operator D2D1::Matrix3x2F() const;
bool operator== (const Transform& other) const;
};
// 随机数产生器
//
// Usage:
// 使用静态方法 Range 获取指定范围内的一个随机数, 如:
// int n = Random::Range(1, 5); // 获取 1~6 内的随机整数, 包含 1 和 6
// 方法同样适用于浮点数的生成, 如:
// double d = Random::Range(1.2, 1.5);
// 注意, 随机数的类型取决于参数的类型。
//
class Random
{
public:
// 取得范围内的一个整型随机数
template<typename T>
static inline T Range(T min, T max)
{
return Random::RandomInt(min, max);
}
// 取得范围内的一个浮点数随机数
static inline float Range(float min, float max)
{
return Random::RandomReal(min, max);
}
// 取得范围内的一个浮点数随机数
static inline double Range(double min, double max)
{
return Random::RandomReal(min, max);
}
private:
template<typename T>
static T RandomInt(T min, T max)
{
std::uniform_int_distribution<T> dist(min, max);
return dist(Random::GetEngine());
}
template<typename T>
static T RandomReal(T min, T max)
{
std::uniform_real_distribution<T> dist(min, max);
return dist(Random::GetEngine());
}
static std::default_random_engine &GetEngine();
};
// 引用计数对象
class Ref
{
public:
Ref();
virtual ~Ref();
// 增加引用计数
LONG Retain();
// 减少引用计数
LONG Release();
// 获取引用计数
LONG GetRefCount() const;
private:
LONG ref_count_;
};
template<class Interface>
inline void SafeRelease(Interface*& p)
{
if (p != nullptr)
{
p->Release();
p = nullptr;
}
}
inline void ThrowIfFailed(HRESULT hr)
{
if (FAILED(hr))
{
static char s_str[64] = {};
sprintf_s(s_str, "Failure with HRESULT of %08X", static_cast<unsigned int>(hr));
throw std::runtime_error(s_str);
}
}
} // end of easy2d namespace
#endif // __E2D_UTIL_H__

View File

@ -36,14 +36,76 @@
#endif
#include "e2dmacros.h"
#include "e2dutil.h"
#include "e2dobject.h"
#include "e2dcomponent.h"
#include "e2dtool.h"
#include "e2daction.h"
#include "e2dtransition.h"
#include "e2dmodule.h"
//
// base
//
#include "base/macros.h"
#include "base/base.h"
#include "base/modules.h"
#include "base/render.h"
#include "base/window.h"
#include "base/input.h"
#include "base/audio.h"
#include "base/time.h"
#include "base/logs.h"
#include "base/Size.h"
#include "base/Rect.hpp"
#include "base/Font.h"
#include "base/Color.h"
#include "base/Resource.h"
#include "base/RefCounter.h"
#include "base/Image.h"
#include "base/Scene.h"
#include "base/Node.h"
#include "base/Sprite.h"
#include "base/Task.h"
#include "base/Text.h"
#include "base/Action.h"
#include "base/ActionCombined.h"
#include "base/ActionFiniteTime.h"
#include "base/Animation.h"
#include "base/CallFunc.h"
#include "base/Canvas.h"
#include "base/Transition.h"
#include "base/KeyEvent.h"
#include "base/MouseEvent.h"
#include "base/Game.h"
//
// math
//
#include "math/scalar.hpp"
#include "math/vector.hpp"
#include "math/Matrix.hpp"
#include "math/Transform.h"
#include "math/rand.h"
//
// utils
//
#include "utils/Path.h"
#include "utils/Data.h"
#include "utils/File.h"
#include "utils/Transcoder.h"
#include "utils/Music.h"
#include "utils/Player.h"
//
// ui
//
#include "ui/Button.h"
#include "ui/Menu.h"
#if defined(DEBUG) || defined(_DEBUG)

View File

@ -1,103 +0,0 @@
// 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.
#include "..\e2devent.h"
namespace easy2d
{
KeyEvent::KeyEvent(UINT message, WPARAM w_param, LPARAM l_param)
: message_(message)
, w_param_(w_param)
, l_param_(l_param)
{
}
KeyCode KeyEvent::GetCode() const
{
switch (w_param_)
{
case 'A': return KeyCode::A;
case 'B': return KeyCode::B;
case 'C': return KeyCode::C;
case 'D': return KeyCode::D;
case 'E': return KeyCode::E;
case 'F': return KeyCode::F;
case 'G': return KeyCode::G;
case 'H': return KeyCode::H;
case 'I': return KeyCode::I;
case 'J': return KeyCode::J;
case 'K': return KeyCode::K;
case 'L': return KeyCode::L;
case 'M': return KeyCode::M;
case 'N': return KeyCode::N;
case 'O': return KeyCode::O;
case 'P': return KeyCode::P;
case 'Q': return KeyCode::Q;
case 'R': return KeyCode::R;
case 'S': return KeyCode::S;
case 'T': return KeyCode::T;
case 'U': return KeyCode::U;
case 'V': return KeyCode::V;
case 'W': return KeyCode::W;
case 'X': return KeyCode::X;
case 'Y': return KeyCode::Y;
case 'Z': return KeyCode::Z;
case '0': return KeyCode::Num0;
case '1': return KeyCode::Num1;
case '2': return KeyCode::Num2;
case '3': return KeyCode::Num3;
case '4': return KeyCode::Num4;
case '5': return KeyCode::Num5;
case '6': return KeyCode::Num6;
case '7': return KeyCode::Num7;
case '8': return KeyCode::Num8;
case '9': return KeyCode::Num9;
case VK_NUMPAD0: return KeyCode::Numpad0;
case VK_NUMPAD1: return KeyCode::Numpad1;
case VK_NUMPAD2: return KeyCode::Numpad2;
case VK_NUMPAD3: return KeyCode::Numpad3;
case VK_NUMPAD4: return KeyCode::Numpad4;
case VK_NUMPAD5: return KeyCode::Numpad5;
case VK_NUMPAD6: return KeyCode::Numpad6;
case VK_NUMPAD7: return KeyCode::Numpad7;
case VK_NUMPAD8: return KeyCode::Numpad8;
case VK_NUMPAD9: return KeyCode::Numpad9;
case VK_UP: return KeyCode::Up;
case VK_DOWN: return KeyCode::Down;
case VK_LEFT: return KeyCode::Left;
case VK_RIGHT: return KeyCode::Right;
case VK_RETURN: return KeyCode::Enter;
case VK_SPACE: return KeyCode::Space;
case VK_ESCAPE: return KeyCode::Esc;
default: return KeyCode::Unknown;
}
}
int KeyEvent::GetCount() const
{
return static_cast<int>((DWORD)l_param_ & 0x0000FFFF);
}
KeyEvent::Type KeyEvent::GetType() const
{
return Type(message_);
}
}

196
core/math/Matrix.hpp Normal file
View File

@ -0,0 +1,196 @@
// 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 "vector.hpp"
namespace easy2d
{
namespace math
{
class Matrix
{
float _11;
float _12;
float _21;
float _22;
float _31;
float _32;
public:
Matrix()
: _11(1.f)
, _12(0.f)
, _21(0.f)
, _22(1.f)
, _31(0.f)
, _32(0.f)
{
}
Matrix(
float _11,
float _12,
float _21,
float _22,
float _31,
float _32)
{
this->_11 = _11;
this->_12 = _12;
this->_21 = _21;
this->_22 = _22;
this->_31 = _31;
this->_32 = _32;
}
inline Matrix operator*(const Matrix &matrix) const
{
return Matrix(
_11 * matrix._11 + _12 * matrix._21,
_11 * matrix._12 + _12 * matrix._22,
_21 * matrix._11 + _22 * matrix._21,
_21 * matrix._12 + _22 * matrix._22,
_31 * matrix._11 + _32 * matrix._21 + matrix._31,
_31 * matrix._12 + _32 * matrix._22 + matrix._32
);
}
inline Matrix& Identity()
{
_11 = 1.f;
_12 = 0.f;
_21 = 0.f;
_22 = 1.f;
_31 = 0.f;
_32 = 0.f;
return *this;
}
inline Matrix& Translate(const Vector2& v)
{
*this = *this * Matrix::Translation(v);
return *this;
}
inline Matrix& Scale(const Vector2& v, const Vector2& center)
{
*this = *this * Matrix::Scaling(v, center);
return *this;
}
inline Matrix& Rotate(float angle, const Vector2& center)
{
*this = *this * Matrix::Rotation(angle, center);
return *this;
}
inline Matrix& Skew(float angle_x, float angle_y, const Vector2& center)
{
*this = *this * Matrix::Skewing(angle_x, angle_y, center);
return *this;
}
inline float Determinant() const
{
return (_11 * _22) - (_12 * _21);
}
inline bool IsIdentity() const
{
return _11 == 1.f && _12 == 0.f &&
_21 == 0.f && _22 == 1.f &&
_31 == 0.f && _32 == 0.f;
}
Vector2 Transform(const Vector2& v) const
{
return Vector2(
v.x * _11 + v.y * _21 + _31,
v.x * _12 + v.y * _22 + _32
);
}
static Matrix Translation(const Vector2& v)
{
return Matrix(
1.f, 0.f,
0.f, 1.f,
v.x, v.y
);
}
static Matrix Translation(
float x,
float y)
{
return Translation(Vector2(x, y));
}
static Matrix Scaling(
const Vector2& v,
const Vector2& center = Vector2())
{
return Matrix(
v.x, 0.f,
0.f, v.y,
center.x - v.x * center.x,
center.y - v.y * center.y
);
}
static Matrix Scaling(
float x,
float y,
const Vector2& center = Vector2())
{
return Scaling(Vector2(x, y), center);
}
static Matrix Rotation(
float angle,
const Vector2& center = Vector2())
{
float s = math::Sin(angle);
float c = math::Cos(angle);
return Matrix(
c, s,
-s, c,
center.x * (1 - c) + center.y * s,
center.y * (1 - c) - center.x * s
);
}
static Matrix Skewing(
float angle_x,
float angle_y,
const Vector2& center = Vector2())
{
float tx = math::Tan(angle_x);
float ty = math::Tan(angle_y);
return Matrix(
1.f, tx,
ty, 1.f,
-center.y * tx, -center.x * ty
);
}
};
}
}

74
core/math/Transform.cpp Normal file
View File

@ -0,0 +1,74 @@
// 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.
#include "Transform.h"
namespace easy2d
{
namespace math
{
Transform::Transform()
: position()
, size()
, scale_x(1.f)
, scale_y(1.f)
, rotation(0)
, skew_x(0)
, skew_y(0)
, pivot_x(0)
, pivot_y(0)
{
}
Transform::operator D2D1::Matrix3x2F() const
{
auto pivot = D2D1::Point2F(size.width * pivot_x, size.height * pivot_y);
auto matrix = D2D1::Matrix3x2F::Scale(
scale_x,
scale_y,
pivot
) * D2D1::Matrix3x2F::Skew(
skew_x,
skew_y,
pivot
) * D2D1::Matrix3x2F::Rotation(
rotation,
pivot
) * D2D1::Matrix3x2F::Translation(
position.x - pivot.x,
position.y - pivot.y
);
return matrix;
}
bool Transform::operator==(const Transform & other) const
{
return position == other.position &&
size == other.size &&
scale_x == other.scale_x &&
scale_y == other.scale_y &&
skew_x == other.skew_x &&
skew_y == other.skew_y &&
rotation == other.rotation &&
pivot_x == other.pivot_x &&
pivot_y == other.pivot_y;
}
}
}

51
core/math/Transform.h Normal file
View File

@ -0,0 +1,51 @@
// 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 "../base/BaseTypes.h"
#include "../base/Size.h"
#include <d2d1.h>
namespace easy2d
{
namespace math
{
class Transform
{
public:
Point position; // 坐标
Size size; // 大小
float scale_x; // 横向缩放
float scale_y; // 纵向缩放
float rotation; // 旋转
float skew_x; // 横向倾斜角度
float skew_y; // 纵向倾斜角度
float pivot_x; // 支点横坐标
float pivot_y; // 支点纵坐标
public:
Transform();
explicit operator D2D1::Matrix3x2F() const;
bool operator== (const Transform& other) const;
};
}
}

View File

@ -18,12 +18,21 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2daction.h"
#include "rand.h"
namespace easy2d
{
FadeOut::FadeOut(float duration)
: OpacityTo(duration, 0)
namespace math
{
namespace
{
std::random_device device;
std::default_random_engine engine(device());
}
std::default_random_engine& GetRandomEngine()
{
return engine;
}
}
}
}

99
core/math/rand.h Normal file
View File

@ -0,0 +1,99 @@
// 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 <random>
namespace easy2d
{
namespace math
{
//
// 随机数产生器
//
// Usage:
// 获取指定范围内的一个随机数, 如:
// int n = math::Rand(1, 5); // 获取 1~6 内的随机整数, 包含 1 和 6
// 方法同样适用于浮点数的生成, 如:
// double d = math::Rand(1.2, 1.5);
// 注意, 获得的随机数类型取决于参数的类型。
//
std::default_random_engine& GetRandomEngine();
template<typename T>
static T RandomInt(T min, T max)
{
std::uniform_int_distribution<T> dist(min, max);
return dist(GetRandomEngine());
}
template<typename T>
static T RandomReal(T min, T max)
{
std::uniform_real_distribution<T> dist(min, max);
return dist(GetRandomEngine());
}
inline int Rand(int min, int max)
{
return RandomInt(min, max);
}
inline unsigned int Rand(unsigned int min, unsigned int max)
{
return RandomInt(min, max);
}
inline long Rand(long min, long max)
{
return RandomInt(min, max);
}
inline unsigned long Rand(unsigned long min, unsigned long max)
{
return RandomInt(min, max);
}
inline char Rand(char min, char max)
{
return static_cast<char>(
RandomInt(static_cast<int>(min), static_cast<int>(max))
);
}
inline unsigned char Rand(unsigned char min, unsigned char max)
{
return static_cast<unsigned char>(
RandomInt(static_cast<unsigned int>(min), static_cast<unsigned int>(max))
);
}
inline float Rand(float min, float max)
{
return RandomReal(min, max);
}
inline double Range(double min, double max)
{
return RandomReal(min, max);
}
}
}

View File

@ -18,70 +18,47 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dutil.h"
#pragma once
#include <cmath>
namespace easy2d
{
Point::Point()
namespace math
{
x = 0;
y = 0;
}
inline int Abs(int v) { return ::abs(v); }
Point::Point(float x, float y)
{
this->x = x;
this->y = y;
}
inline float Abs(float v) { return ::fabsf(v); }
Point::Point(const Point & other)
{
x = other.x;
y = other.y;
}
inline double Abs(double v) { return ::fabs(v); }
Point Point::operator+(const Point & p) const
{
return Point(x + p.x, y + p.y);
}
inline float Sqrt(float v) { return ::sqrtf(v); }
Point Point::operator-(const Point & p) const
{
return Point(x - p.x, y - p.y);
}
inline double Sqrt(double v) { return ::sqrt(v); }
Point Point::operator*(float value) const
{
return Point(x * value, y * value);
}
inline int Sign(int v) { return v < 0 ? -1 : 1; }
Point Point::operator/(float value) const
{
return Point(x / value, y / value);
}
inline float Sign(float v) { return v < 0 ? -1.f : 1.f; }
Point::operator Size() const
{
return Size(x, y);
}
inline double Sign(double v) { return v < 0 ? -1.0 : 1.0; }
float Point::Distance(const Point &p1, const Point &p2)
{
return sqrt(
(p1.x - p2.x) * (p1.x - p2.x) +
(p1.y - p2.y) * (p1.y - p2.y)
);
}
inline float Sin(float v) { return ::sinf(v); }
Point Point::operator-() const
{
return Point(-x, -y);
}
inline double Sin(double v) { return ::sin(v); }
bool Point::operator==(const Point & point) const
{
return (x == point.x) && (y == point.y);
inline float Cos(float v) { return ::cosf(v); }
inline double Cos(double v) { return ::cos(v); }
inline float Tan(float v) { return ::tanf(v); }
inline double Tan(double v) { return ::tan(v); }
inline float Ceil(float v) { return ceil(v); }
inline double Ceil(double v) { return ceil(v); }
inline float Floor(float v) { return floor(v); }
inline double Floor(double v) { return floor(v); }
}
}
}

90
core/math/vector.hpp Normal file
View File

@ -0,0 +1,90 @@
// 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 "scalar.hpp"
namespace easy2d
{
namespace math
{
class Vector2
{
public:
float x;
float y;
public:
Vector2() : x(0.f), y(0.f) {}
Vector2(
float x,
float y
)
: x(x)
, y(y)
{}
Vector2(
const Vector2& other
)
: x(other.x)
, y(other.y)
{}
inline Vector2 operator + (const Vector2 & other) const
{
return Vector2(x + other.x, y + other.y);
}
inline Vector2 operator - (const Vector2 & other) const
{
return Vector2(x - other.x, y - other.y);
}
inline Vector2 operator * (float value) const
{
return Vector2(x * value, y * value);
}
inline Vector2 operator / (float value) const
{
return Vector2(x / value, y / value);
}
inline Vector2 operator - () const
{
return Vector2(-x, -y);
}
inline bool operator== (const Vector2& other) const
{
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();
}
};
}
}

View File

@ -1,625 +0,0 @@
// 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.
#include "..\e2dmodule.h"
#include "..\e2dobject.h"
#include "..\e2dtool.h"
#include "..\e2dtransition.h"
#include <thread>
#include <imm.h>
#pragma comment (lib ,"imm32.lib")
#define WINDOW_STYLE WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME
#define REGISTER_CLASS L"Easy2DApp"
namespace easy2d
{
namespace
{
Game * instance = nullptr;
}
Game * Game::GetInstance()
{
return instance;
}
Game::Game()
: hwnd_(nullptr)
, quit_(true)
, curr_scene_(nullptr)
, next_scene_(nullptr)
, transition_(nullptr)
, title_(L"Easy2D Game")
, width_(640)
, height_(480)
, icon_(0)
, debug_mode_(false)
{
if (instance)
{
throw std::runtime_error("同时只能存在一个游戏实例");
}
instance = this;
::CoInitialize(nullptr);
}
Game::~Game()
{
SafeRelease(transition_);
SafeRelease(curr_scene_);
SafeRelease(next_scene_);
Image::ClearCache();
Player::ClearCache();
Device::Destroy();
if (hwnd_)
{
::DestroyWindow(hwnd_);
}
instance = nullptr;
::CoUninitialize();
}
void Game::Run()
{
// 初始化
Init();
// 开始
OnStart();
// 刷新场景
if (next_scene_)
{
next_scene_->OnEnter();
curr_scene_ = next_scene_;
next_scene_ = nullptr;
}
::ShowWindow(hwnd_, SW_SHOWNORMAL);
::UpdateWindow(hwnd_);
// 运行
const int min_interval = 5;
Time last = Time::Now();
MSG msg = { 0 };
while (!quit_)
{
auto now = Time::Now();
auto dur = now - last;
if (dur.Milliseconds() > min_interval)
{
float dt = (now - last).Seconds();
last = now;
Device::GetInput()->Flush();
OnUpdate(dt);
UpdateScene(dt);
DrawScene();
while (::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
else
{
// ID2D1HwndRenderTarget 开启了垂直同步,在渲染时会等待显示器刷新,
// 它起到了非常稳定的延时作用,所以大部分时候不需要手动挂起线程进行延时。
// 下面的代码仅在一些情况下(例如窗口最小化时)挂起线程,防止占用过高 CPU 。
int wait = min_interval - dur.Milliseconds();
if (wait > 1)
{
std::this_thread::sleep_for(std::chrono::milliseconds(wait));
}
}
}
}
void Game::Quit()
{
quit_ = true;
}
void Game::EnterScene(Scene * scene, Transition * transition)
{
if (scene == nullptr)
{
E2D_WARNING("Next scene is null pointer!");
return;
}
if (curr_scene_ == scene) { return; }
if (next_scene_)
{
next_scene_->Release();
}
next_scene_ = scene;
next_scene_->Retain();
if (transition)
{
if (transition_)
{
transition_->Stop();
transition_->Release();
}
transition_ = transition;
transition_->Retain();
transition_->Init(curr_scene_, next_scene_, this);
}
}
Scene * Game::GetCurrentScene()
{
return curr_scene_;
}
bool Game::IsTransitioning() const
{
return transition_ != nullptr;
}
void Game::UpdateScene(float dt)
{
auto update = [&](Scene * scene) -> void
{
if (scene)
{
scene->OnUpdate(dt);
Node * root = scene->GetRoot();
if (root)
{
root->UpdateChildren(dt);
}
}
};
update(curr_scene_);
update(next_scene_);
if (transition_)
{
transition_->Update();
if (transition_->IsDone())
{
transition_->Release();
transition_ = nullptr;
}
else
{
return;
}
}
if (next_scene_)
{
if (curr_scene_)
{
curr_scene_->OnExit();
curr_scene_->Release();
}
next_scene_->OnEnter();
curr_scene_ = next_scene_;
next_scene_ = nullptr;
}
}
void Game::DrawScene()
{
auto graphics = Device::GetGraphics();
graphics->BeginDraw();
if (transition_)
{
transition_->Draw();
}
else if (curr_scene_)
{
curr_scene_->Draw();
}
if (debug_mode_)
{
if (curr_scene_ && curr_scene_->GetRoot())
{
graphics->GetRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity());
graphics->GetSolidBrush()->SetOpacity(1.f);
curr_scene_->GetRoot()->DrawBorder();
}
if (next_scene_ && next_scene_->GetRoot())
{
graphics->GetRenderTarget()->SetTransform(D2D1::Matrix3x2F::Identity());
graphics->GetSolidBrush()->SetOpacity(1.f);
next_scene_->GetRoot()->DrawBorder();
}
graphics->DrawDebugInfo();
}
graphics->EndDraw();
}
void Game::Init()
{
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 = Game::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_ != 0)
{
wcex.hIcon = (HICON)::LoadImage(
hinstance,
MAKEINTRESOURCE(icon_),
IMAGE_ICON,
0,
0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE
);
}
// 注册窗口类
::RegisterClassEx(&wcex);
// 计算窗口大小
Rect client_rect = Locate(width_, height_);
// 创建窗口
hwnd_ = ::CreateWindowEx(
NULL,
REGISTER_CLASS,
title_.c_str(),
WINDOW_STYLE,
int(client_rect.origin.x),
int(client_rect.origin.y),
int(client_rect.size.width),
int(client_rect.size.height),
nullptr,
nullptr,
hinstance,
this
);
if (hwnd_ == nullptr)
{
::UnregisterClass(REGISTER_CLASS, hinstance);
throw std::runtime_error("Create window failed");
return;
}
::SetWindowLongPtrW(
hwnd_,
GWLP_USERDATA,
PtrToUlong(this)
);
// 初始化设备
Device::Init(hwnd_);
// 禁用输入法
::ImmAssociateContext(hwnd_, nullptr);
// 若开启了调试模式,打开控制台
HWND console = ::GetConsoleWindow();
// 关闭控制台
if (debug_mode_)
{
if (console)
{
::ShowWindow(console, SW_SHOWNORMAL);
}
else
{
// 显示一个新控制台
if (::AllocConsole())
{
console = ::GetConsoleWindow();
// 重定向输入输出
FILE * stdoutStream, *stdinStream, *stderrStream;
freopen_s(&stdoutStream, "conout$", "w+t", stdout);
freopen_s(&stdinStream, "conin$", "r+t", stdin);
freopen_s(&stderrStream, "conout$", "w+t", stderr);
// 禁用控制台关闭按钮
HMENU hmenu = ::GetSystemMenu(console, FALSE);
::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND);
}
}
}
else
{
if (console)
{
::ShowWindow(console, SW_HIDE);
}
}
quit_ = false;
}
Rect Game::Locate(int width, int height)
{
int max_width = ::GetSystemMetrics(SM_CXSCREEN);
int max_height = ::GetSystemMetrics(SM_CYSCREEN);
float dpi = Graphics::GetDpi();
RECT rect = { 0, 0, LONG(ceil(width * dpi / 96.f)), LONG(ceil(height * dpi / 96.f)) };
// 计算合适的窗口大小
::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)
);
}
int Game::GetWidth() const
{
return width_;
}
int Game::GetHeight() const
{
return height_;
}
Size Game::GetSize() const
{
return Size(
static_cast<float>(width_),
static_cast<float>(height_)
);
}
HWND Game::GetHWnd() const
{
return hwnd_;
}
const std::wstring& Game::GetTitle() const
{
return title_;
}
void Game::SetSize(int width, int height)
{
if (width_ == width && height_ == height)
return;
width_ = width;
height_ = height;
if (hwnd_)
{
Rect rect = Locate(width, height);
::MoveWindow(
hwnd_,
int(rect.origin.x),
int(rect.origin.y),
int(rect.size.width),
int(rect.size.height),
TRUE
);
}
}
void Game::SetTitle(const std::wstring& title)
{
title_ = title;
if (hwnd_)
{
::SetWindowText(hwnd_, title.c_str());
}
}
void Game::SetIcon(int resource_id)
{
icon_ = resource_id;
if (hwnd_)
{
HINSTANCE hinstance = GetModuleHandle(nullptr);
HICON icon = (HICON)::LoadImage(
hinstance,
MAKEINTRESOURCE(resource_id),
IMAGE_ICON,
0,
0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE
);
::SendMessage(hwnd_, WM_SETICON, ICON_BIG, (LPARAM)icon);
::SendMessage(hwnd_, WM_SETICON, ICON_SMALL, (LPARAM)icon);
}
}
void Game::SetDebugMode(bool enabled)
{
debug_mode_ = enabled;
}
LRESULT Game::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);
if (w_param == SIZE_RESTORED)
{
float dpi = Graphics::GetDpi();
game->width_ = static_cast<int>(width * 96.f / dpi);
game->height_ = static_cast<int>(height * 96.f / dpi);
}
// 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染
// 目标的大小。它可能会调用失败,但是这里可以忽略有可能的
// 错误,因为这个错误将在下一次调用 EndDraw 时产生
auto render_target = Device::GetGraphics()->GetRenderTarget();
if (render_target)
{
render_target->Resize(D2D1::SizeU(width, height));
}
}
break;
// 处理窗口标题变化消息
case WM_SETTEXT:
{
game->title_ = (const wchar_t*)l_param;
}
break;
// 处理分辨率变化消息
case WM_DISPLAYCHANGE:
{
// 重绘客户区
::InvalidateRect(hwnd, nullptr, FALSE);
}
result = 0;
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

@ -1,831 +0,0 @@
// 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.
#include "..\e2dmodule.h"
#include "..\e2dobject.h"
namespace easy2d
{
//-------------------------------------------------------
// TextRenderer
//-------------------------------------------------------
class TextRenderer
: public IDWriteTextRenderer
{
public:
static HRESULT Create(
IDWriteTextRenderer** ppTextRenderer,
ID2D1Factory* pD2DFactory,
ID2D1HwndRenderTarget* pRT,
ID2D1SolidColorBrush* pBrush
);
STDMETHOD_(void, SetTextStyle)(
CONST D2D1_COLOR_F &fillColor,
BOOL outline,
CONST D2D1_COLOR_F &outline_color,
FLOAT outline_width,
D2D1_LINE_JOIN outlineJoin
);
STDMETHOD(DrawGlyphRun)(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
DWRITE_MEASURING_MODE measuringMode,
__in DWRITE_GLYPH_RUN const* glyphRun,
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
IUnknown* clientDrawingEffect
);
STDMETHOD(DrawUnderline)(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
__in DWRITE_UNDERLINE const* underline,
IUnknown* clientDrawingEffect
);
STDMETHOD(DrawStrikethrough)(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
__in DWRITE_STRIKETHROUGH const* strikethrough,
IUnknown* clientDrawingEffect
);
STDMETHOD(DrawInlineObject)(
__maybenull void* clientDrawingContext,
FLOAT originX,
FLOAT originY,
IDWriteInlineObject* inlineObject,
BOOL IsSideways,
BOOL IsRightToLeft,
IUnknown* clientDrawingEffect
);
STDMETHOD(IsPixelSnappingDisabled)(
__maybenull void* clientDrawingContext,
__out BOOL* isDisabled
);
STDMETHOD(GetCurrentTransform)(
__maybenull void* clientDrawingContext,
__out DWRITE_MATRIX* transform
);
STDMETHOD(GetPixelsPerDip)(
__maybenull void* clientDrawingContext,
__out FLOAT* pixelsPerDip
);
public:
unsigned long STDMETHODCALLTYPE AddRef();
unsigned long STDMETHODCALLTYPE Release();
HRESULT STDMETHODCALLTYPE QueryInterface(
IID const& riid,
void** ppvObject
);
private:
TextRenderer(
ID2D1Factory* pD2DFactory,
ID2D1HwndRenderTarget* pRT,
ID2D1SolidColorBrush* pBrush
);
~TextRenderer();
private:
unsigned long cRefCount_;
D2D1_COLOR_F sFillColor_;
D2D1_COLOR_F sOutlineColor_;
FLOAT fOutlineWidth;
BOOL bShowOutline_;
ID2D1Factory* pD2DFactory_;
ID2D1HwndRenderTarget* pRT_;
ID2D1SolidColorBrush* pBrush_;
ID2D1StrokeStyle* pCurrStrokeStyle_;
};
TextRenderer::TextRenderer(ID2D1Factory* pD2DFactory, ID2D1HwndRenderTarget* pRT, ID2D1SolidColorBrush* pBrush)
: cRefCount_(0)
, pD2DFactory_(pD2DFactory)
, pRT_(pRT)
, pBrush_(pBrush)
, sFillColor_()
, sOutlineColor_()
, fOutlineWidth(1)
, bShowOutline_(TRUE)
, pCurrStrokeStyle_(nullptr)
{
pD2DFactory->AddRef();
pRT->AddRef();
pBrush->AddRef();
}
TextRenderer::~TextRenderer()
{
SafeRelease(pD2DFactory_);
SafeRelease(pRT_);
SafeRelease(pBrush_);
}
HRESULT TextRenderer::Create(
IDWriteTextRenderer** ppTextRenderer,
ID2D1Factory* pD2DFactory,
ID2D1HwndRenderTarget* pRT,
ID2D1SolidColorBrush* pBrush
)
{
*ppTextRenderer = new (std::nothrow) TextRenderer(pD2DFactory, pRT, pBrush);
if (*ppTextRenderer)
{
(*ppTextRenderer)->AddRef();
return S_OK;
}
return E_FAIL;
}
STDMETHODIMP_(void) TextRenderer::SetTextStyle(
CONST D2D1_COLOR_F &fillColor,
BOOL outline,
CONST D2D1_COLOR_F &outline_color,
FLOAT outline_width,
D2D1_LINE_JOIN outlineJoin
)
{
sFillColor_ = fillColor;
bShowOutline_ = outline;
sOutlineColor_ = outline_color;
fOutlineWidth = 2 * outline_width;
switch (outlineJoin)
{
case D2D1_LINE_JOIN_MITER:
pCurrStrokeStyle_ = Device::GetGraphics()->GetMiterStrokeStyle();
break;
case D2D1_LINE_JOIN_BEVEL:
pCurrStrokeStyle_ = Device::GetGraphics()->GetBevelStrokeStyle();
break;
case D2D1_LINE_JOIN_ROUND:
pCurrStrokeStyle_ = Device::GetGraphics()->GetRoundStrokeStyle();
break;
default:
pCurrStrokeStyle_ = nullptr;
break;
}
}
STDMETHODIMP TextRenderer::DrawGlyphRun(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
DWRITE_MEASURING_MODE measuringMode,
__in DWRITE_GLYPH_RUN const* glyphRun,
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
IUnknown* clientDrawingEffect
)
{
HRESULT hr = S_OK;
ID2D1PathGeometry* pPathGeometry = nullptr;
hr = pD2DFactory_->CreatePathGeometry(
&pPathGeometry
);
ID2D1GeometrySink* pSink = nullptr;
if (SUCCEEDED(hr))
{
hr = pPathGeometry->Open(
&pSink
);
}
if (SUCCEEDED(hr))
{
hr = glyphRun->fontFace->GetGlyphRunOutline(
glyphRun->fontEmSize,
glyphRun->glyphIndices,
glyphRun->glyphAdvances,
glyphRun->glyphOffsets,
glyphRun->glyphCount,
glyphRun->isSideways,
glyphRun->bidiLevel % 2,
pSink
);
}
if (SUCCEEDED(hr))
{
hr = pSink->Close();
}
D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F(
1.0f, 0.0f,
0.0f, 1.0f,
baselineOriginX, baselineOriginY
);
ID2D1TransformedGeometry* pTransformedGeometry = nullptr;
if (SUCCEEDED(hr))
{
hr = pD2DFactory_->CreateTransformedGeometry(
pPathGeometry,
&matrix,
&pTransformedGeometry
);
}
if (SUCCEEDED(hr) && bShowOutline_)
{
pBrush_->SetColor(sOutlineColor_);
pRT_->DrawGeometry(
pTransformedGeometry,
pBrush_,
fOutlineWidth,
pCurrStrokeStyle_
);
}
if (SUCCEEDED(hr))
{
pBrush_->SetColor(sFillColor_);
pRT_->FillGeometry(
pTransformedGeometry,
pBrush_
);
}
SafeRelease(pPathGeometry);
SafeRelease(pSink);
SafeRelease(pTransformedGeometry);
return hr;
}
STDMETHODIMP TextRenderer::DrawUnderline(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
__in DWRITE_UNDERLINE const* underline,
IUnknown* clientDrawingEffect
)
{
HRESULT hr;
D2D1_RECT_F rect = D2D1::RectF(
0,
underline->offset,
underline->width,
underline->offset + underline->thickness
);
ID2D1RectangleGeometry* pRectangleGeometry = nullptr;
hr = pD2DFactory_->CreateRectangleGeometry(
&rect,
&pRectangleGeometry
);
D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F(
1.0f, 0.0f,
0.0f, 1.0f,
baselineOriginX, baselineOriginY
);
ID2D1TransformedGeometry* pTransformedGeometry = nullptr;
if (SUCCEEDED(hr))
{
hr = pD2DFactory_->CreateTransformedGeometry(
pRectangleGeometry,
&matrix,
&pTransformedGeometry
);
}
if (SUCCEEDED(hr) && bShowOutline_)
{
pBrush_->SetColor(sOutlineColor_);
pRT_->DrawGeometry(
pTransformedGeometry,
pBrush_,
fOutlineWidth,
pCurrStrokeStyle_
);
}
if (SUCCEEDED(hr))
{
pBrush_->SetColor(sFillColor_);
pRT_->FillGeometry(
pTransformedGeometry,
pBrush_
);
}
SafeRelease(pRectangleGeometry);
SafeRelease(pTransformedGeometry);
return S_OK;
}
STDMETHODIMP TextRenderer::DrawStrikethrough(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
__in DWRITE_STRIKETHROUGH const* strikethrough,
IUnknown* clientDrawingEffect
)
{
HRESULT hr;
D2D1_RECT_F rect = D2D1::RectF(
0,
strikethrough->offset,
strikethrough->width,
strikethrough->offset + strikethrough->thickness
);
ID2D1RectangleGeometry* pRectangleGeometry = nullptr;
hr = pD2DFactory_->CreateRectangleGeometry(
&rect,
&pRectangleGeometry
);
D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F(
1.0f, 0.0f,
0.0f, 1.0f,
baselineOriginX, baselineOriginY
);
ID2D1TransformedGeometry* pTransformedGeometry = nullptr;
if (SUCCEEDED(hr))
{
hr = pD2DFactory_->CreateTransformedGeometry(
pRectangleGeometry,
&matrix,
&pTransformedGeometry
);
}
if (SUCCEEDED(hr) && bShowOutline_)
{
pBrush_->SetColor(sOutlineColor_);
pRT_->DrawGeometry(
pTransformedGeometry,
pBrush_,
fOutlineWidth,
pCurrStrokeStyle_
);
}
if (SUCCEEDED(hr))
{
pBrush_->SetColor(sFillColor_);
pRT_->FillGeometry(
pTransformedGeometry,
pBrush_
);
}
SafeRelease(pRectangleGeometry);
SafeRelease(pTransformedGeometry);
return S_OK;
}
STDMETHODIMP TextRenderer::DrawInlineObject(
__maybenull void* clientDrawingContext,
FLOAT originX,
FLOAT originY,
IDWriteInlineObject* inlineObject,
BOOL IsSideways,
BOOL IsRightToLeft,
IUnknown* clientDrawingEffect
)
{
return E_NOTIMPL;
}
STDMETHODIMP_(unsigned long) TextRenderer::AddRef()
{
return InterlockedIncrement(&cRefCount_);
}
STDMETHODIMP_(unsigned long) TextRenderer::Release()
{
unsigned long newCount = InterlockedDecrement(&cRefCount_);
if (newCount == 0)
{
delete this;
return 0;
}
return newCount;
}
STDMETHODIMP TextRenderer::IsPixelSnappingDisabled(
__maybenull void* clientDrawingContext,
__out BOOL* isDisabled
)
{
*isDisabled = FALSE;
return S_OK;
}
STDMETHODIMP TextRenderer::GetCurrentTransform(
__maybenull void* clientDrawingContext,
__out DWRITE_MATRIX* transform
)
{
pRT_->GetTransform(reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
return S_OK;
}
STDMETHODIMP TextRenderer::GetPixelsPerDip(
__maybenull void* clientDrawingContext,
__out FLOAT* pixelsPerDip
)
{
float x, yUnused;
pRT_->GetDpi(&x, &yUnused);
*pixelsPerDip = x / 96;
return S_OK;
}
STDMETHODIMP TextRenderer::QueryInterface(
IID const& riid,
void** ppvObject
)
{
if (__uuidof(IDWriteTextRenderer) == riid)
{
*ppvObject = this;
}
else if (__uuidof(IDWritePixelSnapping) == riid)
{
*ppvObject = this;
}
else if (__uuidof(IUnknown) == riid)
{
*ppvObject = this;
}
else
{
*ppvObject = nullptr;
return E_FAIL;
}
AddRef();
return S_OK;
}
//-------------------------------------------------------
// Graphics
//-------------------------------------------------------
Graphics::Graphics(HWND hwnd)
: factory_(nullptr)
, imaging_factory_(nullptr)
, write_factory_(nullptr)
, miter_stroke_style_(nullptr)
, bevel_stroke_style_(nullptr)
, round_stroke_style_(nullptr)
, fps_text_format_(nullptr)
, fps_text_layout_(nullptr)
, render_target_(nullptr)
, solid_brush_(nullptr)
, text_renderer_(nullptr)
, clear_color_(D2D1::ColorF(D2D1::ColorF::Black))
{
ThrowIfFailed(
D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&factory_
)
);
ThrowIfFailed(
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<void**>(&imaging_factory_)
)
);
ThrowIfFailed(
DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&write_factory_)
)
);
RECT rc;
::GetClientRect(hwnd, &rc);
D2D1_SIZE_U size = D2D1::SizeU(
rc.right - rc.left,
rc.bottom - rc.top
);
// 创建设备相关资源。这些资源应在 Direct2D 设备消失时重建
// 创建一个 Direct2D 渲染目标
ThrowIfFailed(
factory_->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
hwnd,
size,
D2D1_PRESENT_OPTIONS_NONE),
&render_target_
)
);
// 创建画刷
ThrowIfFailed(
render_target_->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::White),
&solid_brush_
)
);
// 创建自定义的文字渲染器
ThrowIfFailed(
TextRenderer::Create(
&text_renderer_,
factory_,
render_target_,
solid_brush_
)
);
}
Graphics::~Graphics()
{
SafeRelease(fps_text_format_);
SafeRelease(fps_text_layout_);
SafeRelease(text_renderer_);
SafeRelease(solid_brush_);
SafeRelease(render_target_);
SafeRelease(miter_stroke_style_);
SafeRelease(bevel_stroke_style_);
SafeRelease(round_stroke_style_);
SafeRelease(factory_);
SafeRelease(imaging_factory_);
SafeRelease(write_factory_);
}
void Graphics::BeginDraw()
{
render_target_->BeginDraw();
render_target_->Clear(clear_color_);
}
void Graphics::EndDraw()
{
HRESULT hr = render_target_->EndDraw();
if (hr == D2DERR_RECREATE_TARGET)
{
// 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源
// 并在下一次调用时重建资源
hr = S_OK;
SafeRelease(fps_text_format_);
SafeRelease(fps_text_layout_);
SafeRelease(text_renderer_);
SafeRelease(solid_brush_);
SafeRelease(render_target_);
}
ThrowIfFailed(hr);
}
void Graphics::DrawDebugInfo()
{
static int render_times_ = 0;
static Time last_render_time_ = Time::Now();
int duration = (Time::Now() - last_render_time_).Milliseconds();
if (!fps_text_format_)
{
ThrowIfFailed(
write_factory_->CreateTextFormat(
L"",
nullptr,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
20,
L"",
&fps_text_format_
)
);
ThrowIfFailed(
fps_text_format_->SetWordWrapping(
DWRITE_WORD_WRAPPING_NO_WRAP
)
);
}
++render_times_;
if (duration >= 100)
{
wchar_t fps_text[12] = {};
int len = swprintf_s(fps_text, L"FPS: %.1f", 1000.f / duration * render_times_);
last_render_time_ = Time::Now();
render_times_ = 0;
SafeRelease(fps_text_layout_);
ThrowIfFailed(
write_factory_->CreateTextLayout(
fps_text,
static_cast<UINT32>(len),
fps_text_format_,
0,
0,
&fps_text_layout_
)
);
}
if (fps_text_layout_)
{
render_target_->SetTransform(D2D1::Matrix3x2F::Identity());
solid_brush_->SetOpacity(1.0f);
static_cast<TextRenderer*>(text_renderer_)->SetTextStyle(
D2D1::ColorF(D2D1::ColorF::White),
TRUE,
D2D1::ColorF(D2D1::ColorF::Black, 0.4f),
1.5f,
D2D1_LINE_JOIN_ROUND
);
fps_text_layout_->Draw(
nullptr,
text_renderer_,
10,
0
);
}
}
ID2D1HwndRenderTarget * Graphics::GetRenderTarget() const
{
return render_target_;
}
ID2D1SolidColorBrush * Graphics::GetSolidBrush() const
{
return solid_brush_;
}
IDWriteTextRenderer* Graphics::GetTextRender() const
{
return text_renderer_;
}
ID2D1Factory * Graphics::GetFactory() const
{
return factory_;
}
IWICImagingFactory * Graphics::GetImagingFactory() const
{
return imaging_factory_;
}
IDWriteFactory * Graphics::GetWriteFactory() const
{
return write_factory_;
}
ID2D1StrokeStyle * Graphics::GetMiterStrokeStyle()
{
if (!miter_stroke_style_)
{
ThrowIfFailed(
factory_->CreateStrokeStyle(
D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_LINE_JOIN_MITER,
2.0f,
D2D1_DASH_STYLE_SOLID,
0.0f),
nullptr,
0,
&miter_stroke_style_
)
);
}
return miter_stroke_style_;
}
ID2D1StrokeStyle * Graphics::GetBevelStrokeStyle()
{
if (!bevel_stroke_style_)
{
ThrowIfFailed(
factory_->CreateStrokeStyle(
D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_LINE_JOIN_BEVEL,
2.0f,
D2D1_DASH_STYLE_SOLID,
0.0f),
nullptr,
0,
&bevel_stroke_style_
)
);
}
return bevel_stroke_style_;
}
ID2D1StrokeStyle * Graphics::GetRoundStrokeStyle()
{
if (!round_stroke_style_)
{
ThrowIfFailed(
factory_->CreateStrokeStyle(
D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_LINE_JOIN_ROUND,
2.0f,
D2D1_DASH_STYLE_SOLID,
0.0f),
nullptr,
0,
&round_stroke_style_
)
);
}
return round_stroke_style_;
}
void Graphics::SetTextRendererStyle(const Color & fill_color, bool has_outline, const Color & outline_color, float outline_width, Stroke outline_stroke)
{
static_cast<TextRenderer*>(text_renderer_)->SetTextStyle(
D2D1_COLOR_F(fill_color),
has_outline,
D2D1_COLOR_F(outline_color),
outline_width,
D2D1_LINE_JOIN(outline_stroke)
);
}
float Graphics::GetDpi()
{
static float dpi = -1;
if (dpi < 0)
{
HDC hdc = ::GetDC(0);
dpi = static_cast<float>(::GetDeviceCaps(hdc, LOGPIXELSX));
::ReleaseDC(0, hdc);
}
return dpi;
}
}

View File

@ -1,175 +0,0 @@
// 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.
#include "..\e2dmodule.h"
#include "..\e2dtool.h"
namespace easy2d
{
Input::Input(HWND hwnd)
: direct_input_(nullptr)
, keyboard_device_(nullptr)
, mouse_device_(nullptr)
{
ZeroMemory(key_buffer_, sizeof(key_buffer_));
ZeroMemory(&mouse_state_, sizeof(mouse_state_));
HINSTANCE hinstance = GetModuleHandle(nullptr);
// 初始化接口对象
ThrowIfFailed(
DirectInput8Create(
hinstance,
DIRECTINPUT_VERSION,
IID_IDirectInput8,
(void**)&direct_input_,
nullptr
)
);
// 初始化键盘设备
ThrowIfFailed(
direct_input_->CreateDevice(
GUID_SysKeyboard,
&keyboard_device_,
nullptr
)
);
keyboard_device_->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
keyboard_device_->SetDataFormat(&c_dfDIKeyboard);
keyboard_device_->Acquire();
keyboard_device_->Poll();
// 初始化鼠标设备
ThrowIfFailed(
direct_input_->CreateDevice(
GUID_SysMouse,
&mouse_device_,
nullptr
)
);
mouse_device_->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
mouse_device_->SetDataFormat(&c_dfDIMouse);
mouse_device_->Acquire();
mouse_device_->Poll();
}
Input::~Input()
{
if (keyboard_device_)
keyboard_device_->Unacquire();
if (mouse_device_)
mouse_device_->Unacquire();
SafeRelease(mouse_device_);
SafeRelease(keyboard_device_);
SafeRelease(direct_input_);
}
void Input::Flush()
{
if (keyboard_device_)
{
HRESULT hr = keyboard_device_->Poll();
if (FAILED(hr))
{
hr = keyboard_device_->Acquire();
while (hr == DIERR_INPUTLOST)
hr = keyboard_device_->Acquire();
}
else
{
keyboard_device_->GetDeviceState(
sizeof(key_buffer_),
(void**)&key_buffer_
);
}
}
if (mouse_device_)
{
HRESULT hr = mouse_device_->Poll();
if (FAILED(hr))
{
hr = mouse_device_->Acquire();
while (hr == DIERR_INPUTLOST)
hr = mouse_device_->Acquire();
}
else
{
mouse_device_->GetDeviceState(
sizeof(mouse_state_),
(void**)&mouse_state_
);
}
}
}
bool Input::IsDown(KeyCode key)
{
if (key_buffer_[static_cast<int>(key)] & 0x80)
return true;
return false;
}
bool Input::IsDown(MouseCode code)
{
if (mouse_state_.rgbButtons[static_cast<int>(code)] & 0x80)
return true;
return false;
}
float Input::GetMouseX()
{
return GetMousePos().x;
}
float Input::GetMouseY()
{
return GetMousePos().y;
}
Point Input::GetMousePos()
{
POINT mousePos;
::GetCursorPos(&mousePos);
::ScreenToClient(Game::GetInstance()->GetHWnd(), &mousePos);
float dpi = Graphics::GetDpi();
return Point(mousePos.x * 96.f / dpi, mousePos.y * 96.f / dpi);
}
float Input::GetMouseDeltaX()
{
return (float)mouse_state_.lX;
}
float Input::GetMouseDeltaY()
{
return (float)mouse_state_.lY;
}
float Input::GetMouseDeltaZ()
{
return (float)mouse_state_.lZ;
}
}

View File

@ -1,560 +0,0 @@
// 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.
#include "..\e2dtool.h"
#include "..\e2dmodule.h"
namespace easy2d
{
namespace
{
void OutputDebugStringExW(LPCWSTR pszOutput, ...)
{
va_list args = NULL;
va_start(args, pszOutput);
size_t nLen = _vscwprintf(pszOutput, args) + 1;
wchar_t* psBuffer = new wchar_t[nLen];
_vsnwprintf_s(psBuffer, nLen, nLen, pszOutput, args);
va_end(args);
::OutputDebugStringW(psBuffer);
delete[] psBuffer;
}
inline void TraceError(LPCWSTR output)
{
OutputDebugStringExW(L"[easy2d] Music error: %s failed!\r\n", output);
}
inline void TraceError(LPCWSTR output, HRESULT hr)
{
OutputDebugStringExW(L"[easy2d] Music error: %s (%#X)\r\n", output, hr);
}
}
//-------------------------------------------------------
// Transcoder
//-------------------------------------------------------
class Transcoder
{
WAVEFORMATEX* wave_format_;
public:
Transcoder()
: wave_format_(nullptr)
{
}
~Transcoder()
{
if (wave_format_)
{
::CoTaskMemFree(wave_format_);
wave_format_ = nullptr;
}
}
WAVEFORMATEX* GetWaveFormatEx()
{
return wave_format_;
}
bool LoadMediaFile(LPCWSTR file_path, BYTE** wave_data, UINT32* wave_data_size)
{
HRESULT hr = S_OK;
IMFSourceReader* reader = nullptr;
hr = MFCreateSourceReaderFromURL(
file_path,
nullptr,
&reader
);
if (SUCCEEDED(hr))
{
hr = ReadSource(reader, wave_data, wave_data_size);
}
SafeRelease(reader);
return SUCCEEDED(hr);
}
bool LoadMediaResource(Resource& res, BYTE** wave_data, UINT32* wave_data_size)
{
HRESULT hr = S_OK;
HINSTANCE hinstance = GetModuleHandle(nullptr);
IStream* stream = nullptr;
IMFByteStream* byte_stream = nullptr;
IMFSourceReader* reader = nullptr;
if (!res.Load()) { return false; }
stream = SHCreateMemStream(
static_cast<const BYTE*>(res.GetData()),
static_cast<UINT>(res.GetDataSize())
);
if (stream == nullptr)
{
TraceError(L"SHCreateMemStream");
return false;
}
if (SUCCEEDED(hr))
{
hr = MFCreateMFByteStreamOnStream(stream, &byte_stream);
}
if (SUCCEEDED(hr))
{
hr = MFCreateSourceReaderFromByteStream(
byte_stream,
nullptr,
&reader
);
}
if (SUCCEEDED(hr))
{
hr = ReadSource(reader, wave_data, wave_data_size);
}
SafeRelease(stream);
SafeRelease(byte_stream);
SafeRelease(reader);
return SUCCEEDED(hr);
}
HRESULT ReadSource(IMFSourceReader* reader, BYTE** wave_data, UINT32* wave_data_size)
{
HRESULT hr = S_OK;
DWORD max_stream_size = 0;
IMFMediaType* partial_type = nullptr;
IMFMediaType* uncompressed_type = nullptr;
hr = MFCreateMediaType(&partial_type);
if (SUCCEEDED(hr))
{
hr = partial_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
}
if (SUCCEEDED(hr))
{
hr = partial_type->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
}
// 设置 source reader 的媒体类型,它将使用合适的解码器去解码这个音频
if (SUCCEEDED(hr))
{
hr = reader->SetCurrentMediaType(
MF_SOURCE_READER_FIRST_AUDIO_STREAM,
0,
partial_type
);
}
// 从 IMFMediaType 中获取 WAVEFORMAT 结构
if (SUCCEEDED(hr))
{
hr = reader->GetCurrentMediaType(
MF_SOURCE_READER_FIRST_AUDIO_STREAM,
&uncompressed_type
);
}
// 指定音频流
if (SUCCEEDED(hr))
{
hr = reader->SetStreamSelection(
MF_SOURCE_READER_FIRST_AUDIO_STREAM,
true
);
}
// 获取 WAVEFORMAT 数据
if (SUCCEEDED(hr))
{
UINT32 size = 0;
hr = MFCreateWaveFormatExFromMFMediaType(
uncompressed_type,
&wave_format_,
&size
);
}
// 估算音频流大小
if (SUCCEEDED(hr))
{
PROPVARIANT prop;
PropVariantInit(&prop);
hr = reader->GetPresentationAttribute(
MF_SOURCE_READER_MEDIASOURCE,
MF_PD_DURATION,
&prop
);
LONGLONG duration = prop.uhVal.QuadPart;
max_stream_size = static_cast<DWORD>(
(duration * wave_format_->nAvgBytesPerSec) / 10000000 + 1
);
PropVariantClear(&prop);
}
// 读取音频数据
if (SUCCEEDED(hr))
{
DWORD flags = 0;
DWORD position = 0;
IMFSample* sample = nullptr;
IMFMediaBuffer* buffer = nullptr;
BYTE* data = new (std::nothrow) BYTE[max_stream_size];
if (data == nullptr)
{
TraceError(L"Low memory");
hr = E_OUTOFMEMORY;
}
else
{
while (true)
{
hr = reader->ReadSample(
MF_SOURCE_READER_FIRST_AUDIO_STREAM,
0,
nullptr,
&flags,
nullptr,
&sample
);
if (flags & MF_SOURCE_READERF_ENDOFSTREAM) { break; }
if (sample == nullptr) { continue; }
if (SUCCEEDED(hr))
{
hr = sample->ConvertToContiguousBuffer(&buffer);
if (SUCCEEDED(hr))
{
BYTE *audio_data = nullptr;
DWORD sample_buffer_length = 0;
hr = buffer->Lock(
&audio_data,
nullptr,
&sample_buffer_length
);
if (SUCCEEDED(hr))
{
for (DWORD i = 0; i < sample_buffer_length; i++)
{
data[position++] = audio_data[i];
}
hr = buffer->Unlock();
}
}
SafeRelease(buffer);
}
SafeRelease(sample);
if (FAILED(hr)) { break; }
}
if (SUCCEEDED(hr))
{
*wave_data = data;
*wave_data_size = position;
}
}
}
SafeRelease(partial_type);
SafeRelease(uncompressed_type);
return hr;
}
};
//-------------------------------------------------------
// Music
//-------------------------------------------------------
Music::Music()
: opened_(false)
, playing_(false)
, wave_data_(nullptr)
, size_(0)
, voice_(nullptr)
{
}
Music::Music(const std::wstring& file_path)
: opened_(false)
, playing_(false)
, wave_data_(nullptr)
, size_(0)
, voice_(nullptr)
{
Load(file_path);
}
Music::Music(Resource& res)
: opened_(false)
, playing_(false)
, wave_data_(nullptr)
, size_(0)
, voice_(nullptr)
{
Load(res);
}
Music::~Music()
{
Close();
}
bool Music::Load(const std::wstring & file_path)
{
if (opened_)
{
Close();
}
File music_file;
if (!music_file.Open(file_path))
{
E2D_WARNING("Media file not found.");
return false;
}
// 用户输入的路径不一定是完整路径,因为用户可能通过 File::AddSearchPath 添加
// 默认搜索路径,所以需要通过 File::GetPath 获取完整路径
std::wstring music_file_path = music_file.GetPath();
Transcoder transcoder;
if (!transcoder.LoadMediaFile(music_file_path.c_str(), &wave_data_, &size_))
{
return false;
}
HRESULT hr = Device::GetAudio()->CreateVoice(&voice_, transcoder.GetWaveFormatEx());
if (FAILED(hr))
{
if (wave_data_)
{
delete[] wave_data_;
wave_data_ = nullptr;
}
TraceError(L"Create source voice error", hr);
return false;
}
opened_ = true;
return true;
}
bool Music::Load(Resource& res)
{
if (opened_)
{
Close();
}
Transcoder transcoder;
if (!transcoder.LoadMediaResource(res, &wave_data_, &size_))
{
return false;
}
HRESULT hr = Device::GetAudio()->CreateVoice(&voice_, transcoder.GetWaveFormatEx());
if (FAILED(hr))
{
if (wave_data_)
{
delete[] wave_data_;
wave_data_ = nullptr;
}
TraceError(L"Create source voice error", hr);
return false;
}
opened_ = true;
return true;
}
bool Music::Play(int loop_count)
{
if (!opened_)
{
E2D_WARNING("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)
{
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)))
{
TraceError(L"Submitting source buffer error", hr);
return false;
}
hr = voice_->Start(0);
playing_ = SUCCEEDED(hr);
return playing_;
}
void Music::Pause()
{
if (voice_)
{
if (SUCCEEDED(voice_->Stop()))
{
playing_ = false;
}
}
}
void Music::Resume()
{
if (voice_)
{
if (SUCCEEDED(voice_->Start()))
{
playing_ = true;
}
}
}
void Music::Stop()
{
if (voice_)
{
if (SUCCEEDED(voice_->Stop()))
{
voice_->ExitLoop();
voice_->FlushSourceBuffers();
playing_ = false;
}
}
}
void Music::Close()
{
if (voice_)
{
voice_->Stop();
voice_->FlushSourceBuffers();
voice_->DestroyVoice();
voice_ = nullptr;
}
if (wave_data_)
{
delete[] wave_data_;
wave_data_ = nullptr;
}
opened_ = false;
playing_ = false;
}
bool Music::IsPlaying() const
{
if (opened_ && voice_)
{
XAUDIO2_VOICE_STATE state;
voice_->GetState(&state);
if (state.BuffersQueued && playing_)
return true;
}
return false;
}
float Music::GetVolume() const
{
if (voice_)
{
float volume = 0.f;
voice_->GetVolume(&volume);
return volume;
}
return 0.f;
}
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_;
}
}

View File

@ -1,111 +0,0 @@
// 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.
#include "..\e2dtransition.h"
#include "..\e2dobject.h"
namespace easy2d
{
MoveTransition::MoveTransition(float duration, Direction direction)
: Transition(duration)
, direction_(direction)
{
}
void MoveTransition::Init(Scene * prev, Scene * next, Game * game)
{
Transition::Init(prev, next, game);
switch (direction_)
{
case Direction::Up:
pos_delta_ = Point(0, -window_size_.height);
start_pos_ = Point(0, window_size_.height);
break;
case Direction::Down:
pos_delta_ = Point(0, window_size_.height);
start_pos_ = Point(0, -window_size_.height);
break;
case Direction::Left:
pos_delta_ = Point(-window_size_.width, 0);
start_pos_ = Point(window_size_.width, 0);
break;
case Direction::Right:
pos_delta_ = Point(window_size_.width, 0);
start_pos_ = Point(-window_size_.width, 0);
break;
}
if (out_scene_)
{
out_scene_->SetTransform(D2D1::Matrix3x2F::Identity());
}
if (in_scene_)
{
in_scene_->SetTransform(
D2D1::Matrix3x2F::Translation(
start_pos_.x,
start_pos_.y
)
);
}
}
void MoveTransition::Update()
{
Transition::Update();
if (out_scene_)
{
auto translation = pos_delta_ * process_;
out_scene_->SetTransform(
D2D1::Matrix3x2F::Translation(
translation.x,
translation.y
)
);
}
if (in_scene_)
{
auto translation = start_pos_ + pos_delta_ * process_;
in_scene_->SetTransform(
D2D1::Matrix3x2F::Translation(
translation.x,
translation.y
)
);
}
}
void MoveTransition::Reset()
{
if (out_scene_)
{
out_scene_->SetTransform(D2D1::Matrix3x2F::Identity());
}
if (in_scene_)
{
in_scene_->SetTransform(D2D1::Matrix3x2F::Identity());
}
}
}

View File

@ -1,107 +0,0 @@
// 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.
#include "..\e2dtransition.h"
#include "..\e2dobject.h"
namespace easy2d
{
RotationTransition::RotationTransition(float duration, float rotation)
: Transition(duration)
, rotation_(rotation)
{
}
void RotationTransition::Init(Scene * prev, Scene * next, Game * game)
{
Transition::Init(prev, next, game);
if (out_scene_)
{
out_scene_->SetTransform(D2D1::Matrix3x2F::Identity());
}
if (in_scene_)
{
in_scene_->SetTransform(D2D1::Matrix3x2F::Identity());
}
in_layer_param_.opacity = 0;
}
void RotationTransition::Update()
{
Transition::Update();
auto center_pos = D2D1::Point2F(
window_size_.width / 2,
window_size_.height / 2
);
if (process_ < .5f)
{
if (out_scene_)
{
out_scene_->SetTransform(
D2D1::Matrix3x2F::Scale(
(.5f - process_) * 2,
(.5f - process_) * 2,
center_pos
) * D2D1::Matrix3x2F::Rotation(
rotation_ * (.5f - process_) * 2,
center_pos
)
);
}
}
else
{
if (in_scene_)
{
out_layer_param_.opacity = 0;
in_layer_param_.opacity = 1;
in_scene_->SetTransform(
D2D1::Matrix3x2F::Scale(
(process_ - .5f) * 2,
(process_ - .5f) * 2,
center_pos
) * D2D1::Matrix3x2F::Rotation(
rotation_ * (process_ - .5f) * 2,
center_pos
)
);
}
}
}
void RotationTransition::Reset()
{
if (out_scene_)
{
out_scene_->SetTransform(D2D1::Matrix3x2F::Identity());
}
if (in_scene_)
{
in_scene_->SetTransform(D2D1::Matrix3x2F::Identity());
}
}
}

View File

@ -1,167 +0,0 @@
// 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.
#include "..\e2dtransition.h"
#include "..\e2dobject.h"
#include "..\e2dmodule.h"
namespace easy2d
{
Transition::Transition(float duration)
: done_(false)
, started_()
, process_(0)
, window_size_()
, out_scene_(nullptr)
, in_scene_(nullptr)
, out_layer_(nullptr)
, in_layer_(nullptr)
, out_layer_param_()
, in_layer_param_()
{
duration_ = std::max(duration, 0.f);
}
Transition::~Transition()
{
SafeRelease(out_layer_);
SafeRelease(in_layer_);
SafeRelease(out_scene_);
SafeRelease(in_scene_);
}
bool Transition::IsDone()
{
return done_;
}
void Transition::Init(Scene * prev, Scene * next, Game * game)
{
started_ = Time::Now();
out_scene_ = prev;
in_scene_ = next;
if (out_scene_)
out_scene_->Retain();
if (in_scene_)
in_scene_->Retain();
auto graphics = Device::GetGraphics();
if (in_scene_)
{
ThrowIfFailed(
graphics->GetRenderTarget()->CreateLayer(&in_layer_)
);
}
if (out_scene_)
{
ThrowIfFailed(
graphics->GetRenderTarget()->CreateLayer(&out_layer_)
);
}
window_size_ = game->GetSize();
out_layer_param_ = in_layer_param_ = D2D1::LayerParameters(
D2D1::RectF(
0.f,
0.f,
window_size_.width,
window_size_.height
),
nullptr,
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
D2D1::Matrix3x2F::Identity(),
1.f,
graphics->GetSolidBrush(),
D2D1_LAYER_OPTIONS_NONE
);
}
void Transition::Update()
{
if (duration_ == 0)
{
process_ = 1;
}
else
{
process_ = (Time::Now() - started_).Seconds() / duration_;
process_ = std::min(process_, 1.f);
}
if (process_ >= 1)
{
this->Stop();
}
}
void Transition::Draw()
{
auto render_target = Device::GetGraphics()->GetRenderTarget();
if (out_scene_)
{
render_target->SetTransform(out_scene_->GetTransform());
render_target->PushAxisAlignedClip(
D2D1::RectF(
0.f,
0.f,
window_size_.width,
window_size_.height
),
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
);
render_target->PushLayer(out_layer_param_, out_layer_);
out_scene_->Draw();
render_target->PopLayer();
render_target->PopAxisAlignedClip();
}
if (in_scene_)
{
render_target->SetTransform(in_scene_->GetTransform());
render_target->PushAxisAlignedClip(
D2D1::RectF(
0.f,
0.f,
window_size_.width,
window_size_.height
),
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
);
render_target->PushLayer(in_layer_param_, in_layer_);
in_scene_->Draw();
render_target->PopLayer();
render_target->PopAxisAlignedClip();
}
}
void Transition::Stop()
{
done_ = true;
Reset();
}
}

288
core/ui/Button.cpp Normal file
View File

@ -0,0 +1,288 @@
// 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.
#include "Button.h"
#include "../base/input.h"
#define SAFE_SET(pointer, func, ...) if (pointer) { pointer->##func(__VA_ARGS__); }
#define SET_BUTTON_NODE(Old, New) \
if (New != Old) \
{ \
if (Old) this->RemoveChild(Old); \
if (New) \
{ \
New->SetPivot(GetPivotX(), GetPivotY()); \
this->AddChild(New); \
} \
Old = New; \
UpdateVisible(); \
} \
namespace easy2d
{
namespace ui
{
Button::Button()
: callback_(nullptr)
, status_(Status::Normal)
, enabled_(true)
, is_selected_(false)
, normal_(nullptr)
, mouseover_(nullptr)
, selected_(nullptr)
, disabled_(nullptr)
{
}
Button::Button(Node * normal, const Callback& func)
: callback_(nullptr)
, status_(Status::Normal)
, enabled_(true)
, is_selected_(false)
, normal_(nullptr)
, mouseover_(nullptr)
, selected_(nullptr)
, disabled_(nullptr)
{
this->SetNormal(normal);
this->SetCallbackOnClick(func);
}
Button::Button(Node * normal, Node * selected, const Callback& func)
: callback_(nullptr)
, status_(Status::Normal)
, enabled_(true)
, is_selected_(false)
, normal_(nullptr)
, mouseover_(nullptr)
, selected_(nullptr)
, disabled_(nullptr)
{
this->SetNormal(normal);
this->SetSelected(selected);
this->SetCallbackOnClick(func);
}
Button::Button(Node * normal, Node * mouseover, Node * selected, const Callback& func)
: callback_(nullptr)
, status_(Status::Normal)
, enabled_(true)
, is_selected_(false)
, normal_(nullptr)
, mouseover_(nullptr)
, selected_(nullptr)
, disabled_(nullptr)
{
this->SetNormal(normal);
this->SetMouseOver(mouseover);
this->SetSelected(selected);
this->SetCallbackOnClick(func);
}
Button::Button(Node * normal, Node * mouseover, Node * selected, Node * disabled, const Callback& func)
: callback_(nullptr)
, status_(Status::Normal)
, enabled_(true)
, is_selected_(false)
, normal_(nullptr)
, mouseover_(nullptr)
, selected_(nullptr)
, disabled_(nullptr)
{
this->SetNormal(normal);
this->SetMouseOver(mouseover);
this->SetSelected(selected);
this->SetDisabled(disabled);
this->SetCallbackOnClick(func);
}
bool Button::IsEnable() const
{
return enabled_;
}
void Button::SetNormal(Node * normal)
{
SET_BUTTON_NODE(normal_, normal);
if (normal)
{
this->SetSize(normal->GetWidth(), normal->GetHeight());
}
}
void Button::SetMouseOver(Node * mouseover)
{
SET_BUTTON_NODE(mouseover_, mouseover);
}
void Button::SetSelected(Node * selected)
{
SET_BUTTON_NODE(selected_, selected);
}
void Button::SetDisabled(Node * disabled)
{
SET_BUTTON_NODE(disabled_, disabled);
}
void Button::SetEnabled(bool enabled)
{
if (enabled_ != enabled)
{
enabled_ = enabled;
UpdateVisible();
}
}
void Button::SetCallbackOnClick(const Callback& func)
{
callback_ = func;
}
void Button::SetPivot(float pivot_x, float pivot_y)
{
Node::SetPivot(pivot_x, pivot_y);
SAFE_SET(normal_, SetPivot, pivot_x, pivot_y);
SAFE_SET(mouseover_, SetPivot, pivot_x, pivot_y);
SAFE_SET(selected_, SetPivot, pivot_x, pivot_y);
SAFE_SET(disabled_, SetPivot, pivot_x, pivot_y);
}
bool Button::Dispatch(const MouseEvent & e, bool handled)
{
if (!handled && enabled_ && IsVisible() && normal_)
{
bool contains = normal_->ContainsPoint(e.GetPosition());
if (e.GetType() == MouseEvent::Type::LeftUp && is_selected_ && contains)
{
if (callback_)
{
callback_();
}
is_selected_ = false;
SetStatus(Status::Normal);
return true;
}
else if (e.GetType() == MouseEvent::Type::LeftDown)
{
is_selected_ = contains;
SetStatus(contains ? Status::Selected : Status::Normal);
if (contains)
return true;
}
else if (e.GetType() == MouseEvent::Type::LeftUp)
{
is_selected_ = false;
}
else if (e.GetType() == MouseEvent::Type::MoveBy && is_selected_ && contains)
{
SetStatus(Status::Selected);
return true;
}
else
{
if (!e.IsLButtonDown() && is_selected_)
{
is_selected_ = false;
}
SetStatus(contains ? Status::Mouseover : Status::Normal);
if (contains)
return true;
}
}
return Node::Dispatch(e, handled);
}
void Button::Visit()
{
Node::Visit();
if (IsVisible() &&
!enabled_ &&
normal_ &&
normal_->ContainsPoint(input::instance.GetMousePos()))
{
HCURSOR hcursor = ::LoadCursor(nullptr, IDC_NO);
if (hcursor)
{
::SetCursor(hcursor);
}
}
else if (status_ == Status::Mouseover || status_ == Status::Selected)
{
HCURSOR hcursor = ::LoadCursor(nullptr, IDC_HAND);
if (hcursor)
{
::SetCursor(hcursor);
}
}
}
void Button::SetStatus(Status status)
{
if (status_ != status)
{
status_ = status;
UpdateVisible();
}
}
void Button::UpdateVisible()
{
SAFE_SET(normal_, SetVisible, false);
SAFE_SET(mouseover_, SetVisible, false);
SAFE_SET(selected_, SetVisible, false);
SAFE_SET(disabled_, SetVisible, false);
if (enabled_)
{
if (status_ == Status::Selected && selected_)
{
selected_->SetVisible(true);
}
else if (status_ == Status::Mouseover && mouseover_)
{
mouseover_->SetVisible(true);
}
else
{
if (normal_) normal_->SetVisible(true);
}
}
else
{
if (disabled_)
{
disabled_->SetVisible(true);
}
else
{
if (normal_) normal_->SetVisible(true);
}
}
}
}
}

137
core/ui/Button.h Normal file
View File

@ -0,0 +1,137 @@
// 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 "../base/Node.h"
#include <functional>
namespace easy2d
{
namespace ui
{
class Button
: public Node
{
typedef std::function<void()> Callback;
public:
Button();
explicit Button(
Node * normal, /* 普通状态 */
const Callback& func = nullptr /* 按钮点击后的回调函数 */
);
explicit Button(
Node * normal, /* 普通状态 */
Node * selected, /* 鼠标按下状态 */
const Callback& func = nullptr /* 按钮点击后的回调函数 */
);
explicit Button(
Node * normal, /* 普通状态 */
Node * mouseover, /* 鼠标移入状态 */
Node * selected, /* 鼠标按下状态 */
const Callback& func = nullptr /* 按钮点击后的回调函数 */
);
explicit Button(
Node * normal, /* 普通状态 */
Node * mouseover, /* 鼠标移入状态 */
Node * selected, /* 鼠标移入状态 */
Node * disabled, /* 按钮禁用状态 */
const Callback& func = nullptr /* 按钮点击后的回调函数 */
);
// 获取按钮状态是启用还是禁用
bool IsEnable() const;
// 设置按钮启用或禁用
void SetEnabled(
bool enabled
);
// 设置一般情况下显示的按钮
virtual void SetNormal(
Node * normal
);
// 设置鼠标移入按钮时显示的按钮
virtual void SetMouseOver(
Node * mouseover
);
// 设置鼠标按下按钮时显示的按钮
virtual void SetSelected(
Node * selected
);
// 设置按钮被禁用时显示的按钮
virtual void SetDisabled(
Node * disabled
);
// 设置按钮点击后的回调函数
void SetCallbackOnClick(
const Callback& func
);
// 设置支点位置
// 默认为 (0, 0), 范围 [0, 1]
virtual void SetPivot(
float pivot_x,
float pivot_y
) override;
private:
E2D_DISABLE_COPY(Button);
// 按钮状态枚举
enum class Status { Normal, Mouseover, Selected };
// 设置按钮状态
virtual void SetStatus(
Status status
);
// 刷新按钮显示
virtual void UpdateVisible();
// 分发鼠标消息
virtual bool Dispatch(
const MouseEvent& e,
bool handled
) override;
// 遍历节点
virtual void Visit() override;
private:
Node * normal_;
Node * mouseover_;
Node * selected_;
Node * disabled_;
bool enabled_;
bool is_selected_;
Status status_;
Callback callback_;
};
}
}

View File

@ -18,83 +18,85 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dcomponent.h"
#include "Menu.h"
namespace easy2d
{
Menu::Menu()
: enabled_(true)
namespace ui
{
}
Menu::Menu(const std::vector<Button*>& buttons)
: enabled_(true)
{
for (const auto& button : buttons)
Menu::Menu()
: enabled_(true)
{
this->AddButton(button);
}
}
bool Menu::IsEnable() const
{
return enabled_;
}
size_t Menu::GetButtonCount() const
{
return buttons_.size();
}
void Menu::SetEnabled(bool enabled)
{
if (enabled_ != enabled)
Menu::Menu(const std::vector<Button*>& buttons)
: enabled_(true)
{
enabled_ = enabled;
for (const auto& button : buttons_)
for (const auto& button : buttons)
{
button->SetEnabled(enabled);
this->AddButton(button);
}
}
}
void Menu::AddButton(Button * button)
{
if (button)
bool Menu::IsEnable() const
{
this->AddChild(button);
buttons_.push_back(button);
button->SetEnabled(enabled_);
return enabled_;
}
}
bool Menu::RemoveButton(Button * button)
{
if (buttons_.empty())
size_t Menu::GetButtonCount() const
{
return buttons_.size();
}
void Menu::SetEnabled(bool enabled)
{
if (enabled_ != enabled)
{
enabled_ = enabled;
for (const auto& button : buttons_)
{
button->SetEnabled(enabled);
}
}
}
void Menu::AddButton(Button * button)
{
if (button)
{
this->AddChild(button);
buttons_.push_back(button);
button->SetEnabled(enabled_);
}
}
bool Menu::RemoveButton(Button * button)
{
if (buttons_.empty())
{
return false;
}
this->RemoveChild(button);
if (button)
{
auto iter = std::find(buttons_.begin(), buttons_.end(), button);
if (iter != buttons_.end())
{
// ÒÆ³ý°´Å¥Ç°£¬½«ËüÆôÓÃ
button->SetEnabled(true);
buttons_.erase(iter);
return true;
}
}
return false;
}
this->RemoveChild(button);
if (button)
const std::vector<Button*>& Menu::GetAllButtons() const
{
auto iter = std::find(buttons_.begin(), buttons_.end(), button);
if (iter != buttons_.end())
{
// ÒÆ³ý°´Å¥Ç°£¬½«ËüÆôÓÃ
button->SetEnabled(true);
buttons_.erase(iter);
return true;
}
return buttons_;
}
return false;
}
const std::vector<Button*>& Menu::GetAllButtons() const
{
return buttons_;
}
}

72
core/ui/Menu.h Normal file
View File

@ -0,0 +1,72 @@
// 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 "../base/Node.h"
#include "Button.h"
namespace easy2d
{
namespace ui
{
// 菜单
class Menu
: public Node
{
public:
Menu();
explicit Menu(
const std::vector<Button*>& buttons /* 按钮数组 */
);
// 获取菜单是否禁用
bool IsEnable() const;
// 获取菜单中的按钮数量
size_t GetButtonCount() const;
// 设置菜单启用或禁用
void SetEnabled(
bool enabled
);
// 添加按钮
void AddButton(
Button * button
);
// 移除按钮
bool RemoveButton(
Button * button
);
// 获取所有按钮
const std::vector<Button*>& GetAllButtons() const;
private:
E2D_DISABLE_COPY(Menu);
private:
bool enabled_;
std::vector<Button*> buttons_;
};
}
}

View File

@ -18,12 +18,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dtool.h"
#include "Data.h"
#include "Path.h"
namespace easy2d
{
Data::Data(const std::wstring & key, const std::wstring & field)
Data::Data(const String & key, const String & field)
: key_(key)
, field_(field)
, data_path_(Path::GetDataPath())
@ -88,7 +88,7 @@ namespace easy2d
return ret == TRUE;
}
bool Data::SaveString(const std::wstring& value)
bool Data::SaveString(const String& value)
{
BOOL ret = ::WritePrivateProfileStringW(
field_.c_str(),
@ -133,7 +133,7 @@ namespace easy2d
return nValue == TRUE;
}
std::wstring Data::GetString()
String Data::GetString()
{
wchar_t temp[256] = { 0 };
::GetPrivateProfileStringW(

View File

@ -18,52 +18,66 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2daction.h"
#include "..\e2dobject.h"
#pragma once
#include "../base/base.h"
namespace easy2d
{
MoveBy::MoveBy(float duration, Point vector)
: FiniteTimeAction(duration)
// 数据管理工具
class Data
{
delta_pos_ = vector;
}
public:
Data(
const String& key, /* 键值 */
const String& field = L"Defalut" /* 字段名称 */
);
void MoveBy::Init()
{
FiniteTimeAction::Init();
// 该数据是否存在
bool Exists() const;
if (target_)
{
prev_pos_ = start_pos_ = target_->GetPosition();
}
}
// 保存 int 类型的值
bool SaveInt(
int value
);
void MoveBy::Update()
{
FiniteTimeAction::Update();
// 保存 float 类型的值
bool SaveFloat(
float value
);
if (target_)
{
Point currentPos = target_->GetPosition();
Point diff = currentPos - prev_pos_;
start_pos_ = start_pos_ + diff;
// 保存 double 类型的值
bool SaveDouble(
double value
);
Point newPos = start_pos_ + (delta_pos_ * delta_);
target_->SetPosition(newPos);
// 保存 bool 类型的值
bool SaveBool(
bool value
);
prev_pos_ = newPos;
}
}
// 保存 String 类型的值
bool SaveString(
const String& value
);
MoveBy * MoveBy::Clone() const
{
return new MoveBy(duration_, delta_pos_);
}
// 获取 int 类型的值
int GetInt() const;
MoveBy * MoveBy::Reverse() const
{
return new MoveBy(duration_, -delta_pos_);
}
}
// 获取 float 类型的值
float GetFloat() const;
// 获取 double 类型的值
double GetDouble() const;
// 获取 bool 类型的值
bool GetBool() const;
// 获取 字符串 类型的值
String GetString();
protected:
String key_;
String field_;
const String& data_path_;
};
}

View File

@ -1,309 +0,0 @@
// 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.
#include "..\e2dutil.h"
#include <regex>
namespace easy2d
{
const Duration Duration::Millisecond = Duration(1);
const Duration Duration::Second = 1000 * Duration::Millisecond;
const Duration Duration::Minute = 60 * Duration::Second;
const Duration Duration::Hour = 60 * Duration::Minute;
namespace
{
const auto duration_regex = std::wregex(L"[-+]?([0-9]*(\\.[0-9]*)?[a-z]+)+");
typedef std::map<std::wstring, Duration> UnitMap;
const auto unit_map = UnitMap{
{L"ms", Duration::Millisecond},
{L"s", Duration::Second},
{L"m", Duration::Minute},
{L"h", Duration::Hour}
};
}
Duration::Duration()
: milliseconds_(0)
{
}
Duration::Duration(int milliseconds)
: milliseconds_(milliseconds)
{
}
int Duration::Milliseconds() const
{
return milliseconds_;
}
float Duration::Seconds() const
{
int64_t sec = milliseconds_ / Second.milliseconds_;
int64_t ms = milliseconds_ % Second.milliseconds_;
return static_cast<float>(sec) + static_cast<float>(ms) / 1000.f;
}
float Duration::Minutes() const
{
int64_t min = milliseconds_ / Minute.milliseconds_;
int64_t ms = milliseconds_ % Minute.milliseconds_;
return static_cast<float>(min) + static_cast<float>(ms) / (60 * 1000.f);
}
float Duration::Hours() const
{
int64_t hour = milliseconds_ / Hour.milliseconds_;
int64_t ms = milliseconds_ % Hour.milliseconds_;
return static_cast<float>(hour) + static_cast<float>(ms) / (60 * 60 * 1000.f);
}
Duration Duration::Parse(const std::wstring & str)
{
size_t len = str.length();
size_t pos = 0;
bool negative = false;
Duration d;
if (!std::regex_match(str, duration_regex))
{
E2D_WARNING("Duration::Parse: invalid duration");
return d;
}
if (str.empty() || str == L"0") { return d; }
// ·ûºÅλ
if (str[0] == L'-' || str[0] == L'+')
{
negative = (str[0] == L'-');
pos++;
}
while (pos < len)
{
// ÊýÖµ
size_t i = pos;
for (; i < len; ++i)
{
wchar_t ch = str[i];
if (!(ch == L'.' || L'0' <= ch && ch <= L'9'))
{
break;
}
}
std::wstring num_str = str.substr(pos, i - pos);
pos = i;
if (num_str.empty() || num_str == L".")
{
E2D_WARNING("Duration::Parse: invalid duration");
return Duration();
}
// µ¥Î»
for (; i < len; ++i)
{
wchar_t ch = str[i];
if (ch == L'.' || L'0' <= ch && ch <= L'9')
{
break;
}
}
std::wstring unit_str = str.substr(pos, i - pos);
pos = i;
if (unit_map.find(unit_str) == unit_map.end())
{
E2D_WARNING("Duration::Parse: invalid duration");
return Duration();
}
double num = std::stod(num_str);
Duration unit = unit_map.at(unit_str);
d += unit * num;
}
if (negative)
{
d.milliseconds_ = -d.milliseconds_;
}
return d;
}
bool Duration::operator==(const Duration & other) const
{
return milliseconds_ == other.milliseconds_;
}
bool Duration::operator!=(const Duration & other) const
{
return milliseconds_ != other.milliseconds_;
}
bool Duration::operator>(const Duration & other) const
{
return milliseconds_ > other.milliseconds_;
}
bool Duration::operator>=(const Duration & other) const
{
return milliseconds_ >= other.milliseconds_;
}
bool Duration::operator<(const Duration & other) const
{
return milliseconds_ < other.milliseconds_;
}
bool Duration::operator<=(const Duration & other) const
{
return milliseconds_ <= other.milliseconds_;
}
Duration Duration::operator+(const Duration & other) const
{
return Duration(milliseconds_ + other.milliseconds_);
}
Duration Duration::operator-(const Duration & other) const
{
return Duration(milliseconds_ - other.milliseconds_);
}
Duration Duration::operator-() const
{
return Duration(-milliseconds_);
}
Duration Duration::operator*(int value) const
{
return Duration(milliseconds_ * value);
}
Duration Duration::operator/(int value) const
{
return Duration(milliseconds_ / value);
}
Duration Duration::operator*(float value) const
{
return Duration(static_cast<int>(milliseconds_ * value));
}
Duration Duration::operator/(float value) const
{
return Duration(static_cast<int>(milliseconds_ / value));
}
Duration Duration::operator*(double value) const
{
return Duration(static_cast<int>(milliseconds_ * value));
}
Duration Duration::operator/(double value) const
{
return Duration(static_cast<int>(milliseconds_ / value));
}
Duration & Duration::operator+=(const Duration &other)
{
milliseconds_ += other.milliseconds_;
return (*this);
}
Duration & Duration::operator-=(const Duration &other)
{
milliseconds_ -= other.milliseconds_;
return (*this);
}
Duration & Duration::operator*=(int value)
{
milliseconds_ *= value;
return (*this);
}
Duration & Duration::operator/=(int value)
{
milliseconds_ /= value;
return (*this);
}
Duration & Duration::operator*=(float value)
{
milliseconds_ = static_cast<int>(milliseconds_ * value);
return (*this);
}
Duration & Duration::operator/=(float value)
{
milliseconds_ = static_cast<int>(milliseconds_ / value);
return (*this);
}
Duration & Duration::operator*=(double value)
{
milliseconds_ = static_cast<int>(milliseconds_ * value);
return (*this);
}
Duration & Duration::operator/=(double value)
{
milliseconds_ = static_cast<int>(milliseconds_ / value);
return (*this);
}
Duration operator*(int value, const Duration & dur)
{
return dur * value;
}
Duration operator/(int value, const Duration & dur)
{
return dur / value;
}
Duration operator*(float value, const Duration & dur)
{
return dur * value;
}
Duration operator/(float value, const Duration & dur)
{
return dur / value;
}
Duration operator*(double value, const Duration & dur)
{
return dur * value;
}
Duration operator/(double value, const Duration & dur)
{
return dur / value;
}
}

View File

@ -18,21 +18,23 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dtool.h"
#include "..\e2dmodule.h"
#include "File.h"
#include <cwctype>
#include <shobjidl.h>
#include <shobjidl.h>
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
namespace easy2d
{
std::list<std::wstring> File::search_paths_;
std::list<String> File::search_paths_;
File::File()
: file_path_()
{
}
File::File(const std::wstring & file_name)
File::File(const String & file_name)
: file_path_(file_name)
{
this->Open(file_name);
@ -42,12 +44,12 @@ namespace easy2d
{
}
bool File::Open(const std::wstring & file_name)
bool File::Open(const String & file_name)
{
if (file_name.empty())
return false;
auto FindFile = [](const std::wstring & path) -> bool
auto FindFile = [](const String & path) -> bool
{
if (::PathFileExists(path.c_str()))
return true;
@ -78,18 +80,18 @@ namespace easy2d
return false;
}
const std::wstring& File::GetPath() const
const String& File::GetPath() const
{
return file_path_;
}
std::wstring File::GetExtension() const
String File::GetExtension() const
{
std::wstring file_ext;
String file_ext;
// 找到文件名中的最后一个 '.' 的位置
size_t pos = file_path_.find_last_of(L'.');
// 判断 pos 是否是有效位置
if (pos != std::wstring::npos)
if (pos != String::npos)
{
// 截取扩展名
file_ext = file_path_.substr(pos);
@ -106,7 +108,7 @@ namespace easy2d
return false;
}
File File::Extract(Resource& res, const std::wstring& dest_file_name)
File File::Extract(Resource& res, const String& dest_file_name)
{
File file;
HANDLE file_handle = ::CreateFile(
@ -140,11 +142,11 @@ namespace easy2d
return file;
}
void File::AddSearchPath(const std::wstring & path)
void File::AddSearchPath(const String & path)
{
std::wstring tmp = path;
String tmp = path;
size_t pos = 0;
while ((pos = tmp.find(L"/", pos)) != std::wstring::npos)
while ((pos = tmp.find(L"/", pos)) != String::npos)
{
tmp.replace(pos, 1, L"\\");
pos++;
@ -161,9 +163,9 @@ namespace easy2d
}
}
File File::ShowOpenDialog(const std::wstring & title, const std::wstring & filter)
File File::ShowOpenDialog(const String & title, const String & filter)
{
std::wstring file_path;
String file_path;
HRESULT hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
@ -223,9 +225,9 @@ namespace easy2d
return File(file_path);
}
File File::ShowSaveDialog(const std::wstring & title, const std::wstring& def_file, const std::wstring & def_ext)
File File::ShowSaveDialog(const String & title, const String& def_file, const String & def_ext)
{
std::wstring file_path;
String file_path;
HRESULT hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
@ -251,7 +253,7 @@ namespace easy2d
{
file_save->SetDefaultExtension(def_ext.c_str());
std::wstring ext = L"*." + def_ext;
String ext = L"*." + def_ext;
COMDLG_FILTERSPEC spec[] =
{
{ L"", ext.c_str() }

85
core/utils/File.h Normal file
View File

@ -0,0 +1,85 @@
// 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 "../base/base.h"
#include "../base/Resource.h"
namespace easy2d
{
// 文件
class File
{
public:
File();
File(
const String& file_name
);
virtual ~File();
// 打开文件
bool Open(
const String& file_name
);
// 文件是否存在
bool Exists() const;
// 删除文件
bool Delete();
// 获取文件路径
const String& GetPath() const;
// 获取文件扩展名
String GetExtension() const;
// 释放资源到临时文件目录
static File Extract(
Resource& res, /* 资源 */
const String& dest_file_name /* 目标文件名 */
);
// 添加文件搜索路径
static void AddSearchPath(
const String& path
);
// 弹出打开文件对话框
static File ShowOpenDialog(
const String& title = L"打开", /* 对话框标题 */
const String& filter = L"" /* 筛选扩展名,例如 "*.jpg;*.jpeg" */
);
// 弹出保存文件对话框
static File ShowSaveDialog(
const String& title = L"保存", /* 对话框标题 */
const String& def_file = L"", /* 默认保存的文件名 */
const String& def_ext = L"" /* 默认追加的扩展名,例如 "txt" */
);
protected:
String file_path_;
static std::list<String> search_paths_;
};
}

276
core/utils/Music.cpp Normal file
View File

@ -0,0 +1,276 @@
// 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.
#include "Music.h"
#include "Transcoder.h"
#include "File.h"
#include "../base/modules.h"
#include "../base/audio.h"
#include "../base/logs.h"
namespace easy2d
{
Music::Music()
: opened_(false)
, playing_(false)
, wave_data_(nullptr)
, size_(0)
, voice_(nullptr)
{
}
Music::Music(const String& file_path)
: opened_(false)
, playing_(false)
, wave_data_(nullptr)
, size_(0)
, voice_(nullptr)
{
Load(file_path);
}
Music::Music(Resource& res)
: opened_(false)
, playing_(false)
, wave_data_(nullptr)
, size_(0)
, voice_(nullptr)
{
Load(res);
}
Music::~Music()
{
Close();
}
bool Music::Load(const String & file_path)
{
if (opened_)
{
Close();
}
File music_file;
if (!music_file.Open(file_path))
{
E2D_WARNING("Media file not found.");
return false;
}
// 用户输入的路径不一定是完整路径,因为用户可能通过 File::AddSearchPath 添加
// 默认搜索路径,所以需要通过 File::GetPath 获取完整路径
String music_file_path = music_file.GetPath();
Transcoder transcoder;
if (!transcoder.LoadMediaFile(music_file_path.c_str(), &wave_data_, &size_))
{
return false;
}
HRESULT hr = audio::instance.CreateVoice(&voice_, transcoder.GetWaveFormatEx());
if (FAILED(hr))
{
if (wave_data_)
{
delete[] wave_data_;
wave_data_ = nullptr;
}
logs::Trace(L"Create source voice error", hr);
return false;
}
opened_ = true;
return true;
}
bool Music::Load(Resource& res)
{
if (opened_)
{
Close();
}
Transcoder transcoder;
if (!transcoder.LoadMediaResource(res, &wave_data_, &size_))
{
return false;
}
HRESULT hr = audio::instance.CreateVoice(&voice_, transcoder.GetWaveFormatEx());
if (FAILED(hr))
{
if (wave_data_)
{
delete[] wave_data_;
wave_data_ = nullptr;
}
logs::Trace(L"Create source voice error", hr);
return false;
}
opened_ = true;
return true;
}
bool Music::Play(int loop_count)
{
if (!opened_)
{
E2D_WARNING("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)
{
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)))
{
logs::Trace(L"Submitting source buffer error", hr);
return false;
}
hr = voice_->Start(0);
playing_ = SUCCEEDED(hr);
return playing_;
}
void Music::Pause()
{
if (voice_)
{
if (SUCCEEDED(voice_->Stop()))
{
playing_ = false;
}
}
}
void Music::Resume()
{
if (voice_)
{
if (SUCCEEDED(voice_->Start()))
{
playing_ = true;
}
}
}
void Music::Stop()
{
if (voice_)
{
if (SUCCEEDED(voice_->Stop()))
{
voice_->ExitLoop();
voice_->FlushSourceBuffers();
playing_ = false;
}
}
}
void Music::Close()
{
if (voice_)
{
voice_->Stop();
voice_->FlushSourceBuffers();
voice_->DestroyVoice();
voice_ = nullptr;
}
if (wave_data_)
{
delete[] wave_data_;
wave_data_ = nullptr;
}
opened_ = false;
playing_ = false;
}
bool Music::IsPlaying() const
{
if (opened_ && voice_)
{
XAUDIO2_VOICE_STATE state;
voice_->GetState(&state);
if (state.BuffersQueued && playing_)
return true;
}
return false;
}
float Music::GetVolume() const
{
if (voice_)
{
float volume = 0.f;
voice_->GetVolume(&volume);
return volume;
}
return 0.f;
}
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_;
}
}

97
core/utils/Music.h Normal file
View File

@ -0,0 +1,97 @@
// 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 "../base/base.h"
#include "../base/RefCounter.h"
#include "../base/Resource.h"
#include <xaudio2.h>
namespace easy2d
{
// 音乐
class Music
: public RefCounter
{
public:
Music();
Music(
const String& file_path /* 音乐文件路径 */
);
Music(
Resource& res /* 音乐资源 */
);
virtual ~Music();
// 打开音乐文件
bool Load(
const String& file_path /* 音乐文件路径 */
);
// 打开音乐资源
bool Load(
Resource& res /* 音乐资源 */
);
// 播放
bool Play(
int loop_count = 0 /* 播放循环次数 (-1 为循环播放) */
);
// 暂停
void Pause();
// 继续
void Resume();
// 停止
void Stop();
// 关闭并回收资源
void Close();
// 是否正在播放
bool IsPlaying() const;
// 获取音量
float GetVolume() const;
// 设置音量
bool SetVolume(
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_;
};
}

View File

@ -18,17 +18,17 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "..\e2dtool.h"
#include "..\e2dmodule.h"
#include "Path.h"
#include "File.h"
#include "../base/window.h"
#include <shlobj.h>
namespace easy2d
{
namespace
{
// 创建指定文件夹
bool CreateFolder(const std::wstring & dir_path)
bool CreateFolder(const String & dir_path)
{
if (dir_path.empty() || dir_path.size() >= MAX_PATH)
return false;
@ -55,15 +55,15 @@ namespace easy2d
}
const std::wstring& Path::GetDataPath()
const String& Path::GetDataPath()
{
static std::wstring data_path;
static String data_path;
if (data_path.empty())
{
// 设置数据的保存路径
std::wstring local_app_data_path = Path::GetLocalAppDataPath();
std::wstring title = Game::GetInstance()->GetTitle();
std::wstring folder_name = std::to_wstring(std::hash<std::wstring>{}(title));
String local_app_data_path = Path::GetLocalAppDataPath();
String title = window::instance.GetTitle();
String folder_name = std::to_wstring(std::hash<String>{}(title));
if (!local_app_data_path.empty())
{
@ -83,15 +83,15 @@ namespace easy2d
return data_path;
}
const std::wstring& Path::GetTemporaryPath()
const String& Path::GetTemporaryPath()
{
static std::wstring temp_path;
static String temp_path;
if (temp_path.empty())
{
// 设置临时文件保存路径
wchar_t path[_MAX_PATH];
std::wstring title = Game::GetInstance()->GetTitle();
std::wstring folder_name = std::to_wstring(std::hash<std::wstring>{}(title));
String title = window::instance.GetTitle();
String folder_name = std::to_wstring(std::hash<String>{}(title));
if (0 != ::GetTempPath(_MAX_PATH, path))
{
@ -110,9 +110,9 @@ namespace easy2d
return temp_path;
}
const std::wstring& Path::GetLocalAppDataPath()
const String& Path::GetLocalAppDataPath()
{
static std::wstring local_app_data_path;
static String local_app_data_path;
if (local_app_data_path.empty())
{
// 获取 AppData/Local 文件夹的路径
@ -124,9 +124,9 @@ namespace easy2d
return local_app_data_path;
}
const std::wstring& Path::GetExeFilePath()
const String& Path::GetExeFilePath()
{
static std::wstring exe_file_path;
static String exe_file_path;
if (exe_file_path.empty())
{
TCHAR path[_MAX_PATH] = { 0 };

Some files were not shown because too many files have changed in this diff Show More