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