Compare commits
	
		
			9 Commits
		
	
	
		
			upstream_f
			...
			bounce-upg
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | e5897d433d | ||
|  | 1509b9bd0e | ||
|  | d728d45d70 | ||
|  | d7010a99f9 | ||
|  | 795bef7394 | ||
|  | 950de0854b | ||
|  | 5522df60b0 | ||
|  | 77fb26b578 | ||
|  | 3992eb8cc4 | 
| @@ -1,110 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,73 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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 |  | ||||||
| @@ -1,197 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,94 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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 |  | ||||||
| @@ -1,60 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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 |  | ||||||
| @@ -1,138 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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 |  | ||||||
| @@ -1,121 +0,0 @@ | |||||||
| #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 |  | ||||||
| @@ -1,191 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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
									
									
								
							
							
						
						
									
										238
									
								
								external/glfw/mir_init.c
									
									
									
									
										vendored
									
									
								
							| @@ -1,238 +0,0 @@ | |||||||
| //======================================================================== |  | ||||||
| // 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
									
									
								
							
							
						
						
									
										182
									
								
								external/glfw/mir_monitor.c
									
									
									
									
										vendored
									
									
								
							| @@ -1,182 +0,0 @@ | |||||||
| //======================================================================== |  | ||||||
| // 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
									
									
								
							
							
						
						
									
										130
									
								
								external/glfw/mir_platform.h
									
									
									
									
										vendored
									
									
								
							| @@ -1,130 +0,0 @@ | |||||||
| //======================================================================== |  | ||||||
| // 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
									
									
								
							
							
						
						
									
										848
									
								
								external/glfw/mir_window.c
									
									
									
									
										vendored
									
									
								
							| @@ -1,848 +0,0 @@ | |||||||
| //======================================================================== |  | ||||||
| // 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
									
									
								
							
							
						
						
									
										68
									
								
								external/glfw/posix_tls.c
									
									
									
									
										vendored
									
									
								
							| @@ -1,68 +0,0 @@ | |||||||
| //======================================================================== |  | ||||||
| // 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
									
									
								
							
							
						
						
									
										49
									
								
								external/glfw/posix_tls.h
									
									
									
									
										vendored
									
									
								
							| @@ -1,49 +0,0 @@ | |||||||
| //======================================================================== |  | ||||||
| // 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
									
									
								
							
							
						
						
									
										69
									
								
								external/glfw/win32_tls.c
									
									
									
									
										vendored
									
									
								
							| @@ -1,69 +0,0 @@ | |||||||
| //======================================================================== |  | ||||||
| // 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
									
									
								
							
							
						
						
									
										354
									
								
								external/imgui/imgui_impl_glfw_gl2.cpp
									
									
									
									
										vendored
									
									
								
							| @@ -1,354 +0,0 @@ | |||||||
| // 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
									
									
								
							
							
						
						
									
										32
									
								
								external/imgui/imgui_impl_glfw_gl2.h
									
									
									
									
										vendored
									
									
								
							| @@ -1,32 +0,0 @@ | |||||||
| // 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
									
									
								
							
							
						
						
									
										518
									
								
								external/imgui/imgui_impl_glfw_gl3.cpp
									
									
									
									
										vendored
									
									
								
							| @@ -1,518 +0,0 @@ | |||||||
| // 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
									
									
								
							
							
						
						
									
										31
									
								
								external/imgui/imgui_impl_glfw_gl3.h
									
									
									
									
										vendored
									
									
								
							| @@ -1,31 +0,0 @@ | |||||||
| // 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
									
									
								
							
							
						
						
									
										623
									
								
								external/imgui/stb_rect_pack.h
									
									
									
									
										vendored
									
									
								
							| @@ -1,623 +0,0 @@ | |||||||
| // 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
									
									
								
							
							
						
						
									
										1322
									
								
								external/imgui/stb_textedit.h
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4854
									
								
								external/imgui/stb_truetype.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4854
									
								
								external/imgui/stb_truetype.h
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,38 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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 |  | ||||||
| @@ -1,112 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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 |  | ||||||
| @@ -1,76 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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 |  | ||||||
| @@ -1,65 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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 |  | ||||||
| @@ -1,126 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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 |  | ||||||
| @@ -1,281 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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 |  | ||||||
| @@ -1,40 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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 |  | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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 |  | ||||||
| @@ -1,253 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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,6 +29,8 @@ | |||||||
| #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 | ||||||
| @@ -157,6 +159,55 @@ 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> | ||||||
|   | |||||||
| @@ -1,78 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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  |  | ||||||
| @@ -1,41 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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); |  | ||||||
| } |  | ||||||
| @@ -1,62 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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; |  | ||||||
| } |  | ||||||
| @@ -1,179 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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]; |  | ||||||
| } |  | ||||||
| @@ -1,329 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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; |  | ||||||
| } |  | ||||||
| @@ -1,144 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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); |  | ||||||
| } |  | ||||||
| @@ -1,143 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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; |  | ||||||
| } |  | ||||||
| @@ -1,54 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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; |  | ||||||
| } |  | ||||||
| @@ -1,222 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,344 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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); |  | ||||||
| } |  | ||||||
| @@ -1,134 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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; |  | ||||||
| } |  | ||||||
| @@ -1,87 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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; |  | ||||||
| } |  | ||||||
| @@ -1,62 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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