9 Commits

Author SHA1 Message Date
e5897d433d Upgrade bounce 2020-01-30 18:42:47 +00:00
1509b9bd0e Use relative path to triangle.h 2019-07-08 19:49:56 +01:00
d728d45d70 Merge remote-tracking branch 'upstream/master' 2019-07-08 19:42:44 +01:00
d7010a99f9 Tweaks 2018-09-29 21:21:19 +01:00
795bef7394 Fix compilation error on GCC 7.3.1
The extra qualification is necessary for the lookup to succeed.
2018-09-29 21:01:43 +01:00
950de0854b Fix case of windows include (when cross-compiling from Linux, it matters) 2018-09-29 21:00:00 +01:00
5522df60b0 Fix dreamcast timer 2018-09-29 21:00:00 +01:00
77fb26b578 Change to microsecond precision 2018-09-29 21:00:00 +01:00
3992eb8cc4 Add b3Time implementation for the Dreamcast 2018-09-29 21:00:00 +01:00
46 changed files with 51 additions and 15692 deletions

2487
doxyfile

File diff suppressed because it is too large Load Diff

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
;
}

View File

@ -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;
}

View File

@ -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_

View File

@ -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, &region);
// 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;
}

View File

@ -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);
}

View File

@ -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_

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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);

View File

@ -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();
}

View File

@ -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);

View File

@ -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.
------------------------------------------------------------------------------
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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];
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}