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 | ||||
| #elif defined( __APPLE__ ) | ||||
| #define B3_PLATFORM B3_MAC | ||||
| #elif defined(_arch_dreamcast) | ||||
| #define B3_PLATFORM B3_DREAMCAST | ||||
| #else | ||||
| #define B3_PLATFORM B3_UNIX | ||||
| #endif | ||||
| @@ -157,6 +159,55 @@ private: | ||||
| 	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 | ||||
|  | ||||
| #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