Compare commits
	
		
			1 Commits
		
	
	
		
			bounce-upg
			...
			upstream_f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | a61262407c | 
							
								
								
									
										110
									
								
								examples/testbed/framework/profiler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								examples/testbed/framework/profiler.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <testbed/framework/profiler.h> | ||||||
|  |  | ||||||
|  | Profiler* g_profiler = nullptr; | ||||||
|  |  | ||||||
|  | Profiler::Profiler() : m_pool(sizeof(ProfilerNode)) | ||||||
|  | { | ||||||
|  | 	m_root = nullptr; | ||||||
|  | 	m_top = nullptr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Profiler::~Profiler() | ||||||
|  | { | ||||||
|  | 	assert(m_root == nullptr); | ||||||
|  | 	assert(m_top == nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ProfilerNode* Profiler::CreateNode() | ||||||
|  | { | ||||||
|  | 	void* block = m_pool.Allocate(); | ||||||
|  | 	ProfilerNode* n = new (block) ProfilerNode(); | ||||||
|  | 	return n; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Profiler::DestroyNode(ProfilerNode* node) | ||||||
|  | { | ||||||
|  | 	node->~ProfilerNode(); | ||||||
|  | 	m_pool.Free(node); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Profiler::BeginScope(const char* name) | ||||||
|  | { | ||||||
|  | 	m_time.Update(); | ||||||
|  |  | ||||||
|  | 	ProfilerNode* n = CreateNode(); | ||||||
|  | 	n->name = name; | ||||||
|  | 	n->t0 = m_time.GetCurrentMilis(); | ||||||
|  | 	n->t1 = 0.0; | ||||||
|  | 	n->parent = m_top; | ||||||
|  |  | ||||||
|  | 	if (m_root == nullptr) | ||||||
|  | 	{ | ||||||
|  | 		m_root = n; | ||||||
|  | 		m_top = n; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (m_top) | ||||||
|  | 	{ | ||||||
|  | 		m_top->children.PushBack(n); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	m_top = n; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Profiler::EndScope() | ||||||
|  | { | ||||||
|  | 	m_time.Update(); | ||||||
|  | 	 | ||||||
|  | 	assert(m_top != nullptr); | ||||||
|  | 	m_top->t1 = m_time.GetCurrentMilis(); | ||||||
|  | 	assert(m_top->t1 > m_top->t0); | ||||||
|  |  | ||||||
|  | 	m_top = m_top->parent; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Profiler::Begin() | ||||||
|  | { | ||||||
|  | 	// If this assert is hit then it means Profiler::End hasn't been called. | ||||||
|  | 	assert(m_root == nullptr); | ||||||
|  | 	assert(m_top == nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Profiler::RecurseDestroyNode(ProfilerNode* node) | ||||||
|  | { | ||||||
|  | 	for (u32 i = 0; i < node->children.Count(); ++i) | ||||||
|  | 	{ | ||||||
|  | 		RecurseDestroyNode(node->children[i]); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	DestroyNode(node); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Profiler::End() | ||||||
|  | { | ||||||
|  | 	assert(m_top == nullptr); | ||||||
|  |  | ||||||
|  | 	if (m_root) | ||||||
|  | 	{ | ||||||
|  | 		RecurseDestroyNode(m_root); | ||||||
|  | 		m_root = nullptr; | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										73
									
								
								examples/testbed/framework/profiler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								examples/testbed/framework/profiler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef PROFILER_H | ||||||
|  | #define PROFILER_H | ||||||
|  |  | ||||||
|  | #include <bounce/common/math/math.h> | ||||||
|  | #include <bounce/common/memory/block_pool.h> | ||||||
|  | #include <bounce/common/template/array.h> | ||||||
|  | #include <bounce/common/time.h> | ||||||
|  |  | ||||||
|  | // Profiler node | ||||||
|  | struct ProfilerNode | ||||||
|  | { | ||||||
|  | 	const char* name; | ||||||
|  | 	float64 t0; | ||||||
|  | 	float64 t1; | ||||||
|  | 	ProfilerNode* parent; | ||||||
|  | 	b3StackArray<ProfilerNode*, 32> children; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // A single-threaded profiler. | ||||||
|  | class Profiler | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	Profiler(); | ||||||
|  | 	 | ||||||
|  | 	~Profiler(); | ||||||
|  |  | ||||||
|  | 	// Must be called before profiling.  | ||||||
|  | 	void Begin(); | ||||||
|  |  | ||||||
|  | 	// Must be called after profiling. | ||||||
|  | 	void End(); | ||||||
|  |  | ||||||
|  | 	// Begin a new scope. | ||||||
|  | 	void BeginScope(const char* name); | ||||||
|  | 	 | ||||||
|  | 	// End the top scope. | ||||||
|  | 	void EndScope(); | ||||||
|  |  | ||||||
|  | 	// Get the root profiler node. | ||||||
|  | 	ProfilerNode* GetRoot() { return m_root; } | ||||||
|  | private: | ||||||
|  | 	ProfilerNode* CreateNode(); | ||||||
|  | 	void DestroyNode(ProfilerNode* node); | ||||||
|  | 	 | ||||||
|  | 	void RecurseDestroyNode(ProfilerNode* node); | ||||||
|  |  | ||||||
|  | 	b3BlockPool m_pool; // pool of nodes | ||||||
|  | 	b3Time m_time; // timer | ||||||
|  | 	ProfilerNode* m_root; // tree root node | ||||||
|  | 	ProfilerNode* m_top; // top node | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | extern Profiler* g_profiler; | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										197
									
								
								examples/testbed/framework/profiler_st.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								examples/testbed/framework/profiler_st.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,197 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <testbed/framework/profiler_st.h> | ||||||
|  |  | ||||||
|  | ProfilerSt* g_profilerSt = nullptr; | ||||||
|  |  | ||||||
|  | ProfilerSt::ProfilerSt() : m_pool(sizeof(ProfilerStNode)) | ||||||
|  | { | ||||||
|  | 	m_root = nullptr; | ||||||
|  | 	m_top = nullptr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ProfilerSt::~ProfilerSt() | ||||||
|  | { | ||||||
|  | 	assert(m_root == nullptr); | ||||||
|  | 	assert(m_top == nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ProfilerStNodeStat* ProfilerSt::FindStat(const char* name) | ||||||
|  | { | ||||||
|  | 	for (u32 i = 0; i < m_stats.Count(); ++i) | ||||||
|  | 	{ | ||||||
|  | 		if (m_stats[i].name == name) | ||||||
|  | 		{ | ||||||
|  | 			return &m_stats[i]; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nullptr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ProfilerStNodeStat* ProfilerSt::CreateStat() | ||||||
|  | { | ||||||
|  | 	m_stats.PushBack(ProfilerStNodeStat()); | ||||||
|  | 	return &m_stats.Back(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ProfilerStNode* ProfilerSt::CreateNode() | ||||||
|  | { | ||||||
|  | 	void* block = m_pool.Allocate(); | ||||||
|  | 	return new (block) ProfilerStNode(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ProfilerSt::DestroyNode(ProfilerStNode* node) | ||||||
|  | { | ||||||
|  | 	node->~ProfilerStNode(); | ||||||
|  | 	m_pool.Free(node); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ProfilerSt::RecurseDestroyNode(ProfilerStNode* node) | ||||||
|  | { | ||||||
|  | 	for (u32 i = 0; i < node->children.Count(); ++i) | ||||||
|  | 	{ | ||||||
|  | 		return RecurseDestroyNode(node->children[i]); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	DestroyNode(node); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static ProfilerStNode* RecurseFindNode(ProfilerStNode* node, const char* name) | ||||||
|  | { | ||||||
|  | 	if (node->name == name) | ||||||
|  | 	{ | ||||||
|  | 		return node; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ProfilerStNode* result = nullptr; | ||||||
|  | 	for (u32 i = 0; result == nullptr && i < node->children.Count(); ++i) | ||||||
|  | 	{ | ||||||
|  | 		result = RecurseFindNode(node->children[i], name); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ProfilerStNode* ProfilerSt::FindNode(const char* name) | ||||||
|  | { | ||||||
|  | 	if (m_top) | ||||||
|  | 	{ | ||||||
|  | 		return RecurseFindNode(m_top, name); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (m_root) | ||||||
|  | 	{ | ||||||
|  | 		return RecurseFindNode(m_root, name); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nullptr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ProfilerSt::BeginScope(const char* name) | ||||||
|  | { | ||||||
|  | 	ProfilerStNode* fn = FindNode(name); | ||||||
|  |  | ||||||
|  | 	if (fn) | ||||||
|  | 	{ | ||||||
|  | 		m_time.Update(); | ||||||
|  | 		fn->t0 = m_time.GetCurrentMilis(); | ||||||
|  | 		++fn->callCount; | ||||||
|  | 		m_top = fn; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	m_time.Update(); | ||||||
|  |  | ||||||
|  | 	ProfilerStNode* n = CreateNode(); | ||||||
|  | 	n->name = name; | ||||||
|  | 	n->t0 = m_time.GetCurrentMilis(); | ||||||
|  | 	n->elapsed = 0.0f; | ||||||
|  | 	n->callCount = 1; | ||||||
|  | 	n->parent = m_top; | ||||||
|  | 	n->stat = nullptr; | ||||||
|  |  | ||||||
|  | 	if (m_root == nullptr) | ||||||
|  | 	{ | ||||||
|  | 		m_root = n; | ||||||
|  | 		m_top = n; | ||||||
|  |  | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (m_top) | ||||||
|  | 	{ | ||||||
|  | 		m_top->children.PushBack(n); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	m_top = n; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ProfilerSt::EndScope() | ||||||
|  | { | ||||||
|  | 	assert(m_top != nullptr); | ||||||
|  |  | ||||||
|  | 	m_time.Update(); | ||||||
|  |  | ||||||
|  | 	m_top->t1 = m_time.GetCurrentMilis(); | ||||||
|  | 	 | ||||||
|  | 	float64 elapsedTime = m_top->t1 - m_top->t0; | ||||||
|  |  | ||||||
|  | 	m_top->elapsed += elapsedTime; | ||||||
|  | 	 | ||||||
|  | 	ProfilerStNodeStat* stat = FindStat(m_top->name); | ||||||
|  |  | ||||||
|  | 	if (stat == nullptr) | ||||||
|  | 	{ | ||||||
|  | 		stat = CreateStat(); | ||||||
|  | 		stat->name = m_top->name; | ||||||
|  | 		stat->minElapsed = elapsedTime; | ||||||
|  | 		stat->maxElapsed = elapsedTime;	 | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		stat->minElapsed = b3Min(stat->minElapsed, elapsedTime); | ||||||
|  | 		stat->maxElapsed = b3Max(stat->maxElapsed, elapsedTime); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (m_top->stat == nullptr) | ||||||
|  | 	{ | ||||||
|  | 		m_top->stat = stat; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	assert(m_top->stat == stat); | ||||||
|  |  | ||||||
|  | 	m_top = m_top->parent; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ProfilerSt::Begin() | ||||||
|  | { | ||||||
|  | 	assert(m_top == nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ProfilerSt::End() | ||||||
|  | { | ||||||
|  | 	assert(m_top == nullptr); | ||||||
|  | 	 | ||||||
|  | 	if (m_root) | ||||||
|  | 	{ | ||||||
|  | 		RecurseDestroyNode(m_root); | ||||||
|  | 		m_root = nullptr; | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										94
									
								
								examples/testbed/framework/profiler_st.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								examples/testbed/framework/profiler_st.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef PROFILER_ST_H | ||||||
|  | #define PROFILER_ST_H | ||||||
|  |  | ||||||
|  | #include <bounce/common/math/math.h> | ||||||
|  | #include <bounce/common/memory/block_pool.h> | ||||||
|  | #include <bounce/common/template/array.h> | ||||||
|  | #include <bounce/common/time.h> | ||||||
|  |  | ||||||
|  | // Profiler tree node statistics | ||||||
|  | struct ProfilerStNodeStat | ||||||
|  | { | ||||||
|  | 	const char* name; | ||||||
|  | 	float64 minElapsed; | ||||||
|  | 	float64 maxElapsed; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // A profiler tree node | ||||||
|  | struct ProfilerStNode | ||||||
|  | { | ||||||
|  | 	const char* name;  | ||||||
|  | 	float64 t0; | ||||||
|  | 	float64 t1;  | ||||||
|  | 	 | ||||||
|  | 	float64 elapsed; | ||||||
|  | 	u32 callCount; | ||||||
|  | 	 | ||||||
|  | 	ProfilerStNode* parent; | ||||||
|  | 	b3StackArray<ProfilerStNode*, 32> children; | ||||||
|  |  | ||||||
|  | 	ProfilerStNodeStat* stat; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // A profiler tree  | ||||||
|  | class ProfilerSt | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	ProfilerSt(); | ||||||
|  | 	 | ||||||
|  | 	~ProfilerSt(); | ||||||
|  |  | ||||||
|  | 	// Must be called before profiling.  | ||||||
|  | 	void Begin(); | ||||||
|  |  | ||||||
|  | 	// Must be called after profiling. | ||||||
|  | 	void End(); | ||||||
|  |  | ||||||
|  | 	// Begin a new scope. | ||||||
|  | 	void BeginScope(const char* name); | ||||||
|  |  | ||||||
|  | 	// End the top scope. | ||||||
|  | 	void EndScope(); | ||||||
|  |  | ||||||
|  | 	ProfilerStNode* GetRoot() { return m_root; } | ||||||
|  | private: | ||||||
|  | 	ProfilerStNode* CreateNode(); | ||||||
|  | 	void DestroyNode(ProfilerStNode* node); | ||||||
|  | 	 | ||||||
|  | 	void RecurseDestroyNode(ProfilerStNode* node); | ||||||
|  |  | ||||||
|  | 	ProfilerStNode* FindNode(const char* name); | ||||||
|  |  | ||||||
|  | 	ProfilerStNodeStat* CreateStat(); | ||||||
|  |  | ||||||
|  | 	ProfilerStNodeStat* FindStat(const char* name); | ||||||
|  |  | ||||||
|  | 	b3BlockPool m_pool; // pool of nodes | ||||||
|  | 	b3Time m_time; // timer | ||||||
|  | 	ProfilerStNode* m_root; // tree root node | ||||||
|  | 	ProfilerStNode* m_top; // top node | ||||||
|  |  | ||||||
|  | 	b3StackArray<ProfilerStNodeStat, 256> m_stats; // node statistics | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | extern ProfilerSt* g_profilerSt; | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										60
									
								
								examples/testbed/tests/degenerate_capsule.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								examples/testbed/tests/degenerate_capsule.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef DEGENERATE_CAPSULE_H | ||||||
|  | #define DEGENERATE_CAPSULE_H | ||||||
|  |  | ||||||
|  | class DegenerateCapsule : public Collide | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	DegenerateCapsule() | ||||||
|  | 	{ | ||||||
|  | 		m_xfA.position.Set(0.0f, 0.0f, 0.0f); | ||||||
|  | 		m_xfA.rotation = b3QuatMat33(b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.55f * B3_PI)); | ||||||
|  |  | ||||||
|  | 		m_sA.m_centers[0].Set(0.0f, 0.0f, 0.0f); | ||||||
|  | 		m_sA.m_centers[1].Set(0.0f, 0.0f, 0.0f); | ||||||
|  | 		m_sA.m_radius = 0.05f; | ||||||
|  |  | ||||||
|  | 		m_xfB.position.Set(0.f, 0.0f, 0.0f); | ||||||
|  | 		m_xfB.rotation = b3QuatMat33(b3Quat(b3Vec3(0.0f, 0.0f, 1.0f), 0.0f * B3_PI)); | ||||||
|  |  | ||||||
|  | 		b3Transform xf; | ||||||
|  | 		xf.SetIdentity(); | ||||||
|  | 		xf.rotation = b3Diagonal(4.0f, 1.0f, 4.0f); | ||||||
|  |  | ||||||
|  | 		m_box.SetTransform(xf); | ||||||
|  |  | ||||||
|  | 		m_sB.m_hull = &m_box; | ||||||
|  |  | ||||||
|  | 		m_shapeA = &m_sA; | ||||||
|  | 		m_shapeB = &m_sB; | ||||||
|  | 		m_cache.count = 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new DegenerateCapsule(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3CapsuleShape m_sA; | ||||||
|  | 	b3HullShape m_sB; | ||||||
|  | 	b3BoxHull m_box; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										138
									
								
								examples/testbed/tests/hinge_motor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								examples/testbed/tests/hinge_motor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,138 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef HINGE_MOTOR_H | ||||||
|  | #define HINGE_MOTOR_H | ||||||
|  |  | ||||||
|  | class HingeMotor : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	HingeMotor() | ||||||
|  | 	{ | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			b3Body* ground = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			b3HullShape shape; | ||||||
|  | 			shape.m_hull = &m_groundHull; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &shape; | ||||||
|  | 			 | ||||||
|  | 			ground->CreateShape(sd); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Body* hinge, *door; | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			bd.type = b3BodyType::e_staticBody; | ||||||
|  | 			bd.position.Set(0.0f, 7.0f, 0.0f); | ||||||
|  | 			hinge = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			b3CapsuleShape shape; | ||||||
|  | 			shape.m_centers[0].Set(0.0f, 0.0f, -4.0f); | ||||||
|  | 			shape.m_centers[1].Set(0.0f, 0.0f, 4.0f); | ||||||
|  | 			shape.m_radius = 0.5f; | ||||||
|  | 			 | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &shape; | ||||||
|  | 			sd.density = 1.0f; | ||||||
|  |  | ||||||
|  | 			hinge->CreateShape(sd); | ||||||
|  | 			 | ||||||
|  | 			m_body = hinge; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			bd.type = b3BodyType::e_dynamicBody; | ||||||
|  | 			bd.position.Set(2.0f, 7.0f, 0.0f); | ||||||
|  |  | ||||||
|  | 			door = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			m_doorBox.Set(1.0f, 0.5f, 4.0f); | ||||||
|  |  | ||||||
|  | 			b3HullShape hull; | ||||||
|  | 			hull.m_hull = &m_doorBox; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &hull; | ||||||
|  | 			sdef.density = 1.0f; | ||||||
|  | 			 | ||||||
|  | 			door->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 axis(0.0f, 0.0f, 1.0f); | ||||||
|  | 			b3Vec3 anchor(0.0f, 7.0f, 0.0f); | ||||||
|  | 			 | ||||||
|  | 			b3RevoluteJointDef jd; | ||||||
|  | 			jd.Initialize(hinge, door, axis, anchor, 0.0f, B3_PI); | ||||||
|  | 			jd.motorSpeed = B3_PI; | ||||||
|  | 			jd.maxMotorTorque = door->GetMass() * 10000.0f; | ||||||
|  | 			jd.enableMotor = true; | ||||||
|  |  | ||||||
|  | 			m_rj = (b3RevoluteJoint*)m_world.CreateJoint(jd); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Invalidate the orientation | ||||||
|  | 		b3Vec3 axis(1.0f, 0.0f, 0.0f); | ||||||
|  | 		float32 angle = B3_PI; | ||||||
|  | 		door->SetTransform(door->GetPosition(), axis, angle);		 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void KeyDown(int button) | ||||||
|  | 	{ | ||||||
|  | 		if (button == GLFW_KEY_M) | ||||||
|  | 		{ | ||||||
|  | 			m_rj->SetEnableMotor(!m_rj->IsMotorEnabled()); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (button == GLFW_KEY_L) | ||||||
|  | 		{ | ||||||
|  | 			m_rj->SetEnableLimit(!m_rj->IsLimitEnabled()); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if (button == GLFW_KEY_D) | ||||||
|  | 		{ | ||||||
|  | 			m_body->SetType(e_dynamicBody); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (button == GLFW_KEY_S) | ||||||
|  | 		{ | ||||||
|  | 			m_body->SetType(e_staticBody); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (button == GLFW_KEY_K) | ||||||
|  | 		{ | ||||||
|  | 			m_body->SetType(e_kinematicBody); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new HingeMotor(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3BoxHull m_doorBox; | ||||||
|  | 	b3Body* m_body; | ||||||
|  | 	b3RevoluteJoint* m_rj; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										121
									
								
								examples/testbed/tests/shape_cast.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								examples/testbed/tests/shape_cast.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | |||||||
|  | #ifndef SHAPE_CAST_H | ||||||
|  | #define SHAPE_CAST_H | ||||||
|  |  | ||||||
|  | class ShapeCast : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	ShapeCast() | ||||||
|  | 	{ | ||||||
|  | 		m_shapeA.m_hull = &b3BoxHull_identity; | ||||||
|  | 		m_shapeA.m_radius = 0.0f; | ||||||
|  |  | ||||||
|  | 		m_shapeB.m_hull = &b3BoxHull_identity; | ||||||
|  | 		m_shapeB.m_radius = 0.0f; | ||||||
|  |  | ||||||
|  | 		m_xfA.position.Set(-5.0f, 0.0f, 0.0f); | ||||||
|  | 		m_xfA.rotation.SetIdentity(); | ||||||
|  |  | ||||||
|  | 		m_xfB.position.Set(10.0f, 0.0f, 0.0f); | ||||||
|  | 		m_xfB.rotation.SetIdentity(); | ||||||
|  | 		 | ||||||
|  | 		m_proxyA.Set(&m_shapeA, 0); | ||||||
|  | 		m_proxyB.Set(&m_shapeB, 0); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void Step() | ||||||
|  | 	{ | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Left/Right/Up/Down Arrow - Translate shape"); | ||||||
|  | 		g_draw->DrawString(b3Color_white, "X/Y/Z - Rotate shape"); | ||||||
|  |  | ||||||
|  | 		g_draw->DrawTransform(m_xfA); | ||||||
|  | 		g_draw->DrawTransform(m_xfB); | ||||||
|  |  | ||||||
|  | 		m_world.DrawShape(m_xfA, &m_shapeA, b3Color_black); | ||||||
|  | 		m_world.DrawShape(m_xfB, &m_shapeB, b3Color_black); | ||||||
|  |  | ||||||
|  | 		m_world.DrawSolidShape(m_xfA, &m_shapeA, b3Color_white); | ||||||
|  | 		m_world.DrawSolidShape(m_xfB, &m_shapeB, b3Color_white); | ||||||
|  |  | ||||||
|  | 		b3Vec3 translationB = -100.0f * b3Vec3_x; | ||||||
|  | 		g_draw->DrawSegment(m_xfB.position, m_xfB.position + translationB, b3Color_white); | ||||||
|  |  | ||||||
|  | 		b3GJKShapeCastOutput out; | ||||||
|  | 		bool hit = b3GJKShapeCast(&out, m_xfA, m_proxyA, m_xfB, m_proxyB, translationB); | ||||||
|  |  | ||||||
|  | 		g_draw->DrawString(b3Color_white, "Iterations = %d", out.iterations); | ||||||
|  |  | ||||||
|  | 		if (hit) | ||||||
|  | 		{ | ||||||
|  | 			g_draw->DrawPoint(out.point, 4.0f, b3Color_green); | ||||||
|  | 			g_draw->DrawSegment(out.point, out.point + out.normal, b3Color_green); | ||||||
|  |  | ||||||
|  | 			b3Transform xfB; | ||||||
|  | 			xfB.rotation = m_xfB.rotation; | ||||||
|  | 			xfB.position = m_xfB.position + out.t * translationB; | ||||||
|  |  | ||||||
|  | 			m_world.DrawShape(xfB, &m_shapeB, b3Color_black); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void KeyDown(int key) | ||||||
|  | 	{ | ||||||
|  | 		if (key == GLFW_KEY_LEFT) | ||||||
|  | 		{ | ||||||
|  | 			m_xfB.position.x -= 0.105f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_RIGHT) | ||||||
|  | 		{ | ||||||
|  | 			m_xfB.position.x += 0.105f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_UP) | ||||||
|  | 		{ | ||||||
|  | 			m_xfB.position.y += 0.105f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_DOWN) | ||||||
|  | 		{ | ||||||
|  | 			m_xfB.position.y -= 0.105f; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_X) | ||||||
|  | 		{ | ||||||
|  | 			b3Quat qx(b3Vec3(1.0f, 0.0f, 0.0f), 0.05f * B3_PI); | ||||||
|  | 			b3Mat33 xfx = b3QuatMat33(qx); | ||||||
|  |  | ||||||
|  | 			m_xfB.rotation = m_xfB.rotation * xfx; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_Y) | ||||||
|  | 		{ | ||||||
|  | 			b3Quat qy(b3Vec3(0.0f, 1.0f, 0.0f), 0.05f * B3_PI); | ||||||
|  | 			b3Mat33 xfy = b3QuatMat33(qy); | ||||||
|  |  | ||||||
|  | 			m_xfB.rotation = m_xfB.rotation * xfy; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (key == GLFW_KEY_Z) | ||||||
|  | 		{ | ||||||
|  | 			b3Quat qy(b3Vec3(0.0f, 0.0f, 1.0f), 0.05f * B3_PI); | ||||||
|  | 			b3Mat33 xfz = b3QuatMat33(qy); | ||||||
|  |  | ||||||
|  | 			m_xfB.rotation = m_xfB.rotation * xfz; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new ShapeCast(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3HullShape m_shapeA; | ||||||
|  | 	b3Transform m_xfA; | ||||||
|  | 	b3ShapeGJKProxy m_proxyA; | ||||||
|  |  | ||||||
|  | 	b3HullShape m_shapeB; | ||||||
|  | 	b3Transform m_xfB; | ||||||
|  | 	b3ShapeGJKProxy m_proxyB; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										191
									
								
								examples/testbed/tests/spring.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								examples/testbed/tests/spring.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,191 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef SPRING_H | ||||||
|  | #define SPRING_H | ||||||
|  |  | ||||||
|  | class Spring : public Test | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	Spring() | ||||||
|  | 	{ | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bd; | ||||||
|  | 			b3Body* ground = m_world.CreateBody(bd); | ||||||
|  |  | ||||||
|  | 			b3HullShape hs; | ||||||
|  | 			hs.m_hull = &m_groundHull; | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sd; | ||||||
|  | 			sd.shape = &hs; | ||||||
|  | 			 | ||||||
|  | 			ground->CreateShape(sd); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		// Car frame shape | ||||||
|  | 		{ | ||||||
|  | 			b3Transform xf; | ||||||
|  | 			xf.SetIdentity(); | ||||||
|  | 			xf.rotation = b3Diagonal(2.0f, 0.5f, 5.0f); | ||||||
|  |  | ||||||
|  | 			m_frameHull.SetTransform(xf); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3HullShape box; | ||||||
|  | 		box.m_hull = &m_frameHull; | ||||||
|  |  | ||||||
|  | 		// Wheel shape | ||||||
|  | 		b3SphereShape sphere; | ||||||
|  | 		sphere.m_center.SetZero(); | ||||||
|  | 		sphere.m_radius = 1.0f; | ||||||
|  |  | ||||||
|  | 		// Car frame | ||||||
|  | 		b3Body* frame; | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = e_dynamicBody; | ||||||
|  | 			bdef.position.Set(0.0f, 10.0f, 0.0f); | ||||||
|  | 			 | ||||||
|  | 			frame = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 0.3f; | ||||||
|  | 			sdef.shape = &box; | ||||||
|  | 			 | ||||||
|  | 			frame->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		b3Body* wheelLF; | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = e_dynamicBody; | ||||||
|  | 			bdef.position.Set(-1.0f, 7.0f, -4.5f); | ||||||
|  | 			bdef.fixedRotationY = true; | ||||||
|  |  | ||||||
|  | 			wheelLF = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &sphere; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 1.0f; | ||||||
|  | 			 | ||||||
|  | 			wheelLF->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3SpringJointDef def; | ||||||
|  | 			def.Initialize(frame, wheelLF, b3Vec3(-1.0f, 9.0f, -4.5), b3Vec3(-1.0f, 9.0f, -4.5f)); | ||||||
|  | 			def.collideLinked = true; | ||||||
|  | 			def.dampingRatio = 0.5f; | ||||||
|  | 			def.frequencyHz = 4.0f; | ||||||
|  | 			 | ||||||
|  | 			m_world.CreateJoint(def); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Body* wheelRF; | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = e_dynamicBody; | ||||||
|  | 			bdef.position.Set(1.0f, 7.0, -4.5f); | ||||||
|  | 			bdef.fixedRotationY = true; | ||||||
|  |  | ||||||
|  | 			wheelRF = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 1.0f; | ||||||
|  | 			sdef.shape = &sphere; | ||||||
|  | 			 | ||||||
|  | 			wheelRF->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		{ | ||||||
|  | 			b3SpringJointDef def; | ||||||
|  | 			def.Initialize(frame, wheelRF, b3Vec3(1.0f, 9.0, -4.5), b3Vec3(1.0f, 9.0, -4.5f)); | ||||||
|  | 			def.collideLinked = true; | ||||||
|  | 			def.dampingRatio = 0.5f; | ||||||
|  | 			def.frequencyHz = 4.0f; | ||||||
|  |  | ||||||
|  | 			m_world.CreateJoint(def); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		b3Body* wheelLB; | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = e_dynamicBody; | ||||||
|  | 			bdef.position.Set(-1.0f, 7.0f, 4.5f); | ||||||
|  | 			bdef.fixedRotationY = true; | ||||||
|  |  | ||||||
|  | 			wheelLB = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.shape = &sphere; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 1.0f; | ||||||
|  |  | ||||||
|  | 			wheelLB->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3SpringJointDef def; | ||||||
|  | 			def.Initialize(frame, wheelLB, b3Vec3(-1.0f, 9.0f, 4.5f), b3Vec3(-1.0f, 9.0f, 4.5f)); | ||||||
|  | 			def.collideLinked = true; | ||||||
|  | 			def.dampingRatio = 0.8f; | ||||||
|  | 			def.frequencyHz = 4.0f; | ||||||
|  |  | ||||||
|  | 			m_world.CreateJoint(def); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Body* wheelRB; | ||||||
|  | 		{ | ||||||
|  | 			b3BodyDef bdef; | ||||||
|  | 			bdef.type = e_dynamicBody; | ||||||
|  | 			bdef.position.Set(1.0f, 7.0f, 4.5f); | ||||||
|  | 			bdef.fixedRotationY = true; | ||||||
|  |  | ||||||
|  | 			wheelRB = m_world.CreateBody(bdef); | ||||||
|  |  | ||||||
|  | 			b3ShapeDef sdef; | ||||||
|  | 			sdef.density = 0.1f; | ||||||
|  | 			sdef.friction = 1.0f; | ||||||
|  | 			sdef.shape = &sphere; | ||||||
|  |  | ||||||
|  | 			wheelRB->CreateShape(sdef); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		{ | ||||||
|  | 			b3SpringJointDef def; | ||||||
|  | 			def.Initialize(frame, wheelRB, b3Vec3(1.0f, 9.0f, 4.5f), b3Vec3(1.0f, 9.0f, 4.5f)); | ||||||
|  | 			def.collideLinked = true; | ||||||
|  | 			def.frequencyHz = 4.0f; | ||||||
|  | 			def.dampingRatio = 0.8f; | ||||||
|  |  | ||||||
|  | 			m_world.CreateJoint(def); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	static Test* Create() | ||||||
|  | 	{ | ||||||
|  | 		return new Spring(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3BoxHull m_frameHull; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										238
									
								
								external/glfw/mir_init.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										238
									
								
								external/glfw/mir_init.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,238 @@ | |||||||
|  | //======================================================================== | ||||||
|  | // GLFW 3.3 Mir - www.glfw.org | ||||||
|  | //------------------------------------------------------------------------ | ||||||
|  | // Copyright (c) 2014-2015 Brandon Schaefer <brandon.schaefer@canonical.com> | ||||||
|  | // | ||||||
|  | // This software is provided 'as-is', without any express or implied | ||||||
|  | // warranty. In no event will the authors be held liable for any damages | ||||||
|  | // arising from the use of this software. | ||||||
|  | // | ||||||
|  | // Permission is granted to anyone to use this software for any purpose, | ||||||
|  | // including commercial applications, and to alter it and redistribute it | ||||||
|  | // freely, subject to the following restrictions: | ||||||
|  | // | ||||||
|  | // 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | //    claim that you wrote the original software. If you use this software | ||||||
|  | //    in a product, an acknowledgment in the product documentation would | ||||||
|  | //    be appreciated but is not required. | ||||||
|  | // | ||||||
|  | // 2. Altered source versions must be plainly marked as such, and must not | ||||||
|  | //    be misrepresented as being the original software. | ||||||
|  | // | ||||||
|  | // 3. This notice may not be removed or altered from any source | ||||||
|  | //    distribution. | ||||||
|  | // | ||||||
|  | //======================================================================== | ||||||
|  |  | ||||||
|  | #include "internal.h" | ||||||
|  |  | ||||||
|  | #include <linux/input.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Create key code translation tables | ||||||
|  | // | ||||||
|  | static void createKeyTables(void) | ||||||
|  | { | ||||||
|  |     memset(_glfw.mir.publicKeys, -1, sizeof(_glfw.mir.publicKeys)); | ||||||
|  |  | ||||||
|  |     _glfw.mir.publicKeys[KEY_GRAVE]      = GLFW_KEY_GRAVE_ACCENT; | ||||||
|  |     _glfw.mir.publicKeys[KEY_1]          = GLFW_KEY_1; | ||||||
|  |     _glfw.mir.publicKeys[KEY_2]          = GLFW_KEY_2; | ||||||
|  |     _glfw.mir.publicKeys[KEY_3]          = GLFW_KEY_3; | ||||||
|  |     _glfw.mir.publicKeys[KEY_4]          = GLFW_KEY_4; | ||||||
|  |     _glfw.mir.publicKeys[KEY_5]          = GLFW_KEY_5; | ||||||
|  |     _glfw.mir.publicKeys[KEY_6]          = GLFW_KEY_6; | ||||||
|  |     _glfw.mir.publicKeys[KEY_7]          = GLFW_KEY_7; | ||||||
|  |     _glfw.mir.publicKeys[KEY_8]          = GLFW_KEY_8; | ||||||
|  |     _glfw.mir.publicKeys[KEY_9]          = GLFW_KEY_9; | ||||||
|  |     _glfw.mir.publicKeys[KEY_0]          = GLFW_KEY_0; | ||||||
|  |     _glfw.mir.publicKeys[KEY_MINUS]      = GLFW_KEY_MINUS; | ||||||
|  |     _glfw.mir.publicKeys[KEY_EQUAL]      = GLFW_KEY_EQUAL; | ||||||
|  |     _glfw.mir.publicKeys[KEY_Q]          = GLFW_KEY_Q; | ||||||
|  |     _glfw.mir.publicKeys[KEY_W]          = GLFW_KEY_W; | ||||||
|  |     _glfw.mir.publicKeys[KEY_E]          = GLFW_KEY_E; | ||||||
|  |     _glfw.mir.publicKeys[KEY_R]          = GLFW_KEY_R; | ||||||
|  |     _glfw.mir.publicKeys[KEY_T]          = GLFW_KEY_T; | ||||||
|  |     _glfw.mir.publicKeys[KEY_Y]          = GLFW_KEY_Y; | ||||||
|  |     _glfw.mir.publicKeys[KEY_U]          = GLFW_KEY_U; | ||||||
|  |     _glfw.mir.publicKeys[KEY_I]          = GLFW_KEY_I; | ||||||
|  |     _glfw.mir.publicKeys[KEY_O]          = GLFW_KEY_O; | ||||||
|  |     _glfw.mir.publicKeys[KEY_P]          = GLFW_KEY_P; | ||||||
|  |     _glfw.mir.publicKeys[KEY_LEFTBRACE]  = GLFW_KEY_LEFT_BRACKET; | ||||||
|  |     _glfw.mir.publicKeys[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET; | ||||||
|  |     _glfw.mir.publicKeys[KEY_A]          = GLFW_KEY_A; | ||||||
|  |     _glfw.mir.publicKeys[KEY_S]          = GLFW_KEY_S; | ||||||
|  |     _glfw.mir.publicKeys[KEY_D]          = GLFW_KEY_D; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F]          = GLFW_KEY_F; | ||||||
|  |     _glfw.mir.publicKeys[KEY_G]          = GLFW_KEY_G; | ||||||
|  |     _glfw.mir.publicKeys[KEY_H]          = GLFW_KEY_H; | ||||||
|  |     _glfw.mir.publicKeys[KEY_J]          = GLFW_KEY_J; | ||||||
|  |     _glfw.mir.publicKeys[KEY_K]          = GLFW_KEY_K; | ||||||
|  |     _glfw.mir.publicKeys[KEY_L]          = GLFW_KEY_L; | ||||||
|  |     _glfw.mir.publicKeys[KEY_SEMICOLON]  = GLFW_KEY_SEMICOLON; | ||||||
|  |     _glfw.mir.publicKeys[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE; | ||||||
|  |     _glfw.mir.publicKeys[KEY_Z]          = GLFW_KEY_Z; | ||||||
|  |     _glfw.mir.publicKeys[KEY_X]          = GLFW_KEY_X; | ||||||
|  |     _glfw.mir.publicKeys[KEY_C]          = GLFW_KEY_C; | ||||||
|  |     _glfw.mir.publicKeys[KEY_V]          = GLFW_KEY_V; | ||||||
|  |     _glfw.mir.publicKeys[KEY_B]          = GLFW_KEY_B; | ||||||
|  |     _glfw.mir.publicKeys[KEY_N]          = GLFW_KEY_N; | ||||||
|  |     _glfw.mir.publicKeys[KEY_M]          = GLFW_KEY_M; | ||||||
|  |     _glfw.mir.publicKeys[KEY_COMMA]      = GLFW_KEY_COMMA; | ||||||
|  |     _glfw.mir.publicKeys[KEY_DOT]        = GLFW_KEY_PERIOD; | ||||||
|  |     _glfw.mir.publicKeys[KEY_SLASH]      = GLFW_KEY_SLASH; | ||||||
|  |     _glfw.mir.publicKeys[KEY_BACKSLASH]  = GLFW_KEY_BACKSLASH; | ||||||
|  |     _glfw.mir.publicKeys[KEY_ESC]        = GLFW_KEY_ESCAPE; | ||||||
|  |     _glfw.mir.publicKeys[KEY_TAB]        = GLFW_KEY_TAB; | ||||||
|  |     _glfw.mir.publicKeys[KEY_LEFTSHIFT]  = GLFW_KEY_LEFT_SHIFT; | ||||||
|  |     _glfw.mir.publicKeys[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT; | ||||||
|  |     _glfw.mir.publicKeys[KEY_LEFTCTRL]   = GLFW_KEY_LEFT_CONTROL; | ||||||
|  |     _glfw.mir.publicKeys[KEY_RIGHTCTRL]  = GLFW_KEY_RIGHT_CONTROL; | ||||||
|  |     _glfw.mir.publicKeys[KEY_LEFTALT]    = GLFW_KEY_LEFT_ALT; | ||||||
|  |     _glfw.mir.publicKeys[KEY_RIGHTALT]   = GLFW_KEY_RIGHT_ALT; | ||||||
|  |     _glfw.mir.publicKeys[KEY_LEFTMETA]   = GLFW_KEY_LEFT_SUPER; | ||||||
|  |     _glfw.mir.publicKeys[KEY_RIGHTMETA]  = GLFW_KEY_RIGHT_SUPER; | ||||||
|  |     _glfw.mir.publicKeys[KEY_MENU]       = GLFW_KEY_MENU; | ||||||
|  |     _glfw.mir.publicKeys[KEY_NUMLOCK]    = GLFW_KEY_NUM_LOCK; | ||||||
|  |     _glfw.mir.publicKeys[KEY_CAPSLOCK]   = GLFW_KEY_CAPS_LOCK; | ||||||
|  |     _glfw.mir.publicKeys[KEY_PRINT]      = GLFW_KEY_PRINT_SCREEN; | ||||||
|  |     _glfw.mir.publicKeys[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK; | ||||||
|  |     _glfw.mir.publicKeys[KEY_PAUSE]      = GLFW_KEY_PAUSE; | ||||||
|  |     _glfw.mir.publicKeys[KEY_DELETE]     = GLFW_KEY_DELETE; | ||||||
|  |     _glfw.mir.publicKeys[KEY_BACKSPACE]  = GLFW_KEY_BACKSPACE; | ||||||
|  |     _glfw.mir.publicKeys[KEY_ENTER]      = GLFW_KEY_ENTER; | ||||||
|  |     _glfw.mir.publicKeys[KEY_HOME]       = GLFW_KEY_HOME; | ||||||
|  |     _glfw.mir.publicKeys[KEY_END]        = GLFW_KEY_END; | ||||||
|  |     _glfw.mir.publicKeys[KEY_PAGEUP]     = GLFW_KEY_PAGE_UP; | ||||||
|  |     _glfw.mir.publicKeys[KEY_PAGEDOWN]   = GLFW_KEY_PAGE_DOWN; | ||||||
|  |     _glfw.mir.publicKeys[KEY_INSERT]     = GLFW_KEY_INSERT; | ||||||
|  |     _glfw.mir.publicKeys[KEY_LEFT]       = GLFW_KEY_LEFT; | ||||||
|  |     _glfw.mir.publicKeys[KEY_RIGHT]      = GLFW_KEY_RIGHT; | ||||||
|  |     _glfw.mir.publicKeys[KEY_DOWN]       = GLFW_KEY_DOWN; | ||||||
|  |     _glfw.mir.publicKeys[KEY_UP]         = GLFW_KEY_UP; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F1]         = GLFW_KEY_F1; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F2]         = GLFW_KEY_F2; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F3]         = GLFW_KEY_F3; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F4]         = GLFW_KEY_F4; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F5]         = GLFW_KEY_F5; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F6]         = GLFW_KEY_F6; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F7]         = GLFW_KEY_F7; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F8]         = GLFW_KEY_F8; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F9]         = GLFW_KEY_F9; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F10]        = GLFW_KEY_F10; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F11]        = GLFW_KEY_F11; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F12]        = GLFW_KEY_F12; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F13]        = GLFW_KEY_F13; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F14]        = GLFW_KEY_F14; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F15]        = GLFW_KEY_F15; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F16]        = GLFW_KEY_F16; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F17]        = GLFW_KEY_F17; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F18]        = GLFW_KEY_F18; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F19]        = GLFW_KEY_F19; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F20]        = GLFW_KEY_F20; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F21]        = GLFW_KEY_F21; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F22]        = GLFW_KEY_F22; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F23]        = GLFW_KEY_F23; | ||||||
|  |     _glfw.mir.publicKeys[KEY_F24]        = GLFW_KEY_F24; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KPSLASH]    = GLFW_KEY_KP_DIVIDE; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KPDOT]      = GLFW_KEY_KP_MULTIPLY; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KPMINUS]    = GLFW_KEY_KP_SUBTRACT; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KPPLUS]     = GLFW_KEY_KP_ADD; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KP0]        = GLFW_KEY_KP_0; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KP1]        = GLFW_KEY_KP_1; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KP2]        = GLFW_KEY_KP_2; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KP3]        = GLFW_KEY_KP_3; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KP4]        = GLFW_KEY_KP_4; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KP5]        = GLFW_KEY_KP_5; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KP6]        = GLFW_KEY_KP_6; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KP7]        = GLFW_KEY_KP_7; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KP8]        = GLFW_KEY_KP_8; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KP9]        = GLFW_KEY_KP_9; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KPCOMMA]    = GLFW_KEY_KP_DECIMAL; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KPEQUAL]    = GLFW_KEY_KP_EQUAL; | ||||||
|  |     _glfw.mir.publicKeys[KEY_KPENTER]    = GLFW_KEY_KP_ENTER; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | //////                       GLFW internal API                      ////// | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | int _glfwPlatformInit(void) | ||||||
|  | { | ||||||
|  |     int error; | ||||||
|  |  | ||||||
|  |     _glfw.mir.connection = mir_connect_sync(NULL, __PRETTY_FUNCTION__); | ||||||
|  |  | ||||||
|  |     if (!mir_connection_is_valid(_glfw.mir.connection)) | ||||||
|  |     { | ||||||
|  |         _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                         "Mir: Unable to connect to server: %s", | ||||||
|  |                         mir_connection_get_error_message(_glfw.mir.connection)); | ||||||
|  |  | ||||||
|  |         return GLFW_FALSE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _glfw.mir.display = | ||||||
|  |         mir_connection_get_egl_native_display(_glfw.mir.connection); | ||||||
|  |  | ||||||
|  |     createKeyTables(); | ||||||
|  |  | ||||||
|  |     if (!_glfwInitThreadLocalStoragePOSIX()) | ||||||
|  |         return GLFW_FALSE; | ||||||
|  |  | ||||||
|  |     if (!_glfwInitJoysticksLinux()) | ||||||
|  |         return GLFW_FALSE; | ||||||
|  |  | ||||||
|  |     _glfwInitTimerPOSIX(); | ||||||
|  |  | ||||||
|  |     // Need the default conf for when we set a NULL cursor | ||||||
|  |     _glfw.mir.default_conf = mir_cursor_configuration_from_name(mir_arrow_cursor_name); | ||||||
|  |  | ||||||
|  |     _glfw.mir.event_queue = calloc(1, sizeof(EventQueue)); | ||||||
|  |     _glfwInitEventQueueMir(_glfw.mir.event_queue); | ||||||
|  |  | ||||||
|  |     error = pthread_mutex_init(&_glfw.mir.event_mutex, NULL); | ||||||
|  |     if (error) | ||||||
|  |     { | ||||||
|  |         _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                         "Mir: Failed to create event mutex: %s", | ||||||
|  |                         strerror(error)); | ||||||
|  |         return GLFW_FALSE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return GLFW_TRUE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformTerminate(void) | ||||||
|  | { | ||||||
|  |     _glfwTerminateEGL(); | ||||||
|  |     _glfwTerminateJoysticksLinux(); | ||||||
|  |     _glfwTerminateThreadLocalStoragePOSIX(); | ||||||
|  |  | ||||||
|  |     _glfwDeleteEventQueueMir(_glfw.mir.event_queue); | ||||||
|  |  | ||||||
|  |     pthread_mutex_destroy(&_glfw.mir.event_mutex); | ||||||
|  |  | ||||||
|  |     mir_connection_release(_glfw.mir.connection); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const char* _glfwPlatformGetVersionString(void) | ||||||
|  | { | ||||||
|  |     return _GLFW_VERSION_NUMBER " Mir EGL" | ||||||
|  | #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) | ||||||
|  |         " clock_gettime" | ||||||
|  | #else | ||||||
|  |         " gettimeofday" | ||||||
|  | #endif | ||||||
|  | #if defined(__linux__) | ||||||
|  |         " /dev/js" | ||||||
|  | #endif | ||||||
|  | #if defined(_GLFW_BUILD_DLL) | ||||||
|  |         " shared" | ||||||
|  | #endif | ||||||
|  |         ; | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										182
									
								
								external/glfw/mir_monitor.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								external/glfw/mir_monitor.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,182 @@ | |||||||
|  | //======================================================================== | ||||||
|  | // GLFW 3.3 Mir - www.glfw.org | ||||||
|  | //------------------------------------------------------------------------ | ||||||
|  | // Copyright (c) 2014-2015 Brandon Schaefer <brandon.schaefer@canonical.com> | ||||||
|  | // | ||||||
|  | // This software is provided 'as-is', without any express or implied | ||||||
|  | // warranty. In no event will the authors be held liable for any damages | ||||||
|  | // arising from the use of this software. | ||||||
|  | // | ||||||
|  | // Permission is granted to anyone to use this software for any purpose, | ||||||
|  | // including commercial applications, and to alter it and redistribute it | ||||||
|  | // freely, subject to the following restrictions: | ||||||
|  | // | ||||||
|  | // 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | //    claim that you wrote the original software. If you use this software | ||||||
|  | //    in a product, an acknowledgment in the product documentation would | ||||||
|  | //    be appreciated but is not required. | ||||||
|  | // | ||||||
|  | // 2. Altered source versions must be plainly marked as such, and must not | ||||||
|  | //    be misrepresented as being the original software. | ||||||
|  | // | ||||||
|  | // 3. This notice may not be removed or altered from any source | ||||||
|  | //    distribution. | ||||||
|  | // | ||||||
|  | //======================================================================== | ||||||
|  |  | ||||||
|  | #include "internal.h" | ||||||
|  |  | ||||||
|  | #include <stdlib.h> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | //////                       GLFW platform API                      ////// | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | _GLFWmonitor** _glfwPlatformGetMonitors(int* count) | ||||||
|  | { | ||||||
|  |     int i, found = 0; | ||||||
|  |     _GLFWmonitor** monitors = NULL; | ||||||
|  |     MirDisplayConfiguration* displayConfig = | ||||||
|  |         mir_connection_create_display_config(_glfw.mir.connection); | ||||||
|  |  | ||||||
|  |     *count = 0; | ||||||
|  |  | ||||||
|  |     for (i = 0;  i < displayConfig->num_outputs;  i++) | ||||||
|  |     { | ||||||
|  |         const MirDisplayOutput* out = displayConfig->outputs + i; | ||||||
|  |  | ||||||
|  |         if (out->used && | ||||||
|  |             out->connected && | ||||||
|  |             out->num_modes && | ||||||
|  |             out->current_mode < out->num_modes) | ||||||
|  |         { | ||||||
|  |             found++; | ||||||
|  |             monitors        = realloc(monitors, sizeof(_GLFWmonitor*) * found); | ||||||
|  |             monitors[i]     = _glfwAllocMonitor("Unknown", | ||||||
|  |                                                 out->physical_width_mm, | ||||||
|  |                                                 out->physical_height_mm); | ||||||
|  |  | ||||||
|  |             monitors[i]->mir.x         = out->position_x; | ||||||
|  |             monitors[i]->mir.y         = out->position_y; | ||||||
|  |             monitors[i]->mir.output_id = out->output_id; | ||||||
|  |             monitors[i]->mir.cur_mode  = out->current_mode; | ||||||
|  |  | ||||||
|  |             monitors[i]->modes = _glfwPlatformGetVideoModes(monitors[i], | ||||||
|  |                                                             &monitors[i]->modeCount); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     mir_display_config_destroy(displayConfig); | ||||||
|  |  | ||||||
|  |     *count = found; | ||||||
|  |     return monitors; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) | ||||||
|  | { | ||||||
|  |     return first->mir.output_id == second->mir.output_id; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) | ||||||
|  | { | ||||||
|  |     if (xpos) | ||||||
|  |         *xpos = monitor->mir.x; | ||||||
|  |     if (ypos) | ||||||
|  |         *ypos = monitor->mir.y; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void FillInRGBBitsFromPixelFormat(GLFWvidmode* mode, const MirPixelFormat pf) | ||||||
|  | { | ||||||
|  |     switch (pf) | ||||||
|  |     { | ||||||
|  |       case mir_pixel_format_rgb_565: | ||||||
|  |           mode->redBits   = 5; | ||||||
|  |           mode->greenBits = 6; | ||||||
|  |           mode->blueBits  = 5; | ||||||
|  |           break; | ||||||
|  |       case mir_pixel_format_rgba_5551: | ||||||
|  |           mode->redBits   = 5; | ||||||
|  |           mode->greenBits = 5; | ||||||
|  |           mode->blueBits  = 5; | ||||||
|  |           break; | ||||||
|  |       case mir_pixel_format_rgba_4444: | ||||||
|  |           mode->redBits   = 4; | ||||||
|  |           mode->greenBits = 4; | ||||||
|  |           mode->blueBits  = 4; | ||||||
|  |           break; | ||||||
|  |       case mir_pixel_format_abgr_8888: | ||||||
|  |       case mir_pixel_format_xbgr_8888: | ||||||
|  |       case mir_pixel_format_argb_8888: | ||||||
|  |       case mir_pixel_format_xrgb_8888: | ||||||
|  |       case mir_pixel_format_bgr_888: | ||||||
|  |       case mir_pixel_format_rgb_888: | ||||||
|  |       default: | ||||||
|  |           mode->redBits   = 8; | ||||||
|  |           mode->greenBits = 8; | ||||||
|  |           mode->blueBits  = 8; | ||||||
|  |           break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) | ||||||
|  | { | ||||||
|  |     int i; | ||||||
|  |     GLFWvidmode* modes = NULL; | ||||||
|  |     MirDisplayConfiguration* displayConfig = | ||||||
|  |         mir_connection_create_display_config(_glfw.mir.connection); | ||||||
|  |  | ||||||
|  |     for (i = 0;  i < displayConfig->num_outputs;  i++) | ||||||
|  |     { | ||||||
|  |         const MirDisplayOutput* out = displayConfig->outputs + i; | ||||||
|  |         if (out->output_id != monitor->mir.output_id) | ||||||
|  |             continue; | ||||||
|  |  | ||||||
|  |         modes = calloc(out->num_modes, sizeof(GLFWvidmode)); | ||||||
|  |  | ||||||
|  |         for (*found = 0;  *found < out->num_modes;  (*found)++) | ||||||
|  |         { | ||||||
|  |             modes[*found].width  = out->modes[*found].horizontal_resolution; | ||||||
|  |             modes[*found].height = out->modes[*found].vertical_resolution; | ||||||
|  |             modes[*found].refreshRate = out->modes[*found].refresh_rate; | ||||||
|  |  | ||||||
|  |             FillInRGBBitsFromPixelFormat(&modes[*found], out->output_formats[*found]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     mir_display_config_destroy(displayConfig); | ||||||
|  |  | ||||||
|  |     return modes; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) | ||||||
|  | { | ||||||
|  |     *mode = monitor->modes[monitor->mir.cur_mode]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | //////                        GLFW native API                       ////// | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | GLFWAPI int glfwGetMirMonitor(GLFWmonitor* handle) | ||||||
|  | { | ||||||
|  |     _GLFWmonitor* monitor = (_GLFWmonitor*) handle; | ||||||
|  |     _GLFW_REQUIRE_INIT_OR_RETURN(0); | ||||||
|  |     return monitor->mir.output_id; | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										130
									
								
								external/glfw/mir_platform.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								external/glfw/mir_platform.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | |||||||
|  | //======================================================================== | ||||||
|  | // GLFW 3.3 Mir - www.glfw.org | ||||||
|  | //------------------------------------------------------------------------ | ||||||
|  | // Copyright (c) 2014-2015 Brandon Schaefer <brandon.schaefer@canonical.com> | ||||||
|  | // | ||||||
|  | // This software is provided 'as-is', without any express or implied | ||||||
|  | // warranty. In no event will the authors be held liable for any damages | ||||||
|  | // arising from the use of this software. | ||||||
|  | // | ||||||
|  | // Permission is granted to anyone to use this software for any purpose, | ||||||
|  | // including commercial applications, and to alter it and redistribute it | ||||||
|  | // freely, subject to the following restrictions: | ||||||
|  | // | ||||||
|  | // 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | //    claim that you wrote the original software. If you use this software | ||||||
|  | //    in a product, an acknowledgment in the product documentation would | ||||||
|  | //    be appreciated but is not required. | ||||||
|  | // | ||||||
|  | // 2. Altered source versions must be plainly marked as such, and must not | ||||||
|  | //    be misrepresented as being the original software. | ||||||
|  | // | ||||||
|  | // 3. This notice may not be removed or altered from any source | ||||||
|  | //    distribution. | ||||||
|  | // | ||||||
|  | //======================================================================== | ||||||
|  |  | ||||||
|  | #ifndef _glfw3_mir_platform_h_ | ||||||
|  | #define _glfw3_mir_platform_h_ | ||||||
|  |  | ||||||
|  | #include <sys/queue.h> | ||||||
|  | #include <pthread.h> | ||||||
|  | #include <dlfcn.h> | ||||||
|  |  | ||||||
|  | #include <mir_toolkit/mir_client_library.h> | ||||||
|  |  | ||||||
|  | typedef VkFlags VkMirSurfaceCreateFlagsKHR; | ||||||
|  |  | ||||||
|  | typedef struct VkMirSurfaceCreateInfoKHR | ||||||
|  | { | ||||||
|  |     VkStructureType             sType; | ||||||
|  |     const void*                 pNext; | ||||||
|  |     VkMirSurfaceCreateFlagsKHR  flags; | ||||||
|  |     MirConnection*              connection; | ||||||
|  |     MirSurface*                 mirSurface; | ||||||
|  | } VkMirSurfaceCreateInfoKHR; | ||||||
|  |  | ||||||
|  | typedef VkResult (APIENTRY *PFN_vkCreateMirSurfaceKHR)(VkInstance,const VkMirSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*); | ||||||
|  | typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice,uint32_t,MirConnection*); | ||||||
|  |  | ||||||
|  | #include "posix_tls.h" | ||||||
|  | #include "posix_time.h" | ||||||
|  | #include "linux_joystick.h" | ||||||
|  | #include "xkb_unicode.h" | ||||||
|  | #include "egl_context.h" | ||||||
|  |  | ||||||
|  | #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) | ||||||
|  | #define _glfw_dlclose(handle) dlclose(handle) | ||||||
|  | #define _glfw_dlsym(handle, name) dlsym(handle, name) | ||||||
|  |  | ||||||
|  | #define _GLFW_EGL_NATIVE_WINDOW  ((EGLNativeWindowType) window->mir.window) | ||||||
|  | #define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.mir.display) | ||||||
|  |  | ||||||
|  | #define _GLFW_PLATFORM_WINDOW_STATE         _GLFWwindowMir  mir | ||||||
|  | #define _GLFW_PLATFORM_MONITOR_STATE        _GLFWmonitorMir mir | ||||||
|  | #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryMir mir | ||||||
|  | #define _GLFW_PLATFORM_CURSOR_STATE         _GLFWcursorMir  mir | ||||||
|  |  | ||||||
|  | #define _GLFW_PLATFORM_CONTEXT_STATE | ||||||
|  | #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Mir-specific Event Queue | ||||||
|  | // | ||||||
|  | typedef struct EventQueue | ||||||
|  | { | ||||||
|  |     TAILQ_HEAD(, EventNode) head; | ||||||
|  | } EventQueue; | ||||||
|  |  | ||||||
|  | // Mir-specific per-window data | ||||||
|  | // | ||||||
|  | typedef struct _GLFWwindowMir | ||||||
|  | { | ||||||
|  |     MirSurface*             surface; | ||||||
|  |     int                     width; | ||||||
|  |     int                     height; | ||||||
|  |     MirEGLNativeWindowType  window; | ||||||
|  |  | ||||||
|  | } _GLFWwindowMir; | ||||||
|  |  | ||||||
|  | // Mir-specific per-monitor data | ||||||
|  | // | ||||||
|  | typedef struct _GLFWmonitorMir | ||||||
|  | { | ||||||
|  |     int cur_mode; | ||||||
|  |     int output_id; | ||||||
|  |     int x; | ||||||
|  |     int y; | ||||||
|  |  | ||||||
|  | } _GLFWmonitorMir; | ||||||
|  |  | ||||||
|  | // Mir-specific global data | ||||||
|  | // | ||||||
|  | typedef struct _GLFWlibraryMir | ||||||
|  | { | ||||||
|  |     MirConnection*          connection; | ||||||
|  |     MirEGLNativeDisplayType display; | ||||||
|  |     MirCursorConfiguration* default_conf; | ||||||
|  |     EventQueue* event_queue; | ||||||
|  |  | ||||||
|  |     short int       publicKeys[256]; | ||||||
|  |  | ||||||
|  |     pthread_mutex_t event_mutex; | ||||||
|  |     pthread_cond_t  event_cond; | ||||||
|  |  | ||||||
|  | } _GLFWlibraryMir; | ||||||
|  |  | ||||||
|  | // Mir-specific per-cursor data | ||||||
|  | // TODO: Only system cursors are implemented in Mir atm. Need to wait for support. | ||||||
|  | // | ||||||
|  | typedef struct _GLFWcursorMir | ||||||
|  | { | ||||||
|  |     MirCursorConfiguration* conf; | ||||||
|  |     MirBufferStream*        custom_cursor; | ||||||
|  | } _GLFWcursorMir; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | extern void _glfwInitEventQueueMir(EventQueue* queue); | ||||||
|  | extern void _glfwDeleteEventQueueMir(EventQueue* queue); | ||||||
|  |  | ||||||
|  | #endif // _glfw3_mir_platform_h_ | ||||||
							
								
								
									
										848
									
								
								external/glfw/mir_window.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										848
									
								
								external/glfw/mir_window.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,848 @@ | |||||||
|  | //======================================================================== | ||||||
|  | // GLFW 3.3 Mir - www.glfw.org | ||||||
|  | //------------------------------------------------------------------------ | ||||||
|  | // Copyright (c) 2014-2015 Brandon Schaefer <brandon.schaefer@canonical.com> | ||||||
|  | // | ||||||
|  | // This software is provided 'as-is', without any express or implied | ||||||
|  | // warranty. In no event will the authors be held liable for any damages | ||||||
|  | // arising from the use of this software. | ||||||
|  | // | ||||||
|  | // Permission is granted to anyone to use this software for any purpose, | ||||||
|  | // including commercial applications, and to alter it and redistribute it | ||||||
|  | // freely, subject to the following restrictions: | ||||||
|  | // | ||||||
|  | // 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | //    claim that you wrote the original software. If you use this software | ||||||
|  | //    in a product, an acknowledgment in the product documentation would | ||||||
|  | //    be appreciated but is not required. | ||||||
|  | // | ||||||
|  | // 2. Altered source versions must be plainly marked as such, and must not | ||||||
|  | //    be misrepresented as being the original software. | ||||||
|  | // | ||||||
|  | // 3. This notice may not be removed or altered from any source | ||||||
|  | //    distribution. | ||||||
|  | // | ||||||
|  | //======================================================================== | ||||||
|  |  | ||||||
|  | #include "internal.h" | ||||||
|  |  | ||||||
|  | #include <linux/input.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | typedef struct EventNode | ||||||
|  | { | ||||||
|  |     TAILQ_ENTRY(EventNode) entries; | ||||||
|  |     const MirEvent*        event; | ||||||
|  |     _GLFWwindow*           window; | ||||||
|  | } EventNode; | ||||||
|  |  | ||||||
|  | static void deleteNode(EventQueue* queue, EventNode* node) | ||||||
|  | { | ||||||
|  |     mir_event_unref(node->event); | ||||||
|  |     free(node); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static GLFWbool emptyEventQueue(EventQueue* queue) | ||||||
|  | { | ||||||
|  |     return queue->head.tqh_first == NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // TODO The mir_event_ref is not supposed to be used but ... its needed | ||||||
|  | //      in this case. Need to wait until we can read from an FD set up by mir | ||||||
|  | //      for single threaded event handling. | ||||||
|  | static EventNode* newEventNode(const MirEvent* event, _GLFWwindow* context) | ||||||
|  | { | ||||||
|  |     EventNode* new_node = calloc(1, sizeof(EventNode)); | ||||||
|  |     new_node->event     = mir_event_ref(event); | ||||||
|  |     new_node->window    = context; | ||||||
|  |  | ||||||
|  |     return new_node; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void enqueueEvent(const MirEvent* event, _GLFWwindow* context) | ||||||
|  | { | ||||||
|  |     pthread_mutex_lock(&_glfw.mir.event_mutex); | ||||||
|  |  | ||||||
|  |     EventNode* new_node = newEventNode(event, context); | ||||||
|  |     TAILQ_INSERT_TAIL(&_glfw.mir.event_queue->head, new_node, entries); | ||||||
|  |  | ||||||
|  |     pthread_cond_signal(&_glfw.mir.event_cond); | ||||||
|  |  | ||||||
|  |     pthread_mutex_unlock(&_glfw.mir.event_mutex); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static EventNode* dequeueEvent(EventQueue* queue) | ||||||
|  | { | ||||||
|  |     EventNode* node = NULL; | ||||||
|  |  | ||||||
|  |     pthread_mutex_lock(&_glfw.mir.event_mutex); | ||||||
|  |  | ||||||
|  |     node = queue->head.tqh_first; | ||||||
|  |  | ||||||
|  |     if (node) | ||||||
|  |         TAILQ_REMOVE(&queue->head, node, entries); | ||||||
|  |  | ||||||
|  |     pthread_mutex_unlock(&_glfw.mir.event_mutex); | ||||||
|  |  | ||||||
|  |     return node; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* FIXME Soon to be changed upstream mir! So we can use an egl config to figure out | ||||||
|  |          the best pixel format! | ||||||
|  | */ | ||||||
|  | static MirPixelFormat findValidPixelFormat(void) | ||||||
|  | { | ||||||
|  |     unsigned int i, validFormats, mirPixelFormats = 32; | ||||||
|  |     MirPixelFormat formats[mir_pixel_formats]; | ||||||
|  |  | ||||||
|  |     mir_connection_get_available_surface_formats(_glfw.mir.connection, formats, | ||||||
|  |                                                  mirPixelFormats, &validFormats); | ||||||
|  |  | ||||||
|  |     for (i = 0;  i < validFormats;  i++) | ||||||
|  |     { | ||||||
|  |         if (formats[i] == mir_pixel_format_abgr_8888 || | ||||||
|  |             formats[i] == mir_pixel_format_xbgr_8888 || | ||||||
|  |             formats[i] == mir_pixel_format_argb_8888 || | ||||||
|  |             formats[i] == mir_pixel_format_xrgb_8888) | ||||||
|  |         { | ||||||
|  |             return formats[i]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return mir_pixel_format_invalid; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int mirModToGLFWMod(uint32_t mods) | ||||||
|  | { | ||||||
|  |     int publicMods = 0x0; | ||||||
|  |  | ||||||
|  |     if (mods & mir_input_event_modifier_alt) | ||||||
|  |         publicMods |= GLFW_MOD_ALT; | ||||||
|  |     else if (mods & mir_input_event_modifier_shift) | ||||||
|  |         publicMods |= GLFW_MOD_SHIFT; | ||||||
|  |     else if (mods & mir_input_event_modifier_ctrl) | ||||||
|  |         publicMods |= GLFW_MOD_CONTROL; | ||||||
|  |     else if (mods & mir_input_event_modifier_meta) | ||||||
|  |         publicMods |= GLFW_MOD_SUPER; | ||||||
|  |  | ||||||
|  |     return publicMods; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int toGLFWKeyCode(uint32_t key) | ||||||
|  | { | ||||||
|  |     if (key < sizeof(_glfw.mir.publicKeys) / sizeof(_glfw.mir.publicKeys[0])) | ||||||
|  |         return _glfw.mir.publicKeys[key]; | ||||||
|  |  | ||||||
|  |     return GLFW_KEY_UNKNOWN; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void handleKeyEvent(const MirKeyboardEvent* key_event, _GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     const int action    = mir_keyboard_event_action   (key_event); | ||||||
|  |     const int scan_code = mir_keyboard_event_scan_code(key_event); | ||||||
|  |     const int key_code  = mir_keyboard_event_key_code (key_event); | ||||||
|  |     const int modifiers = mir_keyboard_event_modifiers(key_event); | ||||||
|  |  | ||||||
|  |     const int  pressed = action == mir_keyboard_action_up ? GLFW_RELEASE : GLFW_PRESS; | ||||||
|  |     const int  mods    = mirModToGLFWMod(modifiers); | ||||||
|  |     const long text    = _glfwKeySym2Unicode(key_code); | ||||||
|  |     const int  plain   = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); | ||||||
|  |  | ||||||
|  |     _glfwInputKey(window, toGLFWKeyCode(scan_code), scan_code, pressed, mods); | ||||||
|  |  | ||||||
|  |     if (text != -1) | ||||||
|  |         _glfwInputChar(window, text, mods, plain); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void handlePointerButton(_GLFWwindow* window, | ||||||
|  |                               int pressed, | ||||||
|  |                               const MirPointerEvent* pointer_event) | ||||||
|  | { | ||||||
|  |     int mods                = mir_pointer_event_modifiers(pointer_event); | ||||||
|  |     const int publicMods    = mirModToGLFWMod(mods); | ||||||
|  |     MirPointerButton button = mir_pointer_button_primary; | ||||||
|  |     static uint32_t oldButtonStates = 0; | ||||||
|  |     uint32_t newButtonStates        = mir_pointer_event_buttons(pointer_event); | ||||||
|  |     int publicButton                = GLFW_MOUSE_BUTTON_LEFT; | ||||||
|  |  | ||||||
|  |     // XOR our old button states our new states to figure out what was added or removed | ||||||
|  |     button = newButtonStates ^ oldButtonStates; | ||||||
|  |  | ||||||
|  |     switch (button) | ||||||
|  |     { | ||||||
|  |         case mir_pointer_button_primary: | ||||||
|  |             publicButton = GLFW_MOUSE_BUTTON_LEFT; | ||||||
|  |             break; | ||||||
|  |         case mir_pointer_button_secondary: | ||||||
|  |             publicButton = GLFW_MOUSE_BUTTON_RIGHT; | ||||||
|  |             break; | ||||||
|  |         case mir_pointer_button_tertiary: | ||||||
|  |             publicButton = GLFW_MOUSE_BUTTON_MIDDLE; | ||||||
|  |             break; | ||||||
|  |         case mir_pointer_button_forward: | ||||||
|  |             // FIXME What is the forward button? | ||||||
|  |             publicButton = GLFW_MOUSE_BUTTON_4; | ||||||
|  |             break; | ||||||
|  |         case mir_pointer_button_back: | ||||||
|  |             // FIXME What is the back button? | ||||||
|  |             publicButton = GLFW_MOUSE_BUTTON_5; | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     oldButtonStates = newButtonStates; | ||||||
|  |  | ||||||
|  |     _glfwInputMouseClick(window, publicButton, pressed, publicMods); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void handlePointerMotion(_GLFWwindow* window, | ||||||
|  |                                 const MirPointerEvent* pointer_event) | ||||||
|  | { | ||||||
|  |     int current_x = window->virtualCursorPosX; | ||||||
|  |     int current_y = window->virtualCursorPosY; | ||||||
|  |     int x  = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x); | ||||||
|  |     int y  = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y); | ||||||
|  |     int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll); | ||||||
|  |     int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll); | ||||||
|  |  | ||||||
|  |     _glfwInputCursorPos(window, x, y); | ||||||
|  |     if (dx != 0 || dy != 0) | ||||||
|  |       _glfwInputScroll(window, dx, dy); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void handlePointerEvent(const MirPointerEvent* pointer_event, | ||||||
|  |                              _GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     int action = mir_pointer_event_action(pointer_event); | ||||||
|  |  | ||||||
|  |     switch (action) | ||||||
|  |     { | ||||||
|  |           case mir_pointer_action_button_down: | ||||||
|  |               handlePointerButton(window, GLFW_PRESS, pointer_event); | ||||||
|  |               break; | ||||||
|  |           case mir_pointer_action_button_up: | ||||||
|  |               handlePointerButton(window, GLFW_RELEASE, pointer_event); | ||||||
|  |               break; | ||||||
|  |           case mir_pointer_action_motion: | ||||||
|  |               handlePointerMotion(window, pointer_event); | ||||||
|  |               break; | ||||||
|  |           case mir_pointer_action_enter: | ||||||
|  |           case mir_pointer_action_leave: | ||||||
|  |               break; | ||||||
|  |           default: | ||||||
|  |               break; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void handleInput(const MirInputEvent* input_event, _GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     int type = mir_input_event_get_type(input_event); | ||||||
|  |  | ||||||
|  |     switch (type) | ||||||
|  |     { | ||||||
|  |         case mir_input_event_type_key: | ||||||
|  |             handleKeyEvent(mir_input_event_get_keyboard_event(input_event), window); | ||||||
|  |             break; | ||||||
|  |         case mir_input_event_type_pointer: | ||||||
|  |             handlePointerEvent(mir_input_event_get_pointer_event(input_event), window); | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void handleEvent(const MirEvent* event, _GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     int type = mir_event_get_type(event); | ||||||
|  |  | ||||||
|  |     switch (type) | ||||||
|  |     { | ||||||
|  |         case mir_event_type_input: | ||||||
|  |             handleInput(mir_event_get_input_event(event), window); | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void addNewEvent(MirSurface* surface, const MirEvent* event, void* context) | ||||||
|  | { | ||||||
|  |     enqueueEvent(event, context); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static GLFWbool createSurface(_GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     MirSurfaceSpec* spec; | ||||||
|  |     MirBufferUsage buffer_usage = mir_buffer_usage_hardware; | ||||||
|  |     MirPixelFormat pixel_format = findValidPixelFormat(); | ||||||
|  |  | ||||||
|  |     if (pixel_format == mir_pixel_format_invalid) | ||||||
|  |     { | ||||||
|  |         _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                         "Mir: Unable to find a correct pixel format"); | ||||||
|  |         return GLFW_FALSE; | ||||||
|  |     } | ||||||
|  |   | ||||||
|  |     spec = mir_connection_create_spec_for_normal_surface(_glfw.mir.connection, | ||||||
|  |                                                          window->mir.width, | ||||||
|  |                                                          window->mir.height, | ||||||
|  |                                                          pixel_format); | ||||||
|  |  | ||||||
|  |     mir_surface_spec_set_buffer_usage(spec, buffer_usage); | ||||||
|  |     mir_surface_spec_set_name(spec, "MirSurface"); | ||||||
|  |  | ||||||
|  |     window->mir.surface = mir_surface_create_sync(spec); | ||||||
|  |     mir_surface_spec_release(spec); | ||||||
|  |  | ||||||
|  |     if (!mir_surface_is_valid(window->mir.surface)) | ||||||
|  |     { | ||||||
|  |         _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                         "Mir: Unable to create surface: %s", | ||||||
|  |                         mir_surface_get_error_message(window->mir.surface)); | ||||||
|  |  | ||||||
|  |         return GLFW_FALSE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     mir_surface_set_event_handler(window->mir.surface, addNewEvent, window); | ||||||
|  |  | ||||||
|  |     return GLFW_TRUE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | //////                       GLFW internal API                      ////// | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | void _glfwInitEventQueueMir(EventQueue* queue) | ||||||
|  | { | ||||||
|  |     TAILQ_INIT(&queue->head); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwDeleteEventQueueMir(EventQueue* queue) | ||||||
|  | { | ||||||
|  |     if (queue) | ||||||
|  |     { | ||||||
|  |         EventNode* node, *node_next; | ||||||
|  |         node = queue->head.tqh_first; | ||||||
|  |  | ||||||
|  |         while (node != NULL) | ||||||
|  |         { | ||||||
|  |             node_next = node->entries.tqe_next; | ||||||
|  |  | ||||||
|  |             TAILQ_REMOVE(&queue->head, node, entries); | ||||||
|  |             deleteNode(queue, node); | ||||||
|  |  | ||||||
|  |             node = node_next; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         free(queue); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | //////                       GLFW platform API                      ////// | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | int _glfwPlatformCreateWindow(_GLFWwindow* window, | ||||||
|  |                               const _GLFWwndconfig* wndconfig, | ||||||
|  |                               const _GLFWctxconfig* ctxconfig, | ||||||
|  |                               const _GLFWfbconfig* fbconfig) | ||||||
|  | { | ||||||
|  |     if (window->monitor) | ||||||
|  |     { | ||||||
|  |         GLFWvidmode mode; | ||||||
|  |         _glfwPlatformGetVideoMode(window->monitor, &mode); | ||||||
|  |  | ||||||
|  |         mir_surface_set_state(window->mir.surface, mir_surface_state_fullscreen); | ||||||
|  |  | ||||||
|  |         if (wndconfig->width > mode.width || wndconfig->height > mode.height) | ||||||
|  |         { | ||||||
|  |             _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                             "Mir: Requested surface size too large: %ix%i", | ||||||
|  |                             wndconfig->width, wndconfig->height); | ||||||
|  |  | ||||||
|  |             return GLFW_FALSE; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     window->mir.width  = wndconfig->width; | ||||||
|  |     window->mir.height = wndconfig->height; | ||||||
|  |  | ||||||
|  |     if (!createSurface(window)) | ||||||
|  |         return GLFW_FALSE; | ||||||
|  |  | ||||||
|  |     window->mir.window = mir_buffer_stream_get_egl_native_window( | ||||||
|  |                                    mir_surface_get_buffer_stream(window->mir.surface)); | ||||||
|  |  | ||||||
|  |     if (ctxconfig->client != GLFW_NO_API) | ||||||
|  |     { | ||||||
|  |         if (!_glfwInitEGL()) | ||||||
|  |             return GLFW_FALSE; | ||||||
|  |         if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) | ||||||
|  |             return GLFW_FALSE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return GLFW_TRUE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformDestroyWindow(_GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     if (mir_surface_is_valid(window->mir.surface)) | ||||||
|  |     { | ||||||
|  |         mir_surface_release_sync(window->mir.surface); | ||||||
|  |         window->mir.surface = NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (window->context.destroy) | ||||||
|  |         window->context.destroy(window); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) | ||||||
|  | { | ||||||
|  |     MirSurfaceSpec* spec; | ||||||
|  |     const char* e_title = title ? title : ""; | ||||||
|  |  | ||||||
|  |     spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); | ||||||
|  |     mir_surface_spec_set_name(spec, e_title); | ||||||
|  |  | ||||||
|  |     mir_surface_apply_spec(window->mir.surface, spec); | ||||||
|  |     mir_surface_spec_release(spec); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformSetWindowIcon(_GLFWwindow* window, | ||||||
|  |                                 int count, const GLFWimage* images) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) | ||||||
|  | { | ||||||
|  |     MirSurfaceSpec* spec; | ||||||
|  |  | ||||||
|  |     spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); | ||||||
|  |     mir_surface_spec_set_width (spec, width); | ||||||
|  |     mir_surface_spec_set_height(spec, height); | ||||||
|  |  | ||||||
|  |     mir_surface_apply_spec(window->mir.surface, spec); | ||||||
|  |     mir_surface_spec_release(spec); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, | ||||||
|  |                                       int minwidth, int minheight, | ||||||
|  |                                       int maxwidth, int maxheight) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, | ||||||
|  |                                      int* left, int* top, | ||||||
|  |                                      int* right, int* bottom) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) | ||||||
|  | { | ||||||
|  |     if (width) | ||||||
|  |         *width  = window->mir.width; | ||||||
|  |     if (height) | ||||||
|  |         *height = window->mir.height; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformIconifyWindow(_GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     mir_surface_set_state(window->mir.surface, mir_surface_state_minimized); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformRestoreWindow(_GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     mir_surface_set_state(window->mir.surface, mir_surface_state_restored); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformMaximizeWindow(_GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformHideWindow(_GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     MirSurfaceSpec* spec; | ||||||
|  |  | ||||||
|  |     spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); | ||||||
|  |     mir_surface_spec_set_state(spec, mir_surface_state_hidden); | ||||||
|  |  | ||||||
|  |     mir_surface_apply_spec(window->mir.surface, spec); | ||||||
|  |     mir_surface_spec_release(spec); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformShowWindow(_GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     MirSurfaceSpec* spec; | ||||||
|  |  | ||||||
|  |     spec = mir_connection_create_spec_for_changes(_glfw.mir.connection); | ||||||
|  |     mir_surface_spec_set_state(spec, mir_surface_state_restored); | ||||||
|  |  | ||||||
|  |     mir_surface_apply_spec(window->mir.surface, spec); | ||||||
|  |     mir_surface_spec_release(spec); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformFocusWindow(_GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, | ||||||
|  |                                    _GLFWmonitor* monitor, | ||||||
|  |                                    int xpos, int ypos, | ||||||
|  |                                    int width, int height, | ||||||
|  |                                    int refreshRate) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int _glfwPlatformWindowFocused(_GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  |     return GLFW_FALSE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int _glfwPlatformWindowIconified(_GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  |     return GLFW_FALSE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int _glfwPlatformWindowVisible(_GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     return mir_surface_get_visibility(window->mir.surface) == mir_surface_visibility_exposed; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int _glfwPlatformWindowMaximized(_GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  |     return GLFW_FALSE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformPollEvents(void) | ||||||
|  | { | ||||||
|  |     EventNode* node = NULL; | ||||||
|  |  | ||||||
|  |     while ((node = dequeueEvent(_glfw.mir.event_queue))) | ||||||
|  |     { | ||||||
|  |         handleEvent(node->event, node->window); | ||||||
|  |         deleteNode(_glfw.mir.event_queue, node); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformWaitEvents(void) | ||||||
|  | { | ||||||
|  |     pthread_mutex_lock(&_glfw.mir.event_mutex); | ||||||
|  |  | ||||||
|  |     if (emptyEventQueue(_glfw.mir.event_queue)) | ||||||
|  |         pthread_cond_wait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex); | ||||||
|  |  | ||||||
|  |     pthread_mutex_unlock(&_glfw.mir.event_mutex); | ||||||
|  |  | ||||||
|  |     _glfwPlatformPollEvents(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformWaitEventsTimeout(double timeout) | ||||||
|  | { | ||||||
|  |     pthread_mutex_lock(&_glfw.mir.event_mutex); | ||||||
|  |  | ||||||
|  |     if (emptyEventQueue(_glfw.mir.event_queue)) | ||||||
|  |     { | ||||||
|  |         struct timespec time; | ||||||
|  |         clock_gettime(CLOCK_REALTIME, &time); | ||||||
|  |         time.tv_sec += (long) timeout; | ||||||
|  |         time.tv_nsec += (long) ((timeout - (long) timeout) * 1e9); | ||||||
|  |         pthread_cond_timedwait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex, &time); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pthread_mutex_unlock(&_glfw.mir.event_mutex); | ||||||
|  |  | ||||||
|  |     _glfwPlatformPollEvents(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformPostEmptyEvent(void) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) | ||||||
|  | { | ||||||
|  |     if (width) | ||||||
|  |         *width  = window->mir.width; | ||||||
|  |     if (height) | ||||||
|  |         *height = window->mir.height; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // FIXME implement | ||||||
|  | int _glfwPlatformCreateCursor(_GLFWcursor* cursor, | ||||||
|  |                               const GLFWimage* image, | ||||||
|  |                               int xhot, int yhot) | ||||||
|  | { | ||||||
|  |     MirBufferStream* stream; | ||||||
|  |     MirPixelFormat pixel_format = findValidPixelFormat(); | ||||||
|  |  | ||||||
|  |     int i_w = image->width; | ||||||
|  |     int i_h = image->height; | ||||||
|  |  | ||||||
|  |     if (pixel_format == mir_pixel_format_invalid) | ||||||
|  |     { | ||||||
|  |         _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                         "Mir: Unable to find a correct pixel format"); | ||||||
|  |         return GLFW_FALSE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     stream = mir_connection_create_buffer_stream_sync(_glfw.mir.connection, | ||||||
|  |                                                       i_w, i_h, | ||||||
|  |                                                       pixel_format, | ||||||
|  |                                                       mir_buffer_usage_software); | ||||||
|  |  | ||||||
|  |     cursor->mir.conf = mir_cursor_configuration_from_buffer_stream(stream, xhot, yhot); | ||||||
|  |  | ||||||
|  |     char* dest; | ||||||
|  |     unsigned char *pixels; | ||||||
|  |     int i, r_stride, bytes_per_pixel, bytes_per_row; | ||||||
|  |  | ||||||
|  |     MirGraphicsRegion region; | ||||||
|  |     mir_buffer_stream_get_graphics_region(stream, ®ion); | ||||||
|  |  | ||||||
|  |     // FIXME Figure this out based on the current_pf | ||||||
|  |     bytes_per_pixel = 4; | ||||||
|  |     bytes_per_row   = bytes_per_pixel * i_w; | ||||||
|  |  | ||||||
|  |     dest   = region.vaddr; | ||||||
|  |     pixels = image->pixels; | ||||||
|  |  | ||||||
|  |     r_stride = region.stride; | ||||||
|  |  | ||||||
|  |     for (i = 0; i < i_h; i++) | ||||||
|  |     { | ||||||
|  |         memcpy(dest, pixels, bytes_per_row); | ||||||
|  |         dest   += r_stride; | ||||||
|  |         pixels += r_stride; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     cursor->mir.custom_cursor = stream; | ||||||
|  |  | ||||||
|  |     return GLFW_TRUE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const char* getSystemCursorName(int shape) | ||||||
|  | { | ||||||
|  |     switch (shape) | ||||||
|  |     { | ||||||
|  |         case GLFW_ARROW_CURSOR: | ||||||
|  |             return mir_arrow_cursor_name; | ||||||
|  |         case GLFW_IBEAM_CURSOR: | ||||||
|  |             return mir_caret_cursor_name; | ||||||
|  |         case GLFW_CROSSHAIR_CURSOR: | ||||||
|  |             return mir_crosshair_cursor_name; | ||||||
|  |         case GLFW_HAND_CURSOR: | ||||||
|  |             return mir_open_hand_cursor_name; | ||||||
|  |         case GLFW_HRESIZE_CURSOR: | ||||||
|  |             return mir_horizontal_resize_cursor_name; | ||||||
|  |         case GLFW_VRESIZE_CURSOR: | ||||||
|  |             return mir_vertical_resize_cursor_name; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) | ||||||
|  | { | ||||||
|  |     const char* cursor_name = getSystemCursorName(shape); | ||||||
|  |  | ||||||
|  |     if (cursor_name) | ||||||
|  |     { | ||||||
|  |         cursor->mir.conf          = mir_cursor_configuration_from_name(cursor_name); | ||||||
|  |         cursor->mir.custom_cursor = NULL; | ||||||
|  |  | ||||||
|  |         return GLFW_TRUE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return GLFW_FALSE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) | ||||||
|  | { | ||||||
|  |     if (cursor->mir.conf) | ||||||
|  |         mir_cursor_configuration_destroy(cursor->mir.conf); | ||||||
|  |     if (cursor->mir.custom_cursor) | ||||||
|  |         mir_buffer_stream_release_sync(cursor->mir.custom_cursor); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) | ||||||
|  | { | ||||||
|  |     if (cursor && cursor->mir.conf) | ||||||
|  |     { | ||||||
|  |         mir_wait_for(mir_surface_configure_cursor(window->mir.surface, cursor->mir.conf)); | ||||||
|  |         if (cursor->mir.custom_cursor) | ||||||
|  |         { | ||||||
|  |             mir_buffer_stream_swap_buffers_sync(cursor->mir.custom_cursor); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.default_conf)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const char* _glfwPlatformGetKeyName(int key, int scancode) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__); | ||||||
|  |  | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count) | ||||||
|  | { | ||||||
|  |     char** extensions; | ||||||
|  |  | ||||||
|  |     *count = 0; | ||||||
|  |  | ||||||
|  |     if (!_glfw.vk.KHR_mir_surface) | ||||||
|  |         return NULL; | ||||||
|  |  | ||||||
|  |     extensions = calloc(2, sizeof(char*)); | ||||||
|  |     extensions[0] = strdup("VK_KHR_surface"); | ||||||
|  |     extensions[1] = strdup("VK_KHR_mir_surface"); | ||||||
|  |  | ||||||
|  |     *count = 2; | ||||||
|  |     return extensions; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, | ||||||
|  |                                                       VkPhysicalDevice device, | ||||||
|  |                                                       uint32_t queuefamily) | ||||||
|  | { | ||||||
|  |     PFN_vkGetPhysicalDeviceMirPresentationSupportKHR vkGetPhysicalDeviceMirPresentationSupportKHR = | ||||||
|  |         (PFN_vkGetPhysicalDeviceMirPresentationSupportKHR) | ||||||
|  |         vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR"); | ||||||
|  |     if (!vkGetPhysicalDeviceMirPresentationSupportKHR) | ||||||
|  |     { | ||||||
|  |         _glfwInputError(GLFW_API_UNAVAILABLE, | ||||||
|  |                         "Mir: Vulkan instance missing VK_KHR_mir_surface extension"); | ||||||
|  |         return GLFW_FALSE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return vkGetPhysicalDeviceMirPresentationSupportKHR(device, | ||||||
|  |                                                         queuefamily, | ||||||
|  |                                                         _glfw.mir.connection); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, | ||||||
|  |                                           _GLFWwindow* window, | ||||||
|  |                                           const VkAllocationCallbacks* allocator, | ||||||
|  |                                           VkSurfaceKHR* surface) | ||||||
|  | { | ||||||
|  |     VkResult err; | ||||||
|  |     VkMirSurfaceCreateInfoKHR sci; | ||||||
|  |     PFN_vkCreateMirSurfaceKHR vkCreateMirSurfaceKHR; | ||||||
|  |  | ||||||
|  |     vkCreateMirSurfaceKHR = (PFN_vkCreateMirSurfaceKHR) | ||||||
|  |         vkGetInstanceProcAddr(instance, "vkCreateMirSurfaceKHR"); | ||||||
|  |     if (!vkCreateMirSurfaceKHR) | ||||||
|  |     { | ||||||
|  |         _glfwInputError(GLFW_API_UNAVAILABLE, | ||||||
|  |                         "Mir: Vulkan instance missing VK_KHR_mir_surface extension"); | ||||||
|  |         return VK_ERROR_EXTENSION_NOT_PRESENT; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     memset(&sci, 0, sizeof(sci)); | ||||||
|  |     sci.sType = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR; | ||||||
|  |     sci.connection = _glfw.mir.connection; | ||||||
|  |     sci.mirSurface = window->mir.surface; | ||||||
|  |  | ||||||
|  |     err = vkCreateMirSurfaceKHR(instance, &sci, allocator, surface); | ||||||
|  |     if (err) | ||||||
|  |     { | ||||||
|  |         _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                         "Mir: Failed to create Vulkan surface: %s", | ||||||
|  |                         _glfwGetVulkanResultString(err)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return err; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | //////                        GLFW native API                       ////// | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | GLFWAPI MirConnection* glfwGetMirDisplay(void) | ||||||
|  | { | ||||||
|  |     _GLFW_REQUIRE_INIT_OR_RETURN(NULL); | ||||||
|  |     return _glfw.mir.connection; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* handle) | ||||||
|  | { | ||||||
|  |     _GLFWwindow* window = (_GLFWwindow*) handle; | ||||||
|  |     _GLFW_REQUIRE_INIT_OR_RETURN(NULL); | ||||||
|  |     return window->mir.surface; | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										68
									
								
								external/glfw/posix_tls.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								external/glfw/posix_tls.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | |||||||
|  | //======================================================================== | ||||||
|  | // GLFW 3.3 POSIX - www.glfw.org | ||||||
|  | //------------------------------------------------------------------------ | ||||||
|  | // Copyright (c) 2002-2006 Marcus Geelnard | ||||||
|  | // Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org> | ||||||
|  | // | ||||||
|  | // This software is provided 'as-is', without any express or implied | ||||||
|  | // warranty. In no event will the authors be held liable for any damages | ||||||
|  | // arising from the use of this software. | ||||||
|  | // | ||||||
|  | // Permission is granted to anyone to use this software for any purpose, | ||||||
|  | // including commercial applications, and to alter it and redistribute it | ||||||
|  | // freely, subject to the following restrictions: | ||||||
|  | // | ||||||
|  | // 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | //    claim that you wrote the original software. If you use this software | ||||||
|  | //    in a product, an acknowledgment in the product documentation would | ||||||
|  | //    be appreciated but is not required. | ||||||
|  | // | ||||||
|  | // 2. Altered source versions must be plainly marked as such, and must not | ||||||
|  | //    be misrepresented as being the original software. | ||||||
|  | // | ||||||
|  | // 3. This notice may not be removed or altered from any source | ||||||
|  | //    distribution. | ||||||
|  | // | ||||||
|  | //======================================================================== | ||||||
|  |  | ||||||
|  | #include "internal.h" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | //////                       GLFW internal API                      ////// | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | GLFWbool _glfwInitThreadLocalStoragePOSIX(void) | ||||||
|  | { | ||||||
|  |     if (pthread_key_create(&_glfw.posix_tls.context, NULL) != 0) | ||||||
|  |     { | ||||||
|  |         _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                         "POSIX: Failed to create context TLS"); | ||||||
|  |         return GLFW_FALSE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _glfw.posix_tls.allocated = GLFW_TRUE; | ||||||
|  |     return GLFW_TRUE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwTerminateThreadLocalStoragePOSIX(void) | ||||||
|  | { | ||||||
|  |     if (_glfw.posix_tls.allocated) | ||||||
|  |         pthread_key_delete(_glfw.posix_tls.context); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | //////                       GLFW platform API                      ////// | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | void _glfwPlatformSetCurrentContext(_GLFWwindow* context) | ||||||
|  | { | ||||||
|  |     pthread_setspecific(_glfw.posix_tls.context, context); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | _GLFWwindow* _glfwPlatformGetCurrentContext(void) | ||||||
|  | { | ||||||
|  |     return pthread_getspecific(_glfw.posix_tls.context); | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										49
									
								
								external/glfw/posix_tls.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								external/glfw/posix_tls.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | //======================================================================== | ||||||
|  | // GLFW 3.3 POSIX - www.glfw.org | ||||||
|  | //------------------------------------------------------------------------ | ||||||
|  | // Copyright (c) 2002-2006 Marcus Geelnard | ||||||
|  | // Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org> | ||||||
|  | // | ||||||
|  | // This software is provided 'as-is', without any express or implied | ||||||
|  | // warranty. In no event will the authors be held liable for any damages | ||||||
|  | // arising from the use of this software. | ||||||
|  | // | ||||||
|  | // Permission is granted to anyone to use this software for any purpose, | ||||||
|  | // including commercial applications, and to alter it and redistribute it | ||||||
|  | // freely, subject to the following restrictions: | ||||||
|  | // | ||||||
|  | // 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | //    claim that you wrote the original software. If you use this software | ||||||
|  | //    in a product, an acknowledgment in the product documentation would | ||||||
|  | //    be appreciated but is not required. | ||||||
|  | // | ||||||
|  | // 2. Altered source versions must be plainly marked as such, and must not | ||||||
|  | //    be misrepresented as being the original software. | ||||||
|  | // | ||||||
|  | // 3. This notice may not be removed or altered from any source | ||||||
|  | //    distribution. | ||||||
|  | // | ||||||
|  | //======================================================================== | ||||||
|  |  | ||||||
|  | #ifndef _glfw3_posix_tls_h_ | ||||||
|  | #define _glfw3_posix_tls_h_ | ||||||
|  |  | ||||||
|  | #include <pthread.h> | ||||||
|  |  | ||||||
|  | #define _GLFW_PLATFORM_LIBRARY_TLS_STATE _GLFWtlsPOSIX posix_tls | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // POSIX-specific global TLS data | ||||||
|  | // | ||||||
|  | typedef struct _GLFWtlsPOSIX | ||||||
|  | { | ||||||
|  |     GLFWbool        allocated; | ||||||
|  |     pthread_key_t   context; | ||||||
|  |  | ||||||
|  | } _GLFWtlsPOSIX; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | GLFWbool _glfwInitThreadLocalStoragePOSIX(void); | ||||||
|  | void _glfwTerminateThreadLocalStoragePOSIX(void); | ||||||
|  |  | ||||||
|  | #endif // _glfw3_posix_tls_h_ | ||||||
							
								
								
									
										69
									
								
								external/glfw/win32_tls.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								external/glfw/win32_tls.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | //======================================================================== | ||||||
|  | // GLFW 3.3 Win32 - www.glfw.org | ||||||
|  | //------------------------------------------------------------------------ | ||||||
|  | // Copyright (c) 2002-2006 Marcus Geelnard | ||||||
|  | // Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org> | ||||||
|  | // | ||||||
|  | // This software is provided 'as-is', without any express or implied | ||||||
|  | // warranty. In no event will the authors be held liable for any damages | ||||||
|  | // arising from the use of this software. | ||||||
|  | // | ||||||
|  | // Permission is granted to anyone to use this software for any purpose, | ||||||
|  | // including commercial applications, and to alter it and redistribute it | ||||||
|  | // freely, subject to the following restrictions: | ||||||
|  | // | ||||||
|  | // 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | //    claim that you wrote the original software. If you use this software | ||||||
|  | //    in a product, an acknowledgment in the product documentation would | ||||||
|  | //    be appreciated but is not required. | ||||||
|  | // | ||||||
|  | // 2. Altered source versions must be plainly marked as such, and must not | ||||||
|  | //    be misrepresented as being the original software. | ||||||
|  | // | ||||||
|  | // 3. This notice may not be removed or altered from any source | ||||||
|  | //    distribution. | ||||||
|  | // | ||||||
|  | //======================================================================== | ||||||
|  |  | ||||||
|  | #include "internal.h" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | //////                       GLFW internal API                      ////// | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | GLFWbool _glfwInitThreadLocalStorageWin32(void) | ||||||
|  | { | ||||||
|  |     _glfw.win32_tls.context = TlsAlloc(); | ||||||
|  |     if (_glfw.win32_tls.context == TLS_OUT_OF_INDEXES) | ||||||
|  |     { | ||||||
|  |         _glfwInputError(GLFW_PLATFORM_ERROR, | ||||||
|  |                         "Win32: Failed to allocate TLS index"); | ||||||
|  |         return GLFW_FALSE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     _glfw.win32_tls.allocated = GLFW_TRUE; | ||||||
|  |     return GLFW_TRUE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void _glfwTerminateThreadLocalStorageWin32(void) | ||||||
|  | { | ||||||
|  |     if (_glfw.win32_tls.allocated) | ||||||
|  |         TlsFree(_glfw.win32_tls.context); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  | //////                       GLFW platform API                      ////// | ||||||
|  | ////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | void _glfwPlatformSetCurrentContext(_GLFWwindow* context) | ||||||
|  | { | ||||||
|  |     TlsSetValue(_glfw.win32_tls.context, context); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | _GLFWwindow* _glfwPlatformGetCurrentContext(void) | ||||||
|  | { | ||||||
|  |     return TlsGetValue(_glfw.win32_tls.context); | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										354
									
								
								external/imgui/imgui_impl_glfw_gl2.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								external/imgui/imgui_impl_glfw_gl2.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,354 @@ | |||||||
|  | // ImGui GLFW binding with OpenGL (legacy, fixed pipeline) | ||||||
|  | // (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) | ||||||
|  |  | ||||||
|  | // Implemented features: | ||||||
|  | //  [X] User texture binding. Cast 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. | ||||||
|  |  | ||||||
|  | // **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** | ||||||
|  | // **Prefer using the code in the opengl3_example/ folder** | ||||||
|  | // This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read. | ||||||
|  | // If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more | ||||||
|  | // complicated, will require your code to reset every single OpenGL attributes to their initial state, and might | ||||||
|  | // confuse your GPU driver.  | ||||||
|  | // The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API. | ||||||
|  |  | ||||||
|  | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. | ||||||
|  | // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown(). | ||||||
|  | // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. | ||||||
|  | // https://github.com/ocornut/imgui | ||||||
|  |  | ||||||
|  | // CHANGELOG | ||||||
|  | // (minor and older changes stripped away, please see git history for details) | ||||||
|  | //  2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling). | ||||||
|  | //  2018-02-20: Inputs: Renamed GLFW callbacks exposed in .h to not include GL2 in their name. | ||||||
|  | //  2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplGlfwGL2_RenderDrawData() in the .h file so you can call it yourself. | ||||||
|  | //  2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. | ||||||
|  | //  2018-02-06: Inputs: Added mapping for ImGuiKey_Space. | ||||||
|  | //  2018-02-06: Inputs: Honoring the io.WantMoveMouse by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set). | ||||||
|  | //  2018-01-20: Inputs: Added Horizontal Mouse Wheel support. | ||||||
|  | //  2018-01-18: Inputs: Added mapping for ImGuiKey_Insert. | ||||||
|  | //  2018-01-09: Misc: Renamed imgui_impl_glfw.* to imgui_impl_glfw_gl2.*. | ||||||
|  | //  2017-09-01: OpenGL: Save and restore current polygon mode. | ||||||
|  | //  2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1). | ||||||
|  | //  2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers. | ||||||
|  | //  2016-09-10: OpenGL: Uploading font texture as RGBA32 to increase compatibility with users shaders (not ideal). | ||||||
|  | //  2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle. | ||||||
|  |  | ||||||
|  | #include "imgui.h" | ||||||
|  | #include "imgui_impl_glfw_gl2.h" | ||||||
|  |  | ||||||
|  | // GLFW | ||||||
|  | #include <GLFW/glfw3.h> | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #undef APIENTRY | ||||||
|  | #define GLFW_EXPOSE_NATIVE_WIN32 | ||||||
|  | #define GLFW_EXPOSE_NATIVE_WGL | ||||||
|  | #include <GLFW/glfw3native.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | // GLFW data | ||||||
|  | static GLFWwindow*  g_Window = NULL; | ||||||
|  | static double       g_Time = 0.0f; | ||||||
|  | static bool         g_MouseJustPressed[3] = { false, false, false }; | ||||||
|  | static GLFWcursor*  g_MouseCursors[ImGuiMouseCursor_COUNT] = { 0 }; | ||||||
|  |  | ||||||
|  | // OpenGL data | ||||||
|  | static GLuint       g_FontTexture = 0; | ||||||
|  |  | ||||||
|  | // OpenGL2 Render function. | ||||||
|  | // (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) | ||||||
|  | // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.  | ||||||
|  | void ImGui_ImplGlfwGL2_RenderDrawData(ImDrawData* draw_data) | ||||||
|  | { | ||||||
|  |     // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x); | ||||||
|  |     int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); | ||||||
|  |     if (fb_width == 0 || fb_height == 0) | ||||||
|  |         return; | ||||||
|  |     draw_data->ScaleClipRects(io.DisplayFramebufferScale); | ||||||
|  |  | ||||||
|  |     // We are using the OpenGL fixed pipeline to make the example code simpler to read! | ||||||
|  |     // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill. | ||||||
|  |     GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); | ||||||
|  |     GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); | ||||||
|  |     GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); | ||||||
|  |     GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);  | ||||||
|  |     glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); | ||||||
|  |     glEnable(GL_BLEND); | ||||||
|  |     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||||
|  |     glDisable(GL_CULL_FACE); | ||||||
|  |     glDisable(GL_DEPTH_TEST); | ||||||
|  |     glEnable(GL_SCISSOR_TEST); | ||||||
|  |     glEnableClientState(GL_VERTEX_ARRAY); | ||||||
|  |     glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||||||
|  |     glEnableClientState(GL_COLOR_ARRAY); | ||||||
|  |     glEnable(GL_TEXTURE_2D); | ||||||
|  |     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); | ||||||
|  |     //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound | ||||||
|  |  | ||||||
|  |     // Setup viewport, orthographic projection matrix | ||||||
|  |     glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); | ||||||
|  |     glMatrixMode(GL_PROJECTION); | ||||||
|  |     glPushMatrix(); | ||||||
|  |     glLoadIdentity(); | ||||||
|  |     glOrtho(0.0f, io.DisplaySize.x, io.DisplaySize.y, 0.0f, -1.0f, +1.0f); | ||||||
|  |     glMatrixMode(GL_MODELVIEW); | ||||||
|  |     glPushMatrix(); | ||||||
|  |     glLoadIdentity(); | ||||||
|  |  | ||||||
|  |     // Render command lists | ||||||
|  |     for (int n = 0; n < draw_data->CmdListsCount; n++) | ||||||
|  |     { | ||||||
|  |         const ImDrawList* cmd_list = draw_data->CmdLists[n]; | ||||||
|  |         const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; | ||||||
|  |         const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; | ||||||
|  |         glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, pos))); | ||||||
|  |         glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv))); | ||||||
|  |         glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col))); | ||||||
|  |  | ||||||
|  |         for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) | ||||||
|  |         { | ||||||
|  |             const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; | ||||||
|  |             if (pcmd->UserCallback) | ||||||
|  |             { | ||||||
|  |                 pcmd->UserCallback(cmd_list, pcmd); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); | ||||||
|  |                 glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y)); | ||||||
|  |                 glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer); | ||||||
|  |             } | ||||||
|  |             idx_buffer += pcmd->ElemCount; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Restore modified state | ||||||
|  |     glDisableClientState(GL_COLOR_ARRAY); | ||||||
|  |     glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||||||
|  |     glDisableClientState(GL_VERTEX_ARRAY); | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture); | ||||||
|  |     glMatrixMode(GL_MODELVIEW); | ||||||
|  |     glPopMatrix(); | ||||||
|  |     glMatrixMode(GL_PROJECTION); | ||||||
|  |     glPopMatrix(); | ||||||
|  |     glPopAttrib(); | ||||||
|  |     glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]); | ||||||
|  |     glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); | ||||||
|  |     glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const char* ImGui_ImplGlfwGL2_GetClipboardText(void* user_data) | ||||||
|  | { | ||||||
|  |     return glfwGetClipboardString((GLFWwindow*)user_data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void ImGui_ImplGlfwGL2_SetClipboardText(void* user_data, const char* text) | ||||||
|  | { | ||||||
|  |     glfwSetClipboardString((GLFWwindow*)user_data, text); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow*, int button, int action, int /*mods*/) | ||||||
|  | { | ||||||
|  |     if (action == GLFW_PRESS && button >= 0 && button < 3) | ||||||
|  |         g_MouseJustPressed[button] = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui_ImplGlfw_ScrollCallback(GLFWwindow*, double xoffset, double yoffset) | ||||||
|  | { | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     io.MouseWheelH += (float)xoffset; | ||||||
|  |     io.MouseWheel += (float)yoffset; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui_ImplGlfw_KeyCallback(GLFWwindow*, int key, int, int action, int mods) | ||||||
|  | { | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     if (action == GLFW_PRESS) | ||||||
|  |         io.KeysDown[key] = true; | ||||||
|  |     if (action == GLFW_RELEASE) | ||||||
|  |         io.KeysDown[key] = false; | ||||||
|  |  | ||||||
|  |     (void)mods; // Modifiers are not reliable across systems | ||||||
|  |     io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; | ||||||
|  |     io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; | ||||||
|  |     io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; | ||||||
|  |     io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui_ImplGlfw_CharCallback(GLFWwindow*, unsigned int c) | ||||||
|  | { | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     if (c > 0 && c < 0x10000) | ||||||
|  |         io.AddInputCharacter((unsigned short)c); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool ImGui_ImplGlfwGL2_CreateDeviceObjects() | ||||||
|  | { | ||||||
|  |     // Build texture atlas | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     unsigned char* pixels; | ||||||
|  |     int width, height; | ||||||
|  |     io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);   // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. | ||||||
|  |  | ||||||
|  |     // Upload texture to graphics system | ||||||
|  |     GLint last_texture; | ||||||
|  |     glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); | ||||||
|  |     glGenTextures(1, &g_FontTexture); | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, g_FontTexture); | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||||||
|  |     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | ||||||
|  |     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); | ||||||
|  |  | ||||||
|  |     // Store our identifier | ||||||
|  |     io.Fonts->TexID = (void *)(intptr_t)g_FontTexture; | ||||||
|  |  | ||||||
|  |     // Restore state | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, last_texture); | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void    ImGui_ImplGlfwGL2_InvalidateDeviceObjects() | ||||||
|  | { | ||||||
|  |     if (g_FontTexture) | ||||||
|  |     { | ||||||
|  |         glDeleteTextures(1, &g_FontTexture); | ||||||
|  |         ImGui::GetIO().Fonts->TexID = 0; | ||||||
|  |         g_FontTexture = 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); | ||||||
|  |     glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); | ||||||
|  |     glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback); | ||||||
|  |     glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool    ImGui_ImplGlfwGL2_Init(GLFWwindow* window, bool install_callbacks) | ||||||
|  | { | ||||||
|  |     g_Window = window; | ||||||
|  |  | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;                     // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. | ||||||
|  |     io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; | ||||||
|  |     io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; | ||||||
|  |     io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; | ||||||
|  |     io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; | ||||||
|  |     io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP; | ||||||
|  |     io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN; | ||||||
|  |     io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; | ||||||
|  |     io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; | ||||||
|  |     io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT; | ||||||
|  |     io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; | ||||||
|  |     io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; | ||||||
|  |     io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE; | ||||||
|  |     io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; | ||||||
|  |     io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; | ||||||
|  |     io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; | ||||||
|  |     io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; | ||||||
|  |     io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; | ||||||
|  |     io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; | ||||||
|  |     io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; | ||||||
|  |     io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; | ||||||
|  |  | ||||||
|  |     io.SetClipboardTextFn = ImGui_ImplGlfwGL2_SetClipboardText; | ||||||
|  |     io.GetClipboardTextFn = ImGui_ImplGlfwGL2_GetClipboardText; | ||||||
|  |     io.ClipboardUserData = g_Window; | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     io.ImeWindowHandle = glfwGetWin32Window(g_Window); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     // Load cursors | ||||||
|  |     // FIXME: GLFW doesn't expose suitable cursors for ResizeAll, ResizeNESW, ResizeNWSE. We revert to arrow cursor for those. | ||||||
|  |     g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); | ||||||
|  |     g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR); | ||||||
|  |     g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); | ||||||
|  |     g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR); | ||||||
|  |     g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); | ||||||
|  |     g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); | ||||||
|  |     g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); | ||||||
|  |  | ||||||
|  |     if (install_callbacks) | ||||||
|  |         ImGui_ImplGlfw_InstallCallbacks(window); | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui_ImplGlfwGL2_Shutdown() | ||||||
|  | { | ||||||
|  |     // Destroy GLFW mouse cursors | ||||||
|  |     for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) | ||||||
|  |         glfwDestroyCursor(g_MouseCursors[cursor_n]); | ||||||
|  |     memset(g_MouseCursors, 0, sizeof(g_MouseCursors)); | ||||||
|  |  | ||||||
|  |     // Destroy OpenGL objects | ||||||
|  |     ImGui_ImplGlfwGL2_InvalidateDeviceObjects(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui_ImplGlfwGL2_NewFrame() | ||||||
|  | { | ||||||
|  |     if (!g_FontTexture) | ||||||
|  |         ImGui_ImplGlfwGL2_CreateDeviceObjects(); | ||||||
|  |  | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |  | ||||||
|  |     // Setup display size (every frame to accommodate for window resizing) | ||||||
|  |     int w, h; | ||||||
|  |     int display_w, display_h; | ||||||
|  |     glfwGetWindowSize(g_Window, &w, &h); | ||||||
|  |     glfwGetFramebufferSize(g_Window, &display_w, &display_h); | ||||||
|  |     io.DisplaySize = ImVec2((float)w, (float)h); | ||||||
|  |     io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); | ||||||
|  |  | ||||||
|  |     // Setup time step | ||||||
|  |     double current_time =  glfwGetTime(); | ||||||
|  |     io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f); | ||||||
|  |     g_Time = current_time; | ||||||
|  |  | ||||||
|  |     // Setup inputs | ||||||
|  |     // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) | ||||||
|  |     if (glfwGetWindowAttrib(g_Window, GLFW_FOCUSED)) | ||||||
|  |     { | ||||||
|  |         if (io.WantMoveMouse) | ||||||
|  |         { | ||||||
|  |             glfwSetCursorPos(g_Window, (double)io.MousePos.x, (double)io.MousePos.y);   // Set mouse position if requested by io.WantMoveMouse flag (used when io.NavMovesTrue is enabled by user and using directional navigation) | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             double mouse_x, mouse_y; | ||||||
|  |             glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); | ||||||
|  |             io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (int i = 0; i < 3; i++) | ||||||
|  |     { | ||||||
|  |         // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. | ||||||
|  |         io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0; | ||||||
|  |         g_MouseJustPressed[i] = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Update OS/hardware mouse cursor if imgui isn't drawing a software cursor | ||||||
|  |     ImGuiMouseCursor cursor = ImGui::GetMouseCursor(); | ||||||
|  |     if (io.MouseDrawCursor || cursor == ImGuiMouseCursor_None) | ||||||
|  |     { | ||||||
|  |         glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         glfwSetCursor(g_Window, g_MouseCursors[cursor] ? g_MouseCursors[cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]); | ||||||
|  |         glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Start the frame. This call will update the io.WantCaptureMouse, io.WantCaptureKeyboard flag that you can use to dispatch inputs (or not) to your application. | ||||||
|  |     ImGui::NewFrame(); | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								external/imgui/imgui_impl_glfw_gl2.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								external/imgui/imgui_impl_glfw_gl2.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | // ImGui GLFW binding with OpenGL (legacy, fixed pipeline) | ||||||
|  | // (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) | ||||||
|  |  | ||||||
|  | // Implemented features: | ||||||
|  | //  [X] User texture binding. Cast 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. | ||||||
|  |  | ||||||
|  | // **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** | ||||||
|  | // **Prefer using the code in the opengl3_example/ folder** | ||||||
|  | // See imgui_impl_glfw.cpp for details. | ||||||
|  |  | ||||||
|  | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. | ||||||
|  | // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown(). | ||||||
|  | // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. | ||||||
|  | // https://github.com/ocornut/imgui | ||||||
|  |  | ||||||
|  | struct GLFWwindow; | ||||||
|  |  | ||||||
|  | IMGUI_API bool        ImGui_ImplGlfwGL2_Init(GLFWwindow* window, bool install_callbacks); | ||||||
|  | IMGUI_API void        ImGui_ImplGlfwGL2_Shutdown(); | ||||||
|  | IMGUI_API void        ImGui_ImplGlfwGL2_NewFrame(); | ||||||
|  | IMGUI_API void        ImGui_ImplGlfwGL2_RenderDrawData(ImDrawData* draw_data); | ||||||
|  |  | ||||||
|  | // Use if you want to reset your rendering device without losing ImGui state. | ||||||
|  | IMGUI_API void        ImGui_ImplGlfwGL2_InvalidateDeviceObjects(); | ||||||
|  | IMGUI_API bool        ImGui_ImplGlfwGL2_CreateDeviceObjects(); | ||||||
|  |  | ||||||
|  | // GLFW callbacks (registered by default to GLFW if you enable 'install_callbacks' during initialization) | ||||||
|  | // Provided here if you want to chain callbacks yourself. You may also handle inputs yourself and use those as a reference. | ||||||
|  | IMGUI_API void        ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); | ||||||
|  | IMGUI_API void        ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); | ||||||
|  | IMGUI_API void        ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); | ||||||
|  | IMGUI_API void        ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); | ||||||
							
								
								
									
										518
									
								
								external/imgui/imgui_impl_glfw_gl3.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										518
									
								
								external/imgui/imgui_impl_glfw_gl3.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,518 @@ | |||||||
|  | // ImGui GLFW binding with OpenGL3 + shaders | ||||||
|  | // (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) | ||||||
|  | // (GL3W is a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc.) | ||||||
|  |  | ||||||
|  | // Implemented features: | ||||||
|  | //  [X] User texture binding. Cast 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. | ||||||
|  | //  [X] Gamepad navigation mapping. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. | ||||||
|  |  | ||||||
|  | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. | ||||||
|  | // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown(). | ||||||
|  | // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. | ||||||
|  | // https://github.com/ocornut/imgui | ||||||
|  |  | ||||||
|  | // CHANGELOG | ||||||
|  | // (minor and older changes stripped away, please see git history for details) | ||||||
|  | //  2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplGlfwGL3_Init() so user can override the GLSL version e.g. "#version 150". | ||||||
|  | //  2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context. | ||||||
|  | //  2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling). | ||||||
|  | //  2018-02-20: Inputs: Renamed GLFW callbacks exposed in .h to not include GL3 in their name. | ||||||
|  | //  2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplGlfwGL3_RenderDrawData() in the .h file so you can call it yourself. | ||||||
|  | //  2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. | ||||||
|  | //  2018-02-06: Inputs: Added mapping for ImGuiKey_Space. | ||||||
|  | //  2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set. | ||||||
|  | //  2018-01-25: Inputs: Honoring the io.WantMoveMouse by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set). | ||||||
|  | //  2018-01-20: Inputs: Added Horizontal Mouse Wheel support. | ||||||
|  | //  2018-01-18: Inputs: Added mapping for ImGuiKey_Insert. | ||||||
|  | //  2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150. (Also changed GL context from 3.3 to 3.2 in example's main.cpp) | ||||||
|  | //  2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode. | ||||||
|  | //  2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1). | ||||||
|  | //  2017-05-01: OpenGL: Fixed save and restore of current blend function state. | ||||||
|  | //  2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers. | ||||||
|  | //  2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle. | ||||||
|  | //  2016-04-30: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE. | ||||||
|  |  | ||||||
|  | #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) | ||||||
|  | #define _CRT_SECURE_NO_WARNINGS | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "imgui.h" | ||||||
|  | #include "imgui_impl_glfw_gl3.h" | ||||||
|  |  | ||||||
|  | // GLAD | ||||||
|  | #include <glad_4/glad.h> | ||||||
|  |  | ||||||
|  | #include <GLFW/glfw3.h> | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #undef APIENTRY | ||||||
|  | #define GLFW_EXPOSE_NATIVE_WIN32 | ||||||
|  | #define GLFW_EXPOSE_NATIVE_WGL | ||||||
|  | #include <GLFW/glfw3native.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | // GLFW data | ||||||
|  | static GLFWwindow*  g_Window = NULL; | ||||||
|  | static double       g_Time = 0.0f; | ||||||
|  | static bool         g_MouseJustPressed[3] = { false, false, false }; | ||||||
|  | static GLFWcursor*  g_MouseCursors[ImGuiMouseCursor_COUNT] = { 0 }; | ||||||
|  |  | ||||||
|  | // OpenGL3 data | ||||||
|  | static char         g_GlslVersion[32] = "#version 150"; | ||||||
|  | static GLuint       g_FontTexture = 0; | ||||||
|  | static int          g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; | ||||||
|  | static int          g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; | ||||||
|  | static int          g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 0; | ||||||
|  | static unsigned int g_VboHandle = 0, g_ElementsHandle = 0; | ||||||
|  |  | ||||||
|  | // OpenGL3 Render function. | ||||||
|  | // (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) | ||||||
|  | // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.  | ||||||
|  | void ImGui_ImplGlfwGL3_RenderDrawData(ImDrawData* draw_data) | ||||||
|  | { | ||||||
|  |     // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x); | ||||||
|  |     int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); | ||||||
|  |     if (fb_width == 0 || fb_height == 0) | ||||||
|  |         return; | ||||||
|  |     draw_data->ScaleClipRects(io.DisplayFramebufferScale); | ||||||
|  |  | ||||||
|  |     // Backup GL state | ||||||
|  |     GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture); | ||||||
|  |     glActiveTexture(GL_TEXTURE0); | ||||||
|  |     GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); | ||||||
|  |     GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); | ||||||
|  |     GLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler); | ||||||
|  |     GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); | ||||||
|  |     GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer); | ||||||
|  |     GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); | ||||||
|  |     GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); | ||||||
|  |     GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); | ||||||
|  |     GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); | ||||||
|  |     GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb); | ||||||
|  |     GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb); | ||||||
|  |     GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha); | ||||||
|  |     GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha); | ||||||
|  |     GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb); | ||||||
|  |     GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha); | ||||||
|  |     GLboolean last_enable_blend = glIsEnabled(GL_BLEND); | ||||||
|  |     GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); | ||||||
|  |     GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); | ||||||
|  |     GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); | ||||||
|  |  | ||||||
|  |     // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill | ||||||
|  |     glEnable(GL_BLEND); | ||||||
|  |     glBlendEquation(GL_FUNC_ADD); | ||||||
|  |     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||||
|  |     glDisable(GL_CULL_FACE); | ||||||
|  |     glDisable(GL_DEPTH_TEST); | ||||||
|  |     glEnable(GL_SCISSOR_TEST); | ||||||
|  |     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); | ||||||
|  |  | ||||||
|  |     // Setup viewport, orthographic projection matrix | ||||||
|  |     glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); | ||||||
|  |     const float ortho_projection[4][4] = | ||||||
|  |     { | ||||||
|  |         { 2.0f/io.DisplaySize.x, 0.0f,                   0.0f, 0.0f }, | ||||||
|  |         { 0.0f,                  2.0f/-io.DisplaySize.y, 0.0f, 0.0f }, | ||||||
|  |         { 0.0f,                  0.0f,                  -1.0f, 0.0f }, | ||||||
|  |         {-1.0f,                  1.0f,                   0.0f, 1.0f }, | ||||||
|  |     }; | ||||||
|  |     glUseProgram(g_ShaderHandle); | ||||||
|  |     glUniform1i(g_AttribLocationTex, 0); | ||||||
|  |     glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); | ||||||
|  |     glBindSampler(0, 0); // Rely on combined texture/sampler state. | ||||||
|  |  | ||||||
|  |     // Recreate the VAO every time  | ||||||
|  |     // (This is to easily allow multiple GL contexts. VAO are not shared among GL contexts, and we don't track creation/deletion of windows so we don't have an obvious key to use to cache them.) | ||||||
|  |     GLuint vao_handle = 0; | ||||||
|  |     glGenVertexArrays(1, &vao_handle); | ||||||
|  |     glBindVertexArray(vao_handle); | ||||||
|  |     glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); | ||||||
|  |     glEnableVertexAttribArray(g_AttribLocationPosition); | ||||||
|  |     glEnableVertexAttribArray(g_AttribLocationUV); | ||||||
|  |     glEnableVertexAttribArray(g_AttribLocationColor); | ||||||
|  |     glVertexAttribPointer(g_AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos)); | ||||||
|  |     glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv)); | ||||||
|  |     glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col)); | ||||||
|  |  | ||||||
|  |     // Draw | ||||||
|  |     for (int n = 0; n < draw_data->CmdListsCount; n++) | ||||||
|  |     { | ||||||
|  |         const ImDrawList* cmd_list = draw_data->CmdLists[n]; | ||||||
|  |         const ImDrawIdx* idx_buffer_offset = 0; | ||||||
|  |  | ||||||
|  |         glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); | ||||||
|  |         glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); | ||||||
|  |  | ||||||
|  |         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle); | ||||||
|  |         glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); | ||||||
|  |  | ||||||
|  |         for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) | ||||||
|  |         { | ||||||
|  |             const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; | ||||||
|  |             if (pcmd->UserCallback) | ||||||
|  |             { | ||||||
|  |                 pcmd->UserCallback(cmd_list, pcmd); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); | ||||||
|  |                 glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y)); | ||||||
|  |                 glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); | ||||||
|  |             } | ||||||
|  |             idx_buffer_offset += pcmd->ElemCount; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     glDeleteVertexArrays(1, &vao_handle); | ||||||
|  |  | ||||||
|  |     // Restore modified GL state | ||||||
|  |     glUseProgram(last_program); | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, last_texture); | ||||||
|  |     glBindSampler(0, last_sampler); | ||||||
|  |     glActiveTexture(last_active_texture); | ||||||
|  |     glBindVertexArray(last_vertex_array); | ||||||
|  |     glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); | ||||||
|  |     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer); | ||||||
|  |     glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); | ||||||
|  |     glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha); | ||||||
|  |     if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); | ||||||
|  |     if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); | ||||||
|  |     if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); | ||||||
|  |     if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); | ||||||
|  |     glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); | ||||||
|  |     glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); | ||||||
|  |     glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const char* ImGui_ImplGlfwGL3_GetClipboardText(void* user_data) | ||||||
|  | { | ||||||
|  |     return glfwGetClipboardString((GLFWwindow*)user_data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void ImGui_ImplGlfwGL3_SetClipboardText(void* user_data, const char* text) | ||||||
|  | { | ||||||
|  |     glfwSetClipboardString((GLFWwindow*)user_data, text); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow*, int button, int action, int /*mods*/) | ||||||
|  | { | ||||||
|  |     if (action == GLFW_PRESS && button >= 0 && button < 3) | ||||||
|  |         g_MouseJustPressed[button] = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui_ImplGlfw_ScrollCallback(GLFWwindow*, double xoffset, double yoffset) | ||||||
|  | { | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     io.MouseWheelH += (float)xoffset; | ||||||
|  |     io.MouseWheel += (float)yoffset; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui_ImplGlfw_KeyCallback(GLFWwindow*, int key, int, int action, int mods) | ||||||
|  | { | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     if (action == GLFW_PRESS) | ||||||
|  |         io.KeysDown[key] = true; | ||||||
|  |     if (action == GLFW_RELEASE) | ||||||
|  |         io.KeysDown[key] = false; | ||||||
|  |  | ||||||
|  |     (void)mods; // Modifiers are not reliable across systems | ||||||
|  |     io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; | ||||||
|  |     io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; | ||||||
|  |     io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; | ||||||
|  |     io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui_ImplGlfw_CharCallback(GLFWwindow*, unsigned int c) | ||||||
|  | { | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     if (c > 0 && c < 0x10000) | ||||||
|  |         io.AddInputCharacter((unsigned short)c); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool ImGui_ImplGlfwGL3_CreateFontsTexture() | ||||||
|  | { | ||||||
|  |     // Build texture atlas | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     unsigned char* pixels; | ||||||
|  |     int width, height; | ||||||
|  |     io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);   // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. | ||||||
|  |  | ||||||
|  |     // Upload texture to graphics system | ||||||
|  |     GLint last_texture; | ||||||
|  |     glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); | ||||||
|  |     glGenTextures(1, &g_FontTexture); | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, g_FontTexture); | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||||||
|  |     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | ||||||
|  |     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); | ||||||
|  |  | ||||||
|  |     // Store our identifier | ||||||
|  |     io.Fonts->TexID = (void *)(intptr_t)g_FontTexture; | ||||||
|  |  | ||||||
|  |     // Restore state | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, last_texture); | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool ImGui_ImplGlfwGL3_CreateDeviceObjects() | ||||||
|  | { | ||||||
|  |     // Backup GL state | ||||||
|  |     GLint last_texture, last_array_buffer, last_vertex_array; | ||||||
|  |     glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); | ||||||
|  |     glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); | ||||||
|  |     glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); | ||||||
|  |  | ||||||
|  |     const GLchar* vertex_shader = | ||||||
|  |         "uniform mat4 ProjMtx;\n" | ||||||
|  |         "in vec2 Position;\n" | ||||||
|  |         "in vec2 UV;\n" | ||||||
|  |         "in vec4 Color;\n" | ||||||
|  |         "out vec2 Frag_UV;\n" | ||||||
|  |         "out vec4 Frag_Color;\n" | ||||||
|  |         "void main()\n" | ||||||
|  |         "{\n" | ||||||
|  |         "	Frag_UV = UV;\n" | ||||||
|  |         "	Frag_Color = Color;\n" | ||||||
|  |         "	gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" | ||||||
|  |         "}\n"; | ||||||
|  |  | ||||||
|  |     const GLchar* fragment_shader = | ||||||
|  |         "uniform sampler2D Texture;\n" | ||||||
|  |         "in vec2 Frag_UV;\n" | ||||||
|  |         "in vec4 Frag_Color;\n" | ||||||
|  |         "out vec4 Out_Color;\n" | ||||||
|  |         "void main()\n" | ||||||
|  |         "{\n" | ||||||
|  |         "	Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n" | ||||||
|  |         "}\n"; | ||||||
|  |  | ||||||
|  |     const GLchar* vertex_shader_with_version[2] = { g_GlslVersion, vertex_shader }; | ||||||
|  |     const GLchar* fragment_shader_with_version[2] = { g_GlslVersion, fragment_shader }; | ||||||
|  |  | ||||||
|  |     g_ShaderHandle = glCreateProgram(); | ||||||
|  |     g_VertHandle = glCreateShader(GL_VERTEX_SHADER); | ||||||
|  |     g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER); | ||||||
|  |     glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL); | ||||||
|  |     glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL); | ||||||
|  |     glCompileShader(g_VertHandle); | ||||||
|  |     glCompileShader(g_FragHandle); | ||||||
|  |     glAttachShader(g_ShaderHandle, g_VertHandle); | ||||||
|  |     glAttachShader(g_ShaderHandle, g_FragHandle); | ||||||
|  |     glLinkProgram(g_ShaderHandle); | ||||||
|  |  | ||||||
|  |     g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture"); | ||||||
|  |     g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx"); | ||||||
|  |     g_AttribLocationPosition = glGetAttribLocation(g_ShaderHandle, "Position"); | ||||||
|  |     g_AttribLocationUV = glGetAttribLocation(g_ShaderHandle, "UV"); | ||||||
|  |     g_AttribLocationColor = glGetAttribLocation(g_ShaderHandle, "Color"); | ||||||
|  |  | ||||||
|  |     glGenBuffers(1, &g_VboHandle); | ||||||
|  |     glGenBuffers(1, &g_ElementsHandle); | ||||||
|  |  | ||||||
|  |     ImGui_ImplGlfwGL3_CreateFontsTexture(); | ||||||
|  |  | ||||||
|  |     // Restore modified GL state | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, last_texture); | ||||||
|  |     glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); | ||||||
|  |     glBindVertexArray(last_vertex_array); | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void    ImGui_ImplGlfwGL3_InvalidateDeviceObjects() | ||||||
|  | { | ||||||
|  |     if (g_VboHandle) glDeleteBuffers(1, &g_VboHandle); | ||||||
|  |     if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle); | ||||||
|  |     g_VboHandle = g_ElementsHandle = 0; | ||||||
|  |  | ||||||
|  |     if (g_ShaderHandle && g_VertHandle) glDetachShader(g_ShaderHandle, g_VertHandle); | ||||||
|  |     if (g_VertHandle) glDeleteShader(g_VertHandle); | ||||||
|  |     g_VertHandle = 0; | ||||||
|  |  | ||||||
|  |     if (g_ShaderHandle && g_FragHandle) glDetachShader(g_ShaderHandle, g_FragHandle); | ||||||
|  |     if (g_FragHandle) glDeleteShader(g_FragHandle); | ||||||
|  |     g_FragHandle = 0; | ||||||
|  |  | ||||||
|  |     if (g_ShaderHandle) glDeleteProgram(g_ShaderHandle); | ||||||
|  |     g_ShaderHandle = 0; | ||||||
|  |  | ||||||
|  |     if (g_FontTexture) | ||||||
|  |     { | ||||||
|  |         glDeleteTextures(1, &g_FontTexture); | ||||||
|  |         ImGui::GetIO().Fonts->TexID = 0; | ||||||
|  |         g_FontTexture = 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window) | ||||||
|  | { | ||||||
|  |     glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); | ||||||
|  |     glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); | ||||||
|  |     glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback); | ||||||
|  |     glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool    ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks, const char* glsl_version) | ||||||
|  | { | ||||||
|  |     g_Window = window; | ||||||
|  |  | ||||||
|  |     // Store GL version string so we can refer to it later in case we recreate shaders. | ||||||
|  |     if (glsl_version == NULL) | ||||||
|  |         glsl_version = "#version 150"; | ||||||
|  |     IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersion)); | ||||||
|  |     strcpy(g_GlslVersion, glsl_version); | ||||||
|  |     strcat(g_GlslVersion, "\n"); | ||||||
|  |  | ||||||
|  |     // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |     io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; | ||||||
|  |     io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; | ||||||
|  |     io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; | ||||||
|  |     io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; | ||||||
|  |     io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; | ||||||
|  |     io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP; | ||||||
|  |     io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN; | ||||||
|  |     io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; | ||||||
|  |     io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; | ||||||
|  |     io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT; | ||||||
|  |     io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; | ||||||
|  |     io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; | ||||||
|  |     io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE; | ||||||
|  |     io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; | ||||||
|  |     io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; | ||||||
|  |     io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; | ||||||
|  |     io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; | ||||||
|  |     io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; | ||||||
|  |     io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; | ||||||
|  |     io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; | ||||||
|  |     io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; | ||||||
|  |  | ||||||
|  |     io.SetClipboardTextFn = ImGui_ImplGlfwGL3_SetClipboardText; | ||||||
|  |     io.GetClipboardTextFn = ImGui_ImplGlfwGL3_GetClipboardText; | ||||||
|  |     io.ClipboardUserData = g_Window; | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     io.ImeWindowHandle = glfwGetWin32Window(g_Window); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     // Load cursors | ||||||
|  |     // FIXME: GLFW doesn't expose suitable cursors for ResizeAll, ResizeNESW, ResizeNWSE. We revert to arrow cursor for those. | ||||||
|  |     g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); | ||||||
|  |     g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR); | ||||||
|  |     g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); | ||||||
|  |     g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR); | ||||||
|  |     g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); | ||||||
|  |     g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); | ||||||
|  |     g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); | ||||||
|  |  | ||||||
|  |     if (install_callbacks) | ||||||
|  |         ImGui_ImplGlfw_InstallCallbacks(window); | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui_ImplGlfwGL3_Shutdown() | ||||||
|  | { | ||||||
|  |     // Destroy GLFW mouse cursors | ||||||
|  |     for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) | ||||||
|  |         glfwDestroyCursor(g_MouseCursors[cursor_n]); | ||||||
|  |     memset(g_MouseCursors, 0, sizeof(g_MouseCursors)); | ||||||
|  |  | ||||||
|  |     // Destroy OpenGL objects | ||||||
|  |     ImGui_ImplGlfwGL3_InvalidateDeviceObjects(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui_ImplGlfwGL3_NewFrame() | ||||||
|  | { | ||||||
|  |     if (!g_FontTexture) | ||||||
|  |         ImGui_ImplGlfwGL3_CreateDeviceObjects(); | ||||||
|  |  | ||||||
|  |     ImGuiIO& io = ImGui::GetIO(); | ||||||
|  |  | ||||||
|  |     // Setup display size (every frame to accommodate for window resizing) | ||||||
|  |     int w, h; | ||||||
|  |     int display_w, display_h; | ||||||
|  |     glfwGetWindowSize(g_Window, &w, &h); | ||||||
|  |     glfwGetFramebufferSize(g_Window, &display_w, &display_h); | ||||||
|  |     io.DisplaySize = ImVec2((float)w, (float)h); | ||||||
|  |     io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); | ||||||
|  |  | ||||||
|  |     // Setup time step | ||||||
|  |     double current_time =  glfwGetTime(); | ||||||
|  |     io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f); | ||||||
|  |     g_Time = current_time; | ||||||
|  |  | ||||||
|  |     // Setup inputs | ||||||
|  |     // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) | ||||||
|  |     if (glfwGetWindowAttrib(g_Window, GLFW_FOCUSED)) | ||||||
|  |     { | ||||||
|  |         if (io.WantMoveMouse) | ||||||
|  |         { | ||||||
|  |             glfwSetCursorPos(g_Window, (double)io.MousePos.x, (double)io.MousePos.y);   // Set mouse position if requested by io.WantMoveMouse flag (used when io.NavMovesTrue is enabled by user and using directional navigation) | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             double mouse_x, mouse_y; | ||||||
|  |             glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); | ||||||
|  |             io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (int i = 0; i < 3; i++) | ||||||
|  |     { | ||||||
|  |         // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. | ||||||
|  |         io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0; | ||||||
|  |         g_MouseJustPressed[i] = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Update OS/hardware mouse cursor if imgui isn't drawing a software cursor | ||||||
|  |     ImGuiMouseCursor cursor = ImGui::GetMouseCursor(); | ||||||
|  |     if (io.MouseDrawCursor || cursor == ImGuiMouseCursor_None) | ||||||
|  |     { | ||||||
|  |         glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         glfwSetCursor(g_Window, g_MouseCursors[cursor] ? g_MouseCursors[cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]); | ||||||
|  |         glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Gamepad navigation mapping [BETA] | ||||||
|  |     memset(io.NavInputs, 0, sizeof(io.NavInputs)); | ||||||
|  |     if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) | ||||||
|  |     { | ||||||
|  |         // Update gamepad inputs | ||||||
|  |         #define MAP_BUTTON(NAV_NO, BUTTON_NO)       { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; } | ||||||
|  |         #define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; } | ||||||
|  |         int axes_count = 0, buttons_count = 0; | ||||||
|  |         const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count); | ||||||
|  |         const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count); | ||||||
|  |         MAP_BUTTON(ImGuiNavInput_Activate,   0);     // Cross / A | ||||||
|  |         MAP_BUTTON(ImGuiNavInput_Cancel,     1);     // Circle / B | ||||||
|  |         MAP_BUTTON(ImGuiNavInput_Menu,       2);     // Square / X | ||||||
|  |         MAP_BUTTON(ImGuiNavInput_Input,      3);     // Triangle / Y | ||||||
|  |         MAP_BUTTON(ImGuiNavInput_DpadLeft,   13);    // D-Pad Left | ||||||
|  |         MAP_BUTTON(ImGuiNavInput_DpadRight,  11);    // D-Pad Right | ||||||
|  |         MAP_BUTTON(ImGuiNavInput_DpadUp,     10);    // D-Pad Up | ||||||
|  |         MAP_BUTTON(ImGuiNavInput_DpadDown,   12);    // D-Pad Down | ||||||
|  |         MAP_BUTTON(ImGuiNavInput_FocusPrev,  4);     // L1 / LB | ||||||
|  |         MAP_BUTTON(ImGuiNavInput_FocusNext,  5);     // R1 / RB | ||||||
|  |         MAP_BUTTON(ImGuiNavInput_TweakSlow,  4);     // L1 / LB | ||||||
|  |         MAP_BUTTON(ImGuiNavInput_TweakFast,  5);     // R1 / RB | ||||||
|  |         MAP_ANALOG(ImGuiNavInput_LStickLeft, 0,  -0.3f,  -0.9f); | ||||||
|  |         MAP_ANALOG(ImGuiNavInput_LStickRight,0,  +0.3f,  +0.9f); | ||||||
|  |         MAP_ANALOG(ImGuiNavInput_LStickUp,   1,  +0.3f,  +0.9f); | ||||||
|  |         MAP_ANALOG(ImGuiNavInput_LStickDown, 1,  -0.3f,  -0.9f); | ||||||
|  |         #undef MAP_BUTTON | ||||||
|  |         #undef MAP_ANALOG | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Start the frame. This call will update the io.WantCaptureMouse, io.WantCaptureKeyboard flag that you can use to dispatch inputs (or not) to your application. | ||||||
|  |     ImGui::NewFrame(); | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								external/imgui/imgui_impl_glfw_gl3.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								external/imgui/imgui_impl_glfw_gl3.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | // ImGui GLFW binding with OpenGL3 + shaders | ||||||
|  | // (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) | ||||||
|  | // (GL3W is a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc.) | ||||||
|  |  | ||||||
|  | // Implemented features: | ||||||
|  | //  [X] User texture binding. Cast 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. | ||||||
|  | //  [X] Gamepad navigation mapping. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. | ||||||
|  |  | ||||||
|  | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. | ||||||
|  | // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown(). | ||||||
|  | // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. | ||||||
|  | // https://github.com/ocornut/imgui | ||||||
|  |  | ||||||
|  | struct GLFWwindow; | ||||||
|  |  | ||||||
|  | IMGUI_API bool        ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks, const char* glsl_version = NULL); | ||||||
|  | IMGUI_API void        ImGui_ImplGlfwGL3_Shutdown(); | ||||||
|  | IMGUI_API void        ImGui_ImplGlfwGL3_NewFrame(); | ||||||
|  | IMGUI_API void        ImGui_ImplGlfwGL3_RenderDrawData(ImDrawData* draw_data); | ||||||
|  |  | ||||||
|  | // Use if you want to reset your rendering device without losing ImGui state. | ||||||
|  | IMGUI_API void        ImGui_ImplGlfwGL3_InvalidateDeviceObjects(); | ||||||
|  | IMGUI_API bool        ImGui_ImplGlfwGL3_CreateDeviceObjects(); | ||||||
|  |  | ||||||
|  | // GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization) | ||||||
|  | // Provided here if you want to chain callbacks. | ||||||
|  | // You can also handle inputs yourself and use those as a reference. | ||||||
|  | IMGUI_API void        ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); | ||||||
|  | IMGUI_API void        ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); | ||||||
|  | IMGUI_API void        ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); | ||||||
|  | IMGUI_API void        ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); | ||||||
							
								
								
									
										623
									
								
								external/imgui/stb_rect_pack.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										623
									
								
								external/imgui/stb_rect_pack.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,623 @@ | |||||||
|  | // stb_rect_pack.h - v0.11 - public domain - rectangle packing | ||||||
|  | // Sean Barrett 2014 | ||||||
|  | // | ||||||
|  | // Useful for e.g. packing rectangular textures into an atlas. | ||||||
|  | // Does not do rotation. | ||||||
|  | // | ||||||
|  | // Not necessarily the awesomest packing method, but better than | ||||||
|  | // the totally naive one in stb_truetype (which is primarily what | ||||||
|  | // this is meant to replace). | ||||||
|  | // | ||||||
|  | // Has only had a few tests run, may have issues. | ||||||
|  | // | ||||||
|  | // More docs to come. | ||||||
|  | // | ||||||
|  | // No memory allocations; uses qsort() and assert() from stdlib. | ||||||
|  | // Can override those by defining STBRP_SORT and STBRP_ASSERT. | ||||||
|  | // | ||||||
|  | // This library currently uses the Skyline Bottom-Left algorithm. | ||||||
|  | // | ||||||
|  | // Please note: better rectangle packers are welcome! Please | ||||||
|  | // implement them to the same API, but with a different init | ||||||
|  | // function. | ||||||
|  | // | ||||||
|  | // Credits | ||||||
|  | // | ||||||
|  | //  Library | ||||||
|  | //    Sean Barrett | ||||||
|  | //  Minor features | ||||||
|  | //    Martins Mozeiko | ||||||
|  | //    github:IntellectualKitty | ||||||
|  | //     | ||||||
|  | //  Bugfixes / warning fixes | ||||||
|  | //    Jeremy Jaussaud | ||||||
|  | // | ||||||
|  | // Version history: | ||||||
|  | // | ||||||
|  | //     0.11  (2017-03-03)  return packing success/fail result | ||||||
|  | //     0.10  (2016-10-25)  remove cast-away-const to avoid warnings | ||||||
|  | //     0.09  (2016-08-27)  fix compiler warnings | ||||||
|  | //     0.08  (2015-09-13)  really fix bug with empty rects (w=0 or h=0) | ||||||
|  | //     0.07  (2015-09-13)  fix bug with empty rects (w=0 or h=0) | ||||||
|  | //     0.06  (2015-04-15)  added STBRP_SORT to allow replacing qsort | ||||||
|  | //     0.05:  added STBRP_ASSERT to allow replacing assert | ||||||
|  | //     0.04:  fixed minor bug in STBRP_LARGE_RECTS support | ||||||
|  | //     0.01:  initial release | ||||||
|  | // | ||||||
|  | // LICENSE | ||||||
|  | // | ||||||
|  | //   See end of file for license information. | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // | ||||||
|  | //       INCLUDE SECTION | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #ifndef STB_INCLUDE_STB_RECT_PACK_H | ||||||
|  | #define STB_INCLUDE_STB_RECT_PACK_H | ||||||
|  |  | ||||||
|  | #define STB_RECT_PACK_VERSION  1 | ||||||
|  |  | ||||||
|  | #ifdef STBRP_STATIC | ||||||
|  | #define STBRP_DEF static | ||||||
|  | #else | ||||||
|  | #define STBRP_DEF extern | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | typedef struct stbrp_context stbrp_context; | ||||||
|  | typedef struct stbrp_node    stbrp_node; | ||||||
|  | typedef struct stbrp_rect    stbrp_rect; | ||||||
|  |  | ||||||
|  | #ifdef STBRP_LARGE_RECTS | ||||||
|  | typedef int            stbrp_coord; | ||||||
|  | #else | ||||||
|  | typedef unsigned short stbrp_coord; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); | ||||||
|  | // Assign packed locations to rectangles. The rectangles are of type | ||||||
|  | // 'stbrp_rect' defined below, stored in the array 'rects', and there | ||||||
|  | // are 'num_rects' many of them. | ||||||
|  | // | ||||||
|  | // Rectangles which are successfully packed have the 'was_packed' flag | ||||||
|  | // set to a non-zero value and 'x' and 'y' store the minimum location | ||||||
|  | // on each axis (i.e. bottom-left in cartesian coordinates, top-left | ||||||
|  | // if you imagine y increasing downwards). Rectangles which do not fit | ||||||
|  | // have the 'was_packed' flag set to 0. | ||||||
|  | // | ||||||
|  | // You should not try to access the 'rects' array from another thread | ||||||
|  | // while this function is running, as the function temporarily reorders | ||||||
|  | // the array while it executes. | ||||||
|  | // | ||||||
|  | // To pack into another rectangle, you need to call stbrp_init_target | ||||||
|  | // again. To continue packing into the same rectangle, you can call | ||||||
|  | // this function again. Calling this multiple times with multiple rect | ||||||
|  | // arrays will probably produce worse packing results than calling it | ||||||
|  | // a single time with the full rectangle array, but the option is | ||||||
|  | // available. | ||||||
|  | // | ||||||
|  | // The function returns 1 if all of the rectangles were successfully | ||||||
|  | // packed and 0 otherwise. | ||||||
|  |  | ||||||
|  | struct stbrp_rect | ||||||
|  | { | ||||||
|  |    // reserved for your use: | ||||||
|  |    int            id; | ||||||
|  |  | ||||||
|  |    // input: | ||||||
|  |    stbrp_coord    w, h; | ||||||
|  |  | ||||||
|  |    // output: | ||||||
|  |    stbrp_coord    x, y; | ||||||
|  |    int            was_packed;  // non-zero if valid packing | ||||||
|  |  | ||||||
|  | }; // 16 bytes, nominally | ||||||
|  |  | ||||||
|  |  | ||||||
|  | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); | ||||||
|  | // Initialize a rectangle packer to: | ||||||
|  | //    pack a rectangle that is 'width' by 'height' in dimensions | ||||||
|  | //    using temporary storage provided by the array 'nodes', which is 'num_nodes' long | ||||||
|  | // | ||||||
|  | // You must call this function every time you start packing into a new target. | ||||||
|  | // | ||||||
|  | // There is no "shutdown" function. The 'nodes' memory must stay valid for | ||||||
|  | // the following stbrp_pack_rects() call (or calls), but can be freed after | ||||||
|  | // the call (or calls) finish. | ||||||
|  | // | ||||||
|  | // Note: to guarantee best results, either: | ||||||
|  | //       1. make sure 'num_nodes' >= 'width' | ||||||
|  | //   or  2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' | ||||||
|  | // | ||||||
|  | // If you don't do either of the above things, widths will be quantized to multiples | ||||||
|  | // of small integers to guarantee the algorithm doesn't run out of temporary storage. | ||||||
|  | // | ||||||
|  | // If you do #2, then the non-quantized algorithm will be used, but the algorithm | ||||||
|  | // may run out of temporary storage and be unable to pack some rectangles. | ||||||
|  |  | ||||||
|  | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); | ||||||
|  | // Optionally call this function after init but before doing any packing to | ||||||
|  | // change the handling of the out-of-temp-memory scenario, described above. | ||||||
|  | // If you call init again, this will be reset to the default (false). | ||||||
|  |  | ||||||
|  |  | ||||||
|  | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); | ||||||
|  | // Optionally select which packing heuristic the library should use. Different | ||||||
|  | // heuristics will produce better/worse results for different data sets. | ||||||
|  | // If you call init again, this will be reset to the default. | ||||||
|  |  | ||||||
|  | enum | ||||||
|  | { | ||||||
|  |    STBRP_HEURISTIC_Skyline_default=0, | ||||||
|  |    STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, | ||||||
|  |    STBRP_HEURISTIC_Skyline_BF_sortHeight | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // | ||||||
|  | // the details of the following structures don't matter to you, but they must | ||||||
|  | // be visible so you can handle the memory allocations for them | ||||||
|  |  | ||||||
|  | struct stbrp_node | ||||||
|  | { | ||||||
|  |    stbrp_coord  x,y; | ||||||
|  |    stbrp_node  *next; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct stbrp_context | ||||||
|  | { | ||||||
|  |    int width; | ||||||
|  |    int height; | ||||||
|  |    int align; | ||||||
|  |    int init_mode; | ||||||
|  |    int heuristic; | ||||||
|  |    int num_nodes; | ||||||
|  |    stbrp_node *active_head; | ||||||
|  |    stbrp_node *free_head; | ||||||
|  |    stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////////////// | ||||||
|  | // | ||||||
|  | //     IMPLEMENTATION SECTION | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #ifdef STB_RECT_PACK_IMPLEMENTATION | ||||||
|  | #ifndef STBRP_SORT | ||||||
|  | #include <stdlib.h> | ||||||
|  | #define STBRP_SORT qsort | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifndef STBRP_ASSERT | ||||||
|  | #include <assert.h> | ||||||
|  | #define STBRP_ASSERT assert | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef _MSC_VER | ||||||
|  | #define STBRP__NOTUSED(v)  (void)(v) | ||||||
|  | #define STBRP__CDECL __cdecl | ||||||
|  | #else | ||||||
|  | #define STBRP__NOTUSED(v)  (void)sizeof(v) | ||||||
|  | #define STBRP__CDECL | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | enum | ||||||
|  | { | ||||||
|  |    STBRP__INIT_skyline = 1 | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) | ||||||
|  | { | ||||||
|  |    switch (context->init_mode) { | ||||||
|  |       case STBRP__INIT_skyline: | ||||||
|  |          STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); | ||||||
|  |          context->heuristic = heuristic; | ||||||
|  |          break; | ||||||
|  |       default: | ||||||
|  |          STBRP_ASSERT(0); | ||||||
|  |    } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) | ||||||
|  | { | ||||||
|  |    if (allow_out_of_mem) | ||||||
|  |       // if it's ok to run out of memory, then don't bother aligning them; | ||||||
|  |       // this gives better packing, but may fail due to OOM (even though | ||||||
|  |       // the rectangles easily fit). @TODO a smarter approach would be to only | ||||||
|  |       // quantize once we've hit OOM, then we could get rid of this parameter. | ||||||
|  |       context->align = 1; | ||||||
|  |    else { | ||||||
|  |       // if it's not ok to run out of memory, then quantize the widths | ||||||
|  |       // so that num_nodes is always enough nodes. | ||||||
|  |       // | ||||||
|  |       // I.e. num_nodes * align >= width | ||||||
|  |       //                  align >= width / num_nodes | ||||||
|  |       //                  align = ceil(width/num_nodes) | ||||||
|  |  | ||||||
|  |       context->align = (context->width + context->num_nodes-1) / context->num_nodes; | ||||||
|  |    } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) | ||||||
|  | { | ||||||
|  |    int i; | ||||||
|  | #ifndef STBRP_LARGE_RECTS | ||||||
|  |    STBRP_ASSERT(width <= 0xffff && height <= 0xffff); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |    for (i=0; i < num_nodes-1; ++i) | ||||||
|  |       nodes[i].next = &nodes[i+1]; | ||||||
|  |    nodes[i].next = NULL; | ||||||
|  |    context->init_mode = STBRP__INIT_skyline; | ||||||
|  |    context->heuristic = STBRP_HEURISTIC_Skyline_default; | ||||||
|  |    context->free_head = &nodes[0]; | ||||||
|  |    context->active_head = &context->extra[0]; | ||||||
|  |    context->width = width; | ||||||
|  |    context->height = height; | ||||||
|  |    context->num_nodes = num_nodes; | ||||||
|  |    stbrp_setup_allow_out_of_mem(context, 0); | ||||||
|  |  | ||||||
|  |    // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) | ||||||
|  |    context->extra[0].x = 0; | ||||||
|  |    context->extra[0].y = 0; | ||||||
|  |    context->extra[0].next = &context->extra[1]; | ||||||
|  |    context->extra[1].x = (stbrp_coord) width; | ||||||
|  | #ifdef STBRP_LARGE_RECTS | ||||||
|  |    context->extra[1].y = (1<<30); | ||||||
|  | #else | ||||||
|  |    context->extra[1].y = 65535; | ||||||
|  | #endif | ||||||
|  |    context->extra[1].next = NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // find minimum y position if it starts at x1 | ||||||
|  | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) | ||||||
|  | { | ||||||
|  |    stbrp_node *node = first; | ||||||
|  |    int x1 = x0 + width; | ||||||
|  |    int min_y, visited_width, waste_area; | ||||||
|  |  | ||||||
|  |    STBRP__NOTUSED(c); | ||||||
|  |  | ||||||
|  |    STBRP_ASSERT(first->x <= x0); | ||||||
|  |  | ||||||
|  |    #if 0 | ||||||
|  |    // skip in case we're past the node | ||||||
|  |    while (node->next->x <= x0) | ||||||
|  |       ++node; | ||||||
|  |    #else | ||||||
|  |    STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency | ||||||
|  |    #endif | ||||||
|  |  | ||||||
|  |    STBRP_ASSERT(node->x <= x0); | ||||||
|  |  | ||||||
|  |    min_y = 0; | ||||||
|  |    waste_area = 0; | ||||||
|  |    visited_width = 0; | ||||||
|  |    while (node->x < x1) { | ||||||
|  |       if (node->y > min_y) { | ||||||
|  |          // raise min_y higher. | ||||||
|  |          // we've accounted for all waste up to min_y, | ||||||
|  |          // but we'll now add more waste for everything we've visted | ||||||
|  |          waste_area += visited_width * (node->y - min_y); | ||||||
|  |          min_y = node->y; | ||||||
|  |          // the first time through, visited_width might be reduced | ||||||
|  |          if (node->x < x0) | ||||||
|  |             visited_width += node->next->x - x0; | ||||||
|  |          else | ||||||
|  |             visited_width += node->next->x - node->x; | ||||||
|  |       } else { | ||||||
|  |          // add waste area | ||||||
|  |          int under_width = node->next->x - node->x; | ||||||
|  |          if (under_width + visited_width > width) | ||||||
|  |             under_width = width - visited_width; | ||||||
|  |          waste_area += under_width * (min_y - node->y); | ||||||
|  |          visited_width += under_width; | ||||||
|  |       } | ||||||
|  |       node = node->next; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    *pwaste = waste_area; | ||||||
|  |    return min_y; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | typedef struct | ||||||
|  | { | ||||||
|  |    int x,y; | ||||||
|  |    stbrp_node **prev_link; | ||||||
|  | } stbrp__findresult; | ||||||
|  |  | ||||||
|  | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) | ||||||
|  | { | ||||||
|  |    int best_waste = (1<<30), best_x, best_y = (1 << 30); | ||||||
|  |    stbrp__findresult fr; | ||||||
|  |    stbrp_node **prev, *node, *tail, **best = NULL; | ||||||
|  |  | ||||||
|  |    // align to multiple of c->align | ||||||
|  |    width = (width + c->align - 1); | ||||||
|  |    width -= width % c->align; | ||||||
|  |    STBRP_ASSERT(width % c->align == 0); | ||||||
|  |  | ||||||
|  |    node = c->active_head; | ||||||
|  |    prev = &c->active_head; | ||||||
|  |    while (node->x + width <= c->width) { | ||||||
|  |       int y,waste; | ||||||
|  |       y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); | ||||||
|  |       if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL | ||||||
|  |          // bottom left | ||||||
|  |          if (y < best_y) { | ||||||
|  |             best_y = y; | ||||||
|  |             best = prev; | ||||||
|  |          } | ||||||
|  |       } else { | ||||||
|  |          // best-fit | ||||||
|  |          if (y + height <= c->height) { | ||||||
|  |             // can only use it if it first vertically | ||||||
|  |             if (y < best_y || (y == best_y && waste < best_waste)) { | ||||||
|  |                best_y = y; | ||||||
|  |                best_waste = waste; | ||||||
|  |                best = prev; | ||||||
|  |             } | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |       prev = &node->next; | ||||||
|  |       node = node->next; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    best_x = (best == NULL) ? 0 : (*best)->x; | ||||||
|  |  | ||||||
|  |    // if doing best-fit (BF), we also have to try aligning right edge to each node position | ||||||
|  |    // | ||||||
|  |    // e.g, if fitting | ||||||
|  |    // | ||||||
|  |    //     ____________________ | ||||||
|  |    //    |____________________| | ||||||
|  |    // | ||||||
|  |    //            into | ||||||
|  |    // | ||||||
|  |    //   |                         | | ||||||
|  |    //   |             ____________| | ||||||
|  |    //   |____________| | ||||||
|  |    // | ||||||
|  |    // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned | ||||||
|  |    // | ||||||
|  |    // This makes BF take about 2x the time | ||||||
|  |  | ||||||
|  |    if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { | ||||||
|  |       tail = c->active_head; | ||||||
|  |       node = c->active_head; | ||||||
|  |       prev = &c->active_head; | ||||||
|  |       // find first node that's admissible | ||||||
|  |       while (tail->x < width) | ||||||
|  |          tail = tail->next; | ||||||
|  |       while (tail) { | ||||||
|  |          int xpos = tail->x - width; | ||||||
|  |          int y,waste; | ||||||
|  |          STBRP_ASSERT(xpos >= 0); | ||||||
|  |          // find the left position that matches this | ||||||
|  |          while (node->next->x <= xpos) { | ||||||
|  |             prev = &node->next; | ||||||
|  |             node = node->next; | ||||||
|  |          } | ||||||
|  |          STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); | ||||||
|  |          y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); | ||||||
|  |          if (y + height < c->height) { | ||||||
|  |             if (y <= best_y) { | ||||||
|  |                if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { | ||||||
|  |                   best_x = xpos; | ||||||
|  |                   STBRP_ASSERT(y <= best_y); | ||||||
|  |                   best_y = y; | ||||||
|  |                   best_waste = waste; | ||||||
|  |                   best = prev; | ||||||
|  |                } | ||||||
|  |             } | ||||||
|  |          } | ||||||
|  |          tail = tail->next; | ||||||
|  |       }          | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    fr.prev_link = best; | ||||||
|  |    fr.x = best_x; | ||||||
|  |    fr.y = best_y; | ||||||
|  |    return fr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) | ||||||
|  | { | ||||||
|  |    // find best position according to heuristic | ||||||
|  |    stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); | ||||||
|  |    stbrp_node *node, *cur; | ||||||
|  |  | ||||||
|  |    // bail if: | ||||||
|  |    //    1. it failed | ||||||
|  |    //    2. the best node doesn't fit (we don't always check this) | ||||||
|  |    //    3. we're out of memory | ||||||
|  |    if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { | ||||||
|  |       res.prev_link = NULL; | ||||||
|  |       return res; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    // on success, create new node | ||||||
|  |    node = context->free_head; | ||||||
|  |    node->x = (stbrp_coord) res.x; | ||||||
|  |    node->y = (stbrp_coord) (res.y + height); | ||||||
|  |  | ||||||
|  |    context->free_head = node->next; | ||||||
|  |  | ||||||
|  |    // insert the new node into the right starting point, and | ||||||
|  |    // let 'cur' point to the remaining nodes needing to be | ||||||
|  |    // stiched back in | ||||||
|  |  | ||||||
|  |    cur = *res.prev_link; | ||||||
|  |    if (cur->x < res.x) { | ||||||
|  |       // preserve the existing one, so start testing with the next one | ||||||
|  |       stbrp_node *next = cur->next; | ||||||
|  |       cur->next = node; | ||||||
|  |       cur = next; | ||||||
|  |    } else { | ||||||
|  |       *res.prev_link = node; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    // from here, traverse cur and free the nodes, until we get to one | ||||||
|  |    // that shouldn't be freed | ||||||
|  |    while (cur->next && cur->next->x <= res.x + width) { | ||||||
|  |       stbrp_node *next = cur->next; | ||||||
|  |       // move the current node to the free list | ||||||
|  |       cur->next = context->free_head; | ||||||
|  |       context->free_head = cur; | ||||||
|  |       cur = next; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    // stitch the list back in | ||||||
|  |    node->next = cur; | ||||||
|  |  | ||||||
|  |    if (cur->x < res.x + width) | ||||||
|  |       cur->x = (stbrp_coord) (res.x + width); | ||||||
|  |  | ||||||
|  | #ifdef _DEBUG | ||||||
|  |    cur = context->active_head; | ||||||
|  |    while (cur->x < context->width) { | ||||||
|  |       STBRP_ASSERT(cur->x < cur->next->x); | ||||||
|  |       cur = cur->next; | ||||||
|  |    } | ||||||
|  |    STBRP_ASSERT(cur->next == NULL); | ||||||
|  |  | ||||||
|  |    { | ||||||
|  |       int count=0; | ||||||
|  |       cur = context->active_head; | ||||||
|  |       while (cur) { | ||||||
|  |          cur = cur->next; | ||||||
|  |          ++count; | ||||||
|  |       } | ||||||
|  |       cur = context->free_head; | ||||||
|  |       while (cur) { | ||||||
|  |          cur = cur->next; | ||||||
|  |          ++count; | ||||||
|  |       } | ||||||
|  |       STBRP_ASSERT(count == context->num_nodes+2); | ||||||
|  |    } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |    return res; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int STBRP__CDECL rect_height_compare(const void *a, const void *b) | ||||||
|  | { | ||||||
|  |    const stbrp_rect *p = (const stbrp_rect *) a; | ||||||
|  |    const stbrp_rect *q = (const stbrp_rect *) b; | ||||||
|  |    if (p->h > q->h) | ||||||
|  |       return -1; | ||||||
|  |    if (p->h < q->h) | ||||||
|  |       return  1; | ||||||
|  |    return (p->w > q->w) ? -1 : (p->w < q->w); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int STBRP__CDECL rect_original_order(const void *a, const void *b) | ||||||
|  | { | ||||||
|  |    const stbrp_rect *p = (const stbrp_rect *) a; | ||||||
|  |    const stbrp_rect *q = (const stbrp_rect *) b; | ||||||
|  |    return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #ifdef STBRP_LARGE_RECTS | ||||||
|  | #define STBRP__MAXVAL  0xffffffff | ||||||
|  | #else | ||||||
|  | #define STBRP__MAXVAL  0xffff | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) | ||||||
|  | { | ||||||
|  |    int i, all_rects_packed = 1; | ||||||
|  |  | ||||||
|  |    // we use the 'was_packed' field internally to allow sorting/unsorting | ||||||
|  |    for (i=0; i < num_rects; ++i) { | ||||||
|  |       rects[i].was_packed = i; | ||||||
|  |       #ifndef STBRP_LARGE_RECTS | ||||||
|  |       STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff); | ||||||
|  |       #endif | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    // sort according to heuristic | ||||||
|  |    STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); | ||||||
|  |  | ||||||
|  |    for (i=0; i < num_rects; ++i) { | ||||||
|  |       if (rects[i].w == 0 || rects[i].h == 0) { | ||||||
|  |          rects[i].x = rects[i].y = 0;  // empty rect needs no space | ||||||
|  |       } else { | ||||||
|  |          stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); | ||||||
|  |          if (fr.prev_link) { | ||||||
|  |             rects[i].x = (stbrp_coord) fr.x; | ||||||
|  |             rects[i].y = (stbrp_coord) fr.y; | ||||||
|  |          } else { | ||||||
|  |             rects[i].x = rects[i].y = STBRP__MAXVAL; | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    // unsort | ||||||
|  |    STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); | ||||||
|  |  | ||||||
|  |    // set was_packed flags and all_rects_packed status | ||||||
|  |    for (i=0; i < num_rects; ++i) { | ||||||
|  |       rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); | ||||||
|  |       if (!rects[i].was_packed) | ||||||
|  |          all_rects_packed = 0; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    // return the all_rects_packed status | ||||||
|  |    return all_rects_packed; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ------------------------------------------------------------------------------ | ||||||
|  | This software is available under 2 licenses -- choose whichever you prefer. | ||||||
|  | ------------------------------------------------------------------------------ | ||||||
|  | ALTERNATIVE A - MIT License | ||||||
|  | Copyright (c) 2017 Sean Barrett | ||||||
|  | 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. | ||||||
|  | ------------------------------------------------------------------------------ | ||||||
|  | ALTERNATIVE B - Public Domain (www.unlicense.org) | ||||||
|  | This is free and unencumbered software released into the public domain. | ||||||
|  | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this  | ||||||
|  | software, either in source code form or as a compiled binary, for any purpose,  | ||||||
|  | commercial or non-commercial, and by any means. | ||||||
|  | In jurisdictions that recognize copyright laws, the author or authors of this  | ||||||
|  | software dedicate any and all copyright interest in the software to the public  | ||||||
|  | domain. We make this dedication for the benefit of the public at large and to  | ||||||
|  | the detriment of our heirs and successors. We intend this dedication to be an  | ||||||
|  | overt act of relinquishment in perpetuity of all present and future rights to  | ||||||
|  | this software under copyright law. | ||||||
|  | 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 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. | ||||||
|  | ------------------------------------------------------------------------------ | ||||||
|  | */ | ||||||
							
								
								
									
										1322
									
								
								external/imgui/stb_textedit.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1322
									
								
								external/imgui/stb_textedit.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4854
									
								
								external/imgui/stb_truetype.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4854
									
								
								external/imgui/stb_truetype.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										38
									
								
								include/bounce/cloth/cloth_collision.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								include/bounce/cloth/cloth_collision.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef B3_CLOTH_COLLISION_H | ||||||
|  | #define B3_CLOTH_COLLISION_H | ||||||
|  |  | ||||||
|  | #include <bounce/common/math/vec3.h> | ||||||
|  |  | ||||||
|  | // Cloth primitive type | ||||||
|  | enum b3ClothAABBProxyType | ||||||
|  | { | ||||||
|  | 	e_particleProxy, | ||||||
|  | 	e_triangleProxy | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // Cloth primitive broadphase proxy | ||||||
|  | struct b3ClothAABBProxy | ||||||
|  | { | ||||||
|  | 	b3ClothAABBProxyType type; | ||||||
|  | 	void* owner; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										112
									
								
								include/bounce/cloth/cloth_triangle.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								include/bounce/cloth/cloth_triangle.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef B3_CLOTH_TRIANGLE_H | ||||||
|  | #define B3_CLOTH_TRIANGLE_H | ||||||
|  |  | ||||||
|  | #include <bounce/cloth/cloth_collision.h> | ||||||
|  |  | ||||||
|  | // A cloth triangle | ||||||
|  | class b3ClothTriangle | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	// Return the triangle index. | ||||||
|  | 	u32 GetTriangle() const; | ||||||
|  |  | ||||||
|  | 	// Set the triangle radius. | ||||||
|  | 	void SetRadius(float32 radius); | ||||||
|  |  | ||||||
|  | 	// Return the triangle radius. | ||||||
|  | 	float32 GetRadius() const; | ||||||
|  |  | ||||||
|  | 	// Set the triangle coefficient of friction. | ||||||
|  | 	void SetFriction(float32 friction); | ||||||
|  |  | ||||||
|  | 	// Return the triangle coefficient of friction. | ||||||
|  | 	float32 GetFriction() const; | ||||||
|  | private: | ||||||
|  | 	friend class b3Cloth; | ||||||
|  | 	friend class b3Particle; | ||||||
|  | 	friend class b3ShearForce; | ||||||
|  | 	friend class b3StrechForce; | ||||||
|  | 	friend class b3MouseForce; | ||||||
|  | 	friend class b3ClothContactManager; | ||||||
|  | 	friend class b3ParticleTriangleContact; | ||||||
|  | 	friend class b3ClothSolver; | ||||||
|  | 	friend class b3ClothContactSolver; | ||||||
|  |  | ||||||
|  | 	b3ClothTriangle() { } | ||||||
|  | 	~b3ClothTriangle() { } | ||||||
|  |  | ||||||
|  | 	// Synchronize AABB | ||||||
|  | 	void Synchronize(const b3Vec3& displacement); | ||||||
|  |  | ||||||
|  | 	// Cloth | ||||||
|  | 	b3Cloth* m_cloth; | ||||||
|  |  | ||||||
|  | 	// Triangle index | ||||||
|  | 	u32 m_triangle; | ||||||
|  |  | ||||||
|  | 	// Radius | ||||||
|  | 	float32 m_radius; | ||||||
|  |  | ||||||
|  | 	// Coefficient of friction | ||||||
|  | 	float32 m_friction; | ||||||
|  |  | ||||||
|  | 	// AABB Proxy | ||||||
|  | 	b3ClothAABBProxy m_aabbProxy; | ||||||
|  |  | ||||||
|  | 	// Broadphase ID | ||||||
|  | 	u32 m_broadPhaseId; | ||||||
|  |  | ||||||
|  | 	// Alpha | ||||||
|  | 	float32 m_alpha; | ||||||
|  |  | ||||||
|  | 	// Strech matrix | ||||||
|  | 	float32 m_du1, m_dv1; | ||||||
|  | 	float32 m_du2, m_dv2; | ||||||
|  | 	float32 m_inv_det; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | inline u32 b3ClothTriangle::GetTriangle() const | ||||||
|  | { | ||||||
|  | 	return m_triangle; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline void b3ClothTriangle::SetRadius(float32 radius)  | ||||||
|  | { | ||||||
|  | 	m_radius = radius; | ||||||
|  | 	Synchronize(b3Vec3_zero); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline float32 b3ClothTriangle::GetRadius() const | ||||||
|  | { | ||||||
|  | 	return m_radius; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline void b3ClothTriangle::SetFriction(float32 friction) | ||||||
|  | { | ||||||
|  | 	m_friction = friction; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline float32 b3ClothTriangle::GetFriction() const | ||||||
|  | { | ||||||
|  | 	return m_friction; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										76
									
								
								include/bounce/cloth/contacts/cloth_particle_body_contact.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								include/bounce/cloth/contacts/cloth_particle_body_contact.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef B3_CLOTH_PARTICLE_BODY_CONTACT_H | ||||||
|  | #define B3_CLOTH_PARTICLE_BODY_CONTACT_H | ||||||
|  |  | ||||||
|  | #include <bounce/common/template/list.h> | ||||||
|  | #include <bounce/common/math/vec2.h> | ||||||
|  | #include <bounce/common/math/vec3.h> | ||||||
|  | #include <bounce/common/math/transform.h> | ||||||
|  |  | ||||||
|  | class b3Particle; | ||||||
|  | class b3Shape; | ||||||
|  |  | ||||||
|  | // A contact between a particle and a body | ||||||
|  | class b3ParticleBodyContact | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | private: | ||||||
|  | 	friend class b3List2<b3ParticleBodyContact>; | ||||||
|  | 	friend class b3Cloth; | ||||||
|  | 	friend class b3Particle; | ||||||
|  | 	friend class b3ClothContactManager; | ||||||
|  | 	friend class b3ClothSolver; | ||||||
|  | 	friend class b3ClothContactSolver; | ||||||
|  | 	friend struct b3ParticleBodyContactWorldPoint; | ||||||
|  |  | ||||||
|  | 	b3ParticleBodyContact() { } | ||||||
|  | 	~b3ParticleBodyContact() { } | ||||||
|  |  | ||||||
|  | 	void Update(); | ||||||
|  |  | ||||||
|  | 	b3Particle* m_p1; | ||||||
|  | 	b3Shape* m_s2; | ||||||
|  |  | ||||||
|  | 	bool m_active; | ||||||
|  | 	 | ||||||
|  | 	// Contact constraint | ||||||
|  | 	b3Vec3 m_normal1; | ||||||
|  | 	b3Vec3 m_localPoint1; | ||||||
|  | 	b3Vec3 m_localPoint2; | ||||||
|  | 	float32 m_normalImpulse; | ||||||
|  |  | ||||||
|  | 	// Friction constraint | ||||||
|  | 	b3Vec3 m_tangent1, m_tangent2; | ||||||
|  | 	b3Vec2 m_tangentImpulse; | ||||||
|  |  | ||||||
|  | 	b3ParticleBodyContact* m_prev; | ||||||
|  | 	b3ParticleBodyContact* m_next; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct b3ParticleBodyContactWorldPoint | ||||||
|  | { | ||||||
|  | 	void Initialize(const b3ParticleBodyContact* c, float32 rA, const b3Transform& xfA, float32 rB, const b3Transform& xfB); | ||||||
|  |  | ||||||
|  | 	b3Vec3 point; | ||||||
|  | 	b3Vec3 normal; | ||||||
|  | 	float32 separation; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -0,0 +1,65 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef B3_CLOTH_PARTICLE_TRIANGLE_CONTACT_H | ||||||
|  | #define B3_CLOTH_PARTICLE_TRIANGLE_CONTACT_H | ||||||
|  |  | ||||||
|  | #include <bounce/common/template/list.h> | ||||||
|  |  | ||||||
|  | class b3Particle; | ||||||
|  | class b3ClothTriangle; | ||||||
|  |  | ||||||
|  | // Contact between particle and a triangle | ||||||
|  | class b3ParticleTriangleContact | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | private: | ||||||
|  | 	friend class b3List2<b3ParticleTriangleContact>; | ||||||
|  | 	friend class b3Cloth; | ||||||
|  | 	friend class b3Particle; | ||||||
|  | 	friend class b3ClothTriangle; | ||||||
|  | 	friend class b3ClothContactManager; | ||||||
|  | 	friend class b3ClothContactSolver; | ||||||
|  |  | ||||||
|  | 	b3ParticleTriangleContact() { } | ||||||
|  | 	~b3ParticleTriangleContact() { } | ||||||
|  |  | ||||||
|  | 	void Update(); | ||||||
|  |  | ||||||
|  | 	// Particle | ||||||
|  | 	b3Particle* m_p1; | ||||||
|  |  | ||||||
|  | 	// Triangle | ||||||
|  | 	b3ClothTriangle* m_t2; | ||||||
|  | 	b3Particle* m_p2; | ||||||
|  | 	b3Particle* m_p3; | ||||||
|  | 	b3Particle* m_p4; | ||||||
|  |  | ||||||
|  | 	float32 m_w2, m_w3, m_w4; | ||||||
|  |  | ||||||
|  | 	float32 m_normalImpulse; | ||||||
|  | 	float32 m_tangentImpulse1; | ||||||
|  | 	float32 m_tangentImpulse2; | ||||||
|  |  | ||||||
|  | 	bool m_active; | ||||||
|  |  | ||||||
|  | 	b3ParticleTriangleContact* m_prev; | ||||||
|  | 	b3ParticleTriangleContact* m_next; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										126
									
								
								include/bounce/cloth/forces/strech_force.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								include/bounce/cloth/forces/strech_force.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef B3_STRECH_FORCE_H | ||||||
|  | #define B3_STRECH_FORCE_H | ||||||
|  |  | ||||||
|  | #include <bounce/cloth/forces/force.h> | ||||||
|  |  | ||||||
|  | class b3ClothTriangle; | ||||||
|  |  | ||||||
|  | struct b3StrechForceDef : public b3ForceDef | ||||||
|  | { | ||||||
|  | 	b3StrechForceDef() | ||||||
|  | 	{ | ||||||
|  | 		type = e_strechForce; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Triangle | ||||||
|  | 	b3ClothTriangle* triangle; | ||||||
|  |  | ||||||
|  | 	// Streching stiffness | ||||||
|  | 	float32 streching; | ||||||
|  |  | ||||||
|  | 	// Damping stiffness | ||||||
|  | 	float32 damping; | ||||||
|  | 	 | ||||||
|  | 	// Desired strechiness in u direction | ||||||
|  | 	float32 bu; | ||||||
|  |  | ||||||
|  | 	// Desired strechiness in v direction | ||||||
|  | 	float32 bv; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // Strech force acting on a cloth triangle. | ||||||
|  | class b3StrechForce : public b3Force | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	bool HasParticle(const b3Particle* particle) const; | ||||||
|  |  | ||||||
|  | 	b3ClothTriangle* GetTriangle() const; | ||||||
|  |  | ||||||
|  | 	float32 GetStrechingStiffness() const; | ||||||
|  |  | ||||||
|  | 	float32 GetDampingStiffness() const; | ||||||
|  | 	 | ||||||
|  | 	b3Vec3 GetActionForce1() const; | ||||||
|  |  | ||||||
|  | 	b3Vec3 GetActionForce2() const; | ||||||
|  | 	 | ||||||
|  | 	b3Vec3 GetActionForce3() const; | ||||||
|  | private: | ||||||
|  | 	friend class b3Force; | ||||||
|  | 	friend class b3Cloth; | ||||||
|  |  | ||||||
|  | 	b3StrechForce(const b3StrechForceDef* def); | ||||||
|  | 	~b3StrechForce(); | ||||||
|  |  | ||||||
|  | 	void Apply(const b3ClothForceSolverData* data); | ||||||
|  |  | ||||||
|  | 	// Solver shared | ||||||
|  |  | ||||||
|  | 	// Triangle | ||||||
|  | 	b3ClothTriangle* m_triangle; | ||||||
|  |  | ||||||
|  | 	// Streching stiffness | ||||||
|  | 	float32 m_ks; | ||||||
|  |  | ||||||
|  | 	// Damping stiffness | ||||||
|  | 	float32 m_kd; | ||||||
|  | 	 | ||||||
|  | 	// Desired strechiness in u direction | ||||||
|  | 	float32 m_bu; | ||||||
|  |  | ||||||
|  | 	// Desired strechiness in v direction | ||||||
|  | 	float32 m_bv; | ||||||
|  |  | ||||||
|  | 	// Action forces | ||||||
|  | 	b3Vec3 m_f1, m_f2, m_f3; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | inline b3ClothTriangle* b3StrechForce::GetTriangle() const | ||||||
|  | { | ||||||
|  | 	return m_triangle; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline float32 b3StrechForce::GetStrechingStiffness() const | ||||||
|  | { | ||||||
|  | 	return m_ks; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline float32 b3StrechForce::GetDampingStiffness() const | ||||||
|  | { | ||||||
|  | 	return m_kd; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline b3Vec3 b3StrechForce::GetActionForce1() const | ||||||
|  | { | ||||||
|  | 	return m_f1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline b3Vec3 b3StrechForce::GetActionForce2() const | ||||||
|  | { | ||||||
|  | 	return m_f2; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline b3Vec3 b3StrechForce::GetActionForce3() const | ||||||
|  | { | ||||||
|  | 	return m_f3; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										281
									
								
								include/bounce/cloth/particle.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										281
									
								
								include/bounce/cloth/particle.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,281 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef B3_PARTICLE_H | ||||||
|  | #define B3_PARTICLE_H | ||||||
|  |  | ||||||
|  | #include <bounce/cloth/cloth_collision.h> | ||||||
|  | #include <bounce/common/template/list.h> | ||||||
|  |  | ||||||
|  | class b3Cloth; | ||||||
|  |  | ||||||
|  | // Static particle: Can be moved manually. | ||||||
|  | // Kinematic particle: Non-zero velocity, can be moved by the solver. | ||||||
|  | // Dynamic particle: Non-zero velocity determined by force, can be moved by the solver. | ||||||
|  | enum b3ParticleType | ||||||
|  | { | ||||||
|  | 	e_staticParticle, | ||||||
|  | 	e_kinematicParticle, | ||||||
|  | 	e_dynamicParticle | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // Particle definition | ||||||
|  | struct b3ParticleDef | ||||||
|  | { | ||||||
|  | 	b3ParticleDef() | ||||||
|  | 	{ | ||||||
|  | 		type = e_staticParticle; | ||||||
|  | 		mass = 0.0f; | ||||||
|  | 		position.SetZero(); | ||||||
|  | 		velocity.SetZero(); | ||||||
|  | 		force.SetZero(); | ||||||
|  | 		radius = 0.0f; | ||||||
|  | 		friction = 0.0f; | ||||||
|  | 		userData = nullptr; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3ParticleType type; | ||||||
|  | 	float32 mass; | ||||||
|  | 	b3Vec3 position; | ||||||
|  | 	b3Vec3 velocity; | ||||||
|  | 	b3Vec3 force; | ||||||
|  | 	float32 radius; | ||||||
|  | 	float32 friction; | ||||||
|  | 	void* userData; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // A cloth particle. | ||||||
|  | class b3Particle | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	// Set the particle type. | ||||||
|  | 	void SetType(b3ParticleType type); | ||||||
|  |  | ||||||
|  | 	// Get the particle type. | ||||||
|  | 	b3ParticleType GetType() const; | ||||||
|  |  | ||||||
|  | 	// Get the vertex index. | ||||||
|  | 	u32 GetVertex() const; | ||||||
|  |  | ||||||
|  | 	// Set the particle position.  | ||||||
|  | 	// If the particle is dynamic changing the position directly might lead  | ||||||
|  | 	// to physically incorrect simulation behaviour. | ||||||
|  | 	void SetPosition(const b3Vec3& position); | ||||||
|  |  | ||||||
|  | 	// Get the particle position. | ||||||
|  | 	const b3Vec3& GetPosition() const; | ||||||
|  |  | ||||||
|  | 	// Set the particle velocity. | ||||||
|  | 	void SetVelocity(const b3Vec3& velocity); | ||||||
|  |  | ||||||
|  | 	// Get the particle velocity. | ||||||
|  | 	const b3Vec3& GetVelocity() const; | ||||||
|  |  | ||||||
|  | 	// Get the particle mass. | ||||||
|  | 	float32 GetMass() const; | ||||||
|  |  | ||||||
|  | 	// Set the particle radius. | ||||||
|  | 	void SetRadius(float32 radius); | ||||||
|  | 	 | ||||||
|  | 	// Get the particle radius. | ||||||
|  | 	float32 GetRadius() const; | ||||||
|  |  | ||||||
|  | 	// Set the particle coefficient of friction. | ||||||
|  | 	void SetFriction(float32 friction); | ||||||
|  | 	 | ||||||
|  | 	// Get the particle coefficient of friction. | ||||||
|  | 	float32 GetFriction() const; | ||||||
|  | 	 | ||||||
|  | 	// Apply a force. | ||||||
|  | 	void ApplyForce(const b3Vec3& force); | ||||||
|  |  | ||||||
|  | 	// Apply a translation. | ||||||
|  | 	void ApplyTranslation(const b3Vec3& translation); | ||||||
|  |  | ||||||
|  | 	// Get the next particle. | ||||||
|  | 	b3Particle* GetNext(); | ||||||
|  | private: | ||||||
|  | 	friend class b3List2<b3Particle>; | ||||||
|  | 	friend class b3Cloth; | ||||||
|  | 	friend class b3ClothContactManager; | ||||||
|  | 	friend class b3ClothSolver; | ||||||
|  | 	friend class b3ClothForceSolver; | ||||||
|  | 	friend class b3ClothTriangle; | ||||||
|  | 	friend class b3ParticleBodyContact; | ||||||
|  | 	friend class b3ParticleTriangleContact; | ||||||
|  | 	friend class b3ClothContactSolver; | ||||||
|  | 	friend class b3Force; | ||||||
|  | 	friend class b3StrechForce; | ||||||
|  | 	friend class b3ShearForce; | ||||||
|  | 	friend class b3SpringForce; | ||||||
|  | 	friend class b3MouseForce; | ||||||
|  |  | ||||||
|  | 	b3Particle(const b3ParticleDef& def, b3Cloth* cloth); | ||||||
|  | 	~b3Particle(); | ||||||
|  |  | ||||||
|  | 	// Synchronize particle AABB | ||||||
|  | 	void Synchronize(const b3Vec3& displacement); | ||||||
|  |  | ||||||
|  | 	// Synchronize triangles AABB | ||||||
|  | 	void SynchronizeTriangles(); | ||||||
|  |  | ||||||
|  | 	// Destroy contacts. | ||||||
|  | 	void DestroyContacts(); | ||||||
|  |  | ||||||
|  | 	// Type | ||||||
|  | 	b3ParticleType m_type; | ||||||
|  |  | ||||||
|  | 	// Position | ||||||
|  | 	b3Vec3 m_position; | ||||||
|  |  | ||||||
|  | 	// Velocity | ||||||
|  | 	b3Vec3 m_velocity; | ||||||
|  |  | ||||||
|  | 	// Applied external force | ||||||
|  | 	b3Vec3 m_force; | ||||||
|  |  | ||||||
|  | 	// Applied translation | ||||||
|  | 	b3Vec3 m_translation; | ||||||
|  |  | ||||||
|  | 	// Mass | ||||||
|  | 	float32 m_mass; | ||||||
|  |  | ||||||
|  | 	// Inverse mass | ||||||
|  | 	float32 m_invMass; | ||||||
|  |  | ||||||
|  | 	// Radius | ||||||
|  | 	float32 m_radius; | ||||||
|  |  | ||||||
|  | 	// Coefficient of friction | ||||||
|  | 	float32 m_friction; | ||||||
|  | 	 | ||||||
|  | 	// User data.  | ||||||
|  | 	void* m_userData; | ||||||
|  |  | ||||||
|  | 	// Cloth mesh vertex index. | ||||||
|  | 	u32 m_vertex; | ||||||
|  |  | ||||||
|  | 	// Solver temp | ||||||
|  |  | ||||||
|  | 	// Identifier | ||||||
|  | 	u32 m_solverId; | ||||||
|  |  | ||||||
|  | 	// Solution | ||||||
|  | 	b3Vec3 m_x; | ||||||
|  |  | ||||||
|  | 	// Parent cloth | ||||||
|  | 	b3Cloth* m_cloth; | ||||||
|  |  | ||||||
|  | 	// AABB Proxy | ||||||
|  | 	b3ClothAABBProxy m_aabbProxy; | ||||||
|  |  | ||||||
|  | 	// Broadphase ID | ||||||
|  | 	u32 m_broadPhaseId; | ||||||
|  |  | ||||||
|  | 	// Links to the cloth particle list. | ||||||
|  | 	b3Particle* m_prev; | ||||||
|  | 	b3Particle* m_next; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | inline b3ParticleType b3Particle::GetType() const | ||||||
|  | { | ||||||
|  | 	return m_type; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline u32 b3Particle::GetVertex() const | ||||||
|  | { | ||||||
|  | 	return m_vertex; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline void b3Particle::SetPosition(const b3Vec3& position) | ||||||
|  | { | ||||||
|  | 	b3Vec3 displacement = position - m_position; | ||||||
|  |  | ||||||
|  | 	m_position = position; | ||||||
|  | 	m_translation.SetZero(); | ||||||
|  |  | ||||||
|  | 	Synchronize(displacement); | ||||||
|  | 	SynchronizeTriangles(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline const b3Vec3& b3Particle::GetPosition() const | ||||||
|  | { | ||||||
|  | 	return m_position; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline void b3Particle::SetVelocity(const b3Vec3& velocity) | ||||||
|  | { | ||||||
|  | 	if (m_type == e_staticParticle) | ||||||
|  | 	{ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	m_velocity = velocity; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline const b3Vec3& b3Particle::GetVelocity() const | ||||||
|  | { | ||||||
|  | 	return m_velocity; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline float32 b3Particle::GetMass() const | ||||||
|  | { | ||||||
|  | 	return m_mass; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline void b3Particle::SetRadius(float32 radius) | ||||||
|  | { | ||||||
|  | 	m_radius = radius; | ||||||
|  | 	 | ||||||
|  | 	Synchronize(b3Vec3_zero); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline float32 b3Particle::GetRadius() const | ||||||
|  | { | ||||||
|  | 	return m_radius; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline void b3Particle::SetFriction(float32 friction) | ||||||
|  | { | ||||||
|  | 	m_friction = friction; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline float32 b3Particle::GetFriction() const | ||||||
|  | { | ||||||
|  | 	return m_friction; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline void b3Particle::ApplyForce(const b3Vec3& force) | ||||||
|  | { | ||||||
|  | 	if (m_type != e_dynamicParticle) | ||||||
|  | 	{ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	m_force += force; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline void b3Particle::ApplyTranslation(const b3Vec3& translation) | ||||||
|  | { | ||||||
|  | 	m_translation += translation; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline b3Particle* b3Particle::GetNext() | ||||||
|  | { | ||||||
|  | 	return m_next; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										40
									
								
								include/bounce/collision/sat/sat_edge_and_hull.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								include/bounce/collision/sat/sat_edge_and_hull.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef B3_EDGE_HULL_SAT_H | ||||||
|  | #define B3_EDGE_HULL_SAT_H | ||||||
|  |  | ||||||
|  | #include <bounce/collision/sat/sat.h> | ||||||
|  |  | ||||||
|  | struct b3Capsule; | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | float32 b3ProjectEdge(const b3Capsule* hull, const b3Plane& plane); | ||||||
|  |  | ||||||
|  | b3FaceQuery b3QueryFaceSeparation(const b3Transform& xf1, const b3Capsule* hull1, | ||||||
|  | 	const b3Transform& xf2, const b3Hull* hull2); | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | float32 b3ProjectEdge(const b3Vec3& P1, const b3Vec3& E1, const b3Vec3& P2, const b3Vec3& E2, const b3Vec3& C2); | ||||||
|  |  | ||||||
|  | b3EdgeQuery b3QueryEdgeSeparation(const b3Transform& xf1, const b3Capsule* hull1, | ||||||
|  | 	const b3Transform& xf2, const b3Hull* hull2); | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										33
									
								
								include/bounce/collision/sat/sat_vertex_and_hull.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								include/bounce/collision/sat/sat_vertex_and_hull.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef B3_VERTEX_HULL_SAT_H | ||||||
|  | #define B3_VERTEX_HULL_SAT_H | ||||||
|  |  | ||||||
|  | #include <bounce/collision/sat/sat.h> | ||||||
|  |  | ||||||
|  | struct b3Sphere; | ||||||
|  |  | ||||||
|  | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | float32 b3ProjectVertex(const b3Sphere* hull, const b3Plane& plane); | ||||||
|  |  | ||||||
|  | b3FaceQuery b3QueryFaceSeparation(const b3Transform& xf1, const b3Sphere* hull1, | ||||||
|  | 	const b3Transform& xf2, const b3Hull* hull2); | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										253
									
								
								include/bounce/collision/shapes/aabb3.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								include/bounce/collision/shapes/aabb3.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,253 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef B3_AABB_3_H | ||||||
|  | #define B3_AABB_3_H | ||||||
|  |  | ||||||
|  | #include <bounce/common/math/transform.h> | ||||||
|  |  | ||||||
|  | // A min-max representation of a three-dimensional AABB. | ||||||
|  | struct b3AABB3  | ||||||
|  | { | ||||||
|  | 	b3Vec3 m_lower; // lower vertex | ||||||
|  | 	b3Vec3 m_upper; // upper vertex | ||||||
|  |  | ||||||
|  | 	// Get the support vertex in a given direction. | ||||||
|  | 	b3Vec3 GetSupportVertex(const b3Vec3& direction) const | ||||||
|  | 	{ | ||||||
|  | 		b3Vec3 support; | ||||||
|  | 		support.x = direction.x < 0.0f ? m_lower.x : m_upper.x; | ||||||
|  | 		support.y = direction.y < 0.0f ? m_lower.y : m_upper.y; | ||||||
|  | 		support.z = direction.z < 0.0f ? m_lower.z : m_upper.z; | ||||||
|  | 		return support; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Set this AABB from a list of points. | ||||||
|  | 	void Set(const b3Vec3* points, u32 count) | ||||||
|  | 	{ | ||||||
|  | 		m_lower = m_upper = points[0]; | ||||||
|  | 		for (u32 i = 1; i < count; ++i) | ||||||
|  | 		{ | ||||||
|  | 			m_lower = b3Min(m_lower, points[i]); | ||||||
|  | 			m_upper = b3Max(m_upper, points[i]); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Set this AABB from a list of points and a transform. | ||||||
|  | 	void Set(const b3Vec3* points, u32 count, const b3Transform& xf) | ||||||
|  | 	{ | ||||||
|  | 		m_lower = m_upper = b3Mul(xf, points[0]); | ||||||
|  | 		for (u32 i = 1; i < count; ++i) | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 v = b3Mul(xf, points[i]); | ||||||
|  | 			m_lower = b3Min(m_lower, v); | ||||||
|  | 			m_upper = b3Max(m_upper, v); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Set this AABB from a triangle. | ||||||
|  | 	void Set(const b3Vec3& v1, const b3Vec3& v2, const b3Vec3& v3) | ||||||
|  | 	{ | ||||||
|  | 		m_lower = b3Min(v1, b3Min(v2, v3)); | ||||||
|  | 		m_upper = b3Max(v1, b3Max(v2, v3)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Set this AABB from a center point and a radius vector. | ||||||
|  | 	void Set(const b3Vec3& center, const b3Vec3& r) | ||||||
|  | 	{ | ||||||
|  | 		m_lower = center - r; | ||||||
|  | 		m_upper = center + r; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Set this AABB from a center point and a radius value. | ||||||
|  | 	void Set(const b3Vec3& center, float32 radius) | ||||||
|  | 	{ | ||||||
|  | 		b3Vec3 r(radius, radius, radius);	 | ||||||
|  | 		Set(center, r); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Extend this AABB by a scalar. | ||||||
|  | 	void Extend(float32 s)  | ||||||
|  | 	{ | ||||||
|  | 		b3Vec3 r(s, s, s); | ||||||
|  | 		m_lower -= r; | ||||||
|  | 		m_upper += r; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	// Extend this AABB by a radius vector. | ||||||
|  | 	void Extend(const b3Vec3& r) | ||||||
|  | 	{ | ||||||
|  | 		m_lower -= r; | ||||||
|  | 		m_upper += r; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Compute the centroid of this AABB. | ||||||
|  | 	b3Vec3 Centroid() const  | ||||||
|  | 	{ | ||||||
|  | 		return  0.5f * (m_lower + m_upper); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Compute the width of this AABB. | ||||||
|  | 	float32 Width() const  | ||||||
|  | 	{ | ||||||
|  | 		return m_upper.x - m_lower.x; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Compute the height of this AABB. | ||||||
|  | 	float32 Height() const  | ||||||
|  | 	{ | ||||||
|  | 		return m_upper.y - m_lower.y; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Compute the depth of this AABB. | ||||||
|  | 	float32 Depth() const  | ||||||
|  | 	{ | ||||||
|  | 		return m_upper.z - m_lower.z; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Compute the total of cubic units contained in this AABB. | ||||||
|  | 	float32 Volume() const  | ||||||
|  | 	{ | ||||||
|  | 		return Width() * Height() * Depth(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Compute the surface area of this AABB. | ||||||
|  | 	float32 SurfaceArea() const  | ||||||
|  | 	{ | ||||||
|  | 		return 2.0f * (Width() * Depth() + Width() * Height() + Depth() * Height()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Read the index of the longest axis of this AABB. | ||||||
|  | 	u32 GetLongestAxisIndex() const | ||||||
|  | 	{ | ||||||
|  | 		b3Vec3 c = Centroid(); | ||||||
|  | 		b3Vec3 r = m_upper - c; | ||||||
|  | 		float32 max = r[0]; | ||||||
|  | 		u32 i = 0; | ||||||
|  | 		if (r[1] > max) | ||||||
|  | 		{ | ||||||
|  | 			max = r[1]; | ||||||
|  | 			i = 1; | ||||||
|  | 		} | ||||||
|  | 		if (r[2] > max) | ||||||
|  | 		{ | ||||||
|  | 			max = r[2]; | ||||||
|  | 			i = 2; | ||||||
|  | 		} | ||||||
|  | 		return i; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Test if this AABB contains a point. | ||||||
|  | 	bool Contains(const b3Vec3& point) const | ||||||
|  | 	{ | ||||||
|  | 		return	m_lower.x <= point.x && point.x <= m_upper.x && | ||||||
|  | 				m_lower.y <= point.y && point.y <= m_upper.y && | ||||||
|  | 				m_lower.z <= point.z && point.z <= m_upper.z; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Test if this AABB contains another AABB. | ||||||
|  | 	bool Contains(const b3AABB3& aabb) const | ||||||
|  | 	{ | ||||||
|  | 		return Contains(aabb.m_lower) && Contains(aabb.m_upper); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Test if a ray intersects this AABB. | ||||||
|  | 	bool TestRay(float32& minFraction, const b3Vec3& p1, const b3Vec3& p2, float32 maxFraction) const | ||||||
|  | 	{ | ||||||
|  | 		b3Vec3 d = p2 - p1; | ||||||
|  | 		 | ||||||
|  | 		float32 lower = 0.0f; | ||||||
|  | 		float32 upper = maxFraction; | ||||||
|  | 		 | ||||||
|  | 		for (u32 i = 0; i < 3; ++i) | ||||||
|  | 		{ | ||||||
|  | 			float32 numerators[2], denominators[2]; | ||||||
|  |  | ||||||
|  | 			numerators[0] = p1[i] - m_lower[i]; | ||||||
|  | 			numerators[1] = m_upper[i] - p1[i]; | ||||||
|  |  | ||||||
|  | 			denominators[0] = -d[i]; | ||||||
|  | 			denominators[1] = d[i]; | ||||||
|  | 			 | ||||||
|  | 			for (u32 j = 0; j < 2; ++j) | ||||||
|  | 			{ | ||||||
|  | 				float32 numerator = numerators[j]; | ||||||
|  | 				float32 denominator = denominators[j]; | ||||||
|  | 				 | ||||||
|  | 				if (denominator == 0.0f) | ||||||
|  | 				{ | ||||||
|  | 					// s is parallel to this half-space. | ||||||
|  | 					if (numerator < 0.0f) | ||||||
|  | 					{ | ||||||
|  | 						// s is outside of this half-space. | ||||||
|  | 						// dot(n, p1) and dot(n, p2) < 0. | ||||||
|  | 						return false; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 				{ | ||||||
|  | 					if (denominator < 0.0f) | ||||||
|  | 					{ | ||||||
|  | 						// s enters this half-space. | ||||||
|  | 						if (numerator < lower * denominator) | ||||||
|  | 						{ | ||||||
|  | 							// Increase lower. | ||||||
|  | 							lower = numerator / denominator; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					else | ||||||
|  | 					{ | ||||||
|  | 						// s exits the half-space.	 | ||||||
|  | 						if (numerator < upper * denominator) | ||||||
|  | 						{ | ||||||
|  | 							// Decrease upper. | ||||||
|  | 							upper = numerator / denominator; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					// Exit if intersection becomes empty. | ||||||
|  | 					if (upper < lower) | ||||||
|  | 					{ | ||||||
|  | 						return false; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		B3_ASSERT(lower >= 0.0f && lower <= maxFraction); | ||||||
|  | 		minFraction = lower; | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // Compute an AABB that encloses two AABBs. | ||||||
|  | inline b3AABB3 b3Combine(const b3AABB3& a, const b3AABB3& b)  | ||||||
|  | { | ||||||
|  | 	b3AABB3 aabb; | ||||||
|  | 	aabb.m_lower = b3Min(a.m_lower, b.m_lower); | ||||||
|  | 	aabb.m_upper = b3Max(a.m_upper, b.m_upper); | ||||||
|  | 	return aabb; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Test if two AABBs are overlapping. | ||||||
|  | inline bool b3TestOverlap(const b3AABB3& a, const b3AABB3& b)  | ||||||
|  | { | ||||||
|  | 	return (a.m_lower.x <= b.m_upper.x) &&	(a.m_lower.y <= b.m_upper.y) &&	(a.m_lower.z <= b.m_upper.z) && | ||||||
|  | 		(a.m_upper.x >= b.m_lower.x) && (a.m_upper.y >= b.m_lower.y) &&	(a.m_upper.z >= b.m_lower.z); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -29,8 +29,6 @@ | |||||||
| #define B3_PLATFORM B3_WINDOWS | #define B3_PLATFORM B3_WINDOWS | ||||||
| #elif defined( __APPLE__ ) | #elif defined( __APPLE__ ) | ||||||
| #define B3_PLATFORM B3_MAC | #define B3_PLATFORM B3_MAC | ||||||
| #elif defined(_arch_dreamcast) |  | ||||||
| #define B3_PLATFORM B3_DREAMCAST |  | ||||||
| #else | #else | ||||||
| #define B3_PLATFORM B3_UNIX | #define B3_PLATFORM B3_UNIX | ||||||
| #endif | #endif | ||||||
| @@ -159,55 +157,6 @@ private: | |||||||
| 	double m_t; | 	double m_t; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #elif B3_PLATFORM == B3_DREAMCAST |  | ||||||
|  |  | ||||||
| #include <kos.h> |  | ||||||
|  |  | ||||||
| class b3Time |  | ||||||
| { |  | ||||||
| public: |  | ||||||
|     b3Time() |  | ||||||
|     { |  | ||||||
|         m_c0 = timer_us_gettime64(); |  | ||||||
|         m_t0 = 0.0; |  | ||||||
|         m_t = 0.0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Get the accumulated time in miliseconds from this timer. |  | ||||||
|     double GetCurrentMilis() const |  | ||||||
|     { |  | ||||||
|         return m_t; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Get the elapsed time since this timer was updated. |  | ||||||
|     double GetElapsedMilis() const |  | ||||||
|     { |  | ||||||
|         return m_t - m_t0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Add the elapsed time since this function was called to this timer. |  | ||||||
|     void Update() |  | ||||||
|     { |  | ||||||
|         uint64_t c = timer_us_gettime64(); |  | ||||||
|         double dt = double(c - m_c0) * 0.000001; |  | ||||||
|         m_c0 = c; |  | ||||||
|         Add(dt); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Add time to this timer. |  | ||||||
|     void Add(double dt) |  | ||||||
|     { |  | ||||||
|         m_t0 = m_t; |  | ||||||
|         m_t += dt; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| private: |  | ||||||
|     uint64_t m_c0; |  | ||||||
|     double m_t0; |  | ||||||
|     double m_t; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #else | #else | ||||||
|  |  | ||||||
| #include <time.h> | #include <time.h> | ||||||
|   | |||||||
| @@ -0,0 +1,78 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef B3_SOFT_BODY_NODE_BODY_CONTACT_H | ||||||
|  | #define B3_SOFT_BODY_NODE_BODY_CONTACT_H | ||||||
|  |  | ||||||
|  | #include <bounce/common/template/list.h> | ||||||
|  | #include <bounce/common/math/vec2.h> | ||||||
|  | #include <bounce/common/math/vec3.h> | ||||||
|  | #include <bounce/common/math/transform.h> | ||||||
|  |  | ||||||
|  | struct b3SoftBodyNode; | ||||||
|  | class b3Shape; | ||||||
|  |  | ||||||
|  | // A contact between a node and a body | ||||||
|  | class b3NodeBodyContact | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | private: | ||||||
|  | 	friend class b3List2<b3NodeBodyContact>; | ||||||
|  | 	friend class b3SoftBody; | ||||||
|  | 	friend class b3SoftBodyContactManager; | ||||||
|  | 	friend struct b3SoftBodyNode; | ||||||
|  | 	friend class b3SoftBodySolver; | ||||||
|  | 	friend class b3SoftBodyContactSolver; | ||||||
|  | 	friend struct b3NodeBodyContactWorldPoint; | ||||||
|  |  | ||||||
|  | 	b3NodeBodyContact() { } | ||||||
|  | 	~b3NodeBodyContact() { } | ||||||
|  | 	 | ||||||
|  | 	void Update(); | ||||||
|  |  | ||||||
|  | 	b3SoftBodyNode* m_n1; | ||||||
|  | 	b3Shape* m_s2; | ||||||
|  |  | ||||||
|  | 	// Is the contact active? | ||||||
|  | 	bool m_active; | ||||||
|  | 	 | ||||||
|  | 	// Contact constraint | ||||||
|  | 	b3Vec3 m_normal1; | ||||||
|  | 	b3Vec3 m_localPoint1; | ||||||
|  | 	b3Vec3 m_localPoint2; | ||||||
|  | 	float32 m_normalImpulse; | ||||||
|  |  | ||||||
|  | 	// Friction constraint | ||||||
|  | 	b3Vec3 m_tangent1, m_tangent2; | ||||||
|  | 	b3Vec2 m_tangentImpulse; | ||||||
|  |  | ||||||
|  | 	// List pointers into the soft body | ||||||
|  | 	b3NodeBodyContact* m_prev; | ||||||
|  | 	b3NodeBodyContact* m_next; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct b3NodeBodyContactWorldPoint | ||||||
|  | { | ||||||
|  | 	void Initialize(const b3NodeBodyContact* c, float32 rA, const b3Transform& xfA, float32 rB, const b3Transform& xfB); | ||||||
|  |  | ||||||
|  | 	b3Vec3 point; | ||||||
|  | 	b3Vec3 normal; | ||||||
|  | 	float32 separation; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif  | ||||||
							
								
								
									
										41
									
								
								src/bounce/cloth/cloth_triangle.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/bounce/cloth/cloth_triangle.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <bounce/cloth/cloth_triangle.h> | ||||||
|  | #include <bounce/cloth/cloth.h> | ||||||
|  | #include <bounce/cloth/particle.h> | ||||||
|  | #include <bounce/cloth/cloth_mesh.h> | ||||||
|  |  | ||||||
|  | void b3ClothTriangle::Synchronize(const b3Vec3& displacement) | ||||||
|  | { | ||||||
|  | 	b3ClothMeshTriangle* triangle = m_cloth->m_mesh->triangles + m_triangle; | ||||||
|  |  | ||||||
|  | 	b3Particle* p1 = m_cloth->m_particles[triangle->v1]; | ||||||
|  | 	b3Particle* p2 = m_cloth->m_particles[triangle->v2]; | ||||||
|  | 	b3Particle* p3 = m_cloth->m_particles[triangle->v3]; | ||||||
|  |  | ||||||
|  | 	b3Vec3 x1 = p1->m_position; | ||||||
|  | 	b3Vec3 x2 = p2->m_position; | ||||||
|  | 	b3Vec3 x3 = p3->m_position; | ||||||
|  |  | ||||||
|  | 	b3AABB3 aabb; | ||||||
|  | 	aabb.Set(x1, x2, x3); | ||||||
|  | 	aabb.Extend(m_radius); | ||||||
|  |  | ||||||
|  | 	m_cloth->m_contactManager.m_broadPhase.MoveProxy(m_broadPhaseId, aabb, displacement); | ||||||
|  | } | ||||||
							
								
								
									
										62
									
								
								src/bounce/cloth/contacts/cloth_particle_body_contact.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/bounce/cloth/contacts/cloth_particle_body_contact.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <bounce/cloth/contacts/cloth_particle_body_contact.h> | ||||||
|  | #include <bounce/cloth/particle.h> | ||||||
|  | #include <bounce/dynamics/shapes/shape.h> | ||||||
|  | #include <bounce/dynamics/body.h> | ||||||
|  |  | ||||||
|  | void b3ParticleBodyContact::Update() | ||||||
|  | { | ||||||
|  | 	b3Sphere sphere; | ||||||
|  | 	sphere.radius = m_p1->m_radius; | ||||||
|  | 	sphere.vertex = m_p1->m_position; | ||||||
|  |  | ||||||
|  | 	b3Shape* shape = m_s2; | ||||||
|  | 	b3Body* body = shape->GetBody(); | ||||||
|  | 	b3Transform xf = body->GetTransform(); | ||||||
|  |  | ||||||
|  | 	b3TestSphereOutput out; | ||||||
|  | 	if (shape->TestSphere(&out, sphere, xf) == false) | ||||||
|  | 	{ | ||||||
|  | 		m_active = false; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	m_active = true; | ||||||
|  | 	m_normal1 = -out.normal; | ||||||
|  | 	m_localPoint1.SetZero(); | ||||||
|  | 	m_localPoint2 = body->GetLocalPoint(out.point); | ||||||
|  | 	m_tangent1 = b3Perp(m_normal1); | ||||||
|  | 	m_tangent2 = b3Cross(m_tangent1, m_normal1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void b3ParticleBodyContactWorldPoint::Initialize(const b3ParticleBodyContact* c, float32 rA, const b3Transform& xfA, float32 rB, const b3Transform& xfB) | ||||||
|  | { | ||||||
|  | 	b3Vec3 nA = c->m_normal1; | ||||||
|  |  | ||||||
|  | 	b3Vec3 cA = xfA * c->m_localPoint1; | ||||||
|  | 	b3Vec3 cB = xfB * c->m_localPoint2; | ||||||
|  |  | ||||||
|  | 	b3Vec3 pA = cA + rA * nA; | ||||||
|  | 	b3Vec3 pB = cB - rB * nA; | ||||||
|  |  | ||||||
|  | 	point = 0.5f * (pA + pB); | ||||||
|  | 	normal = nA; | ||||||
|  | 	separation = b3Dot(cB - cA, nA) - rA - rB; | ||||||
|  | } | ||||||
							
								
								
									
										179
									
								
								src/bounce/cloth/contacts/cloth_particle_triangle_contact.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								src/bounce/cloth/contacts/cloth_particle_triangle_contact.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,179 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <bounce/cloth/contacts/cloth_particle_triangle_contact.h> | ||||||
|  | #include <bounce/cloth/cloth_mesh.h> | ||||||
|  | #include <bounce/cloth/particle.h> | ||||||
|  | #include <bounce/cloth/cloth_triangle.h> | ||||||
|  | #include <bounce/common/geometry.h> | ||||||
|  |  | ||||||
|  | // Solve constrained Barycentric coordinates for point Q | ||||||
|  | static void b3Solve3(float32 out[3], | ||||||
|  | 	const b3Vec3& A, const b3Vec3& B, const b3Vec3& C, | ||||||
|  | 	const b3Vec3& Q) | ||||||
|  | { | ||||||
|  | 	// Test vertex regions | ||||||
|  | 	float32 wAB[3], wBC[3], wCA[3]; | ||||||
|  | 	b3BarycentricCoordinates(wAB, A, B, Q); | ||||||
|  | 	b3BarycentricCoordinates(wBC, B, C, Q); | ||||||
|  | 	b3BarycentricCoordinates(wCA, C, A, Q); | ||||||
|  |  | ||||||
|  | 	// R A | ||||||
|  | 	if (wAB[1] <= 0.0f && wCA[0] <= 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		out[0] = 1.0f; | ||||||
|  | 		out[1] = 0.0f; | ||||||
|  | 		out[2] = 0.0f; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// R B | ||||||
|  | 	if (wAB[0] <= 0.0f && wBC[1] <= 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		out[0] = 0.0f; | ||||||
|  | 		out[1] = 1.0f; | ||||||
|  | 		out[2] = 0.0f; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// R C | ||||||
|  | 	if (wBC[0] <= 0.0f && wCA[1] <= 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		out[0] = 0.0f; | ||||||
|  | 		out[1] = 0.0f; | ||||||
|  | 		out[2] = 1.0f; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Test edge regions		 | ||||||
|  | 	float32 wABC[4]; | ||||||
|  | 	b3BarycentricCoordinates(wABC, A, B, C, Q); | ||||||
|  |  | ||||||
|  | 	// R AB | ||||||
|  | 	if (wAB[0] > 0.0f && wAB[1] > 0.0f && wABC[3] * wABC[2] <= 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		float32 divisor = wAB[2]; | ||||||
|  | 		B3_ASSERT(divisor > 0.0f); | ||||||
|  | 		float32 s = 1.0f / divisor; | ||||||
|  | 		out[0] = s * wAB[0]; | ||||||
|  | 		out[1] = s * wAB[1]; | ||||||
|  | 		out[2] = 0.0f; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// R BC | ||||||
|  | 	if (wBC[0] > 0.0f && wBC[1] > 0.0f && wABC[3] * wABC[0] <= 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		float32 divisor = wBC[2]; | ||||||
|  | 		B3_ASSERT(divisor > 0.0f); | ||||||
|  | 		float32 s = 1.0f / divisor; | ||||||
|  | 		out[0] = 0.0f; | ||||||
|  | 		out[1] = s * wBC[0]; | ||||||
|  | 		out[2] = s * wBC[1]; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// R CA | ||||||
|  | 	if (wCA[0] > 0.0f && wCA[1] > 0.0f && wABC[3] * wABC[1] <= 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		float32 divisor = wCA[2]; | ||||||
|  | 		B3_ASSERT(divisor > 0.0f); | ||||||
|  | 		float32 s = 1.0f / divisor; | ||||||
|  | 		out[0] = s * wCA[1]; | ||||||
|  | 		out[1] = 0.0f; | ||||||
|  | 		out[2] = s * wCA[0]; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// R ABC/ACB | ||||||
|  | 	float32 divisor = wABC[3]; | ||||||
|  | 	if (divisor == 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		float32 s = 1.0f / 3.0f; | ||||||
|  | 		out[0] = s; | ||||||
|  | 		out[1] = s; | ||||||
|  | 		out[2] = s; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	B3_ASSERT(divisor > 0.0f); | ||||||
|  | 	float32 s = 1.0f / divisor; | ||||||
|  | 	out[0] = s * wABC[0]; | ||||||
|  | 	out[1] = s * wABC[1]; | ||||||
|  | 	out[2] = s * wABC[2]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void b3ParticleTriangleContact::Update() | ||||||
|  | { | ||||||
|  | 	b3Vec3 A = m_p2->m_position; | ||||||
|  | 	b3Vec3 B = m_p3->m_position; | ||||||
|  | 	b3Vec3 C = m_p4->m_position; | ||||||
|  |  | ||||||
|  | 	b3Vec3 N = b3Cross(B - A, C - A); | ||||||
|  | 	float32 len = N.Normalize(); | ||||||
|  |  | ||||||
|  | 	// Is ABC degenerate? | ||||||
|  | 	if (len == 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		m_active = false; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	float32 r1 = m_p1->m_radius; | ||||||
|  | 	float32 r2 = m_t2->m_radius; | ||||||
|  |  | ||||||
|  | 	float32 totalRadius = r1 + r2; | ||||||
|  |  | ||||||
|  | 	b3Vec3 P1 = m_p1->m_position; | ||||||
|  |  | ||||||
|  | 	float32 distance = b3Dot(N, P1 - A); | ||||||
|  |  | ||||||
|  | 	// Is P1 below the plane? | ||||||
|  | 	if (distance < -totalRadius) | ||||||
|  | 	{ | ||||||
|  | 		m_active = false; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Is P1 above the plane? | ||||||
|  | 	if (distance > totalRadius) | ||||||
|  | 	{ | ||||||
|  | 		m_active = false; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Closest point on ABC to P1 | ||||||
|  | 	float32 wABC[3]; | ||||||
|  | 	b3Solve3(wABC, A, B, C, P1); | ||||||
|  |  | ||||||
|  | 	b3Vec3 P2 = wABC[0] * A + wABC[1] * B + wABC[2] * C; | ||||||
|  |  | ||||||
|  | 	if (b3DistanceSquared(P1, P2) > totalRadius * totalRadius) | ||||||
|  | 	{ | ||||||
|  | 		m_active = false; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Activate the contact | ||||||
|  | 	m_active = true; | ||||||
|  |  | ||||||
|  | 	// Store Barycentric coordinates for P1 | ||||||
|  | 	m_w2 = wABC[0]; | ||||||
|  | 	m_w3 = wABC[1]; | ||||||
|  | 	m_w4 = wABC[2]; | ||||||
|  | } | ||||||
							
								
								
									
										329
									
								
								src/bounce/cloth/forces/strech_force.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										329
									
								
								src/bounce/cloth/forces/strech_force.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,329 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <bounce/cloth/forces/strech_force.h> | ||||||
|  | #include <bounce/cloth/cloth_triangle.h> | ||||||
|  | #include <bounce/cloth/particle.h> | ||||||
|  | #include <bounce/cloth/cloth.h> | ||||||
|  | #include <bounce/cloth/cloth_mesh.h> | ||||||
|  | #include <bounce/cloth/cloth_force_solver.h> | ||||||
|  | #include <bounce/sparse/dense_vec3.h> | ||||||
|  | #include <bounce/sparse/sparse_mat33.h> | ||||||
|  |  | ||||||
|  | b3StrechForce::b3StrechForce(const b3StrechForceDef* def) | ||||||
|  | { | ||||||
|  | 	m_type = e_strechForce; | ||||||
|  | 	m_triangle = def->triangle; | ||||||
|  | 	m_ks = def->streching; | ||||||
|  | 	m_kd = def->damping; | ||||||
|  | 	m_bu = def->bu; | ||||||
|  | 	m_bv = def->bv; | ||||||
|  | 	m_f1.SetZero(); | ||||||
|  | 	m_f2.SetZero(); | ||||||
|  | 	m_f3.SetZero(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | b3StrechForce::~b3StrechForce() | ||||||
|  | { | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool b3StrechForce::HasParticle(const b3Particle* particle) const | ||||||
|  | { | ||||||
|  | 	b3Cloth* cloth = m_triangle->m_cloth; | ||||||
|  | 	u32 triangleIndex = m_triangle->m_triangle; | ||||||
|  | 	b3ClothMeshTriangle* triangle = cloth->m_mesh->triangles + triangleIndex; | ||||||
|  |  | ||||||
|  | 	b3Particle* p1 = cloth->m_particles[triangle->v1]; | ||||||
|  | 	b3Particle* p2 = cloth->m_particles[triangle->v2]; | ||||||
|  | 	b3Particle* p3 = cloth->m_particles[triangle->v3]; | ||||||
|  |  | ||||||
|  | 	return p1 == particle || p2 == particle || p3 == particle; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void b3StrechForce::Apply(const b3ClothForceSolverData* data) | ||||||
|  | { | ||||||
|  | 	b3Cloth* cloth = m_triangle->m_cloth; | ||||||
|  | 	u32 triangleIndex = m_triangle->m_triangle; | ||||||
|  | 	b3ClothMeshTriangle* triangle = cloth->m_mesh->triangles + triangleIndex; | ||||||
|  |  | ||||||
|  | 	float32 alpha = m_triangle->m_alpha; | ||||||
|  | 	float32 du1 = m_triangle->m_du1; | ||||||
|  | 	float32 dv1 = m_triangle->m_dv1; | ||||||
|  | 	float32 du2 = m_triangle->m_du2; | ||||||
|  | 	float32 dv2 = m_triangle->m_dv2; | ||||||
|  | 	float32 inv_det = m_triangle->m_inv_det; | ||||||
|  |  | ||||||
|  | 	b3Particle* p1 = cloth->m_particles[triangle->v1]; | ||||||
|  | 	b3Particle* p2 = cloth->m_particles[triangle->v2]; | ||||||
|  | 	b3Particle* p3 = cloth->m_particles[triangle->v3]; | ||||||
|  |  | ||||||
|  | 	u32 i1 = p1->m_solverId; | ||||||
|  | 	u32 i2 = p2->m_solverId; | ||||||
|  | 	u32 i3 = p3->m_solverId; | ||||||
|  |  | ||||||
|  | 	b3DenseVec3& x = *data->x; | ||||||
|  | 	b3DenseVec3& v = *data->v; | ||||||
|  | 	b3DenseVec3& f = *data->f; | ||||||
|  | 	b3SparseMat33& dfdx = *data->dfdx; | ||||||
|  | 	b3SparseMat33& dfdv = *data->dfdv; | ||||||
|  |  | ||||||
|  | 	b3Vec3 x1 = x[i1]; | ||||||
|  | 	b3Vec3 x2 = x[i2]; | ||||||
|  | 	b3Vec3 x3 = x[i3]; | ||||||
|  |  | ||||||
|  | 	b3Vec3 v1 = v[i1]; | ||||||
|  | 	b3Vec3 v2 = v[i2]; | ||||||
|  | 	b3Vec3 v3 = v[i3]; | ||||||
|  |  | ||||||
|  | 	b3Mat33 I; I.SetIdentity(); | ||||||
|  |  | ||||||
|  | 	b3Vec3 dx1 = x2 - x1; | ||||||
|  | 	b3Vec3 dx2 = x3 - x1; | ||||||
|  |  | ||||||
|  | 	b3Vec3 wu = inv_det * (dv2 * dx1 - dv1 * dx2); | ||||||
|  | 	float32 len_wu = b3Length(wu); | ||||||
|  |  | ||||||
|  | 	b3Vec3 wv = inv_det * (-du2 * dx1 + du1 * dx2); | ||||||
|  | 	float32 len_wv = b3Length(wv); | ||||||
|  |  | ||||||
|  | 	b3Vec3 dwudx; | ||||||
|  | 	dwudx[0] = inv_det * (dv1 - dv2); | ||||||
|  | 	dwudx[1] = inv_det * dv2; | ||||||
|  | 	dwudx[2] = -inv_det * dv1; | ||||||
|  |  | ||||||
|  | 	b3Vec3 dwvdx; | ||||||
|  | 	dwvdx[0] = inv_det * (du2 - du1); | ||||||
|  | 	dwvdx[1] = -inv_det * du2; | ||||||
|  | 	dwvdx[2] = inv_det * du1; | ||||||
|  |  | ||||||
|  | 	m_f1.SetZero(); | ||||||
|  | 	m_f2.SetZero(); | ||||||
|  | 	m_f3.SetZero(); | ||||||
|  |  | ||||||
|  | 	if (len_wu > 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		float32 inv_len_wu = 1.0f / len_wu; | ||||||
|  | 		b3Vec3 n_wu = inv_len_wu * wu; | ||||||
|  |  | ||||||
|  | 		// Jacobian | ||||||
|  | 		b3Vec3 dCudx[3]; | ||||||
|  | 		for (u32 i = 0; i < 3; ++i) | ||||||
|  | 		{ | ||||||
|  | 			dCudx[i] = alpha * dwudx[i] * n_wu; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (m_ks > 0.0f) | ||||||
|  | 		{ | ||||||
|  | 			if (len_wu > m_bu) | ||||||
|  | 			{ | ||||||
|  | 				float32 Cu = alpha * (len_wu - m_bu); | ||||||
|  |  | ||||||
|  | 				// Force | ||||||
|  | 				b3Vec3 fs[3]; | ||||||
|  | 				for (u32 i = 0; i < 3; ++i) | ||||||
|  | 				{ | ||||||
|  | 					fs[i] = -m_ks * Cu * dCudx[i]; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				m_f1 += fs[0]; | ||||||
|  | 				m_f2 += fs[1]; | ||||||
|  | 				m_f3 += fs[2]; | ||||||
|  |  | ||||||
|  | 				// Force derivative | ||||||
|  | 				b3Mat33 K[3][3]; | ||||||
|  | 				for (u32 i = 0; i < 3; ++i) | ||||||
|  | 				{ | ||||||
|  | 					for (u32 j = 0; j < 3; ++j) | ||||||
|  | 					{ | ||||||
|  | 						b3Mat33 d2Cuxij = (alpha * inv_len_wu * dwudx[i] * dwudx[j]) * (I - b3Outer(n_wu, n_wu)); | ||||||
|  |  | ||||||
|  | 						b3Mat33 Kij = -m_ks * (b3Outer(dCudx[i], dCudx[j]) + Cu * d2Cuxij); | ||||||
|  |  | ||||||
|  | 						K[i][j] = Kij; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				dfdx(i1, i1) += K[0][0]; | ||||||
|  | 				dfdx(i1, i2) += K[0][1]; | ||||||
|  | 				dfdx(i1, i3) += K[0][2]; | ||||||
|  |  | ||||||
|  | 				dfdx(i2, i1) += K[1][0]; | ||||||
|  | 				dfdx(i2, i2) += K[1][1]; | ||||||
|  | 				dfdx(i2, i3) += K[1][2]; | ||||||
|  |  | ||||||
|  | 				dfdx(i3, i1) += K[2][0]; | ||||||
|  | 				dfdx(i3, i2) += K[2][1]; | ||||||
|  | 				dfdx(i3, i3) += K[2][2]; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (m_kd > 0.0f) | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 vs[3] = { v1, v2, v3 }; | ||||||
|  | 			float32 dCudt = 0.0f; | ||||||
|  | 			for (u32 i = 0; i < 3; ++i) | ||||||
|  | 			{ | ||||||
|  | 				dCudt += b3Dot(dCudx[i], vs[i]); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Force | ||||||
|  | 			b3Vec3 fs[3]; | ||||||
|  | 			for (u32 i = 0; i < 3; ++i) | ||||||
|  | 			{ | ||||||
|  | 				fs[i] = -m_kd * dCudt * dCudx[i]; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			m_f1 += fs[0]; | ||||||
|  | 			m_f2 += fs[1]; | ||||||
|  | 			m_f3 += fs[2]; | ||||||
|  |  | ||||||
|  | 			// Force derivative | ||||||
|  | 			b3Mat33 K[3][3]; | ||||||
|  | 			for (u32 i = 0; i < 3; ++i) | ||||||
|  | 			{ | ||||||
|  | 				for (u32 j = 0; j < 3; ++j) | ||||||
|  | 				{ | ||||||
|  | 					b3Mat33 Kij = -m_kd * b3Outer(dCudx[i], dCudx[j]); | ||||||
|  |  | ||||||
|  | 					K[i][j] = Kij; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			dfdv(i1, i1) += K[0][0]; | ||||||
|  | 			dfdv(i1, i2) += K[0][1]; | ||||||
|  | 			dfdv(i1, i3) += K[0][2]; | ||||||
|  |  | ||||||
|  | 			dfdv(i2, i1) += K[1][0]; | ||||||
|  | 			dfdv(i2, i2) += K[1][1]; | ||||||
|  | 			dfdv(i2, i3) += K[1][2]; | ||||||
|  |  | ||||||
|  | 			dfdv(i3, i1) += K[2][0]; | ||||||
|  | 			dfdv(i3, i2) += K[2][1]; | ||||||
|  | 			dfdv(i3, i3) += K[2][2]; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (len_wv > 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		float32 inv_len_wv = 1.0f / len_wv; | ||||||
|  | 		b3Vec3 n_wv = inv_len_wv * wv; | ||||||
|  |  | ||||||
|  | 		// Jacobian | ||||||
|  | 		b3Vec3 dCvdx[3]; | ||||||
|  | 		for (u32 i = 0; i < 3; ++i) | ||||||
|  | 		{ | ||||||
|  | 			dCvdx[i] = alpha * dwvdx[i] * n_wv; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (m_ks > 0.0f) | ||||||
|  | 		{ | ||||||
|  | 			if (len_wv > m_bv) | ||||||
|  | 			{ | ||||||
|  | 				float32 Cv = alpha * (len_wv - m_bv); | ||||||
|  |  | ||||||
|  | 				// Force | ||||||
|  | 				b3Vec3 fs[3]; | ||||||
|  | 				for (u32 i = 0; i < 3; ++i) | ||||||
|  | 				{ | ||||||
|  | 					fs[i] = -m_ks * Cv * dCvdx[i]; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				m_f1 += fs[0]; | ||||||
|  | 				m_f2 += fs[1]; | ||||||
|  | 				m_f3 += fs[2]; | ||||||
|  |  | ||||||
|  | 				// Force derivative | ||||||
|  | 				b3Mat33 K[3][3]; | ||||||
|  | 				for (u32 i = 0; i < 3; ++i) | ||||||
|  | 				{ | ||||||
|  | 					for (u32 j = 0; j < 3; ++j) | ||||||
|  | 					{ | ||||||
|  | 						b3Mat33 d2Cvxij = (alpha * inv_len_wv * dwvdx[i] * dwvdx[j]) * (I - b3Outer(n_wv, n_wv)); | ||||||
|  |  | ||||||
|  | 						b3Mat33 Kij = -m_ks * (b3Outer(dCvdx[i], dCvdx[j]) + Cv * d2Cvxij); | ||||||
|  |  | ||||||
|  | 						K[i][j] = Kij; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				dfdx(i1, i1) += K[0][0]; | ||||||
|  | 				dfdx(i1, i2) += K[0][1]; | ||||||
|  | 				dfdx(i1, i3) += K[0][2]; | ||||||
|  |  | ||||||
|  | 				dfdx(i2, i1) += K[1][0]; | ||||||
|  | 				dfdx(i2, i2) += K[1][1]; | ||||||
|  | 				dfdx(i2, i3) += K[1][2]; | ||||||
|  |  | ||||||
|  | 				dfdx(i3, i1) += K[2][0]; | ||||||
|  | 				dfdx(i3, i2) += K[2][1]; | ||||||
|  | 				dfdx(i3, i3) += K[2][2]; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (m_kd > 0.0f) | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 vs[3] = { v1, v2, v3 }; | ||||||
|  |  | ||||||
|  | 			float32 dCvdt = 0.0f; | ||||||
|  | 			for (u32 i = 0; i < 3; ++i) | ||||||
|  | 			{ | ||||||
|  | 				dCvdt += b3Dot(dCvdx[i], vs[i]); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Force | ||||||
|  | 			b3Vec3 fs[3]; | ||||||
|  | 			for (u32 i = 0; i < 3; ++i) | ||||||
|  | 			{ | ||||||
|  | 				fs[i] = -m_kd * dCvdt * dCvdx[i]; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			m_f1 += fs[0]; | ||||||
|  | 			m_f2 += fs[1]; | ||||||
|  | 			m_f3 += fs[2]; | ||||||
|  |  | ||||||
|  | 			// Force derivative | ||||||
|  | 			b3Mat33 K[3][3]; | ||||||
|  | 			for (u32 i = 0; i < 3; ++i) | ||||||
|  | 			{ | ||||||
|  | 				for (u32 j = 0; j < 3; ++j) | ||||||
|  | 				{ | ||||||
|  | 					b3Mat33 Kij = -m_kd * b3Outer(dCvdx[i], dCvdx[j]); | ||||||
|  |  | ||||||
|  | 					K[i][j] = Kij; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			dfdv(i1, i1) += K[0][0]; | ||||||
|  | 			dfdv(i1, i2) += K[0][1]; | ||||||
|  | 			dfdv(i1, i3) += K[0][2]; | ||||||
|  |  | ||||||
|  | 			dfdv(i2, i1) += K[1][0]; | ||||||
|  | 			dfdv(i2, i2) += K[1][1]; | ||||||
|  | 			dfdv(i2, i3) += K[1][2]; | ||||||
|  |  | ||||||
|  | 			dfdv(i3, i1) += K[2][0]; | ||||||
|  | 			dfdv(i3, i2) += K[2][1]; | ||||||
|  | 			dfdv(i3, i3) += K[2][2]; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	f[i1] += m_f1; | ||||||
|  | 	f[i2] += m_f2; | ||||||
|  | 	f[i3] += m_f3; | ||||||
|  | } | ||||||
							
								
								
									
										144
									
								
								src/bounce/cloth/particle.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								src/bounce/cloth/particle.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <bounce/cloth/particle.h> | ||||||
|  | #include <bounce/cloth/cloth.h> | ||||||
|  | #include <bounce/cloth/cloth_mesh.h> | ||||||
|  | #include <bounce/cloth/cloth_triangle.h> | ||||||
|  |  | ||||||
|  | b3Particle::b3Particle(const b3ParticleDef& def, b3Cloth* cloth) | ||||||
|  | { | ||||||
|  | 	m_cloth = cloth; | ||||||
|  | 	m_type = def.type; | ||||||
|  | 	m_position = def.position; | ||||||
|  | 	m_velocity = def.velocity; | ||||||
|  | 	m_force = def.force; | ||||||
|  | 	m_translation.SetZero(); | ||||||
|  | 	m_mass = def.mass; | ||||||
|  |  | ||||||
|  | 	if (m_mass == 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		m_type = e_staticParticle; | ||||||
|  | 		m_mass = 1.0f; | ||||||
|  | 		m_invMass = 1.0f; | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		m_type = e_dynamicParticle; | ||||||
|  | 		m_invMass = 1.0f / m_mass; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	m_radius = def.radius; | ||||||
|  | 	m_friction = def.friction; | ||||||
|  | 	m_userData = nullptr; | ||||||
|  | 	m_x.SetZero(); | ||||||
|  | 	m_vertex = ~0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | b3Particle::~b3Particle() | ||||||
|  | { | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void b3Particle::Synchronize(const b3Vec3& displacement) | ||||||
|  | { | ||||||
|  | 	b3AABB3 aabb; | ||||||
|  | 	aabb.Set(m_position, m_radius); | ||||||
|  |  | ||||||
|  | 	m_cloth->m_contactManager.m_broadPhase.MoveProxy(m_broadPhaseId, aabb, displacement); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void b3Particle::SynchronizeTriangles() | ||||||
|  | { | ||||||
|  | 	if (m_vertex == ~0) | ||||||
|  | 	{ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for (u32 i = 0; i < m_cloth->m_mesh->triangleCount; ++i) | ||||||
|  | 	{ | ||||||
|  | 		b3ClothMeshTriangle* triangle = m_cloth->m_mesh->triangles + i; | ||||||
|  |  | ||||||
|  | 		if (triangle->v1 == m_vertex || triangle->v2 == m_vertex || triangle->v3 == m_vertex) | ||||||
|  | 		{ | ||||||
|  | 			m_cloth->GetTriangle(i)->Synchronize(b3Vec3_zero); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void b3Particle::DestroyContacts() | ||||||
|  | { | ||||||
|  | 	{ | ||||||
|  | 		// Destroy body contacts | ||||||
|  | 		b3ParticleBodyContact* c = m_cloth->m_contactManager.m_particleBodyContactList.m_head; | ||||||
|  | 		while (c) | ||||||
|  | 		{ | ||||||
|  | 			if (c->m_p1 == this) | ||||||
|  | 			{ | ||||||
|  | 				b3ParticleBodyContact* quack = c; | ||||||
|  | 				c = c->m_next; | ||||||
|  | 				m_cloth->m_contactManager.Destroy(quack); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			c = c->m_next; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	{ | ||||||
|  | 		// Destroy triangle contacts | ||||||
|  | 		b3ParticleTriangleContact* c = m_cloth->m_contactManager.m_particleTriangleContactList.m_head; | ||||||
|  | 		while (c) | ||||||
|  | 		{ | ||||||
|  | 			if (c->m_p1 == this) | ||||||
|  | 			{ | ||||||
|  | 				b3ParticleTriangleContact* quack = c; | ||||||
|  | 				c = c->m_next; | ||||||
|  | 				m_cloth->m_contactManager.Destroy(quack); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			c = c->m_next; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void b3Particle::SetType(b3ParticleType type) | ||||||
|  | { | ||||||
|  | 	if (m_type == type) | ||||||
|  | 	{ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	m_type = type; | ||||||
|  | 	m_force.SetZero(); | ||||||
|  |  | ||||||
|  | 	if (type == e_staticParticle) | ||||||
|  | 	{ | ||||||
|  | 		m_velocity.SetZero(); | ||||||
|  | 		m_translation.SetZero(); | ||||||
|  |  | ||||||
|  | 		Synchronize(b3Vec3_zero); | ||||||
|  | 		SynchronizeTriangles(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	DestroyContacts(); | ||||||
|  |  | ||||||
|  | 	// Move the proxy so new contacts can be created. | ||||||
|  | 	m_cloth->m_contactManager.m_broadPhase.TouchProxy(m_broadPhaseId); | ||||||
|  | } | ||||||
							
								
								
									
										143
									
								
								src/bounce/collision/sat/sat_edge_and_hull.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								src/bounce/collision/sat/sat_edge_and_hull.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <bounce/collision/sat/sat_edge_and_hull.h> | ||||||
|  | #include <bounce/collision/shapes/capsule.h> | ||||||
|  | #include <bounce/collision/shapes/hull.h> | ||||||
|  |  | ||||||
|  | float32 b3ProjectEdge(const b3Capsule* hull, const b3Plane& plane) | ||||||
|  | { | ||||||
|  | 	b3Vec3 support = hull->GetVertex(hull->GetSupportVertex(-plane.normal)); | ||||||
|  | 	return b3Distance(support, plane); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | b3FaceQuery b3QueryFaceSeparation(const b3Transform& xf1, const b3Capsule* hull1, | ||||||
|  | 	const b3Transform& xf2, const b3Hull* hull2) | ||||||
|  | { | ||||||
|  | 	// Perform computations in the local space of the first hull. | ||||||
|  | 	b3Transform xf = b3MulT(xf1, xf2); | ||||||
|  |  | ||||||
|  | 	// Here greater means less than since is a signed distance. | ||||||
|  | 	u32 maxIndex = 0; | ||||||
|  | 	float32 maxSeparation = -B3_MAX_FLOAT; | ||||||
|  |  | ||||||
|  | 	for (u32 i = 0; i < hull2->faceCount; ++i) | ||||||
|  | 	{ | ||||||
|  | 		b3Plane plane = b3Mul(xf, hull2->GetPlane(i)); | ||||||
|  | 		float32 separation = b3ProjectEdge(hull1, plane); | ||||||
|  | 		if (separation > maxSeparation) | ||||||
|  | 		{ | ||||||
|  | 			maxIndex = i; | ||||||
|  | 			maxSeparation = separation; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3FaceQuery out; | ||||||
|  | 	out.index = maxIndex; | ||||||
|  | 	out.separation = maxSeparation; | ||||||
|  | 	return out; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Qualify the two hull normals against the plane of the ring of the capsule. | ||||||
|  | bool b3IsMinkowskiFaceEdge(const b3Vec3& N, const b3Vec3& C, const b3Vec3& D) | ||||||
|  | { | ||||||
|  | 	return b3Dot(N, C) * b3Dot(N, D) < 0.0f; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | float32 b3ProjectEdge(const b3Vec3& P1, const b3Vec3& E1, | ||||||
|  | 	const b3Vec3& P2, const b3Vec3& E2, const b3Vec3& C2) | ||||||
|  | { | ||||||
|  | 	float32 L1 = b3Length(E1); | ||||||
|  | 	if (L1 < B3_LINEAR_SLOP) | ||||||
|  | 	{ | ||||||
|  | 		return -B3_MAX_FLOAT; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	float32 L2 = b3Length(E2); | ||||||
|  | 	if (L2 < B3_LINEAR_SLOP) | ||||||
|  | 	{ | ||||||
|  | 		return -B3_MAX_FLOAT; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Skip over almost parallel edges. | ||||||
|  | 	const float32 kTol = 0.005f; | ||||||
|  |  | ||||||
|  | 	b3Vec3 E1_x_E2 = b3Cross(E1, E2); | ||||||
|  | 	float32 L = b3Length(E1_x_E2); | ||||||
|  | 	if (L < kTol * L1 * L2) | ||||||
|  | 	{ | ||||||
|  | 		return -B3_MAX_FLOAT; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Ensure consistent normal orientation to hull B. | ||||||
|  | 	b3Vec3 N = (1.0f / L) * E1_x_E2; | ||||||
|  | 	if (b3Dot(N, P2 - C2) > 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		N = -N; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// d = dot(N, P2) - offset = dot(N, P2) - dot(N, P1) = dot(N, P2 - P1)  | ||||||
|  | 	return b3Dot(N, P2 - P1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | b3EdgeQuery b3QueryEdgeSeparation(const b3Transform& xf1, const b3Capsule* hull1, const b3Transform& xf2, const b3Hull* hull2) | ||||||
|  | { | ||||||
|  | 	// Query minimum edge separation. | ||||||
|  | 	u32 maxIndex = 0; | ||||||
|  | 	float32 maxSeparation = -B3_MAX_FLOAT; | ||||||
|  |  | ||||||
|  | 	// Perform computations in the local space of the second hull. | ||||||
|  | 	b3Transform xf = b3MulT(xf2, xf1); | ||||||
|  |  | ||||||
|  | 	b3Vec3 P1 = b3Mul(xf, hull1->vertices[0]); | ||||||
|  | 	b3Vec3 Q1 = b3Mul(xf, hull1->vertices[1]); | ||||||
|  | 	b3Vec3 E1 = Q1 - P1; | ||||||
|  |  | ||||||
|  | 	b3Vec3 C2 = hull2->centroid; | ||||||
|  |  | ||||||
|  | 	for (u32 i = 0; i < hull2->edgeCount; i += 2) | ||||||
|  | 	{ | ||||||
|  | 		const b3HalfEdge* edge2 = hull2->GetEdge(i); | ||||||
|  | 		const b3HalfEdge* twin2 = hull2->GetEdge(i + 1); | ||||||
|  |  | ||||||
|  | 		B3_ASSERT(edge2->twin == i + 1 && twin2->twin == i); | ||||||
|  |  | ||||||
|  | 		b3Vec3 P2 = hull2->GetVertex(edge2->origin); | ||||||
|  | 		b3Vec3 Q2 = hull2->GetVertex(twin2->origin); | ||||||
|  | 		b3Vec3 E2 = Q2 - P2; | ||||||
|  |  | ||||||
|  | 		b3Vec3 U2 = hull2->GetPlane(edge2->face).normal; | ||||||
|  | 		b3Vec3 V2 = hull2->GetPlane(twin2->face).normal; | ||||||
|  |  | ||||||
|  | 		if (b3IsMinkowskiFaceEdge(E1, U2, V2)) | ||||||
|  | 		{ | ||||||
|  | 			float32 separation = b3ProjectEdge(P1, E1, P2, E2, C2); | ||||||
|  | 			if (separation > maxSeparation) | ||||||
|  | 			{ | ||||||
|  | 				maxSeparation = separation; | ||||||
|  | 				maxIndex = i; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3EdgeQuery out; | ||||||
|  | 	out.index1 = 0; | ||||||
|  | 	out.index2 = maxIndex; | ||||||
|  | 	out.separation = maxSeparation; | ||||||
|  | 	return out; | ||||||
|  | } | ||||||
							
								
								
									
										54
									
								
								src/bounce/collision/sat/sat_vertex_and_hull.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/bounce/collision/sat/sat_vertex_and_hull.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <bounce/collision/sat/sat_vertex_and_hull.h> | ||||||
|  | #include <bounce/collision/shapes/sphere.h> | ||||||
|  | #include <bounce/collision/shapes/hull.h> | ||||||
|  |  | ||||||
|  | float32 b3ProjectVertex(const b3Sphere* hull, const b3Plane& plane) | ||||||
|  | { | ||||||
|  | 	b3Vec3 support = hull->GetVertex(hull->GetSupportVertex(-plane.normal)); | ||||||
|  | 	return b3Distance(support, plane); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | b3FaceQuery b3QueryFaceSeparation(const b3Transform& xf1, const b3Sphere* hull, | ||||||
|  | 	const b3Transform& xf2, const b3Hull* hull2) | ||||||
|  | { | ||||||
|  | 	// Perform computations in the local space of the second hull. | ||||||
|  | 	b3Vec3 support = b3MulT(xf2, b3Mul(xf1, hull->vertex)); | ||||||
|  |  | ||||||
|  | 	u32 maxIndex = 0; | ||||||
|  | 	float32 maxSeparation = -B3_MAX_FLOAT; | ||||||
|  |  | ||||||
|  | 	for (u32 i = 0; i < hull2->faceCount; ++i) | ||||||
|  | 	{ | ||||||
|  | 		b3Plane plane = hull2->GetPlane(i); | ||||||
|  | 		float32 separation = b3Distance(support, plane); | ||||||
|  |  | ||||||
|  | 		if (separation > maxSeparation) | ||||||
|  | 		{ | ||||||
|  | 			maxIndex = i; | ||||||
|  | 			maxSeparation = separation; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	b3FaceQuery out; | ||||||
|  | 	out.index = maxIndex; | ||||||
|  | 	out.separation = maxSeparation; | ||||||
|  | 	return out; | ||||||
|  | } | ||||||
							
								
								
									
										222
									
								
								src/bounce/dynamics/contacts/collide/collide_capsule_hull.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								src/bounce/dynamics/contacts/collide/collide_capsule_hull.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,222 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <bounce/dynamics/contacts/collide/collide.h> | ||||||
|  | #include <bounce/dynamics/contacts/collide/clip.h> | ||||||
|  | #include <bounce/dynamics/contacts/manifold.h> | ||||||
|  | #include <bounce/dynamics/shapes/sphere_shape.h> | ||||||
|  | #include <bounce/dynamics/shapes/capsule_shape.h> | ||||||
|  | #include <bounce/dynamics/shapes/hull_shape.h> | ||||||
|  | #include <bounce/collision/shapes/sphere.h> | ||||||
|  | #include <bounce/collision/shapes/capsule.h> | ||||||
|  | #include <bounce/collision/shapes/hull.h> | ||||||
|  |  | ||||||
|  | static void b3BuildEdgeContact(b3Manifold& manifold, | ||||||
|  | 	const b3Transform& xf1, const b3CapsuleShape* s1, | ||||||
|  | 	const b3Transform& xf2, u32 index2, const b3HullShape* s2) | ||||||
|  | { | ||||||
|  | 	b3Vec3 P1 = xf1 * s1->m_centers[0]; | ||||||
|  | 	b3Vec3 Q1 = xf1 * s1->m_centers[1]; | ||||||
|  | 	b3Vec3 E1 = Q1 - P1; | ||||||
|  | 	b3Vec3 N1 = E1; | ||||||
|  | 	float32 L1 = N1.Normalize(); | ||||||
|  | 	B3_ASSERT(L1 > 0.0f); | ||||||
|  |  | ||||||
|  | 	const b3Hull* hull2 = s2->m_hull; | ||||||
|  | 	const b3HalfEdge* edge2 = hull2->GetEdge(index2); | ||||||
|  | 	const b3HalfEdge* twin2 = hull2->GetEdge(index2 + 1); | ||||||
|  |  | ||||||
|  | 	b3Vec3 C2 = xf2 * hull2->centroid; | ||||||
|  | 	b3Vec3 P2 = xf2 * hull2->GetVertex(edge2->origin); | ||||||
|  | 	b3Vec3 Q2 = xf2 * hull2->GetVertex(twin2->origin); | ||||||
|  | 	b3Vec3 E2 = Q2 - P2; | ||||||
|  | 	b3Vec3 N2 = E2; | ||||||
|  | 	float32 L2 = N2.Normalize(); | ||||||
|  | 	B3_ASSERT(L2 > 0.0f); | ||||||
|  |  | ||||||
|  | 	// Compute the closest points on the two lines. | ||||||
|  | 	float32 b = b3Dot(N1, N2); | ||||||
|  | 	float32 den = 1.0f - b * b; | ||||||
|  | 	if (den == 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	float32 inv_den = 1.0f / den; | ||||||
|  |  | ||||||
|  | 	b3Vec3 E3 = P1 - P2; | ||||||
|  |  | ||||||
|  | 	float32 d = b3Dot(N1, E3); | ||||||
|  | 	float32 e = b3Dot(N2, E3); | ||||||
|  |  | ||||||
|  | 	float32 s = inv_den * (b * e - d); | ||||||
|  | 	float32 t = inv_den * (e - b * d); | ||||||
|  |  | ||||||
|  | 	b3Vec3 c1 = P1 + s * N1; | ||||||
|  | 	b3Vec3 c2 = P2 + t * N2; | ||||||
|  |  | ||||||
|  | 	// Ensure normal orientation to hull 2. | ||||||
|  | 	b3Vec3 N = b3Cross(E1, E2); | ||||||
|  | 	float32 LN = N.Normalize(); | ||||||
|  | 	B3_ASSERT(LN > 0.0f); | ||||||
|  | 	if (b3Dot(N, P2 - C2) > 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		N = -N; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3FeaturePair pair = b3MakePair(0, 1, index2, index2 + 1); | ||||||
|  | 	 | ||||||
|  | 	manifold.pointCount = 1; | ||||||
|  | 	manifold.points[0].localNormal1 = b3MulT(xf1.rotation, N); | ||||||
|  | 	manifold.points[0].localPoint1 = b3MulT(xf1, c1); | ||||||
|  | 	manifold.points[0].localPoint2 = b3MulT(xf2, c2); | ||||||
|  | 	manifold.points[0].key = b3MakeKey(pair); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void b3BuildFaceContact(b3Manifold& manifold, | ||||||
|  | 	const b3Transform& xf1, const b3CapsuleShape* s1, | ||||||
|  | 	const b3Transform& xf2, u32 index2, const b3HullShape* s2) | ||||||
|  | { | ||||||
|  | 	// Clip edge 1 against the side planes of the face 2. | ||||||
|  | 	const b3Capsule hull1(xf1 * s1->m_centers[0], xf1 * s1->m_centers[1], 0.0f); | ||||||
|  | 	float32 r1 = s1->m_radius; | ||||||
|  |  | ||||||
|  | 	b3ClipVertex edge1[2]; | ||||||
|  | 	b3BuildEdge(edge1, &hull1); | ||||||
|  | 	 | ||||||
|  | 	const b3Hull* hull2 = s2->m_hull; | ||||||
|  | 	float32 r2 = s2->m_radius; | ||||||
|  |  | ||||||
|  | 	b3ClipVertex clipEdge1[2]; | ||||||
|  | 	u32 clipCount = b3ClipEdgeToFace(clipEdge1, edge1, xf2, r2, index2, hull2); | ||||||
|  |  | ||||||
|  | 	// Project clipped edge 1 onto face plane 2. | ||||||
|  | 	b3Plane localPlane2 = hull2->GetPlane(index2); | ||||||
|  | 	b3Plane plane2 = xf2 * localPlane2; | ||||||
|  | 	const b3Face* face2 = hull2->GetFace(index2); | ||||||
|  | 	const b3HalfEdge* edge2 = hull2->GetEdge(face2->edge); | ||||||
|  | 	b3Vec3 localPoint2 = hull2->GetVertex(edge2->origin); | ||||||
|  |  | ||||||
|  | 	// Ensure normal orientation to hull 2. | ||||||
|  | 	b3Vec3 n1 = -plane2.normal; | ||||||
|  |  | ||||||
|  | 	float32 totalRadius = r1 + r2; | ||||||
|  |  | ||||||
|  | 	u32 pointCount = 0; | ||||||
|  | 	for (u32 i = 0; i < clipCount; ++i) | ||||||
|  | 	{ | ||||||
|  | 		b3Vec3 c1 = clipEdge1[i].position; | ||||||
|  | 		float32 s = b3Distance(c1, plane2); | ||||||
|  | 		if (s <= totalRadius) | ||||||
|  | 		{ | ||||||
|  | 			b3Vec3 c2 = b3ClosestPointOnPlane(c1, plane2); | ||||||
|  | 			 | ||||||
|  | 			b3ManifoldPoint* mp = manifold.points + pointCount; | ||||||
|  | 			mp->localNormal1 = b3MulT(xf1.rotation, n1); | ||||||
|  | 			mp->localPoint1 = b3MulT(xf1, c1); | ||||||
|  | 			mp->localPoint2 = b3MulT(xf2, c2); | ||||||
|  | 			mp->key = b3MakeKey(clipEdge1[i].pair); | ||||||
|  | 			 | ||||||
|  | 			++pointCount; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	manifold.pointCount = pointCount; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void b3CollideCapsuleAndHull(b3Manifold& manifold,  | ||||||
|  | 	const b3Transform& xf1, const b3CapsuleShape* s1, | ||||||
|  | 	const b3Transform& xf2, const b3HullShape* s2) | ||||||
|  | { | ||||||
|  | 	b3ShapeGJKProxy proxy1(s1, 0); | ||||||
|  | 	b3ShapeGJKProxy proxy2(s2, 0); | ||||||
|  |  | ||||||
|  | 	b3GJKOutput gjk = b3GJK(xf1, proxy1, xf2, proxy2); | ||||||
|  |  | ||||||
|  | 	float32 r1 = s1->m_radius; | ||||||
|  | 	float32 r2 = s2->m_radius; | ||||||
|  |  | ||||||
|  | 	float32 totalRadius = r1 + r2; | ||||||
|  |  | ||||||
|  | 	if (gjk.distance > totalRadius) | ||||||
|  | 	{ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	const b3Capsule hull1(s1->m_centers[0], s1->m_centers[1], 0.0f); | ||||||
|  | 	const b3Hull* hull2 = s2->m_hull; | ||||||
|  |  | ||||||
|  | 	if (gjk.distance > B3_EPSILON) | ||||||
|  | 	{ | ||||||
|  | 		// Define incident face. | ||||||
|  | 		b3Vec3 N1 = (gjk.point2 - gjk.point1) / gjk.distance; | ||||||
|  | 		b3Vec3 localN1 = b3MulT(xf2.rotation, N1); | ||||||
|  |  | ||||||
|  | 		// Search reference face. | ||||||
|  | 		u32 index2 = hull2->GetSupportFace(-localN1); | ||||||
|  | 		b3Vec3 localN2 = hull2->GetPlane(index2).normal; | ||||||
|  | 		b3Vec3 N2 = xf2.rotation * localN2; | ||||||
|  |  | ||||||
|  | 		// Paralell vectors |v1xv2| = sin(theta) | ||||||
|  | 		const float32 kTol = 0.005f; | ||||||
|  | 		b3Vec3 N = b3Cross(N1, N2); | ||||||
|  | 		float32 L = b3Dot(N, N); | ||||||
|  | 		if (L < kTol * kTol) | ||||||
|  | 		{ | ||||||
|  | 			// Reference face found. | ||||||
|  | 			// Try to build a face contact. | ||||||
|  | 			b3BuildFaceContact(manifold, xf1, s1, xf2, index2, s2); | ||||||
|  | 			if (manifold.pointCount == 2) | ||||||
|  | 			{ | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		manifold.pointCount = 1; | ||||||
|  | 		manifold.points[0].localNormal1 = b3MulT(xf1.rotation, N1); | ||||||
|  | 		manifold.points[0].localPoint1 = b3MulT(xf1, gjk.point1); | ||||||
|  | 		manifold.points[0].localPoint2 = b3MulT(xf2, gjk.point2); | ||||||
|  | 		manifold.points[0].key.triangleKey = B3_NULL_TRIANGLE; | ||||||
|  | 		manifold.points[0].key.key1 = 0; | ||||||
|  | 		manifold.points[0].key.key2 = 0; | ||||||
|  |  | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	b3FaceQuery faceQuery2 = b3QueryFaceSeparation(xf1, &hull1, xf2, hull2); | ||||||
|  | 	if (faceQuery2.separation > totalRadius) | ||||||
|  | 	{ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3EdgeQuery edgeQuery = b3QueryEdgeSeparation(xf1, &hull1, xf2, hull2); | ||||||
|  | 	if (edgeQuery.separation > totalRadius) | ||||||
|  | 	{ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	const float32 kTol = 0.1f * B3_LINEAR_SLOP; | ||||||
|  | 	if (edgeQuery.separation > faceQuery2.separation + kTol) | ||||||
|  | 	{ | ||||||
|  | 		b3BuildEdgeContact(manifold, xf1, s1, xf2, edgeQuery.index2, s2); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		b3BuildFaceContact(manifold, xf1, s1, xf2, faceQuery2.index, s2); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										344
									
								
								src/bounce/dynamics/contacts/collide/collide_hulls_cache.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										344
									
								
								src/bounce/dynamics/contacts/collide/collide_hulls_cache.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,344 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <bounce/dynamics/contacts/collide/collide.h> | ||||||
|  | #include <bounce/dynamics/contacts/collide/clip.h> | ||||||
|  | #include <bounce/dynamics/contacts/manifold.h> | ||||||
|  | #include <bounce/dynamics/shapes/hull_shape.h> | ||||||
|  | #include <bounce/dynamics/body.h> | ||||||
|  | #include <bounce/collision/shapes/hull.h> | ||||||
|  |  | ||||||
|  | void b3BuildEdgeContact(b3Manifold& manifold, | ||||||
|  | 	const b3Transform& xf1, u32 index1, const b3HullShape* s1, | ||||||
|  | 	const b3Transform& xf2, u32 index2, const b3HullShape* s2); | ||||||
|  |  | ||||||
|  | void b3BuildFaceContact(b3Manifold& manifold, | ||||||
|  | 	const b3Transform& xf1, u32 index1, const b3HullShape* s1, | ||||||
|  | 	const b3Transform& xf2, const b3HullShape* s2, | ||||||
|  | 	bool flipNormal); | ||||||
|  |  | ||||||
|  | static void b3RebuildEdgeContact(b3Manifold& manifold, | ||||||
|  | 	const b3Transform& xf1, u32 index1, const b3HullShape* s1, | ||||||
|  | 	const b3Transform& xf2, u32 index2, const b3HullShape* s2) | ||||||
|  | { | ||||||
|  | 	const b3Hull* hull1 = s1->m_hull; | ||||||
|  | 	const b3HalfEdge* edge1 = hull1->GetEdge(index1); | ||||||
|  | 	const b3HalfEdge* twin1 = hull1->GetEdge(index1 + 1); | ||||||
|  |  | ||||||
|  | 	b3Vec3 C1 = xf1 * hull1->centroid; | ||||||
|  | 	b3Vec3 P1 = xf1 * hull1->GetVertex(edge1->origin); | ||||||
|  | 	b3Vec3 Q1 = xf1 * hull1->GetVertex(twin1->origin); | ||||||
|  | 	b3Vec3 E1 = Q1 - P1; | ||||||
|  | 	b3Vec3 N1 = E1; | ||||||
|  | 	float32 L1 = N1.Normalize(); | ||||||
|  | 	B3_ASSERT(L1 > 0.0f); | ||||||
|  |  | ||||||
|  | 	const b3Hull* hull2 = s2->m_hull; | ||||||
|  | 	const b3HalfEdge* edge2 = hull2->GetEdge(index2); | ||||||
|  | 	const b3HalfEdge* twin2 = hull2->GetEdge(index2 + 1); | ||||||
|  |  | ||||||
|  | 	b3Vec3 C2 = xf2 * hull2->centroid; | ||||||
|  | 	b3Vec3 P2 = xf2 * hull2->GetVertex(edge2->origin); | ||||||
|  | 	b3Vec3 Q2 = xf2 * hull2->GetVertex(twin2->origin); | ||||||
|  | 	b3Vec3 E2 = Q2 - P2; | ||||||
|  | 	b3Vec3 N2 = E2; | ||||||
|  | 	float32 L2 = N2.Normalize(); | ||||||
|  | 	B3_ASSERT(L2 > 0.0f); | ||||||
|  |  | ||||||
|  | 	// Compute the closest points on the two lines. | ||||||
|  | 	float32 b = b3Dot(N1, N2); | ||||||
|  | 	float32 den = 1.0f - b * b; | ||||||
|  | 	if (den == 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	float32 inv_den = 1.0f / den; | ||||||
|  |  | ||||||
|  | 	b3Vec3 E3 = P1 - P2; | ||||||
|  |  | ||||||
|  | 	float32 d = b3Dot(N1, E3); | ||||||
|  | 	float32 e = b3Dot(N2, E3); | ||||||
|  |  | ||||||
|  | 	float32 s = inv_den * (b * e - d); | ||||||
|  | 	float32 t = inv_den * (e - b * d); | ||||||
|  |  | ||||||
|  | 	b3Vec3 c1 = P1 + s * N1; | ||||||
|  | 	b3Vec3 c2 = P2 + t * N2; | ||||||
|  |  | ||||||
|  | 	// Check if the closest points are still lying on the opposite segments  | ||||||
|  | 	// using Barycentric coordinates. | ||||||
|  | 	float32 w2[3]; | ||||||
|  | 	b3BarycentricCoordinates(w2, P1, Q1, c2); | ||||||
|  |  | ||||||
|  | 	float32 w1[3]; | ||||||
|  | 	b3BarycentricCoordinates(w1, P2, Q2, c1); | ||||||
|  |  | ||||||
|  | 	if (w2[1] > 0.0f && w2[1] <= w2[2] && | ||||||
|  | 		w1[1] > 0.0f && w1[1] <= w1[2]) | ||||||
|  | 	{ | ||||||
|  | 		b3Vec3 N = b3Cross(E1, E2); | ||||||
|  | 		float32 LN = N.Normalize(); | ||||||
|  | 		B3_ASSERT(LN > 0.0f); | ||||||
|  | 		if (b3Dot(N, P1 - C1) < 0.0f) | ||||||
|  | 		{ | ||||||
|  | 			N = -N; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3FeaturePair pair = b3MakePair(index1, index1 + 1, index2, index2 + 1); | ||||||
|  |  | ||||||
|  | 		manifold.pointCount = 1; | ||||||
|  | 		manifold.points[0].localNormal1 = b3MulT(xf1.rotation, N); | ||||||
|  | 		manifold.points[0].localPoint1 = b3MulT(xf1, c1); | ||||||
|  | 		manifold.points[0].localPoint2 = b3MulT(xf2, c2); | ||||||
|  | 		manifold.points[0].key = b3MakeKey(pair); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void b3RebuildFaceContact(b3Manifold& manifold, | ||||||
|  | 	const b3Transform& xf1, u32 index1, const b3HullShape* s1, | ||||||
|  | 	const b3Transform& xf2, const b3HullShape* s2, bool flipNormal) | ||||||
|  | { | ||||||
|  | 	const b3Body* body1 = s1->GetBody(); | ||||||
|  | 	const b3Body* body2 = s2->GetBody(); | ||||||
|  |  | ||||||
|  | 	const b3Sweep& sweep1 = body1->GetSweep(); | ||||||
|  | 	b3Quat q10 = sweep1.orientation0; | ||||||
|  | 	b3Quat q1 = sweep1.orientation; | ||||||
|  |  | ||||||
|  | 	const b3Sweep& sweep2 = body2->GetSweep(); | ||||||
|  | 	b3Quat q20 = sweep2.orientation0; | ||||||
|  | 	b3Quat q2 = sweep2.orientation; | ||||||
|  |  | ||||||
|  | 	// Check if the relative orientation has changed. | ||||||
|  | 	// Here the second orientation seen by the first orientation. | ||||||
|  | 	// dp = p2 - p1 | ||||||
|  | 	// dq * q1 = q2 | ||||||
|  | 	// dq = inv(q1) * q2 | ||||||
|  |  | ||||||
|  | 	// The old relative rotation. | ||||||
|  | 	// "q0(2) - q0(1)" | ||||||
|  | 	b3Quat dq0 = b3Conjugate(q10) * q20; | ||||||
|  |  | ||||||
|  | 	// The new relative rotation. | ||||||
|  | 	// "q(2) - q(1)" | ||||||
|  | 	b3Quat dq = b3Conjugate(q1) * q2; | ||||||
|  |  | ||||||
|  | 	// Relative rotation between the new relative rotation and the old relative rotation. | ||||||
|  | 	// "dq(2) - dq0(1)" | ||||||
|  | 	b3Quat q = b3Conjugate(dq0) * dq; | ||||||
|  |  | ||||||
|  | 	// Check the relative absolute cosine because  | ||||||
|  | 	// we want to check orientation similarity. | ||||||
|  | 	const float32 kTol = 0.995f; | ||||||
|  | 	if (b3Abs(q.w) > kTol) | ||||||
|  | 	{ | ||||||
|  | 		b3BuildFaceContact(manifold, xf1, index1, s1, xf2, s2, flipNormal); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void b3CollideCache(b3Manifold& manifold, | ||||||
|  | 	const b3Transform& xf1, const b3HullShape* s1, | ||||||
|  | 	const b3Transform& xf2, const b3HullShape* s2, | ||||||
|  | 	b3FeatureCache* cache) | ||||||
|  | { | ||||||
|  | 	B3_ASSERT(cache->m_featurePair.state == b3SATCacheType::e_empty); | ||||||
|  |  | ||||||
|  | 	const b3Hull* hull1 = s1->m_hull; | ||||||
|  | 	float32 r1 = s1->m_radius; | ||||||
|  |  | ||||||
|  | 	const b3Hull* hull2 = s2->m_hull; | ||||||
|  | 	float32 r2 = s2->m_radius; | ||||||
|  |  | ||||||
|  | 	float32 totalRadius = r1 + r2; | ||||||
|  |  | ||||||
|  | 	b3FaceQuery faceQuery1 = b3QueryFaceSeparation(xf1, hull1, xf2, hull2); | ||||||
|  | 	if (faceQuery1.separation > totalRadius) | ||||||
|  | 	{ | ||||||
|  | 		// Write a separation cache. | ||||||
|  | 		cache->m_featurePair = b3MakeFeaturePair(b3SATCacheType::e_separation, b3SATFeatureType::e_face1, faceQuery1.index, faceQuery1.index); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3FaceQuery faceQuery2 = b3QueryFaceSeparation(xf2, hull2, xf1, hull1); | ||||||
|  | 	if (faceQuery2.separation > totalRadius) | ||||||
|  | 	{ | ||||||
|  | 		// Write a separation cache. | ||||||
|  | 		cache->m_featurePair = b3MakeFeaturePair(b3SATCacheType::e_separation, b3SATFeatureType::e_face2, faceQuery2.index, faceQuery2.index); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3EdgeQuery edgeQuery = b3QueryEdgeSeparation(xf1, hull1, xf2, hull2); | ||||||
|  | 	if (edgeQuery.separation > totalRadius) | ||||||
|  | 	{ | ||||||
|  | 		// Write a separation cache. | ||||||
|  | 		cache->m_featurePair = b3MakeFeaturePair(b3SATCacheType::e_separation, b3SATFeatureType::e_edge1, edgeQuery.index1, edgeQuery.index2); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	const float32 kTol = 0.1f * B3_LINEAR_SLOP; | ||||||
|  | 	if (edgeQuery.separation > b3Max(faceQuery1.separation, faceQuery2.separation) + kTol) | ||||||
|  | 	{ | ||||||
|  | 		b3BuildEdgeContact(manifold, xf1, edgeQuery.index1, s1, xf2, edgeQuery.index2, s2); | ||||||
|  | 		if (manifold.pointCount > 0) | ||||||
|  | 		{ | ||||||
|  | 			// Write an overlap cache.		 | ||||||
|  | 			cache->m_featurePair = b3MakeFeaturePair(b3SATCacheType::e_overlap, b3SATFeatureType::e_edge1, edgeQuery.index1, edgeQuery.index2); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		if (faceQuery1.separation + kTol > faceQuery2.separation) | ||||||
|  | 		{ | ||||||
|  | 			b3BuildFaceContact(manifold, xf1, faceQuery1.index, s1, xf2, s2, false); | ||||||
|  | 			if (manifold.pointCount > 0) | ||||||
|  | 			{ | ||||||
|  | 				// Write an overlap cache. | ||||||
|  | 				cache->m_featurePair = b3MakeFeaturePair(b3SATCacheType::e_overlap, b3SATFeatureType::e_face1, faceQuery1.index, faceQuery1.index); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			b3BuildFaceContact(manifold, xf2, faceQuery2.index, s2, xf1, s1, true); | ||||||
|  | 			if (manifold.pointCount > 0) | ||||||
|  | 			{ | ||||||
|  | 				// Write an overlap cache. | ||||||
|  | 				cache->m_featurePair = b3MakeFeaturePair(b3SATCacheType::e_overlap, b3SATFeatureType::e_face2, faceQuery2.index, faceQuery2.index); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Heuristic failed. Fallback. | ||||||
|  | 	if (edgeQuery.separation > b3Max(faceQuery1.separation, faceQuery2.separation)) | ||||||
|  | 	{ | ||||||
|  | 		b3BuildEdgeContact(manifold, xf1, edgeQuery.index1, s1, xf2, edgeQuery.index2, s2); | ||||||
|  | 		if (manifold.pointCount > 0) | ||||||
|  | 		{ | ||||||
|  | 			// Write an overlap cache.		 | ||||||
|  | 			cache->m_featurePair = b3MakeFeaturePair(b3SATCacheType::e_overlap, b3SATFeatureType::e_edge1, edgeQuery.index1, edgeQuery.index2); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		if (faceQuery1.separation > faceQuery2.separation) | ||||||
|  | 		{ | ||||||
|  | 			b3BuildFaceContact(manifold, xf1, faceQuery1.index, s1, xf2, s2, false); | ||||||
|  | 			if (manifold.pointCount > 0) | ||||||
|  | 			{ | ||||||
|  | 				// Write an overlap cache. | ||||||
|  | 				cache->m_featurePair = b3MakeFeaturePair(b3SATCacheType::e_overlap, b3SATFeatureType::e_face1, faceQuery1.index, faceQuery1.index); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			b3BuildFaceContact(manifold, xf2, faceQuery2.index, s2, xf1, s1, true); | ||||||
|  | 			if (manifold.pointCount > 0) | ||||||
|  | 			{ | ||||||
|  | 				// Write an overlap cache. | ||||||
|  | 				cache->m_featurePair = b3MakeFeaturePair(b3SATCacheType::e_overlap, b3SATFeatureType::e_face2, faceQuery2.index, faceQuery2.index); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// When both convex hulls are not simplified clipping might fail and create no contact points. | ||||||
|  | 	// For example, when a hull contains tiny faces, coplanar faces, and/or non-sharped edges. | ||||||
|  | 	// So we simply create a contact point between the segments. | ||||||
|  | 	// The hulls might overlap, but is better than solving no contact points. | ||||||
|  | 	b3BuildEdgeContact(manifold, xf1, edgeQuery.index1, s1, xf2, edgeQuery.index2, s2); | ||||||
|  |  | ||||||
|  | 	// If the shapes are overlapping then at least on point must be created. | ||||||
|  | 	B3_ASSERT(manifold.pointCount > 0); | ||||||
|  |  | ||||||
|  | 	// Write an overlap cache.		 | ||||||
|  | 	cache->m_featurePair = b3MakeFeaturePair(b3SATCacheType::e_overlap, b3SATFeatureType::e_edge1, edgeQuery.index1, edgeQuery.index2); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | extern u32 b3_convexCacheHits; | ||||||
|  |  | ||||||
|  | void b3CollideHulls(b3Manifold& manifold, | ||||||
|  | 	const b3Transform& xf1, const b3HullShape* s1, | ||||||
|  | 	const b3Transform& xf2, const b3HullShape* s2, | ||||||
|  | 	b3FeatureCache* cache) | ||||||
|  | { | ||||||
|  | 	const b3Hull* hull1 = s1->m_hull; | ||||||
|  | 	float32 r1 = s1->m_radius; | ||||||
|  |  | ||||||
|  | 	const b3Hull* hull2 = s2->m_hull; | ||||||
|  | 	float32 r2 = s2->m_radius; | ||||||
|  |  | ||||||
|  | 	float32 totalRadius = r1 + r2; | ||||||
|  |  | ||||||
|  | 	// Read cache | ||||||
|  | 	b3SATCacheType state0 = cache->m_featurePair.state; | ||||||
|  | 	b3SATCacheType state1 = cache->ReadState(xf1, hull1, xf2, hull2, totalRadius); | ||||||
|  |  | ||||||
|  | 	if (state0 == b3SATCacheType::e_separation && | ||||||
|  | 		state1 == b3SATCacheType::e_separation) | ||||||
|  | 	{ | ||||||
|  | 		// Separation cache hit. | ||||||
|  | 		++b3_convexCacheHits; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (state0 == b3SATCacheType::e_overlap && | ||||||
|  | 		state1 == b3SATCacheType::e_overlap) | ||||||
|  | 	{ | ||||||
|  | 		// Try to rebuild or reclip the features. | ||||||
|  | 		switch (cache->m_featurePair.type) | ||||||
|  | 		{ | ||||||
|  | 		case b3SATFeatureType::e_edge1: | ||||||
|  | 		{ | ||||||
|  | 			b3RebuildEdgeContact(manifold, xf1, cache->m_featurePair.index1, s1, xf2, cache->m_featurePair.index2, s2); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		case b3SATFeatureType::e_face1: | ||||||
|  | 		{ | ||||||
|  | 			b3RebuildFaceContact(manifold, xf1, cache->m_featurePair.index1, s1, xf2, s2, false); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		case b3SATFeatureType::e_face2: | ||||||
|  | 		{ | ||||||
|  | 			b3RebuildFaceContact(manifold, xf2, cache->m_featurePair.index1, s2, xf1, s1, true); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		default: | ||||||
|  | 		{ | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (manifold.pointCount > 0) | ||||||
|  | 		{ | ||||||
|  | 			// Overlap cache hit. | ||||||
|  | 			++b3_convexCacheHits; | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Separation cache miss. | ||||||
|  | 	// Overlap cache miss. | ||||||
|  | 	// Flush the cache. | ||||||
|  | 	cache->m_featurePair.state = b3SATCacheType::e_empty; | ||||||
|  | 	b3CollideCache(manifold, xf1, s1, xf2, s2, cache); | ||||||
|  | } | ||||||
							
								
								
									
										134
									
								
								src/bounce/dynamics/contacts/collide/collide_sphere_capsule.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								src/bounce/dynamics/contacts/collide/collide_sphere_capsule.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,134 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <bounce/dynamics/contacts/collide/collide.h> | ||||||
|  | #include <bounce/dynamics/contacts/manifold.h> | ||||||
|  | #include <bounce/dynamics/shapes/sphere_shape.h> | ||||||
|  | #include <bounce/dynamics/shapes/capsule_shape.h> | ||||||
|  |  | ||||||
|  | void b3CollideSphereAndCapsule(b3Manifold& manifold,  | ||||||
|  | 	const b3Transform& xf1, const b3SphereShape* s1, | ||||||
|  | 	const b3Transform& xf2, const b3CapsuleShape* s2) | ||||||
|  | { | ||||||
|  | 	b3Vec3 Q = b3Mul(xf1, s1->m_center); | ||||||
|  |  | ||||||
|  | 	b3Vec3 A = b3Mul(xf2, s2->m_centers[0]); | ||||||
|  | 	b3Vec3 B = b3Mul(xf2, s2->m_centers[1]); | ||||||
|  | 	b3Vec3 AB = B - A; | ||||||
|  | 	 | ||||||
|  | 	// Barycentric coordinates for Q | ||||||
|  | 	float32 u = b3Dot(B - Q, AB); | ||||||
|  | 	float32 v = b3Dot(Q - A, AB); | ||||||
|  | 	 | ||||||
|  | 	float32 radius = s1->m_radius + s2->m_radius; | ||||||
|  |  | ||||||
|  | 	if (v <= 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		// A | ||||||
|  | 		b3Vec3 P = A; | ||||||
|  | 		b3Vec3 d = P - Q; | ||||||
|  | 		float32 dd = b3Dot(d, d); | ||||||
|  | 		if (dd > radius * radius) | ||||||
|  | 		{ | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Vec3 n(0.0f, 1.0f, 0.0f); | ||||||
|  | 		float32 len = b3Length(d); | ||||||
|  | 		if (len > B3_EPSILON) | ||||||
|  | 		{ | ||||||
|  | 			n = d / len; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		manifold.pointCount = 1; | ||||||
|  | 		manifold.points[0].localNormal1 = b3MulT(xf1.rotation, n); | ||||||
|  | 		manifold.points[0].localPoint1 = s1->m_center; | ||||||
|  | 		manifold.points[0].localPoint2 = s2->m_centers[0]; | ||||||
|  | 		manifold.points[0].key.triangleKey = B3_NULL_TRIANGLE; | ||||||
|  | 		manifold.points[0].key.key1 = 0; | ||||||
|  | 		manifold.points[0].key.key2 = 0; | ||||||
|  |  | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (u <= 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		// B | ||||||
|  | 		b3Vec3 P = B; | ||||||
|  | 		b3Vec3 d = P - Q; | ||||||
|  | 		float32 dd = b3Dot(d, d); | ||||||
|  | 		if (dd > radius * radius) | ||||||
|  | 		{ | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b3Vec3 n(0.0f, 1.0f, 0.0f); | ||||||
|  | 		float32 len = b3Length(d); | ||||||
|  | 		if (len > B3_EPSILON) | ||||||
|  | 		{ | ||||||
|  | 			n = d / len; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		manifold.pointCount = 1; | ||||||
|  | 		manifold.points[0].localNormal1 = b3MulT(xf1.rotation, n); | ||||||
|  | 		manifold.points[0].localPoint1 = s1->m_center; | ||||||
|  | 		manifold.points[0].localPoint2 = s2->m_centers[1]; | ||||||
|  | 		manifold.points[0].key.triangleKey = B3_NULL_TRIANGLE; | ||||||
|  | 		manifold.points[0].key.key1 = 0; | ||||||
|  | 		manifold.points[0].key.key2 = 0; | ||||||
|  |  | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// AB | ||||||
|  | 	float32 s = b3Dot(AB, AB); | ||||||
|  | 	//B3_ASSERT(s > 0.0f); | ||||||
|  | 	b3Vec3 P; | ||||||
|  | 	if (s < B3_LINEAR_SLOP * B3_LINEAR_SLOP) | ||||||
|  | 	{ | ||||||
|  | 		P = A; | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		P = (u * A + v * B) / s; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	b3Vec3 d = P - Q; | ||||||
|  | 	float32 dd = b3Dot(d, d); | ||||||
|  | 	if (dd > radius * radius) | ||||||
|  | 	{ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	b3Vec3 QA = A - Q; | ||||||
|  | 	b3Vec3 e = b3Cross(AB, QA); | ||||||
|  | 	b3Vec3 n = b3Cross(AB, e); | ||||||
|  | 	if (b3Dot(n, QA) < 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		n = -n; | ||||||
|  | 	} | ||||||
|  | 	n.Normalize(); | ||||||
|  | 	 | ||||||
|  | 	manifold.pointCount = 1; | ||||||
|  | 	manifold.points[0].localNormal1 = b3MulT(xf1.rotation, n); | ||||||
|  | 	manifold.points[0].localPoint1 = s1->m_center; | ||||||
|  | 	manifold.points[0].localPoint2 = b3MulT(xf2, P); | ||||||
|  | 	manifold.points[0].key.triangleKey = B3_NULL_TRIANGLE; | ||||||
|  | 	manifold.points[0].key.key1 = 0; | ||||||
|  | 	manifold.points[0].key.key2 = 0; | ||||||
|  | } | ||||||
							
								
								
									
										87
									
								
								src/bounce/dynamics/contacts/collide/collide_sphere_hull.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/bounce/dynamics/contacts/collide/collide_sphere_hull.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <bounce/dynamics/contacts/collide/collide.h> | ||||||
|  | #include <bounce/dynamics/contacts/manifold.h> | ||||||
|  | #include <bounce/dynamics/shapes/sphere_shape.h> | ||||||
|  | #include <bounce/dynamics/shapes/hull_shape.h> | ||||||
|  | #include <bounce/collision/shapes/sphere.h> | ||||||
|  | #include <bounce/collision/shapes/hull.h> | ||||||
|  |  | ||||||
|  | void b3CollideSphereAndHull(b3Manifold& manifold,  | ||||||
|  | 	const b3Transform& xf1, const b3SphereShape* s1,  | ||||||
|  | 	const b3Transform& xf2, const b3HullShape* s2)  | ||||||
|  | { | ||||||
|  | 	b3ShapeGJKProxy proxy1(s1, 0);	 | ||||||
|  | 	b3ShapeGJKProxy proxy2(s2, 0);	 | ||||||
|  | 	 | ||||||
|  | 	b3GJKOutput gjk = b3GJK(xf1, proxy1, xf2, proxy2);	 | ||||||
|  | 		 | ||||||
|  | 	float32 r1 = s1->m_radius; | ||||||
|  | 	float32 r2 = s2->m_radius; | ||||||
|  |  | ||||||
|  | 	float32 totalRadius = r1 + r2; | ||||||
|  | 	 | ||||||
|  | 	if (gjk.distance > totalRadius) | ||||||
|  | 	{ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if (gjk.distance > 0.0f) | ||||||
|  | 	{ | ||||||
|  | 		b3Vec3 c1 = gjk.point1; | ||||||
|  | 		b3Vec3 c2 = gjk.point2; | ||||||
|  | 		b3Vec3 normal = (c2 - c1) / gjk.distance; | ||||||
|  | 		 | ||||||
|  | 		manifold.pointCount = 1; | ||||||
|  | 		manifold.points[0].localNormal1 = b3MulT(xf1.rotation, normal); | ||||||
|  | 		manifold.points[0].localPoint1 = s1->m_center; | ||||||
|  | 		manifold.points[0].localPoint2 = b3MulT(xf2, c2); | ||||||
|  | 		manifold.points[0].key.triangleKey = B3_NULL_TRIANGLE; | ||||||
|  | 		manifold.points[0].key.key1 = 0; | ||||||
|  | 		manifold.points[0].key.key2 = 0; | ||||||
|  |  | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	const b3Sphere hull1(s1->m_center, 0.0f); | ||||||
|  | 	const b3Hull* hull2 = s2->m_hull; | ||||||
|  |  | ||||||
|  | 	b3FaceQuery faceQuery = b3QueryFaceSeparation(xf1, &hull1, xf2, hull2); | ||||||
|  | 	if (faceQuery.separation > totalRadius) | ||||||
|  | 	{ | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b3Plane localPlane2 = hull2->planes[faceQuery.index]; | ||||||
|  | 	b3Plane plane2 = xf2 * localPlane2; | ||||||
|  | 	 | ||||||
|  | 	b3Vec3 c1 = xf1 * hull1.vertex; | ||||||
|  | 	b3Vec3 c2 = b3ClosestPointOnPlane(c1, plane2); | ||||||
|  | 	 | ||||||
|  | 	// Ensure normal orientation to shape 2 | ||||||
|  | 	b3Vec3 n1 = -plane2.normal; | ||||||
|  |  | ||||||
|  | 	manifold.pointCount = 1; | ||||||
|  | 	manifold.points[0].localNormal1 = b3MulT(xf1.rotation, n1); | ||||||
|  | 	manifold.points[0].localPoint1 = s1->m_center; | ||||||
|  | 	manifold.points[0].localPoint2 = b3MulT(xf2, c2); | ||||||
|  | 	manifold.points[0].key.triangleKey = B3_NULL_TRIANGLE; | ||||||
|  | 	manifold.points[0].key.key1 = 0; | ||||||
|  | 	manifold.points[0].key.key2 = 0; | ||||||
|  | } | ||||||
							
								
								
									
										62
									
								
								src/bounce/softbody/contacts/softbody_node_body_contact.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/bounce/softbody/contacts/softbody_node_body_contact.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | /* | ||||||
|  | * Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io | ||||||
|  | * | ||||||
|  | * This software is provided 'as-is', without any express or implied | ||||||
|  | * warranty.  In no event will the authors be held liable for any damages | ||||||
|  | * arising from the use of this software. | ||||||
|  | * Permission is granted to anyone to use this software for any purpose, | ||||||
|  | * including commercial applications, and to alter it and redistribute it | ||||||
|  | * freely, subject to the following restrictions: | ||||||
|  | * 1. The origin of this software must not be misrepresented; you must not | ||||||
|  | * claim that you wrote the original software. If you use this software | ||||||
|  | * in a product, an acknowledgment in the product documentation would be | ||||||
|  | * appreciated but is not required. | ||||||
|  | * 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  | * misrepresented as being the original software. | ||||||
|  | * 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #include <bounce/softbody/contacts/softbody_node_body_contact.h> | ||||||
|  | #include <bounce/softbody/softbody_node.h> | ||||||
|  | #include <bounce/dynamics/shapes/shape.h> | ||||||
|  | #include <bounce/dynamics/body.h> | ||||||
|  |  | ||||||
|  | void b3NodeBodyContact::Update() | ||||||
|  | { | ||||||
|  | 	b3Sphere sphere; | ||||||
|  | 	sphere.radius = m_n1->m_radius; | ||||||
|  | 	sphere.vertex = m_n1->m_position; | ||||||
|  |  | ||||||
|  | 	b3Shape* shape = m_s2; | ||||||
|  | 	b3Body* body = shape->GetBody(); | ||||||
|  | 	b3Transform xf = body->GetTransform(); | ||||||
|  |  | ||||||
|  | 	b3TestSphereOutput out; | ||||||
|  | 	if (shape->TestSphere(&out, sphere, xf) == false) | ||||||
|  | 	{ | ||||||
|  | 		m_active = false; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	m_active = true; | ||||||
|  | 	m_normal1 = -out.normal; | ||||||
|  | 	m_localPoint1.SetZero(); | ||||||
|  | 	m_localPoint2 = body->GetLocalPoint(out.point); | ||||||
|  | 	m_tangent1 = b3Perp(m_normal1); | ||||||
|  | 	m_tangent2 = b3Cross(m_tangent1, m_normal1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void b3NodeBodyContactWorldPoint::Initialize(const b3NodeBodyContact* c, float32 rA, const b3Transform& xfA, float32 rB, const b3Transform& xfB) | ||||||
|  | { | ||||||
|  | 	b3Vec3 nA = c->m_normal1; | ||||||
|  |  | ||||||
|  | 	b3Vec3 cA = xfA * c->m_localPoint1; | ||||||
|  | 	b3Vec3 cB = xfB * c->m_localPoint2; | ||||||
|  |  | ||||||
|  | 	b3Vec3 pA = cA + rA * nA; | ||||||
|  | 	b3Vec3 pB = cB - rB * nA; | ||||||
|  |  | ||||||
|  | 	point = 0.5f * (pA + pB); | ||||||
|  | 	normal = nA; | ||||||
|  | 	separation = b3Dot(cB - cA, nA) - rA - rB; | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user