change: add namespace modules & load libraries from dll
refactoring: time package refactoring: the whole project has been changed
This commit is contained in:
		
							parent
							
								
									b129a1bf18
								
							
						
					
					
						commit
						f4cadddce4
					
				|  | @ -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; | ||||
| 	} | ||||
| } | ||||
|  | @ -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) | ||||
| 	{ | ||||
| 	} | ||||
| } | ||||
|  | @ -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_; | ||||
| 	} | ||||
| } | ||||
|  | @ -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; | ||||
| 	} | ||||
| } | ||||
|  | @ -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; | ||||
| 	} | ||||
| } | ||||
|  | @ -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,17 +86,17 @@ 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(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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; | ||||
| 	} | ||||
| } | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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_); | ||||
| 	} | ||||
| } | ||||
|  | @ -18,97 +18,11 @@ | |||
| // 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__
 | ||||
| } | ||||
|  | @ -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) | ||||
| 	{ | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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	/* 鼠标中键 */ | ||||
| 	}; | ||||
| } | ||||
|  | @ -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() | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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 | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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) | ||||
|  | @ -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; | ||||
| 	}; | ||||
| } | ||||
|  | @ -18,12 +18,11 @@ | |||
| // 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) | ||||
|  | @ -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) | ||||
| 	public: | ||||
| 		// 字体粗细值
 | ||||
| 		enum Weight : unsigned int | ||||
| 		{ | ||||
| 		Transition::Init(prev, next, game); | ||||
| 			Thin		= 100, | ||||
| 			ExtraLight	= 200, | ||||
| 			Light		= 300, | ||||
| 			Normal		= 400, | ||||
| 			Medium		= 500, | ||||
| 			Bold		= 700, | ||||
| 			ExtraBold	= 800, | ||||
| 			Black		= 900, | ||||
| 			ExtraBlack	= 950 | ||||
| 		}; | ||||
| 
 | ||||
| 		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; | ||||
| 		} | ||||
| 	} | ||||
| 	public: | ||||
| 		explicit Font( | ||||
| 			const std::wstring& family	= L"", | ||||
| 			float size					= 22, | ||||
| 			unsigned int weight			= Font::Weight::Normal, | ||||
| 			bool italic					= false | ||||
| 		); | ||||
| 	}; | ||||
| } | ||||
|  | @ -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; | ||||
| 	} | ||||
| } | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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; | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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; | ||||
| 
 | ||||
| 		InputDevice::InputDevice() | ||||
| 		{ | ||||
| 			ZeroMemory(keys_, sizeof(keys_)); | ||||
| 		} | ||||
| 
 | ||||
| 	Graphics * Device::GetGraphics() | ||||
| 		InputDevice::~InputDevice() | ||||
| 		{ | ||||
| 		return graphics_device; | ||||
| 		} | ||||
| 
 | ||||
| 	Input * Device::GetInput() | ||||
| 		void InputDevice::Update(HWND hwnd, float xscale, float yscale) | ||||
| 		{ | ||||
| 		return input_device; | ||||
| 			::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); | ||||
| 		} | ||||
| 
 | ||||
| 	Audio * Device::GetAudio() | ||||
| 		bool InputDevice::IsDown(KeyCode code) | ||||
| 		{ | ||||
| 		return audio_device; | ||||
| 			if (keys_[static_cast<int>(code)] & 0x80) | ||||
| 				return true; | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 	void Device::Init(HWND hwnd) | ||||
| 		bool InputDevice::IsDown(MouseCode code) | ||||
| 		{ | ||||
| 		graphics_device = new (std::nothrow) Graphics(hwnd); | ||||
| 		input_device = new (std::nothrow) Input(hwnd); | ||||
| 		audio_device = new (std::nothrow) Audio(); | ||||
| 			if (keys_[static_cast<int>(code)] & 0x80) | ||||
| 				return true; | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 	void Device::Destroy() | ||||
| 		float InputDevice::GetMouseX() | ||||
| 		{ | ||||
| 		if (audio_device) | ||||
| 		{ | ||||
| 			delete audio_device; | ||||
| 			audio_device = nullptr; | ||||
| 			return mouse_pos_.x; | ||||
| 		} | ||||
| 
 | ||||
| 		if (input_device) | ||||
| 		float InputDevice::GetMouseY() | ||||
| 		{ | ||||
| 			delete input_device; | ||||
| 			input_device = nullptr; | ||||
| 			return mouse_pos_.y; | ||||
| 		} | ||||
| 
 | ||||
| 		if (graphics_device) | ||||
| 		Point InputDevice::GetMousePos() | ||||
| 		{ | ||||
| 			delete graphics_device; | ||||
| 			graphics_device = nullptr; | ||||
| 			return mouse_pos_; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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 | ||||
| 		// 输入设备
 | ||||
| 		class InputDevice | ||||
| 		{ | ||||
| 		return new Delay(delay_); | ||||
| 	} | ||||
| 		public: | ||||
| 			InputDevice(); | ||||
| 
 | ||||
| 	Delay * Delay::Reverse() const | ||||
| 	{ | ||||
| 		return new Delay(delay_); | ||||
| 	} | ||||
| 			~InputDevice(); | ||||
| 
 | ||||
| 	void Delay::Reset() | ||||
| 	{ | ||||
| 		Action::Reset(); | ||||
| 		delta_ = 0; | ||||
| 	} | ||||
| 			// 检测键盘某按键是否正被按下
 | ||||
| 			bool IsDown( | ||||
| 				KeyCode code | ||||
| 			); | ||||
| 
 | ||||
| 	void Delay::Init() | ||||
| 	{ | ||||
| 		Action::Init(); | ||||
| 	} | ||||
| 			// 检测鼠标按键是否正被按下
 | ||||
| 			bool IsDown( | ||||
| 				MouseCode code | ||||
| 			); | ||||
| 
 | ||||
| 	void Delay::Update() | ||||
| 	{ | ||||
| 		Action::Update(); | ||||
| 			// 获得鼠标X轴坐标值
 | ||||
| 			float GetMouseX(); | ||||
| 
 | ||||
| 		delta_ = (Time::Now() - started_).Seconds(); | ||||
| 			// 获得鼠标Y轴坐标值
 | ||||
| 			float GetMouseY(); | ||||
| 
 | ||||
| 		if (delta_ >= delay_) | ||||
| 		{ | ||||
| 			this->Stop(); | ||||
| 		} | ||||
| 	} | ||||
| 			// 获得鼠标坐标值
 | ||||
| 			Point GetMousePos(); | ||||
| 
 | ||||
| 	void Delay::ResetTime() | ||||
| 	{ | ||||
| 		Action::ResetTime(); | ||||
| 		started_ = Time::Now() - Duration::Second * delta_; | ||||
| 			// 刷新设备状态
 | ||||
| 			void Update( | ||||
| 				HWND hwnd, | ||||
| 				float xscale, | ||||
| 				float yscale | ||||
| 			); | ||||
| 
 | ||||
| 		protected: | ||||
| 			BYTE keys_[256]; | ||||
| 			Point mouse_pos_; | ||||
| 		}; | ||||
| 
 | ||||
| 		extern InputDevice instance; | ||||
| 	} | ||||
| } | ||||
|  | @ -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_); | ||||
| 	} | ||||
| } | ||||
|  | @ -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; | ||||
| 	} | ||||
| 	public: | ||||
| 		// 按键消息类型
 | ||||
| 		enum class Type : int | ||||
| 		{ | ||||
| 			Down = 0x0100,	// 按下
 | ||||
| 			Up				// 抬起
 | ||||
| 		}; | ||||
| 
 | ||||
| 	void RotateBy::Init() | ||||
| 	{ | ||||
| 		FiniteTimeAction::Init(); | ||||
| 	public: | ||||
| 		explicit KeyEvent( | ||||
| 			UINT message, | ||||
| 			WPARAM w_param, | ||||
| 			LPARAM l_param | ||||
| 		); | ||||
| 
 | ||||
| 		if (target_) | ||||
| 		{ | ||||
| 			start_val_ = target_->GetRotation(); | ||||
| 		} | ||||
| 	} | ||||
| 		// 获取事件类型
 | ||||
| 		KeyEvent::Type GetType() const; | ||||
| 
 | ||||
| 	void RotateBy::Update() | ||||
| 	{ | ||||
| 		FiniteTimeAction::Update(); | ||||
| 		// 获取按键键值
 | ||||
| 		KeyCode GetCode() const; | ||||
| 
 | ||||
| 		if (target_) | ||||
| 		{ | ||||
| 			target_->SetRotation(start_val_ + delta_val_ * delta_); | ||||
| 		} | ||||
| 	} | ||||
| 		// 获取按键次数
 | ||||
| 		int GetCount() const; | ||||
| 
 | ||||
| 	RotateBy * RotateBy::Clone() const | ||||
| 	{ | ||||
| 		return new RotateBy(duration_, delta_val_); | ||||
| 	} | ||||
| 	protected: | ||||
| 		UINT	message_; | ||||
| 		WPARAM	w_param_; | ||||
| 		LPARAM	l_param_; | ||||
| 	}; | ||||
| 
 | ||||
| 	RotateBy * RotateBy::Reverse() const | ||||
| 
 | ||||
| 	// 按键消息处理接口
 | ||||
| 	class KeyEventHandler | ||||
| 	{ | ||||
| 		return new RotateBy(duration_, -delta_val_); | ||||
| 	} | ||||
| 	public: | ||||
| 		// 处理按键消息
 | ||||
| 		virtual void Handle(KeyEvent e) = 0; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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 | ||||
| 		); | ||||
| 	} | ||||
| 
 | ||||
|  | @ -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; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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); | ||||
| 		} | ||||
| 	}; | ||||
| } | ||||
|  | @ -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_; | ||||
| 	} | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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 | ||||
| { | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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 | ||||
| { | ||||
|  | @ -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) | ||||
| 	{ | ||||
| 		delta_x_ = scale; | ||||
| 		delta_y_ = scale; | ||||
| 	} | ||||
| 	class Node; | ||||
| 
 | ||||
| 	ScaleBy::ScaleBy(float duration, float scale_x, float scale_y) | ||||
| 		: FiniteTimeAction(duration) | ||||
| 	// 场景
 | ||||
| 	class Scene | ||||
| 		: public RefCounter | ||||
| 	{ | ||||
| 		delta_x_ = scale_x; | ||||
| 		delta_y_ = scale_y; | ||||
| 	} | ||||
| 	public: | ||||
| 		Scene(); | ||||
| 
 | ||||
| 	void ScaleBy::Init() | ||||
| 	{ | ||||
| 		FiniteTimeAction::Init(); | ||||
| 		explicit Scene( | ||||
| 			Node * root | ||||
| 		); | ||||
| 
 | ||||
| 		if (target_) | ||||
| 		{ | ||||
| 			start_scale_x_ = target_->GetScaleX(); | ||||
| 			start_scale_y_ = target_->GetScaleY(); | ||||
| 		} | ||||
| 	} | ||||
| 		virtual ~Scene(); | ||||
| 
 | ||||
| 	void ScaleBy::Update() | ||||
| 	{ | ||||
| 		FiniteTimeAction::Update(); | ||||
| 		// 进入场景
 | ||||
| 		virtual void OnEnter() {} | ||||
| 
 | ||||
| 		if (target_) | ||||
| 		{ | ||||
| 			target_->SetScale(start_scale_x_ + delta_x_ * delta_, start_scale_y_ + delta_y_ * delta_); | ||||
| 		} | ||||
| 	} | ||||
| 		// 退出场景
 | ||||
| 		virtual void OnExit() {} | ||||
| 
 | ||||
| 	ScaleBy * ScaleBy::Clone() const | ||||
| 	{ | ||||
| 		return new ScaleBy(duration_, delta_x_, delta_y_); | ||||
| 	} | ||||
| 		// 更新场景
 | ||||
| 		virtual void OnUpdate(float dt) {} | ||||
| 
 | ||||
| 	ScaleBy * ScaleBy::Reverse() const | ||||
| 	{ | ||||
| 		return new ScaleBy(duration_, -delta_x_, -delta_y_); | ||||
| 	} | ||||
| 		// 设置根节点
 | ||||
| 		void SetRoot( | ||||
| 			Node * root | ||||
| 		); | ||||
| 
 | ||||
| 		// 获取根节点
 | ||||
| 		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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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); | ||||
|  | @ -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; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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(), | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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_; | ||||
| 	} | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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; | ||||
| 	} | ||||
| } | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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()); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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__
 | ||||
| } | ||||
|  | @ -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() | ||||
| 		AudioDevice::~AudioDevice() | ||||
| 		{ | ||||
| 		SafeRelease(action_); | ||||
| 		} | ||||
| 
 | ||||
| 	Loop * Loop::Clone() const | ||||
| 		void AudioDevice::Initialize() | ||||
| 		{ | ||||
| 		if (action_) | ||||
| 		{ | ||||
| 			return new Loop(action_->Clone()); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			return nullptr; | ||||
| 		} | ||||
| 			ThrowIfFailed( | ||||
| 				modules::MediaFoundation.MFStartup(MF_VERSION, MFSTARTUP_FULL) | ||||
| 			); | ||||
| 
 | ||||
| 			ThrowIfFailed( | ||||
| 				modules::XAudio2.XAudio2Create(&x_audio2_, 0, XAUDIO2_DEFAULT_PROCESSOR) | ||||
| 			); | ||||
| 
 | ||||
| 			ThrowIfFailed( | ||||
| 				x_audio2_->CreateMasteringVoice(&mastering_voice_) | ||||
| 			); | ||||
| 		} | ||||
| 
 | ||||
| 	Loop * Loop::Reverse() const | ||||
| 		void AudioDevice::Uninitialize() | ||||
| 		{ | ||||
| 		if (action_) | ||||
| 			if (mastering_voice_) | ||||
| 			{ | ||||
| 			return new Loop(action_->Clone()); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			return nullptr; | ||||
| 		} | ||||
| 				mastering_voice_->DestroyVoice(); | ||||
| 				mastering_voice_ = nullptr; | ||||
| 			} | ||||
| 
 | ||||
| 	void Loop::Init() | ||||
| 	{ | ||||
| 		Action::Init(); | ||||
| 			SafeRelease(x_audio2_); | ||||
| 
 | ||||
| 		if (action_) | ||||
| 		{ | ||||
| 			action_->target_ = target_; | ||||
| 			action_->Init(); | ||||
| 		} | ||||
| 			modules::MediaFoundation.MFShutdown(); | ||||
| 		} | ||||
| 
 | ||||
| 	void Loop::Update() | ||||
| 		HRESULT AudioDevice::CreateVoice(IXAudio2SourceVoice ** voice, WAVEFORMATEX * wfx) | ||||
| 		{ | ||||
| 		Action::Update(); | ||||
| 
 | ||||
| 		if (times_ == total_times_) | ||||
| 		{ | ||||
| 			this->Stop(); | ||||
| 			return; | ||||
| 			return x_audio2_->CreateSourceVoice(voice, wfx, 0, XAUDIO2_DEFAULT_FREQ_RATIO); | ||||
| 		} | ||||
| 
 | ||||
| 		if (action_) | ||||
| 		void AudioDevice::Open() | ||||
| 		{ | ||||
| 			action_->Update(); | ||||
| 
 | ||||
| 			if (action_->IsDone()) | ||||
| 			{ | ||||
| 				++times_; | ||||
| 
 | ||||
| 				Action::Reset(); | ||||
| 				action_->Reset(); | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			this->Stop(); | ||||
| 		} | ||||
| 			x_audio2_->StartEngine(); | ||||
| 		} | ||||
| 
 | ||||
| 	void Loop::Reset() | ||||
| 		void AudioDevice::Close() | ||||
| 		{ | ||||
| 		Action::Reset(); | ||||
| 
 | ||||
| 		if (action_) action_->Reset(); | ||||
| 		times_ = 0; | ||||
| 			x_audio2_->StopEngine(); | ||||
| 		} | ||||
| 
 | ||||
| 	void Loop::ResetTime() | ||||
| 	{ | ||||
| 		if (action_) action_->ResetTime(); | ||||
| 	} | ||||
| } | ||||
|  | @ -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 | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| 	void EmergeTransition::Init(Scene * prev, Scene * next, Game * game) | ||||
| 		// 音频设备
 | ||||
| 		class AudioDevice | ||||
| 		{ | ||||
| 		Transition::Init(prev, next, game); | ||||
| 		public: | ||||
| 			AudioDevice(); | ||||
| 
 | ||||
| 		out_layer_param_.opacity = 1; | ||||
| 		in_layer_param_.opacity = 0; | ||||
| 	} | ||||
| 			~AudioDevice(); | ||||
| 
 | ||||
| 	void EmergeTransition::Update() | ||||
| 	{ | ||||
| 		Transition::Update(); | ||||
| 			void Initialize(); | ||||
| 
 | ||||
| 		out_layer_param_.opacity = 1 - process_; | ||||
| 		in_layer_param_.opacity = process_; | ||||
| 			void Uninitialize(); | ||||
| 
 | ||||
| 			// 开启设备
 | ||||
| 			void Open(); | ||||
| 
 | ||||
| 			// 关闭设备
 | ||||
| 			void Close(); | ||||
| 
 | ||||
| 			// 创建音源
 | ||||
| 			HRESULT CreateVoice( | ||||
| 				IXAudio2SourceVoice ** voice, | ||||
| 				WAVEFORMATEX * wfx | ||||
| 			); | ||||
| 
 | ||||
| 		protected: | ||||
| 			IXAudio2 * x_audio2_; | ||||
| 			IXAudio2MasteringVoice*	mastering_voice_; | ||||
| 		}; | ||||
| 
 | ||||
| 		extern AudioDevice instance; | ||||
| 	} | ||||
| } | ||||
|  | @ -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_; | ||||
| 	} | ||||
| } | ||||
|  | @ -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 | ||||
| 	{ | ||||
| 	} | ||||
| 		namespace | ||||
| 		{ | ||||
| 			inline void OutputDebugStringExW(LPCWSTR pszOutput, ...) | ||||
| 			{ | ||||
| 				va_list args = NULL; | ||||
| 				va_start(args, pszOutput); | ||||
| 
 | ||||
| 	void FiniteTimeAction::Reset() | ||||
| 	{ | ||||
| 		Action::Reset(); | ||||
| 		delta_ = 0; | ||||
| 	} | ||||
| 				size_t nLen = ::_vscwprintf(pszOutput, args) + 1; | ||||
| 				wchar_t* psBuffer = new wchar_t[nLen]; | ||||
| 				::_vsnwprintf_s(psBuffer, nLen, nLen, pszOutput, args); | ||||
| 
 | ||||
| 	void FiniteTimeAction::Init() | ||||
| 	{ | ||||
| 		Action::Init(); | ||||
| 	} | ||||
| 				va_end(args); | ||||
| 
 | ||||
| 	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(); | ||||
| 			} | ||||
| 				::OutputDebugStringW(psBuffer); | ||||
| 				delete[] psBuffer; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 	void FiniteTimeAction::ResetTime() | ||||
| 		inline void Trace(LPCWSTR output) | ||||
| 		{ | ||||
| 		Action::ResetTime(); | ||||
| 		started_ = Time::Now() - Duration::Second * (delta_ * duration_); | ||||
| 			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)); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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__
 | ||||
|  | @ -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); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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(); | ||||
| 	} | ||||
| } | ||||
|  | @ -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); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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 | ||||
| 		typedef struct | ||||
| 		{ | ||||
| 		return new JumpBy(duration_, delta_pos_, height_, jumps_); | ||||
| 	} | ||||
| 			ID2D1Factory*			Factory; | ||||
| 			IWICImagingFactory*		WICImagingFactory; | ||||
| 			IDWriteFactory*			DWriteFactory; | ||||
| 			ITextRenderer*			TextRenderer; | ||||
| 			ID2D1SolidColorBrush*	SolidColorBrush; | ||||
| 			ID2D1HwndRenderTarget*	HwndRenderTarget; | ||||
| 			ID2D1StrokeStyle*		MiterStrokeStyle; | ||||
| 			ID2D1StrokeStyle*		BevelStrokeStyle; | ||||
| 			ID2D1StrokeStyle*		RoundStrokeStyle; | ||||
| 		} _D2D_Resource; | ||||
| 
 | ||||
| 	JumpBy * JumpBy::Reverse() const | ||||
| 		extern _D2D_Resource D2D; | ||||
| 
 | ||||
| 		void Initialize(HWND hwnd); | ||||
| 
 | ||||
| 		void CreateDeviceResources(HWND hwnd); | ||||
| 
 | ||||
| 		void Uninitialize(); | ||||
| 
 | ||||
| 		class GraphicsDevice | ||||
| 		{ | ||||
| 		return new JumpBy(duration_, -delta_pos_, height_, jumps_); | ||||
| 	} | ||||
| 		public: | ||||
| 			GraphicsDevice(); | ||||
| 
 | ||||
| 	void JumpBy::Init() | ||||
| 	{ | ||||
| 		FiniteTimeAction::Init(); | ||||
| 			~GraphicsDevice(); | ||||
| 
 | ||||
| 		if (target_) | ||||
| 		{ | ||||
| 			prev_pos_ = start_pos_ = target_->GetPosition(); | ||||
| 		} | ||||
| 	} | ||||
| 			// 开始渲染
 | ||||
| 			void BeginDraw(HWND hwnd); | ||||
| 
 | ||||
| 	void JumpBy::Update() | ||||
| 	{ | ||||
| 		FiniteTimeAction::Update(); | ||||
| 			// 结束渲染
 | ||||
| 			void EndDraw(); | ||||
| 
 | ||||
| 		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_; | ||||
| 			// 渲染调试信息
 | ||||
| 			void DrawDebugInfo(); | ||||
| 
 | ||||
| 			Point currentPos = target_->GetPosition(); | ||||
| 			// 设置背景色
 | ||||
| 			void SetBackgroundColor( | ||||
| 				const Color& color | ||||
| 			); | ||||
| 
 | ||||
| 			Point diff = currentPos - prev_pos_; | ||||
| 			start_pos_ = diff + start_pos_; | ||||
| 		protected: | ||||
| 			D2D1_COLOR_F		clear_color_; | ||||
| 			IDWriteTextFormat*	fps_text_format_; | ||||
| 			IDWriteTextLayout*	fps_text_layout_; | ||||
| 		}; | ||||
| 
 | ||||
| 			Point newPos = start_pos_ + Point(x, y); | ||||
| 			target_->SetPosition(newPos); | ||||
| 
 | ||||
| 			prev_pos_ = newPos; | ||||
| 		} | ||||
| 		extern GraphicsDevice instance; | ||||
| 	} | ||||
| } | ||||
|  | @ -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; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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); | ||||
| 	} | ||||
| } | ||||
|  | @ -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; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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) | ||||
| 		typedef struct Property | ||||
| 		{ | ||||
| 		Transition::Init(prev, next, game); | ||||
| 			String	title;	/* 标题 */ | ||||
| 			int		width;	/* 宽度 */ | ||||
| 			int		height;	/* 高度 */ | ||||
| 			LPCWSTR	icon;	/* 图标 */ | ||||
| 
 | ||||
| 		in_layer_param_.opacity = 0; | ||||
| 	} | ||||
| 			Property() | ||||
| 				: title(L"Easy2D Game") | ||||
| 				, width(640) | ||||
| 				, height(480) | ||||
| 				, icon(nullptr) | ||||
| 			{} | ||||
| 		} Property; | ||||
| 
 | ||||
| 	void BoxTransition::Update() | ||||
| 		class WindowInfo | ||||
| 		{ | ||||
| 		Transition::Update(); | ||||
| 		public: | ||||
| 			HWND handle; | ||||
| 			float xscale; | ||||
| 			float yscale; | ||||
| 
 | ||||
| 		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_) | ||||
| 		public: | ||||
| 			WindowInfo(); | ||||
| 
 | ||||
| 			void Initialize( | ||||
| 				const Property& property | ||||
| 			); | ||||
| 		} | ||||
| 		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_ | ||||
| 			); | ||||
| 		} | ||||
| 
 | ||||
| 			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; | ||||
| 	} | ||||
| } | ||||
|  | @ -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); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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__
 | ||||
							
								
								
									
										327
									
								
								core/e2dmodule.h
								
								
								
								
							
							
						
						
									
										327
									
								
								core/e2dmodule.h
								
								
								
								
							|  | @ -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__
 | ||||
							
								
								
									
										1106
									
								
								core/e2dobject.h
								
								
								
								
							
							
						
						
									
										1106
									
								
								core/e2dobject.h
								
								
								
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										339
									
								
								core/e2dtool.h
								
								
								
								
							
							
						
						
									
										339
									
								
								core/e2dtool.h
								
								
								
								
							|  | @ -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__
 | ||||
							
								
								
									
										668
									
								
								core/e2dutil.h
								
								
								
								
							
							
						
						
									
										668
									
								
								core/e2dutil.h
								
								
								
								
							|  | @ -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__
 | ||||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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_); | ||||
| 	} | ||||
| } | ||||
|  | @ -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 | ||||
| 				); | ||||
| 			} | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
|  | @ -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; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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; | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
|  | @ -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; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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); } | ||||
| 	} | ||||
| } | ||||
|  | @ -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(); | ||||
| 			} | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
|  | @ -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; | ||||
| 	} | ||||
| } | ||||
|  | @ -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; | ||||
| 	} | ||||
| } | ||||
|  | @ -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; | ||||
| 	} | ||||
| } | ||||
|  | @ -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_; | ||||
| 	} | ||||
| } | ||||
|  | @ -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()); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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()); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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(); | ||||
| 	} | ||||
| } | ||||
|  | @ -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); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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_; | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
|  | @ -18,11 +18,12 @@ | |||
| // 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 | ||||
| { | ||||
| 	namespace ui | ||||
| 	{ | ||||
| 		Menu::Menu() | ||||
| 			: enabled_(true) | ||||
| 		{ | ||||
|  | @ -97,4 +98,5 @@ namespace easy2d | |||
| 		{ | ||||
| 			return buttons_; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -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_; | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
|  | @ -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( | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -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 <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() } | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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_; | ||||
| 	} | ||||
| } | ||||
|  | @ -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_; | ||||
| 	}; | ||||
| } | ||||
|  | @ -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
		Loading…
	
		Reference in New Issue