aboutsummaryrefslogtreecommitdiff
path: root/src/libjin/3rdparty/Box2D/Dynamics/Joints
diff options
context:
space:
mode:
Diffstat (limited to 'src/libjin/3rdparty/Box2D/Dynamics/Joints')
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2DistanceJoint.cpp260
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2DistanceJoint.h169
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2FrictionJoint.cpp251
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2FrictionJoint.h119
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2GearJoint.cpp419
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2GearJoint.h125
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2Joint.cpp211
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2Joint.h226
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MotorJoint.cpp309
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MotorJoint.h133
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MouseJoint.cpp222
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MouseJoint.h129
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp642
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PrismaticJoint.h196
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PulleyJoint.cpp348
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PulleyJoint.h152
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp511
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RevoluteJoint.h204
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RopeJoint.cpp241
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RopeJoint.h114
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WeldJoint.cpp344
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WeldJoint.h126
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WheelJoint.cpp456
-rw-r--r--src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WheelJoint.h216
24 files changed, 6123 insertions, 0 deletions
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2DistanceJoint.cpp b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2DistanceJoint.cpp
new file mode 100644
index 0000000..126133c
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2DistanceJoint.cpp
@@ -0,0 +1,260 @@
+/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.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 "Box2D/Dynamics/Joints/b2DistanceJoint.h"
+#include "Box2D/Dynamics/b2Body.h"
+#include "Box2D/Dynamics/b2TimeStep.h"
+
+// 1-D constrained system
+// m (v2 - v1) = lambda
+// v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass.
+// x2 = x1 + h * v2
+
+// 1-D mass-damper-spring system
+// m (v2 - v1) + h * d * v2 + h * k *
+
+// C = norm(p2 - p1) - L
+// u = (p2 - p1) / norm(p2 - p1)
+// Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1))
+// J = [-u -cross(r1, u) u cross(r2, u)]
+// K = J * invM * JT
+// = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2
+
+void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2,
+ const b2Vec2& anchor1, const b2Vec2& anchor2)
+{
+ bodyA = b1;
+ bodyB = b2;
+ localAnchorA = bodyA->GetLocalPoint(anchor1);
+ localAnchorB = bodyB->GetLocalPoint(anchor2);
+ b2Vec2 d = anchor2 - anchor1;
+ length = d.Length();
+}
+
+b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def)
+: b2Joint(def)
+{
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+ m_length = def->length;
+ m_frequencyHz = def->frequencyHz;
+ m_dampingRatio = def->dampingRatio;
+ m_impulse = 0.0f;
+ m_gamma = 0.0f;
+ m_bias = 0.0f;
+}
+
+void b2DistanceJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ m_u = cB + m_rB - cA - m_rA;
+
+ // Handle singularity.
+ float32 length = m_u.Length();
+ if (length > b2_linearSlop)
+ {
+ m_u *= 1.0f / length;
+ }
+ else
+ {
+ m_u.Set(0.0f, 0.0f);
+ }
+
+ float32 crAu = b2Cross(m_rA, m_u);
+ float32 crBu = b2Cross(m_rB, m_u);
+ float32 invMass = m_invMassA + m_invIA * crAu * crAu + m_invMassB + m_invIB * crBu * crBu;
+
+ // Compute the effective mass matrix.
+ m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
+
+ if (m_frequencyHz > 0.0f)
+ {
+ float32 C = length - m_length;
+
+ // Frequency
+ float32 omega = 2.0f * b2_pi * m_frequencyHz;
+
+ // Damping coefficient
+ float32 d = 2.0f * m_mass * m_dampingRatio * omega;
+
+ // Spring stiffness
+ float32 k = m_mass * omega * omega;
+
+ // magic formulas
+ float32 h = data.step.dt;
+ m_gamma = h * (d + h * k);
+ m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f;
+ m_bias = C * h * k * m_gamma;
+
+ invMass += m_gamma;
+ m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
+ }
+ else
+ {
+ m_gamma = 0.0f;
+ m_bias = 0.0f;
+ }
+
+ if (data.step.warmStarting)
+ {
+ // Scale the impulse to support a variable time step.
+ m_impulse *= data.step.dtRatio;
+
+ b2Vec2 P = m_impulse * m_u;
+ vA -= m_invMassA * P;
+ wA -= m_invIA * b2Cross(m_rA, P);
+ vB += m_invMassB * P;
+ wB += m_invIB * b2Cross(m_rB, P);
+ }
+ else
+ {
+ m_impulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2DistanceJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ // Cdot = dot(u, v + cross(w, r))
+ b2Vec2 vpA = vA + b2Cross(wA, m_rA);
+ b2Vec2 vpB = vB + b2Cross(wB, m_rB);
+ float32 Cdot = b2Dot(m_u, vpB - vpA);
+
+ float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse);
+ m_impulse += impulse;
+
+ b2Vec2 P = impulse * m_u;
+ vA -= m_invMassA * P;
+ wA -= m_invIA * b2Cross(m_rA, P);
+ vB += m_invMassB * P;
+ wB += m_invIB * b2Cross(m_rB, P);
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2DistanceJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ if (m_frequencyHz > 0.0f)
+ {
+ // There is no position correction for soft distance constraints.
+ return true;
+ }
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+
+ b2Rot qA(aA), qB(aB);
+
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ b2Vec2 u = cB + rB - cA - rA;
+
+ float32 length = u.Normalize();
+ float32 C = length - m_length;
+ C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection);
+
+ float32 impulse = -m_mass * C;
+ b2Vec2 P = impulse * u;
+
+ cA -= m_invMassA * P;
+ aA -= m_invIA * b2Cross(rA, P);
+ cB += m_invMassB * P;
+ aB += m_invIB * b2Cross(rB, P);
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+
+ return b2Abs(C) < b2_linearSlop;
+}
+
+b2Vec2 b2DistanceJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2DistanceJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2DistanceJoint::GetReactionForce(float32 inv_dt) const
+{
+ b2Vec2 F = (inv_dt * m_impulse) * m_u;
+ return F;
+}
+
+float32 b2DistanceJoint::GetReactionTorque(float32 inv_dt) const
+{
+ B2_NOT_USED(inv_dt);
+ return 0.0f;
+}
+
+void b2DistanceJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2DistanceJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.length = %.15lef;\n", m_length);
+ b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz);
+ b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2DistanceJoint.h b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2DistanceJoint.h
new file mode 100644
index 0000000..ba59210
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2DistanceJoint.h
@@ -0,0 +1,169 @@
+/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.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 B2_DISTANCE_JOINT_H
+#define B2_DISTANCE_JOINT_H
+
+#include "Box2D/Dynamics/Joints/b2Joint.h"
+
+/// Distance joint definition. This requires defining an
+/// anchor point on both bodies and the non-zero length of the
+/// distance joint. The definition uses local anchor points
+/// so that the initial configuration can violate the constraint
+/// slightly. This helps when saving and loading a game.
+/// @warning Do not use a zero or short length.
+struct b2DistanceJointDef : public b2JointDef
+{
+ b2DistanceJointDef()
+ {
+ type = e_distanceJoint;
+ localAnchorA.Set(0.0f, 0.0f);
+ localAnchorB.Set(0.0f, 0.0f);
+ length = 1.0f;
+ frequencyHz = 0.0f;
+ dampingRatio = 0.0f;
+ }
+
+ /// Initialize the bodies, anchors, and length using the world
+ /// anchors.
+ void Initialize(b2Body* bodyA, b2Body* bodyB,
+ const b2Vec2& anchorA, const b2Vec2& anchorB);
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The natural length between the anchor points.
+ float32 length;
+
+ /// The mass-spring-damper frequency in Hertz. A value of 0
+ /// disables softness.
+ float32 frequencyHz;
+
+ /// The damping ratio. 0 = no damping, 1 = critical damping.
+ float32 dampingRatio;
+};
+
+/// A distance joint constrains two points on two bodies
+/// to remain at a fixed distance from each other. You can view
+/// this as a massless, rigid rod.
+class b2DistanceJoint : public b2Joint
+{
+public:
+
+ b2Vec2 GetAnchorA() const override;
+ b2Vec2 GetAnchorB() const override;
+
+ /// Get the reaction force given the inverse time step.
+ /// Unit is N.
+ b2Vec2 GetReactionForce(float32 inv_dt) const override;
+
+ /// Get the reaction torque given the inverse time step.
+ /// Unit is N*m. This is always zero for a distance joint.
+ float32 GetReactionTorque(float32 inv_dt) const override;
+
+ /// The local anchor point relative to bodyA's origin.
+ const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
+
+ /// The local anchor point relative to bodyB's origin.
+ const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
+
+ /// Set/get the natural length.
+ /// Manipulating the length can lead to non-physical behavior when the frequency is zero.
+ void SetLength(float32 length);
+ float32 GetLength() const;
+
+ /// Set/get frequency in Hz.
+ void SetFrequency(float32 hz);
+ float32 GetFrequency() const;
+
+ /// Set/get damping ratio.
+ void SetDampingRatio(float32 ratio);
+ float32 GetDampingRatio() const;
+
+ /// Dump joint to dmLog
+ void Dump() override;
+
+protected:
+
+ friend class b2Joint;
+ b2DistanceJoint(const b2DistanceJointDef* data);
+
+ void InitVelocityConstraints(const b2SolverData& data) override;
+ void SolveVelocityConstraints(const b2SolverData& data) override;
+ bool SolvePositionConstraints(const b2SolverData& data) override;
+
+ float32 m_frequencyHz;
+ float32 m_dampingRatio;
+ float32 m_bias;
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ float32 m_gamma;
+ float32 m_impulse;
+ float32 m_length;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_u;
+ b2Vec2 m_rA;
+ b2Vec2 m_rB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+ float32 m_mass;
+};
+
+inline void b2DistanceJoint::SetLength(float32 length)
+{
+ m_length = length;
+}
+
+inline float32 b2DistanceJoint::GetLength() const
+{
+ return m_length;
+}
+
+inline void b2DistanceJoint::SetFrequency(float32 hz)
+{
+ m_frequencyHz = hz;
+}
+
+inline float32 b2DistanceJoint::GetFrequency() const
+{
+ return m_frequencyHz;
+}
+
+inline void b2DistanceJoint::SetDampingRatio(float32 ratio)
+{
+ m_dampingRatio = ratio;
+}
+
+inline float32 b2DistanceJoint::GetDampingRatio() const
+{
+ return m_dampingRatio;
+}
+
+#endif
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2FrictionJoint.cpp b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2FrictionJoint.cpp
new file mode 100644
index 0000000..cb122eb
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2FrictionJoint.cpp
@@ -0,0 +1,251 @@
+/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.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 "Box2D/Dynamics/Joints/b2FrictionJoint.h"
+#include "Box2D/Dynamics/b2Body.h"
+#include "Box2D/Dynamics/b2TimeStep.h"
+
+// Point-to-point constraint
+// Cdot = v2 - v1
+// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
+// J = [-I -r1_skew I r2_skew ]
+// Identity used:
+// w k % (rx i + ry j) = w * (-ry i + rx j)
+
+// Angle constraint
+// Cdot = w2 - w1
+// J = [0 0 -1 0 0 1]
+// K = invI1 + invI2
+
+void b2FrictionJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)
+{
+ bodyA = bA;
+ bodyB = bB;
+ localAnchorA = bodyA->GetLocalPoint(anchor);
+ localAnchorB = bodyB->GetLocalPoint(anchor);
+}
+
+b2FrictionJoint::b2FrictionJoint(const b2FrictionJointDef* def)
+: b2Joint(def)
+{
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+
+ m_linearImpulse.SetZero();
+ m_angularImpulse = 0.0f;
+
+ m_maxForce = def->maxForce;
+ m_maxTorque = def->maxTorque;
+}
+
+void b2FrictionJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ // Compute the effective mass matrix.
+ m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ // J = [-I -r1_skew I r2_skew]
+ // [ 0 -1 0 1]
+ // r_skew = [-ry; rx]
+
+ // Matlab
+ // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
+ // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
+ // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ b2Mat22 K;
+ K.ex.x = mA + mB + iA * m_rA.y * m_rA.y + iB * m_rB.y * m_rB.y;
+ K.ex.y = -iA * m_rA.x * m_rA.y - iB * m_rB.x * m_rB.y;
+ K.ey.x = K.ex.y;
+ K.ey.y = mA + mB + iA * m_rA.x * m_rA.x + iB * m_rB.x * m_rB.x;
+
+ m_linearMass = K.GetInverse();
+
+ m_angularMass = iA + iB;
+ if (m_angularMass > 0.0f)
+ {
+ m_angularMass = 1.0f / m_angularMass;
+ }
+
+ if (data.step.warmStarting)
+ {
+ // Scale impulses to support a variable time step.
+ m_linearImpulse *= data.step.dtRatio;
+ m_angularImpulse *= data.step.dtRatio;
+
+ b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y);
+ vA -= mA * P;
+ wA -= iA * (b2Cross(m_rA, P) + m_angularImpulse);
+ vB += mB * P;
+ wB += iB * (b2Cross(m_rB, P) + m_angularImpulse);
+ }
+ else
+ {
+ m_linearImpulse.SetZero();
+ m_angularImpulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2FrictionJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ float32 h = data.step.dt;
+
+ // Solve angular friction
+ {
+ float32 Cdot = wB - wA;
+ float32 impulse = -m_angularMass * Cdot;
+
+ float32 oldImpulse = m_angularImpulse;
+ float32 maxImpulse = h * m_maxTorque;
+ m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse);
+ impulse = m_angularImpulse - oldImpulse;
+
+ wA -= iA * impulse;
+ wB += iB * impulse;
+ }
+
+ // Solve linear friction
+ {
+ b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
+
+ b2Vec2 impulse = -b2Mul(m_linearMass, Cdot);
+ b2Vec2 oldImpulse = m_linearImpulse;
+ m_linearImpulse += impulse;
+
+ float32 maxImpulse = h * m_maxForce;
+
+ if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse)
+ {
+ m_linearImpulse.Normalize();
+ m_linearImpulse *= maxImpulse;
+ }
+
+ impulse = m_linearImpulse - oldImpulse;
+
+ vA -= mA * impulse;
+ wA -= iA * b2Cross(m_rA, impulse);
+
+ vB += mB * impulse;
+ wB += iB * b2Cross(m_rB, impulse);
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2FrictionJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ B2_NOT_USED(data);
+
+ return true;
+}
+
+b2Vec2 b2FrictionJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2FrictionJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2FrictionJoint::GetReactionForce(float32 inv_dt) const
+{
+ return inv_dt * m_linearImpulse;
+}
+
+float32 b2FrictionJoint::GetReactionTorque(float32 inv_dt) const
+{
+ return inv_dt * m_angularImpulse;
+}
+
+void b2FrictionJoint::SetMaxForce(float32 force)
+{
+ b2Assert(b2IsValid(force) && force >= 0.0f);
+ m_maxForce = force;
+}
+
+float32 b2FrictionJoint::GetMaxForce() const
+{
+ return m_maxForce;
+}
+
+void b2FrictionJoint::SetMaxTorque(float32 torque)
+{
+ b2Assert(b2IsValid(torque) && torque >= 0.0f);
+ m_maxTorque = torque;
+}
+
+float32 b2FrictionJoint::GetMaxTorque() const
+{
+ return m_maxTorque;
+}
+
+void b2FrictionJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2FrictionJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.maxForce = %.15lef;\n", m_maxForce);
+ b2Log(" jd.maxTorque = %.15lef;\n", m_maxTorque);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2FrictionJoint.h b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2FrictionJoint.h
new file mode 100644
index 0000000..d964f84
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2FrictionJoint.h
@@ -0,0 +1,119 @@
+/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.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 B2_FRICTION_JOINT_H
+#define B2_FRICTION_JOINT_H
+
+#include "Box2D/Dynamics/Joints/b2Joint.h"
+
+/// Friction joint definition.
+struct b2FrictionJointDef : public b2JointDef
+{
+ b2FrictionJointDef()
+ {
+ type = e_frictionJoint;
+ localAnchorA.SetZero();
+ localAnchorB.SetZero();
+ maxForce = 0.0f;
+ maxTorque = 0.0f;
+ }
+
+ /// Initialize the bodies, anchors, axis, and reference angle using the world
+ /// anchor and world axis.
+ void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The maximum friction force in N.
+ float32 maxForce;
+
+ /// The maximum friction torque in N-m.
+ float32 maxTorque;
+};
+
+/// Friction joint. This is used for top-down friction.
+/// It provides 2D translational friction and angular friction.
+class b2FrictionJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const override;
+ b2Vec2 GetAnchorB() const override;
+
+ b2Vec2 GetReactionForce(float32 inv_dt) const override;
+ float32 GetReactionTorque(float32 inv_dt) const override;
+
+ /// The local anchor point relative to bodyA's origin.
+ const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
+
+ /// The local anchor point relative to bodyB's origin.
+ const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
+
+ /// Set the maximum friction force in N.
+ void SetMaxForce(float32 force);
+
+ /// Get the maximum friction force in N.
+ float32 GetMaxForce() const;
+
+ /// Set the maximum friction torque in N*m.
+ void SetMaxTorque(float32 torque);
+
+ /// Get the maximum friction torque in N*m.
+ float32 GetMaxTorque() const;
+
+ /// Dump joint to dmLog
+ void Dump() override;
+
+protected:
+
+ friend class b2Joint;
+
+ b2FrictionJoint(const b2FrictionJointDef* def);
+
+ void InitVelocityConstraints(const b2SolverData& data) override;
+ void SolveVelocityConstraints(const b2SolverData& data) override;
+ bool SolvePositionConstraints(const b2SolverData& data) override;
+
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+
+ // Solver shared
+ b2Vec2 m_linearImpulse;
+ float32 m_angularImpulse;
+ float32 m_maxForce;
+ float32 m_maxTorque;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_rA;
+ b2Vec2 m_rB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+ b2Mat22 m_linearMass;
+ float32 m_angularMass;
+};
+
+#endif
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2GearJoint.cpp b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2GearJoint.cpp
new file mode 100644
index 0000000..1ce575b
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2GearJoint.cpp
@@ -0,0 +1,419 @@
+/*
+* Copyright (c) 2007-2011 Erin Catto http://www.box2d.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 "Box2D/Dynamics/Joints/b2GearJoint.h"
+#include "Box2D/Dynamics/Joints/b2RevoluteJoint.h"
+#include "Box2D/Dynamics/Joints/b2PrismaticJoint.h"
+#include "Box2D/Dynamics/b2Body.h"
+#include "Box2D/Dynamics/b2TimeStep.h"
+
+// Gear Joint:
+// C0 = (coordinate1 + ratio * coordinate2)_initial
+// C = (coordinate1 + ratio * coordinate2) - C0 = 0
+// J = [J1 ratio * J2]
+// K = J * invM * JT
+// = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T
+//
+// Revolute:
+// coordinate = rotation
+// Cdot = angularVelocity
+// J = [0 0 1]
+// K = J * invM * JT = invI
+//
+// Prismatic:
+// coordinate = dot(p - pg, ug)
+// Cdot = dot(v + cross(w, r), ug)
+// J = [ug cross(r, ug)]
+// K = J * invM * JT = invMass + invI * cross(r, ug)^2
+
+b2GearJoint::b2GearJoint(const b2GearJointDef* def)
+: b2Joint(def)
+{
+ m_joint1 = def->joint1;
+ m_joint2 = def->joint2;
+
+ m_typeA = m_joint1->GetType();
+ m_typeB = m_joint2->GetType();
+
+ b2Assert(m_typeA == e_revoluteJoint || m_typeA == e_prismaticJoint);
+ b2Assert(m_typeB == e_revoluteJoint || m_typeB == e_prismaticJoint);
+
+ float32 coordinateA, coordinateB;
+
+ // TODO_ERIN there might be some problem with the joint edges in b2Joint.
+
+ m_bodyC = m_joint1->GetBodyA();
+ m_bodyA = m_joint1->GetBodyB();
+
+ // Get geometry of joint1
+ b2Transform xfA = m_bodyA->m_xf;
+ float32 aA = m_bodyA->m_sweep.a;
+ b2Transform xfC = m_bodyC->m_xf;
+ float32 aC = m_bodyC->m_sweep.a;
+
+ if (m_typeA == e_revoluteJoint)
+ {
+ b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint1;
+ m_localAnchorC = revolute->m_localAnchorA;
+ m_localAnchorA = revolute->m_localAnchorB;
+ m_referenceAngleA = revolute->m_referenceAngle;
+ m_localAxisC.SetZero();
+
+ coordinateA = aA - aC - m_referenceAngleA;
+ }
+ else
+ {
+ b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint1;
+ m_localAnchorC = prismatic->m_localAnchorA;
+ m_localAnchorA = prismatic->m_localAnchorB;
+ m_referenceAngleA = prismatic->m_referenceAngle;
+ m_localAxisC = prismatic->m_localXAxisA;
+
+ b2Vec2 pC = m_localAnchorC;
+ b2Vec2 pA = b2MulT(xfC.q, b2Mul(xfA.q, m_localAnchorA) + (xfA.p - xfC.p));
+ coordinateA = b2Dot(pA - pC, m_localAxisC);
+ }
+
+ m_bodyD = m_joint2->GetBodyA();
+ m_bodyB = m_joint2->GetBodyB();
+
+ // Get geometry of joint2
+ b2Transform xfB = m_bodyB->m_xf;
+ float32 aB = m_bodyB->m_sweep.a;
+ b2Transform xfD = m_bodyD->m_xf;
+ float32 aD = m_bodyD->m_sweep.a;
+
+ if (m_typeB == e_revoluteJoint)
+ {
+ b2RevoluteJoint* revolute = (b2RevoluteJoint*)def->joint2;
+ m_localAnchorD = revolute->m_localAnchorA;
+ m_localAnchorB = revolute->m_localAnchorB;
+ m_referenceAngleB = revolute->m_referenceAngle;
+ m_localAxisD.SetZero();
+
+ coordinateB = aB - aD - m_referenceAngleB;
+ }
+ else
+ {
+ b2PrismaticJoint* prismatic = (b2PrismaticJoint*)def->joint2;
+ m_localAnchorD = prismatic->m_localAnchorA;
+ m_localAnchorB = prismatic->m_localAnchorB;
+ m_referenceAngleB = prismatic->m_referenceAngle;
+ m_localAxisD = prismatic->m_localXAxisA;
+
+ b2Vec2 pD = m_localAnchorD;
+ b2Vec2 pB = b2MulT(xfD.q, b2Mul(xfB.q, m_localAnchorB) + (xfB.p - xfD.p));
+ coordinateB = b2Dot(pB - pD, m_localAxisD);
+ }
+
+ m_ratio = def->ratio;
+
+ m_constant = coordinateA + m_ratio * coordinateB;
+
+ m_impulse = 0.0f;
+}
+
+void b2GearJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_indexC = m_bodyC->m_islandIndex;
+ m_indexD = m_bodyD->m_islandIndex;
+ m_lcA = m_bodyA->m_sweep.localCenter;
+ m_lcB = m_bodyB->m_sweep.localCenter;
+ m_lcC = m_bodyC->m_sweep.localCenter;
+ m_lcD = m_bodyD->m_sweep.localCenter;
+ m_mA = m_bodyA->m_invMass;
+ m_mB = m_bodyB->m_invMass;
+ m_mC = m_bodyC->m_invMass;
+ m_mD = m_bodyD->m_invMass;
+ m_iA = m_bodyA->m_invI;
+ m_iB = m_bodyB->m_invI;
+ m_iC = m_bodyC->m_invI;
+ m_iD = m_bodyD->m_invI;
+
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ float32 aC = data.positions[m_indexC].a;
+ b2Vec2 vC = data.velocities[m_indexC].v;
+ float32 wC = data.velocities[m_indexC].w;
+
+ float32 aD = data.positions[m_indexD].a;
+ b2Vec2 vD = data.velocities[m_indexD].v;
+ float32 wD = data.velocities[m_indexD].w;
+
+ b2Rot qA(aA), qB(aB), qC(aC), qD(aD);
+
+ m_mass = 0.0f;
+
+ if (m_typeA == e_revoluteJoint)
+ {
+ m_JvAC.SetZero();
+ m_JwA = 1.0f;
+ m_JwC = 1.0f;
+ m_mass += m_iA + m_iC;
+ }
+ else
+ {
+ b2Vec2 u = b2Mul(qC, m_localAxisC);
+ b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC);
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA);
+ m_JvAC = u;
+ m_JwC = b2Cross(rC, u);
+ m_JwA = b2Cross(rA, u);
+ m_mass += m_mC + m_mA + m_iC * m_JwC * m_JwC + m_iA * m_JwA * m_JwA;
+ }
+
+ if (m_typeB == e_revoluteJoint)
+ {
+ m_JvBD.SetZero();
+ m_JwB = m_ratio;
+ m_JwD = m_ratio;
+ m_mass += m_ratio * m_ratio * (m_iB + m_iD);
+ }
+ else
+ {
+ b2Vec2 u = b2Mul(qD, m_localAxisD);
+ b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB);
+ m_JvBD = m_ratio * u;
+ m_JwD = m_ratio * b2Cross(rD, u);
+ m_JwB = m_ratio * b2Cross(rB, u);
+ m_mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * m_JwD * m_JwD + m_iB * m_JwB * m_JwB;
+ }
+
+ // Compute effective mass.
+ m_mass = m_mass > 0.0f ? 1.0f / m_mass : 0.0f;
+
+ if (data.step.warmStarting)
+ {
+ vA += (m_mA * m_impulse) * m_JvAC;
+ wA += m_iA * m_impulse * m_JwA;
+ vB += (m_mB * m_impulse) * m_JvBD;
+ wB += m_iB * m_impulse * m_JwB;
+ vC -= (m_mC * m_impulse) * m_JvAC;
+ wC -= m_iC * m_impulse * m_JwC;
+ vD -= (m_mD * m_impulse) * m_JvBD;
+ wD -= m_iD * m_impulse * m_JwD;
+ }
+ else
+ {
+ m_impulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+ data.velocities[m_indexC].v = vC;
+ data.velocities[m_indexC].w = wC;
+ data.velocities[m_indexD].v = vD;
+ data.velocities[m_indexD].w = wD;
+}
+
+void b2GearJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+ b2Vec2 vC = data.velocities[m_indexC].v;
+ float32 wC = data.velocities[m_indexC].w;
+ b2Vec2 vD = data.velocities[m_indexD].v;
+ float32 wD = data.velocities[m_indexD].w;
+
+ float32 Cdot = b2Dot(m_JvAC, vA - vC) + b2Dot(m_JvBD, vB - vD);
+ Cdot += (m_JwA * wA - m_JwC * wC) + (m_JwB * wB - m_JwD * wD);
+
+ float32 impulse = -m_mass * Cdot;
+ m_impulse += impulse;
+
+ vA += (m_mA * impulse) * m_JvAC;
+ wA += m_iA * impulse * m_JwA;
+ vB += (m_mB * impulse) * m_JvBD;
+ wB += m_iB * impulse * m_JwB;
+ vC -= (m_mC * impulse) * m_JvAC;
+ wC -= m_iC * impulse * m_JwC;
+ vD -= (m_mD * impulse) * m_JvBD;
+ wD -= m_iD * impulse * m_JwD;
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+ data.velocities[m_indexC].v = vC;
+ data.velocities[m_indexC].w = wC;
+ data.velocities[m_indexD].v = vD;
+ data.velocities[m_indexD].w = wD;
+}
+
+bool b2GearJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 cC = data.positions[m_indexC].c;
+ float32 aC = data.positions[m_indexC].a;
+ b2Vec2 cD = data.positions[m_indexD].c;
+ float32 aD = data.positions[m_indexD].a;
+
+ b2Rot qA(aA), qB(aB), qC(aC), qD(aD);
+
+ float32 linearError = 0.0f;
+
+ float32 coordinateA, coordinateB;
+
+ b2Vec2 JvAC, JvBD;
+ float32 JwA, JwB, JwC, JwD;
+ float32 mass = 0.0f;
+
+ if (m_typeA == e_revoluteJoint)
+ {
+ JvAC.SetZero();
+ JwA = 1.0f;
+ JwC = 1.0f;
+ mass += m_iA + m_iC;
+
+ coordinateA = aA - aC - m_referenceAngleA;
+ }
+ else
+ {
+ b2Vec2 u = b2Mul(qC, m_localAxisC);
+ b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC);
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA);
+ JvAC = u;
+ JwC = b2Cross(rC, u);
+ JwA = b2Cross(rA, u);
+ mass += m_mC + m_mA + m_iC * JwC * JwC + m_iA * JwA * JwA;
+
+ b2Vec2 pC = m_localAnchorC - m_lcC;
+ b2Vec2 pA = b2MulT(qC, rA + (cA - cC));
+ coordinateA = b2Dot(pA - pC, m_localAxisC);
+ }
+
+ if (m_typeB == e_revoluteJoint)
+ {
+ JvBD.SetZero();
+ JwB = m_ratio;
+ JwD = m_ratio;
+ mass += m_ratio * m_ratio * (m_iB + m_iD);
+
+ coordinateB = aB - aD - m_referenceAngleB;
+ }
+ else
+ {
+ b2Vec2 u = b2Mul(qD, m_localAxisD);
+ b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB);
+ JvBD = m_ratio * u;
+ JwD = m_ratio * b2Cross(rD, u);
+ JwB = m_ratio * b2Cross(rB, u);
+ mass += m_ratio * m_ratio * (m_mD + m_mB) + m_iD * JwD * JwD + m_iB * JwB * JwB;
+
+ b2Vec2 pD = m_localAnchorD - m_lcD;
+ b2Vec2 pB = b2MulT(qD, rB + (cB - cD));
+ coordinateB = b2Dot(pB - pD, m_localAxisD);
+ }
+
+ float32 C = (coordinateA + m_ratio * coordinateB) - m_constant;
+
+ float32 impulse = 0.0f;
+ if (mass > 0.0f)
+ {
+ impulse = -C / mass;
+ }
+
+ cA += m_mA * impulse * JvAC;
+ aA += m_iA * impulse * JwA;
+ cB += m_mB * impulse * JvBD;
+ aB += m_iB * impulse * JwB;
+ cC -= m_mC * impulse * JvAC;
+ aC -= m_iC * impulse * JwC;
+ cD -= m_mD * impulse * JvBD;
+ aD -= m_iD * impulse * JwD;
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+ data.positions[m_indexC].c = cC;
+ data.positions[m_indexC].a = aC;
+ data.positions[m_indexD].c = cD;
+ data.positions[m_indexD].a = aD;
+
+ // TODO_ERIN not implemented
+ return linearError < b2_linearSlop;
+}
+
+b2Vec2 b2GearJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2GearJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2GearJoint::GetReactionForce(float32 inv_dt) const
+{
+ b2Vec2 P = m_impulse * m_JvAC;
+ return inv_dt * P;
+}
+
+float32 b2GearJoint::GetReactionTorque(float32 inv_dt) const
+{
+ float32 L = m_impulse * m_JwA;
+ return inv_dt * L;
+}
+
+void b2GearJoint::SetRatio(float32 ratio)
+{
+ b2Assert(b2IsValid(ratio));
+ m_ratio = ratio;
+}
+
+float32 b2GearJoint::GetRatio() const
+{
+ return m_ratio;
+}
+
+void b2GearJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ int32 index1 = m_joint1->m_index;
+ int32 index2 = m_joint2->m_index;
+
+ b2Log(" b2GearJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.joint1 = joints[%d];\n", index1);
+ b2Log(" jd.joint2 = joints[%d];\n", index2);
+ b2Log(" jd.ratio = %.15lef;\n", m_ratio);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2GearJoint.h b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2GearJoint.h
new file mode 100644
index 0000000..53f7e58
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2GearJoint.h
@@ -0,0 +1,125 @@
+/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.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 B2_GEAR_JOINT_H
+#define B2_GEAR_JOINT_H
+
+#include "Box2D/Dynamics/Joints/b2Joint.h"
+
+/// Gear joint definition. This definition requires two existing
+/// revolute or prismatic joints (any combination will work).
+struct b2GearJointDef : public b2JointDef
+{
+ b2GearJointDef()
+ {
+ type = e_gearJoint;
+ joint1 = nullptr;
+ joint2 = nullptr;
+ ratio = 1.0f;
+ }
+
+ /// The first revolute/prismatic joint attached to the gear joint.
+ b2Joint* joint1;
+
+ /// The second revolute/prismatic joint attached to the gear joint.
+ b2Joint* joint2;
+
+ /// The gear ratio.
+ /// @see b2GearJoint for explanation.
+ float32 ratio;
+};
+
+/// A gear joint is used to connect two joints together. Either joint
+/// can be a revolute or prismatic joint. You specify a gear ratio
+/// to bind the motions together:
+/// coordinate1 + ratio * coordinate2 = constant
+/// The ratio can be negative or positive. If one joint is a revolute joint
+/// and the other joint is a prismatic joint, then the ratio will have units
+/// of length or units of 1/length.
+/// @warning You have to manually destroy the gear joint if joint1 or joint2
+/// is destroyed.
+class b2GearJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const override;
+ b2Vec2 GetAnchorB() const override;
+
+ b2Vec2 GetReactionForce(float32 inv_dt) const override;
+ float32 GetReactionTorque(float32 inv_dt) const override;
+
+ /// Get the first joint.
+ b2Joint* GetJoint1() { return m_joint1; }
+
+ /// Get the second joint.
+ b2Joint* GetJoint2() { return m_joint2; }
+
+ /// Set/Get the gear ratio.
+ void SetRatio(float32 ratio);
+ float32 GetRatio() const;
+
+ /// Dump joint to dmLog
+ void Dump() override;
+
+protected:
+
+ friend class b2Joint;
+ b2GearJoint(const b2GearJointDef* data);
+
+ void InitVelocityConstraints(const b2SolverData& data) override;
+ void SolveVelocityConstraints(const b2SolverData& data) override;
+ bool SolvePositionConstraints(const b2SolverData& data) override;
+
+ b2Joint* m_joint1;
+ b2Joint* m_joint2;
+
+ b2JointType m_typeA;
+ b2JointType m_typeB;
+
+ // Body A is connected to body C
+ // Body B is connected to body D
+ b2Body* m_bodyC;
+ b2Body* m_bodyD;
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ b2Vec2 m_localAnchorC;
+ b2Vec2 m_localAnchorD;
+
+ b2Vec2 m_localAxisC;
+ b2Vec2 m_localAxisD;
+
+ float32 m_referenceAngleA;
+ float32 m_referenceAngleB;
+
+ float32 m_constant;
+ float32 m_ratio;
+
+ float32 m_impulse;
+
+ // Solver temp
+ int32 m_indexA, m_indexB, m_indexC, m_indexD;
+ b2Vec2 m_lcA, m_lcB, m_lcC, m_lcD;
+ float32 m_mA, m_mB, m_mC, m_mD;
+ float32 m_iA, m_iB, m_iC, m_iD;
+ b2Vec2 m_JvAC, m_JvBD;
+ float32 m_JwA, m_JwB, m_JwC, m_JwD;
+ float32 m_mass;
+};
+
+#endif
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2Joint.cpp b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2Joint.cpp
new file mode 100644
index 0000000..8103b01
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2Joint.cpp
@@ -0,0 +1,211 @@
+/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.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 "Box2D/Dynamics/Joints/b2Joint.h"
+#include "Box2D/Dynamics/Joints/b2DistanceJoint.h"
+#include "Box2D/Dynamics/Joints/b2WheelJoint.h"
+#include "Box2D/Dynamics/Joints/b2MouseJoint.h"
+#include "Box2D/Dynamics/Joints/b2RevoluteJoint.h"
+#include "Box2D/Dynamics/Joints/b2PrismaticJoint.h"
+#include "Box2D/Dynamics/Joints/b2PulleyJoint.h"
+#include "Box2D/Dynamics/Joints/b2GearJoint.h"
+#include "Box2D/Dynamics/Joints/b2WeldJoint.h"
+#include "Box2D/Dynamics/Joints/b2FrictionJoint.h"
+#include "Box2D/Dynamics/Joints/b2RopeJoint.h"
+#include "Box2D/Dynamics/Joints/b2MotorJoint.h"
+#include "Box2D/Dynamics/b2Body.h"
+#include "Box2D/Dynamics/b2World.h"
+#include "Box2D/Common/b2BlockAllocator.h"
+
+#include <new>
+
+b2Joint* b2Joint::Create(const b2JointDef* def, b2BlockAllocator* allocator)
+{
+ b2Joint* joint = nullptr;
+
+ switch (def->type)
+ {
+ case e_distanceJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2DistanceJoint));
+ joint = new (mem) b2DistanceJoint(static_cast<const b2DistanceJointDef*>(def));
+ }
+ break;
+
+ case e_mouseJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2MouseJoint));
+ joint = new (mem) b2MouseJoint(static_cast<const b2MouseJointDef*>(def));
+ }
+ break;
+
+ case e_prismaticJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2PrismaticJoint));
+ joint = new (mem) b2PrismaticJoint(static_cast<const b2PrismaticJointDef*>(def));
+ }
+ break;
+
+ case e_revoluteJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2RevoluteJoint));
+ joint = new (mem) b2RevoluteJoint(static_cast<const b2RevoluteJointDef*>(def));
+ }
+ break;
+
+ case e_pulleyJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2PulleyJoint));
+ joint = new (mem) b2PulleyJoint(static_cast<const b2PulleyJointDef*>(def));
+ }
+ break;
+
+ case e_gearJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2GearJoint));
+ joint = new (mem) b2GearJoint(static_cast<const b2GearJointDef*>(def));
+ }
+ break;
+
+ case e_wheelJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2WheelJoint));
+ joint = new (mem) b2WheelJoint(static_cast<const b2WheelJointDef*>(def));
+ }
+ break;
+
+ case e_weldJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2WeldJoint));
+ joint = new (mem) b2WeldJoint(static_cast<const b2WeldJointDef*>(def));
+ }
+ break;
+
+ case e_frictionJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2FrictionJoint));
+ joint = new (mem) b2FrictionJoint(static_cast<const b2FrictionJointDef*>(def));
+ }
+ break;
+
+ case e_ropeJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2RopeJoint));
+ joint = new (mem) b2RopeJoint(static_cast<const b2RopeJointDef*>(def));
+ }
+ break;
+
+ case e_motorJoint:
+ {
+ void* mem = allocator->Allocate(sizeof(b2MotorJoint));
+ joint = new (mem) b2MotorJoint(static_cast<const b2MotorJointDef*>(def));
+ }
+ break;
+
+ default:
+ b2Assert(false);
+ break;
+ }
+
+ return joint;
+}
+
+void b2Joint::Destroy(b2Joint* joint, b2BlockAllocator* allocator)
+{
+ joint->~b2Joint();
+ switch (joint->m_type)
+ {
+ case e_distanceJoint:
+ allocator->Free(joint, sizeof(b2DistanceJoint));
+ break;
+
+ case e_mouseJoint:
+ allocator->Free(joint, sizeof(b2MouseJoint));
+ break;
+
+ case e_prismaticJoint:
+ allocator->Free(joint, sizeof(b2PrismaticJoint));
+ break;
+
+ case e_revoluteJoint:
+ allocator->Free(joint, sizeof(b2RevoluteJoint));
+ break;
+
+ case e_pulleyJoint:
+ allocator->Free(joint, sizeof(b2PulleyJoint));
+ break;
+
+ case e_gearJoint:
+ allocator->Free(joint, sizeof(b2GearJoint));
+ break;
+
+ case e_wheelJoint:
+ allocator->Free(joint, sizeof(b2WheelJoint));
+ break;
+
+ case e_weldJoint:
+ allocator->Free(joint, sizeof(b2WeldJoint));
+ break;
+
+ case e_frictionJoint:
+ allocator->Free(joint, sizeof(b2FrictionJoint));
+ break;
+
+ case e_ropeJoint:
+ allocator->Free(joint, sizeof(b2RopeJoint));
+ break;
+
+ case e_motorJoint:
+ allocator->Free(joint, sizeof(b2MotorJoint));
+ break;
+
+ default:
+ b2Assert(false);
+ break;
+ }
+}
+
+b2Joint::b2Joint(const b2JointDef* def)
+{
+ b2Assert(def->bodyA != def->bodyB);
+
+ m_type = def->type;
+ m_prev = nullptr;
+ m_next = nullptr;
+ m_bodyA = def->bodyA;
+ m_bodyB = def->bodyB;
+ m_index = 0;
+ m_collideConnected = def->collideConnected;
+ m_islandFlag = false;
+ m_userData = def->userData;
+
+ m_edgeA.joint = nullptr;
+ m_edgeA.other = nullptr;
+ m_edgeA.prev = nullptr;
+ m_edgeA.next = nullptr;
+
+ m_edgeB.joint = nullptr;
+ m_edgeB.other = nullptr;
+ m_edgeB.prev = nullptr;
+ m_edgeB.next = nullptr;
+}
+
+bool b2Joint::IsActive() const
+{
+ return m_bodyA->IsActive() && m_bodyB->IsActive();
+}
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2Joint.h b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2Joint.h
new file mode 100644
index 0000000..2ab5616
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2Joint.h
@@ -0,0 +1,226 @@
+/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.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 B2_JOINT_H
+#define B2_JOINT_H
+
+#include "Box2D/Common/b2Math.h"
+
+class b2Body;
+class b2Joint;
+struct b2SolverData;
+class b2BlockAllocator;
+
+enum b2JointType
+{
+ e_unknownJoint,
+ e_revoluteJoint,
+ e_prismaticJoint,
+ e_distanceJoint,
+ e_pulleyJoint,
+ e_mouseJoint,
+ e_gearJoint,
+ e_wheelJoint,
+ e_weldJoint,
+ e_frictionJoint,
+ e_ropeJoint,
+ e_motorJoint
+};
+
+enum b2LimitState
+{
+ e_inactiveLimit,
+ e_atLowerLimit,
+ e_atUpperLimit,
+ e_equalLimits
+};
+
+struct b2Jacobian
+{
+ b2Vec2 linear;
+ float32 angularA;
+ float32 angularB;
+};
+
+/// A joint edge is used to connect bodies and joints together
+/// in a joint graph where each body is a node and each joint
+/// is an edge. A joint edge belongs to a doubly linked list
+/// maintained in each attached body. Each joint has two joint
+/// nodes, one for each attached body.
+struct b2JointEdge
+{
+ b2Body* other; ///< provides quick access to the other body attached.
+ b2Joint* joint; ///< the joint
+ b2JointEdge* prev; ///< the previous joint edge in the body's joint list
+ b2JointEdge* next; ///< the next joint edge in the body's joint list
+};
+
+/// Joint definitions are used to construct joints.
+struct b2JointDef
+{
+ b2JointDef()
+ {
+ type = e_unknownJoint;
+ userData = nullptr;
+ bodyA = nullptr;
+ bodyB = nullptr;
+ collideConnected = false;
+ }
+
+ /// The joint type is set automatically for concrete joint types.
+ b2JointType type;
+
+ /// Use this to attach application specific data to your joints.
+ void* userData;
+
+ /// The first attached body.
+ b2Body* bodyA;
+
+ /// The second attached body.
+ b2Body* bodyB;
+
+ /// Set this flag to true if the attached bodies should collide.
+ bool collideConnected;
+};
+
+/// The base joint class. Joints are used to constraint two bodies together in
+/// various fashions. Some joints also feature limits and motors.
+class b2Joint
+{
+public:
+
+ /// Get the type of the concrete joint.
+ b2JointType GetType() const;
+
+ /// Get the first body attached to this joint.
+ b2Body* GetBodyA();
+
+ /// Get the second body attached to this joint.
+ b2Body* GetBodyB();
+
+ /// Get the anchor point on bodyA in world coordinates.
+ virtual b2Vec2 GetAnchorA() const = 0;
+
+ /// Get the anchor point on bodyB in world coordinates.
+ virtual b2Vec2 GetAnchorB() const = 0;
+
+ /// Get the reaction force on bodyB at the joint anchor in Newtons.
+ virtual b2Vec2 GetReactionForce(float32 inv_dt) const = 0;
+
+ /// Get the reaction torque on bodyB in N*m.
+ virtual float32 GetReactionTorque(float32 inv_dt) const = 0;
+
+ /// Get the next joint the world joint list.
+ b2Joint* GetNext();
+ const b2Joint* GetNext() const;
+
+ /// Get the user data pointer.
+ void* GetUserData() const;
+
+ /// Set the user data pointer.
+ void SetUserData(void* data);
+
+ /// Short-cut function to determine if either body is inactive.
+ bool IsActive() const;
+
+ /// Get collide connected.
+ /// Note: modifying the collide connect flag won't work correctly because
+ /// the flag is only checked when fixture AABBs begin to overlap.
+ bool GetCollideConnected() const;
+
+ /// Dump this joint to the log file.
+ virtual void Dump() { b2Log("// Dump is not supported for this joint type.\n"); }
+
+ /// Shift the origin for any points stored in world coordinates.
+ virtual void ShiftOrigin(const b2Vec2& newOrigin) { B2_NOT_USED(newOrigin); }
+
+protected:
+ friend class b2World;
+ friend class b2Body;
+ friend class b2Island;
+ friend class b2GearJoint;
+
+ static b2Joint* Create(const b2JointDef* def, b2BlockAllocator* allocator);
+ static void Destroy(b2Joint* joint, b2BlockAllocator* allocator);
+
+ b2Joint(const b2JointDef* def);
+ virtual ~b2Joint() {}
+
+ virtual void InitVelocityConstraints(const b2SolverData& data) = 0;
+ virtual void SolveVelocityConstraints(const b2SolverData& data) = 0;
+
+ // This returns true if the position errors are within tolerance.
+ virtual bool SolvePositionConstraints(const b2SolverData& data) = 0;
+
+ b2JointType m_type;
+ b2Joint* m_prev;
+ b2Joint* m_next;
+ b2JointEdge m_edgeA;
+ b2JointEdge m_edgeB;
+ b2Body* m_bodyA;
+ b2Body* m_bodyB;
+
+ int32 m_index;
+
+ bool m_islandFlag;
+ bool m_collideConnected;
+
+ void* m_userData;
+};
+
+inline b2JointType b2Joint::GetType() const
+{
+ return m_type;
+}
+
+inline b2Body* b2Joint::GetBodyA()
+{
+ return m_bodyA;
+}
+
+inline b2Body* b2Joint::GetBodyB()
+{
+ return m_bodyB;
+}
+
+inline b2Joint* b2Joint::GetNext()
+{
+ return m_next;
+}
+
+inline const b2Joint* b2Joint::GetNext() const
+{
+ return m_next;
+}
+
+inline void* b2Joint::GetUserData() const
+{
+ return m_userData;
+}
+
+inline void b2Joint::SetUserData(void* data)
+{
+ m_userData = data;
+}
+
+inline bool b2Joint::GetCollideConnected() const
+{
+ return m_collideConnected;
+}
+
+#endif
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MotorJoint.cpp b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MotorJoint.cpp
new file mode 100644
index 0000000..7906845
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MotorJoint.cpp
@@ -0,0 +1,309 @@
+/*
+* Copyright (c) 2006-2012 Erin Catto http://www.box2d.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 "Box2D/Dynamics/Joints/b2MotorJoint.h"
+#include "Box2D/Dynamics/b2Body.h"
+#include "Box2D/Dynamics/b2TimeStep.h"
+
+// Point-to-point constraint
+// Cdot = v2 - v1
+// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
+// J = [-I -r1_skew I r2_skew ]
+// Identity used:
+// w k % (rx i + ry j) = w * (-ry i + rx j)
+//
+// r1 = offset - c1
+// r2 = -c2
+
+// Angle constraint
+// Cdot = w2 - w1
+// J = [0 0 -1 0 0 1]
+// K = invI1 + invI2
+
+void b2MotorJointDef::Initialize(b2Body* bA, b2Body* bB)
+{
+ bodyA = bA;
+ bodyB = bB;
+ b2Vec2 xB = bodyB->GetPosition();
+ linearOffset = bodyA->GetLocalPoint(xB);
+
+ float32 angleA = bodyA->GetAngle();
+ float32 angleB = bodyB->GetAngle();
+ angularOffset = angleB - angleA;
+}
+
+b2MotorJoint::b2MotorJoint(const b2MotorJointDef* def)
+: b2Joint(def)
+{
+ m_linearOffset = def->linearOffset;
+ m_angularOffset = def->angularOffset;
+
+ m_linearImpulse.SetZero();
+ m_angularImpulse = 0.0f;
+
+ m_maxForce = def->maxForce;
+ m_maxTorque = def->maxTorque;
+ m_correctionFactor = def->correctionFactor;
+}
+
+void b2MotorJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ // Compute the effective mass matrix.
+ m_rA = b2Mul(qA, m_linearOffset - m_localCenterA);
+ m_rB = b2Mul(qB, -m_localCenterB);
+
+ // J = [-I -r1_skew I r2_skew]
+ // r_skew = [-ry; rx]
+
+ // Matlab
+ // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
+ // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
+ // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
+
+
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ // Upper 2 by 2 of K for point to point
+ b2Mat22 K;
+ K.ex.x = mA + mB + iA * m_rA.y * m_rA.y + iB * m_rB.y * m_rB.y;
+ K.ex.y = -iA * m_rA.x * m_rA.y - iB * m_rB.x * m_rB.y;
+ K.ey.x = K.ex.y;
+ K.ey.y = mA + mB + iA * m_rA.x * m_rA.x + iB * m_rB.x * m_rB.x;
+
+ m_linearMass = K.GetInverse();
+
+ m_angularMass = iA + iB;
+ if (m_angularMass > 0.0f)
+ {
+ m_angularMass = 1.0f / m_angularMass;
+ }
+
+ m_linearError = cB + m_rB - cA - m_rA;
+ m_angularError = aB - aA - m_angularOffset;
+
+ if (data.step.warmStarting)
+ {
+ // Scale impulses to support a variable time step.
+ m_linearImpulse *= data.step.dtRatio;
+ m_angularImpulse *= data.step.dtRatio;
+
+ b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y);
+ vA -= mA * P;
+ wA -= iA * (b2Cross(m_rA, P) + m_angularImpulse);
+ vB += mB * P;
+ wB += iB * (b2Cross(m_rB, P) + m_angularImpulse);
+ }
+ else
+ {
+ m_linearImpulse.SetZero();
+ m_angularImpulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2MotorJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ float32 h = data.step.dt;
+ float32 inv_h = data.step.inv_dt;
+
+ // Solve angular friction
+ {
+ float32 Cdot = wB - wA + inv_h * m_correctionFactor * m_angularError;
+ float32 impulse = -m_angularMass * Cdot;
+
+ float32 oldImpulse = m_angularImpulse;
+ float32 maxImpulse = h * m_maxTorque;
+ m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse);
+ impulse = m_angularImpulse - oldImpulse;
+
+ wA -= iA * impulse;
+ wB += iB * impulse;
+ }
+
+ // Solve linear friction
+ {
+ b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA) + inv_h * m_correctionFactor * m_linearError;
+
+ b2Vec2 impulse = -b2Mul(m_linearMass, Cdot);
+ b2Vec2 oldImpulse = m_linearImpulse;
+ m_linearImpulse += impulse;
+
+ float32 maxImpulse = h * m_maxForce;
+
+ if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse)
+ {
+ m_linearImpulse.Normalize();
+ m_linearImpulse *= maxImpulse;
+ }
+
+ impulse = m_linearImpulse - oldImpulse;
+
+ vA -= mA * impulse;
+ wA -= iA * b2Cross(m_rA, impulse);
+
+ vB += mB * impulse;
+ wB += iB * b2Cross(m_rB, impulse);
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2MotorJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ B2_NOT_USED(data);
+
+ return true;
+}
+
+b2Vec2 b2MotorJoint::GetAnchorA() const
+{
+ return m_bodyA->GetPosition();
+}
+
+b2Vec2 b2MotorJoint::GetAnchorB() const
+{
+ return m_bodyB->GetPosition();
+}
+
+b2Vec2 b2MotorJoint::GetReactionForce(float32 inv_dt) const
+{
+ return inv_dt * m_linearImpulse;
+}
+
+float32 b2MotorJoint::GetReactionTorque(float32 inv_dt) const
+{
+ return inv_dt * m_angularImpulse;
+}
+
+void b2MotorJoint::SetMaxForce(float32 force)
+{
+ b2Assert(b2IsValid(force) && force >= 0.0f);
+ m_maxForce = force;
+}
+
+float32 b2MotorJoint::GetMaxForce() const
+{
+ return m_maxForce;
+}
+
+void b2MotorJoint::SetMaxTorque(float32 torque)
+{
+ b2Assert(b2IsValid(torque) && torque >= 0.0f);
+ m_maxTorque = torque;
+}
+
+float32 b2MotorJoint::GetMaxTorque() const
+{
+ return m_maxTorque;
+}
+
+void b2MotorJoint::SetCorrectionFactor(float32 factor)
+{
+ b2Assert(b2IsValid(factor) && 0.0f <= factor && factor <= 1.0f);
+ m_correctionFactor = factor;
+}
+
+float32 b2MotorJoint::GetCorrectionFactor() const
+{
+ return m_correctionFactor;
+}
+
+void b2MotorJoint::SetLinearOffset(const b2Vec2& linearOffset)
+{
+ if (linearOffset.x != m_linearOffset.x || linearOffset.y != m_linearOffset.y)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_linearOffset = linearOffset;
+ }
+}
+
+const b2Vec2& b2MotorJoint::GetLinearOffset() const
+{
+ return m_linearOffset;
+}
+
+void b2MotorJoint::SetAngularOffset(float32 angularOffset)
+{
+ if (angularOffset != m_angularOffset)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_angularOffset = angularOffset;
+ }
+}
+
+float32 b2MotorJoint::GetAngularOffset() const
+{
+ return m_angularOffset;
+}
+
+void b2MotorJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2MotorJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.linearOffset.Set(%.15lef, %.15lef);\n", m_linearOffset.x, m_linearOffset.y);
+ b2Log(" jd.angularOffset = %.15lef;\n", m_angularOffset);
+ b2Log(" jd.maxForce = %.15lef;\n", m_maxForce);
+ b2Log(" jd.maxTorque = %.15lef;\n", m_maxTorque);
+ b2Log(" jd.correctionFactor = %.15lef;\n", m_correctionFactor);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MotorJoint.h b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MotorJoint.h
new file mode 100644
index 0000000..f384f41
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MotorJoint.h
@@ -0,0 +1,133 @@
+/*
+* Copyright (c) 2006-2012 Erin Catto http://www.box2d.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 B2_MOTOR_JOINT_H
+#define B2_MOTOR_JOINT_H
+
+#include "Box2D/Dynamics/Joints/b2Joint.h"
+
+/// Motor joint definition.
+struct b2MotorJointDef : public b2JointDef
+{
+ b2MotorJointDef()
+ {
+ type = e_motorJoint;
+ linearOffset.SetZero();
+ angularOffset = 0.0f;
+ maxForce = 1.0f;
+ maxTorque = 1.0f;
+ correctionFactor = 0.3f;
+ }
+
+ /// Initialize the bodies and offsets using the current transforms.
+ void Initialize(b2Body* bodyA, b2Body* bodyB);
+
+ /// Position of bodyB minus the position of bodyA, in bodyA's frame, in meters.
+ b2Vec2 linearOffset;
+
+ /// The bodyB angle minus bodyA angle in radians.
+ float32 angularOffset;
+
+ /// The maximum motor force in N.
+ float32 maxForce;
+
+ /// The maximum motor torque in N-m.
+ float32 maxTorque;
+
+ /// Position correction factor in the range [0,1].
+ float32 correctionFactor;
+};
+
+/// A motor joint is used to control the relative motion
+/// between two bodies. A typical usage is to control the movement
+/// of a dynamic body with respect to the ground.
+class b2MotorJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const override;
+ b2Vec2 GetAnchorB() const override;
+
+ b2Vec2 GetReactionForce(float32 inv_dt) const override;
+ float32 GetReactionTorque(float32 inv_dt) const override;
+
+ /// Set/get the target linear offset, in frame A, in meters.
+ void SetLinearOffset(const b2Vec2& linearOffset);
+ const b2Vec2& GetLinearOffset() const;
+
+ /// Set/get the target angular offset, in radians.
+ void SetAngularOffset(float32 angularOffset);
+ float32 GetAngularOffset() const;
+
+ /// Set the maximum friction force in N.
+ void SetMaxForce(float32 force);
+
+ /// Get the maximum friction force in N.
+ float32 GetMaxForce() const;
+
+ /// Set the maximum friction torque in N*m.
+ void SetMaxTorque(float32 torque);
+
+ /// Get the maximum friction torque in N*m.
+ float32 GetMaxTorque() const;
+
+ /// Set the position correction factor in the range [0,1].
+ void SetCorrectionFactor(float32 factor);
+
+ /// Get the position correction factor in the range [0,1].
+ float32 GetCorrectionFactor() const;
+
+ /// Dump to b2Log
+ void Dump() override;
+
+protected:
+
+ friend class b2Joint;
+
+ b2MotorJoint(const b2MotorJointDef* def);
+
+ void InitVelocityConstraints(const b2SolverData& data) override;
+ void SolveVelocityConstraints(const b2SolverData& data) override;
+ bool SolvePositionConstraints(const b2SolverData& data) override;
+
+ // Solver shared
+ b2Vec2 m_linearOffset;
+ float32 m_angularOffset;
+ b2Vec2 m_linearImpulse;
+ float32 m_angularImpulse;
+ float32 m_maxForce;
+ float32 m_maxTorque;
+ float32 m_correctionFactor;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_rA;
+ b2Vec2 m_rB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ b2Vec2 m_linearError;
+ float32 m_angularError;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+ b2Mat22 m_linearMass;
+ float32 m_angularMass;
+};
+
+#endif
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MouseJoint.cpp b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MouseJoint.cpp
new file mode 100644
index 0000000..637e4cd
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MouseJoint.cpp
@@ -0,0 +1,222 @@
+/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.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 "Box2D/Dynamics/Joints/b2MouseJoint.h"
+#include "Box2D/Dynamics/b2Body.h"
+#include "Box2D/Dynamics/b2TimeStep.h"
+
+// p = attached point, m = mouse point
+// C = p - m
+// Cdot = v
+// = v + cross(w, r)
+// J = [I r_skew]
+// Identity used:
+// w k % (rx i + ry j) = w * (-ry i + rx j)
+
+b2MouseJoint::b2MouseJoint(const b2MouseJointDef* def)
+: b2Joint(def)
+{
+ b2Assert(def->target.IsValid());
+ b2Assert(b2IsValid(def->maxForce) && def->maxForce >= 0.0f);
+ b2Assert(b2IsValid(def->frequencyHz) && def->frequencyHz >= 0.0f);
+ b2Assert(b2IsValid(def->dampingRatio) && def->dampingRatio >= 0.0f);
+
+ m_targetA = def->target;
+ m_localAnchorB = b2MulT(m_bodyB->GetTransform(), m_targetA);
+
+ m_maxForce = def->maxForce;
+ m_impulse.SetZero();
+
+ m_frequencyHz = def->frequencyHz;
+ m_dampingRatio = def->dampingRatio;
+
+ m_beta = 0.0f;
+ m_gamma = 0.0f;
+}
+
+void b2MouseJoint::SetTarget(const b2Vec2& target)
+{
+ if (target != m_targetA)
+ {
+ m_bodyB->SetAwake(true);
+ m_targetA = target;
+ }
+}
+
+const b2Vec2& b2MouseJoint::GetTarget() const
+{
+ return m_targetA;
+}
+
+void b2MouseJoint::SetMaxForce(float32 force)
+{
+ m_maxForce = force;
+}
+
+float32 b2MouseJoint::GetMaxForce() const
+{
+ return m_maxForce;
+}
+
+void b2MouseJoint::SetFrequency(float32 hz)
+{
+ m_frequencyHz = hz;
+}
+
+float32 b2MouseJoint::GetFrequency() const
+{
+ return m_frequencyHz;
+}
+
+void b2MouseJoint::SetDampingRatio(float32 ratio)
+{
+ m_dampingRatio = ratio;
+}
+
+float32 b2MouseJoint::GetDampingRatio() const
+{
+ return m_dampingRatio;
+}
+
+void b2MouseJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIB = m_bodyB->m_invI;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qB(aB);
+
+ float32 mass = m_bodyB->GetMass();
+
+ // Frequency
+ float32 omega = 2.0f * b2_pi * m_frequencyHz;
+
+ // Damping coefficient
+ float32 d = 2.0f * mass * m_dampingRatio * omega;
+
+ // Spring stiffness
+ float32 k = mass * (omega * omega);
+
+ // magic formulas
+ // gamma has units of inverse mass.
+ // beta has units of inverse time.
+ float32 h = data.step.dt;
+ b2Assert(d + h * k > b2_epsilon);
+ m_gamma = h * (d + h * k);
+ if (m_gamma != 0.0f)
+ {
+ m_gamma = 1.0f / m_gamma;
+ }
+ m_beta = h * k * m_gamma;
+
+ // Compute the effective mass matrix.
+ m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)]
+ // = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y]
+ // [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x]
+ b2Mat22 K;
+ K.ex.x = m_invMassB + m_invIB * m_rB.y * m_rB.y + m_gamma;
+ K.ex.y = -m_invIB * m_rB.x * m_rB.y;
+ K.ey.x = K.ex.y;
+ K.ey.y = m_invMassB + m_invIB * m_rB.x * m_rB.x + m_gamma;
+
+ m_mass = K.GetInverse();
+
+ m_C = cB + m_rB - m_targetA;
+ m_C *= m_beta;
+
+ // Cheat with some damping
+ wB *= 0.98f;
+
+ if (data.step.warmStarting)
+ {
+ m_impulse *= data.step.dtRatio;
+ vB += m_invMassB * m_impulse;
+ wB += m_invIB * b2Cross(m_rB, m_impulse);
+ }
+ else
+ {
+ m_impulse.SetZero();
+ }
+
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2MouseJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ // Cdot = v + cross(w, r)
+ b2Vec2 Cdot = vB + b2Cross(wB, m_rB);
+ b2Vec2 impulse = b2Mul(m_mass, -(Cdot + m_C + m_gamma * m_impulse));
+
+ b2Vec2 oldImpulse = m_impulse;
+ m_impulse += impulse;
+ float32 maxImpulse = data.step.dt * m_maxForce;
+ if (m_impulse.LengthSquared() > maxImpulse * maxImpulse)
+ {
+ m_impulse *= maxImpulse / m_impulse.Length();
+ }
+ impulse = m_impulse - oldImpulse;
+
+ vB += m_invMassB * impulse;
+ wB += m_invIB * b2Cross(m_rB, impulse);
+
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2MouseJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ B2_NOT_USED(data);
+ return true;
+}
+
+b2Vec2 b2MouseJoint::GetAnchorA() const
+{
+ return m_targetA;
+}
+
+b2Vec2 b2MouseJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2MouseJoint::GetReactionForce(float32 inv_dt) const
+{
+ return inv_dt * m_impulse;
+}
+
+float32 b2MouseJoint::GetReactionTorque(float32 inv_dt) const
+{
+ return inv_dt * 0.0f;
+}
+
+void b2MouseJoint::ShiftOrigin(const b2Vec2& newOrigin)
+{
+ m_targetA -= newOrigin;
+}
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MouseJoint.h b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MouseJoint.h
new file mode 100644
index 0000000..7441978
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2MouseJoint.h
@@ -0,0 +1,129 @@
+/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.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 B2_MOUSE_JOINT_H
+#define B2_MOUSE_JOINT_H
+
+#include "Box2D/Dynamics/Joints/b2Joint.h"
+
+/// Mouse joint definition. This requires a world target point,
+/// tuning parameters, and the time step.
+struct b2MouseJointDef : public b2JointDef
+{
+ b2MouseJointDef()
+ {
+ type = e_mouseJoint;
+ target.Set(0.0f, 0.0f);
+ maxForce = 0.0f;
+ frequencyHz = 5.0f;
+ dampingRatio = 0.7f;
+ }
+
+ /// The initial world target point. This is assumed
+ /// to coincide with the body anchor initially.
+ b2Vec2 target;
+
+ /// The maximum constraint force that can be exerted
+ /// to move the candidate body. Usually you will express
+ /// as some multiple of the weight (multiplier * mass * gravity).
+ float32 maxForce;
+
+ /// The response speed.
+ float32 frequencyHz;
+
+ /// The damping ratio. 0 = no damping, 1 = critical damping.
+ float32 dampingRatio;
+};
+
+/// A mouse joint is used to make a point on a body track a
+/// specified world point. This a soft constraint with a maximum
+/// force. This allows the constraint to stretch and without
+/// applying huge forces.
+/// NOTE: this joint is not documented in the manual because it was
+/// developed to be used in the testbed. If you want to learn how to
+/// use the mouse joint, look at the testbed.
+class b2MouseJoint : public b2Joint
+{
+public:
+
+ /// Implements b2Joint.
+ b2Vec2 GetAnchorA() const override;
+
+ /// Implements b2Joint.
+ b2Vec2 GetAnchorB() const override;
+
+ /// Implements b2Joint.
+ b2Vec2 GetReactionForce(float32 inv_dt) const override;
+
+ /// Implements b2Joint.
+ float32 GetReactionTorque(float32 inv_dt) const override;
+
+ /// Use this to update the target point.
+ void SetTarget(const b2Vec2& target);
+ const b2Vec2& GetTarget() const;
+
+ /// Set/get the maximum force in Newtons.
+ void SetMaxForce(float32 force);
+ float32 GetMaxForce() const;
+
+ /// Set/get the frequency in Hertz.
+ void SetFrequency(float32 hz);
+ float32 GetFrequency() const;
+
+ /// Set/get the damping ratio (dimensionless).
+ void SetDampingRatio(float32 ratio);
+ float32 GetDampingRatio() const;
+
+ /// The mouse joint does not support dumping.
+ void Dump() override { b2Log("Mouse joint dumping is not supported.\n"); }
+
+ /// Implement b2Joint::ShiftOrigin
+ void ShiftOrigin(const b2Vec2& newOrigin) override;
+
+protected:
+ friend class b2Joint;
+
+ b2MouseJoint(const b2MouseJointDef* def);
+
+ void InitVelocityConstraints(const b2SolverData& data) override;
+ void SolveVelocityConstraints(const b2SolverData& data) override;
+ bool SolvePositionConstraints(const b2SolverData& data) override;
+
+ b2Vec2 m_localAnchorB;
+ b2Vec2 m_targetA;
+ float32 m_frequencyHz;
+ float32 m_dampingRatio;
+ float32 m_beta;
+
+ // Solver shared
+ b2Vec2 m_impulse;
+ float32 m_maxForce;
+ float32 m_gamma;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_rB;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassB;
+ float32 m_invIB;
+ b2Mat22 m_mass;
+ b2Vec2 m_C;
+};
+
+#endif
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp
new file mode 100644
index 0000000..5da19b6
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp
@@ -0,0 +1,642 @@
+/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.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 "Box2D/Dynamics/Joints/b2PrismaticJoint.h"
+#include "Box2D/Dynamics/b2Body.h"
+#include "Box2D/Dynamics/b2TimeStep.h"
+
+// Linear constraint (point-to-line)
+// d = p2 - p1 = x2 + r2 - x1 - r1
+// C = dot(perp, d)
+// Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1))
+// = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2)
+// J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)]
+//
+// Angular constraint
+// C = a2 - a1 + a_initial
+// Cdot = w2 - w1
+// J = [0 0 -1 0 0 1]
+//
+// K = J * invM * JT
+//
+// J = [-a -s1 a s2]
+// [0 -1 0 1]
+// a = perp
+// s1 = cross(d + r1, a) = cross(p2 - x1, a)
+// s2 = cross(r2, a) = cross(p2 - x2, a)
+
+
+// Motor/Limit linear constraint
+// C = dot(ax1, d)
+// Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2)
+// J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)]
+
+// Block Solver
+// We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even
+// when the mass has poor distribution (leading to large torques about the joint anchor points).
+//
+// The Jacobian has 3 rows:
+// J = [-uT -s1 uT s2] // linear
+// [0 -1 0 1] // angular
+// [-vT -a1 vT a2] // limit
+//
+// u = perp
+// v = axis
+// s1 = cross(d + r1, u), s2 = cross(r2, u)
+// a1 = cross(d + r1, v), a2 = cross(r2, v)
+
+// M * (v2 - v1) = JT * df
+// J * v2 = bias
+//
+// v2 = v1 + invM * JT * df
+// J * (v1 + invM * JT * df) = bias
+// K * df = bias - J * v1 = -Cdot
+// K = J * invM * JT
+// Cdot = J * v1 - bias
+//
+// Now solve for f2.
+// df = f2 - f1
+// K * (f2 - f1) = -Cdot
+// f2 = invK * (-Cdot) + f1
+//
+// Clamp accumulated limit impulse.
+// lower: f2(3) = max(f2(3), 0)
+// upper: f2(3) = min(f2(3), 0)
+//
+// Solve for correct f2(1:2)
+// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1
+// = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3)
+// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2)
+// f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
+//
+// Now compute impulse to be applied:
+// df = f2 - f1
+
+void b2PrismaticJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis)
+{
+ bodyA = bA;
+ bodyB = bB;
+ localAnchorA = bodyA->GetLocalPoint(anchor);
+ localAnchorB = bodyB->GetLocalPoint(anchor);
+ localAxisA = bodyA->GetLocalVector(axis);
+ referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
+}
+
+b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def)
+: b2Joint(def)
+{
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+ m_localXAxisA = def->localAxisA;
+ m_localXAxisA.Normalize();
+ m_localYAxisA = b2Cross(1.0f, m_localXAxisA);
+ m_referenceAngle = def->referenceAngle;
+
+ m_impulse.SetZero();
+ m_motorMass = 0.0f;
+ m_motorImpulse = 0.0f;
+
+ m_lowerTranslation = def->lowerTranslation;
+ m_upperTranslation = def->upperTranslation;
+ m_maxMotorForce = def->maxMotorForce;
+ m_motorSpeed = def->motorSpeed;
+ m_enableLimit = def->enableLimit;
+ m_enableMotor = def->enableMotor;
+ m_limitState = e_inactiveLimit;
+
+ m_axis.SetZero();
+ m_perp.SetZero();
+}
+
+void b2PrismaticJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ // Compute the effective masses.
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ b2Vec2 d = (cB - cA) + rB - rA;
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ // Compute motor Jacobian and effective mass.
+ {
+ m_axis = b2Mul(qA, m_localXAxisA);
+ m_a1 = b2Cross(d + rA, m_axis);
+ m_a2 = b2Cross(rB, m_axis);
+
+ m_motorMass = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2;
+ if (m_motorMass > 0.0f)
+ {
+ m_motorMass = 1.0f / m_motorMass;
+ }
+ }
+
+ // Prismatic constraint.
+ {
+ m_perp = b2Mul(qA, m_localYAxisA);
+
+ m_s1 = b2Cross(d + rA, m_perp);
+ m_s2 = b2Cross(rB, m_perp);
+
+ float32 k11 = mA + mB + iA * m_s1 * m_s1 + iB * m_s2 * m_s2;
+ float32 k12 = iA * m_s1 + iB * m_s2;
+ float32 k13 = iA * m_s1 * m_a1 + iB * m_s2 * m_a2;
+ float32 k22 = iA + iB;
+ if (k22 == 0.0f)
+ {
+ // For bodies with fixed rotation.
+ k22 = 1.0f;
+ }
+ float32 k23 = iA * m_a1 + iB * m_a2;
+ float32 k33 = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2;
+
+ m_K.ex.Set(k11, k12, k13);
+ m_K.ey.Set(k12, k22, k23);
+ m_K.ez.Set(k13, k23, k33);
+ }
+
+ // Compute motor and limit terms.
+ if (m_enableLimit)
+ {
+ float32 jointTranslation = b2Dot(m_axis, d);
+ if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)
+ {
+ m_limitState = e_equalLimits;
+ }
+ else if (jointTranslation <= m_lowerTranslation)
+ {
+ if (m_limitState != e_atLowerLimit)
+ {
+ m_limitState = e_atLowerLimit;
+ m_impulse.z = 0.0f;
+ }
+ }
+ else if (jointTranslation >= m_upperTranslation)
+ {
+ if (m_limitState != e_atUpperLimit)
+ {
+ m_limitState = e_atUpperLimit;
+ m_impulse.z = 0.0f;
+ }
+ }
+ else
+ {
+ m_limitState = e_inactiveLimit;
+ m_impulse.z = 0.0f;
+ }
+ }
+ else
+ {
+ m_limitState = e_inactiveLimit;
+ m_impulse.z = 0.0f;
+ }
+
+ if (m_enableMotor == false)
+ {
+ m_motorImpulse = 0.0f;
+ }
+
+ if (data.step.warmStarting)
+ {
+ // Account for variable time step.
+ m_impulse *= data.step.dtRatio;
+ m_motorImpulse *= data.step.dtRatio;
+
+ b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis;
+ float32 LA = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1;
+ float32 LB = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2;
+
+ vA -= mA * P;
+ wA -= iA * LA;
+
+ vB += mB * P;
+ wB += iB * LB;
+ }
+ else
+ {
+ m_impulse.SetZero();
+ m_motorImpulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2PrismaticJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ // Solve linear motor constraint.
+ if (m_enableMotor && m_limitState != e_equalLimits)
+ {
+ float32 Cdot = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA;
+ float32 impulse = m_motorMass * (m_motorSpeed - Cdot);
+ float32 oldImpulse = m_motorImpulse;
+ float32 maxImpulse = data.step.dt * m_maxMotorForce;
+ m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
+ impulse = m_motorImpulse - oldImpulse;
+
+ b2Vec2 P = impulse * m_axis;
+ float32 LA = impulse * m_a1;
+ float32 LB = impulse * m_a2;
+
+ vA -= mA * P;
+ wA -= iA * LA;
+
+ vB += mB * P;
+ wB += iB * LB;
+ }
+
+ b2Vec2 Cdot1;
+ Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA;
+ Cdot1.y = wB - wA;
+
+ if (m_enableLimit && m_limitState != e_inactiveLimit)
+ {
+ // Solve prismatic and limit constraint in block form.
+ float32 Cdot2;
+ Cdot2 = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA;
+ b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
+
+ b2Vec3 f1 = m_impulse;
+ b2Vec3 df = m_K.Solve33(-Cdot);
+ m_impulse += df;
+
+ if (m_limitState == e_atLowerLimit)
+ {
+ m_impulse.z = b2Max(m_impulse.z, 0.0f);
+ }
+ else if (m_limitState == e_atUpperLimit)
+ {
+ m_impulse.z = b2Min(m_impulse.z, 0.0f);
+ }
+
+ // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
+ b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.ez.x, m_K.ez.y);
+ b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y);
+ m_impulse.x = f2r.x;
+ m_impulse.y = f2r.y;
+
+ df = m_impulse - f1;
+
+ b2Vec2 P = df.x * m_perp + df.z * m_axis;
+ float32 LA = df.x * m_s1 + df.y + df.z * m_a1;
+ float32 LB = df.x * m_s2 + df.y + df.z * m_a2;
+
+ vA -= mA * P;
+ wA -= iA * LA;
+
+ vB += mB * P;
+ wB += iB * LB;
+ }
+ else
+ {
+ // Limit is inactive, just solve the prismatic constraint in block form.
+ b2Vec2 df = m_K.Solve22(-Cdot1);
+ m_impulse.x += df.x;
+ m_impulse.y += df.y;
+
+ b2Vec2 P = df.x * m_perp;
+ float32 LA = df.x * m_s1 + df.y;
+ float32 LB = df.x * m_s2 + df.y;
+
+ vA -= mA * P;
+ wA -= iA * LA;
+
+ vB += mB * P;
+ wB += iB * LB;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+// A velocity based solver computes reaction forces(impulses) using the velocity constraint solver.Under this context,
+// the position solver is not there to resolve forces.It is only there to cope with integration error.
+//
+// Therefore, the pseudo impulses in the position solver do not have any physical meaning.Thus it is okay if they suck.
+//
+// We could take the active state from the velocity solver.However, the joint might push past the limit when the velocity
+// solver indicates the limit is inactive.
+bool b2PrismaticJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+
+ b2Rot qA(aA), qB(aB);
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ // Compute fresh Jacobians
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ b2Vec2 d = cB + rB - cA - rA;
+
+ b2Vec2 axis = b2Mul(qA, m_localXAxisA);
+ float32 a1 = b2Cross(d + rA, axis);
+ float32 a2 = b2Cross(rB, axis);
+ b2Vec2 perp = b2Mul(qA, m_localYAxisA);
+
+ float32 s1 = b2Cross(d + rA, perp);
+ float32 s2 = b2Cross(rB, perp);
+
+ b2Vec3 impulse;
+ b2Vec2 C1;
+ C1.x = b2Dot(perp, d);
+ C1.y = aB - aA - m_referenceAngle;
+
+ float32 linearError = b2Abs(C1.x);
+ float32 angularError = b2Abs(C1.y);
+
+ bool active = false;
+ float32 C2 = 0.0f;
+ if (m_enableLimit)
+ {
+ float32 translation = b2Dot(axis, d);
+ if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)
+ {
+ // Prevent large angular corrections
+ C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection);
+ linearError = b2Max(linearError, b2Abs(translation));
+ active = true;
+ }
+ else if (translation <= m_lowerTranslation)
+ {
+ // Prevent large linear corrections and allow some slop.
+ C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
+ linearError = b2Max(linearError, m_lowerTranslation - translation);
+ active = true;
+ }
+ else if (translation >= m_upperTranslation)
+ {
+ // Prevent large linear corrections and allow some slop.
+ C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection);
+ linearError = b2Max(linearError, translation - m_upperTranslation);
+ active = true;
+ }
+ }
+
+ if (active)
+ {
+ float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
+ float32 k12 = iA * s1 + iB * s2;
+ float32 k13 = iA * s1 * a1 + iB * s2 * a2;
+ float32 k22 = iA + iB;
+ if (k22 == 0.0f)
+ {
+ // For fixed rotation
+ k22 = 1.0f;
+ }
+ float32 k23 = iA * a1 + iB * a2;
+ float32 k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2;
+
+ b2Mat33 K;
+ K.ex.Set(k11, k12, k13);
+ K.ey.Set(k12, k22, k23);
+ K.ez.Set(k13, k23, k33);
+
+ b2Vec3 C;
+ C.x = C1.x;
+ C.y = C1.y;
+ C.z = C2;
+
+ impulse = K.Solve33(-C);
+ }
+ else
+ {
+ float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
+ float32 k12 = iA * s1 + iB * s2;
+ float32 k22 = iA + iB;
+ if (k22 == 0.0f)
+ {
+ k22 = 1.0f;
+ }
+
+ b2Mat22 K;
+ K.ex.Set(k11, k12);
+ K.ey.Set(k12, k22);
+
+ b2Vec2 impulse1 = K.Solve(-C1);
+ impulse.x = impulse1.x;
+ impulse.y = impulse1.y;
+ impulse.z = 0.0f;
+ }
+
+ b2Vec2 P = impulse.x * perp + impulse.z * axis;
+ float32 LA = impulse.x * s1 + impulse.y + impulse.z * a1;
+ float32 LB = impulse.x * s2 + impulse.y + impulse.z * a2;
+
+ cA -= mA * P;
+ aA -= iA * LA;
+ cB += mB * P;
+ aB += iB * LB;
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+
+ return linearError <= b2_linearSlop && angularError <= b2_angularSlop;
+}
+
+b2Vec2 b2PrismaticJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2PrismaticJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2PrismaticJoint::GetReactionForce(float32 inv_dt) const
+{
+ return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis);
+}
+
+float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const
+{
+ return inv_dt * m_impulse.y;
+}
+
+float32 b2PrismaticJoint::GetJointTranslation() const
+{
+ b2Vec2 pA = m_bodyA->GetWorldPoint(m_localAnchorA);
+ b2Vec2 pB = m_bodyB->GetWorldPoint(m_localAnchorB);
+ b2Vec2 d = pB - pA;
+ b2Vec2 axis = m_bodyA->GetWorldVector(m_localXAxisA);
+
+ float32 translation = b2Dot(d, axis);
+ return translation;
+}
+
+float32 b2PrismaticJoint::GetJointSpeed() const
+{
+ b2Body* bA = m_bodyA;
+ b2Body* bB = m_bodyB;
+
+ b2Vec2 rA = b2Mul(bA->m_xf.q, m_localAnchorA - bA->m_sweep.localCenter);
+ b2Vec2 rB = b2Mul(bB->m_xf.q, m_localAnchorB - bB->m_sweep.localCenter);
+ b2Vec2 p1 = bA->m_sweep.c + rA;
+ b2Vec2 p2 = bB->m_sweep.c + rB;
+ b2Vec2 d = p2 - p1;
+ b2Vec2 axis = b2Mul(bA->m_xf.q, m_localXAxisA);
+
+ b2Vec2 vA = bA->m_linearVelocity;
+ b2Vec2 vB = bB->m_linearVelocity;
+ float32 wA = bA->m_angularVelocity;
+ float32 wB = bB->m_angularVelocity;
+
+ float32 speed = b2Dot(d, b2Cross(wA, axis)) + b2Dot(axis, vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA));
+ return speed;
+}
+
+bool b2PrismaticJoint::IsLimitEnabled() const
+{
+ return m_enableLimit;
+}
+
+void b2PrismaticJoint::EnableLimit(bool flag)
+{
+ if (flag != m_enableLimit)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_enableLimit = flag;
+ m_impulse.z = 0.0f;
+ }
+}
+
+float32 b2PrismaticJoint::GetLowerLimit() const
+{
+ return m_lowerTranslation;
+}
+
+float32 b2PrismaticJoint::GetUpperLimit() const
+{
+ return m_upperTranslation;
+}
+
+void b2PrismaticJoint::SetLimits(float32 lower, float32 upper)
+{
+ b2Assert(lower <= upper);
+ if (lower != m_lowerTranslation || upper != m_upperTranslation)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_lowerTranslation = lower;
+ m_upperTranslation = upper;
+ m_impulse.z = 0.0f;
+ }
+}
+
+bool b2PrismaticJoint::IsMotorEnabled() const
+{
+ return m_enableMotor;
+}
+
+void b2PrismaticJoint::EnableMotor(bool flag)
+{
+ if (flag != m_enableMotor)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_enableMotor = flag;
+ }
+}
+
+void b2PrismaticJoint::SetMotorSpeed(float32 speed)
+{
+ if (speed != m_motorSpeed)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_motorSpeed = speed;
+ }
+}
+
+void b2PrismaticJoint::SetMaxMotorForce(float32 force)
+{
+ if (force != m_maxMotorForce)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_maxMotorForce = force;
+ }
+}
+
+float32 b2PrismaticJoint::GetMotorForce(float32 inv_dt) const
+{
+ return inv_dt * m_motorImpulse;
+}
+
+void b2PrismaticJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2PrismaticJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y);
+ b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle);
+ b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit);
+ b2Log(" jd.lowerTranslation = %.15lef;\n", m_lowerTranslation);
+ b2Log(" jd.upperTranslation = %.15lef;\n", m_upperTranslation);
+ b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor);
+ b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed);
+ b2Log(" jd.maxMotorForce = %.15lef;\n", m_maxMotorForce);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PrismaticJoint.h b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PrismaticJoint.h
new file mode 100644
index 0000000..131dffd
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PrismaticJoint.h
@@ -0,0 +1,196 @@
+/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.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 B2_PRISMATIC_JOINT_H
+#define B2_PRISMATIC_JOINT_H
+
+#include "Box2D/Dynamics/Joints/b2Joint.h"
+
+/// Prismatic joint definition. This requires defining a line of
+/// motion using an axis and an anchor point. The definition uses local
+/// anchor points and a local axis so that the initial configuration
+/// can violate the constraint slightly. The joint translation is zero
+/// when the local anchor points coincide in world space. Using local
+/// anchors and a local axis helps when saving and loading a game.
+struct b2PrismaticJointDef : public b2JointDef
+{
+ b2PrismaticJointDef()
+ {
+ type = e_prismaticJoint;
+ localAnchorA.SetZero();
+ localAnchorB.SetZero();
+ localAxisA.Set(1.0f, 0.0f);
+ referenceAngle = 0.0f;
+ enableLimit = false;
+ lowerTranslation = 0.0f;
+ upperTranslation = 0.0f;
+ enableMotor = false;
+ maxMotorForce = 0.0f;
+ motorSpeed = 0.0f;
+ }
+
+ /// Initialize the bodies, anchors, axis, and reference angle using the world
+ /// anchor and unit world axis.
+ void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis);
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The local translation unit axis in bodyA.
+ b2Vec2 localAxisA;
+
+ /// The constrained angle between the bodies: bodyB_angle - bodyA_angle.
+ float32 referenceAngle;
+
+ /// Enable/disable the joint limit.
+ bool enableLimit;
+
+ /// The lower translation limit, usually in meters.
+ float32 lowerTranslation;
+
+ /// The upper translation limit, usually in meters.
+ float32 upperTranslation;
+
+ /// Enable/disable the joint motor.
+ bool enableMotor;
+
+ /// The maximum motor torque, usually in N-m.
+ float32 maxMotorForce;
+
+ /// The desired motor speed in radians per second.
+ float32 motorSpeed;
+};
+
+/// A prismatic joint. This joint provides one degree of freedom: translation
+/// along an axis fixed in bodyA. Relative rotation is prevented. You can
+/// use a joint limit to restrict the range of motion and a joint motor to
+/// drive the motion or to model joint friction.
+class b2PrismaticJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const override;
+ b2Vec2 GetAnchorB() const override;
+
+ b2Vec2 GetReactionForce(float32 inv_dt) const override;
+ float32 GetReactionTorque(float32 inv_dt) const override;
+
+ /// The local anchor point relative to bodyA's origin.
+ const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
+
+ /// The local anchor point relative to bodyB's origin.
+ const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
+
+ /// The local joint axis relative to bodyA.
+ const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; }
+
+ /// Get the reference angle.
+ float32 GetReferenceAngle() const { return m_referenceAngle; }
+
+ /// Get the current joint translation, usually in meters.
+ float32 GetJointTranslation() const;
+
+ /// Get the current joint translation speed, usually in meters per second.
+ float32 GetJointSpeed() const;
+
+ /// Is the joint limit enabled?
+ bool IsLimitEnabled() const;
+
+ /// Enable/disable the joint limit.
+ void EnableLimit(bool flag);
+
+ /// Get the lower joint limit, usually in meters.
+ float32 GetLowerLimit() const;
+
+ /// Get the upper joint limit, usually in meters.
+ float32 GetUpperLimit() const;
+
+ /// Set the joint limits, usually in meters.
+ void SetLimits(float32 lower, float32 upper);
+
+ /// Is the joint motor enabled?
+ bool IsMotorEnabled() const;
+
+ /// Enable/disable the joint motor.
+ void EnableMotor(bool flag);
+
+ /// Set the motor speed, usually in meters per second.
+ void SetMotorSpeed(float32 speed);
+
+ /// Get the motor speed, usually in meters per second.
+ float32 GetMotorSpeed() const;
+
+ /// Set the maximum motor force, usually in N.
+ void SetMaxMotorForce(float32 force);
+ float32 GetMaxMotorForce() const { return m_maxMotorForce; }
+
+ /// Get the current motor force given the inverse time step, usually in N.
+ float32 GetMotorForce(float32 inv_dt) const;
+
+ /// Dump to b2Log
+ void Dump() override;
+
+protected:
+ friend class b2Joint;
+ friend class b2GearJoint;
+ b2PrismaticJoint(const b2PrismaticJointDef* def);
+
+ void InitVelocityConstraints(const b2SolverData& data) override;
+ void SolveVelocityConstraints(const b2SolverData& data) override;
+ bool SolvePositionConstraints(const b2SolverData& data) override;
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ b2Vec2 m_localXAxisA;
+ b2Vec2 m_localYAxisA;
+ float32 m_referenceAngle;
+ b2Vec3 m_impulse;
+ float32 m_motorImpulse;
+ float32 m_lowerTranslation;
+ float32 m_upperTranslation;
+ float32 m_maxMotorForce;
+ float32 m_motorSpeed;
+ bool m_enableLimit;
+ bool m_enableMotor;
+ b2LimitState m_limitState;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+ b2Vec2 m_axis, m_perp;
+ float32 m_s1, m_s2;
+ float32 m_a1, m_a2;
+ b2Mat33 m_K;
+ float32 m_motorMass;
+};
+
+inline float32 b2PrismaticJoint::GetMotorSpeed() const
+{
+ return m_motorSpeed;
+}
+
+#endif
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PulleyJoint.cpp b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PulleyJoint.cpp
new file mode 100644
index 0000000..1525f41
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PulleyJoint.cpp
@@ -0,0 +1,348 @@
+/*
+* Copyright (c) 2007 Erin Catto http://www.box2d.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 "Box2D/Dynamics/Joints/b2PulleyJoint.h"
+#include "Box2D/Dynamics/b2Body.h"
+#include "Box2D/Dynamics/b2TimeStep.h"
+
+// Pulley:
+// length1 = norm(p1 - s1)
+// length2 = norm(p2 - s2)
+// C0 = (length1 + ratio * length2)_initial
+// C = C0 - (length1 + ratio * length2)
+// u1 = (p1 - s1) / norm(p1 - s1)
+// u2 = (p2 - s2) / norm(p2 - s2)
+// Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2))
+// J = -[u1 cross(r1, u1) ratio * u2 ratio * cross(r2, u2)]
+// K = J * invM * JT
+// = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2)
+
+void b2PulleyJointDef::Initialize(b2Body* bA, b2Body* bB,
+ const b2Vec2& groundA, const b2Vec2& groundB,
+ const b2Vec2& anchorA, const b2Vec2& anchorB,
+ float32 r)
+{
+ bodyA = bA;
+ bodyB = bB;
+ groundAnchorA = groundA;
+ groundAnchorB = groundB;
+ localAnchorA = bodyA->GetLocalPoint(anchorA);
+ localAnchorB = bodyB->GetLocalPoint(anchorB);
+ b2Vec2 dA = anchorA - groundA;
+ lengthA = dA.Length();
+ b2Vec2 dB = anchorB - groundB;
+ lengthB = dB.Length();
+ ratio = r;
+ b2Assert(ratio > b2_epsilon);
+}
+
+b2PulleyJoint::b2PulleyJoint(const b2PulleyJointDef* def)
+: b2Joint(def)
+{
+ m_groundAnchorA = def->groundAnchorA;
+ m_groundAnchorB = def->groundAnchorB;
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+
+ m_lengthA = def->lengthA;
+ m_lengthB = def->lengthB;
+
+ b2Assert(def->ratio != 0.0f);
+ m_ratio = def->ratio;
+
+ m_constant = def->lengthA + m_ratio * def->lengthB;
+
+ m_impulse = 0.0f;
+}
+
+void b2PulleyJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ // Get the pulley axes.
+ m_uA = cA + m_rA - m_groundAnchorA;
+ m_uB = cB + m_rB - m_groundAnchorB;
+
+ float32 lengthA = m_uA.Length();
+ float32 lengthB = m_uB.Length();
+
+ if (lengthA > 10.0f * b2_linearSlop)
+ {
+ m_uA *= 1.0f / lengthA;
+ }
+ else
+ {
+ m_uA.SetZero();
+ }
+
+ if (lengthB > 10.0f * b2_linearSlop)
+ {
+ m_uB *= 1.0f / lengthB;
+ }
+ else
+ {
+ m_uB.SetZero();
+ }
+
+ // Compute effective mass.
+ float32 ruA = b2Cross(m_rA, m_uA);
+ float32 ruB = b2Cross(m_rB, m_uB);
+
+ float32 mA = m_invMassA + m_invIA * ruA * ruA;
+ float32 mB = m_invMassB + m_invIB * ruB * ruB;
+
+ m_mass = mA + m_ratio * m_ratio * mB;
+
+ if (m_mass > 0.0f)
+ {
+ m_mass = 1.0f / m_mass;
+ }
+
+ if (data.step.warmStarting)
+ {
+ // Scale impulses to support variable time steps.
+ m_impulse *= data.step.dtRatio;
+
+ // Warm starting.
+ b2Vec2 PA = -(m_impulse) * m_uA;
+ b2Vec2 PB = (-m_ratio * m_impulse) * m_uB;
+
+ vA += m_invMassA * PA;
+ wA += m_invIA * b2Cross(m_rA, PA);
+ vB += m_invMassB * PB;
+ wB += m_invIB * b2Cross(m_rB, PB);
+ }
+ else
+ {
+ m_impulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2PulleyJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Vec2 vpA = vA + b2Cross(wA, m_rA);
+ b2Vec2 vpB = vB + b2Cross(wB, m_rB);
+
+ float32 Cdot = -b2Dot(m_uA, vpA) - m_ratio * b2Dot(m_uB, vpB);
+ float32 impulse = -m_mass * Cdot;
+ m_impulse += impulse;
+
+ b2Vec2 PA = -impulse * m_uA;
+ b2Vec2 PB = -m_ratio * impulse * m_uB;
+ vA += m_invMassA * PA;
+ wA += m_invIA * b2Cross(m_rA, PA);
+ vB += m_invMassB * PB;
+ wB += m_invIB * b2Cross(m_rB, PB);
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2PulleyJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+
+ b2Rot qA(aA), qB(aB);
+
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ // Get the pulley axes.
+ b2Vec2 uA = cA + rA - m_groundAnchorA;
+ b2Vec2 uB = cB + rB - m_groundAnchorB;
+
+ float32 lengthA = uA.Length();
+ float32 lengthB = uB.Length();
+
+ if (lengthA > 10.0f * b2_linearSlop)
+ {
+ uA *= 1.0f / lengthA;
+ }
+ else
+ {
+ uA.SetZero();
+ }
+
+ if (lengthB > 10.0f * b2_linearSlop)
+ {
+ uB *= 1.0f / lengthB;
+ }
+ else
+ {
+ uB.SetZero();
+ }
+
+ // Compute effective mass.
+ float32 ruA = b2Cross(rA, uA);
+ float32 ruB = b2Cross(rB, uB);
+
+ float32 mA = m_invMassA + m_invIA * ruA * ruA;
+ float32 mB = m_invMassB + m_invIB * ruB * ruB;
+
+ float32 mass = mA + m_ratio * m_ratio * mB;
+
+ if (mass > 0.0f)
+ {
+ mass = 1.0f / mass;
+ }
+
+ float32 C = m_constant - lengthA - m_ratio * lengthB;
+ float32 linearError = b2Abs(C);
+
+ float32 impulse = -mass * C;
+
+ b2Vec2 PA = -impulse * uA;
+ b2Vec2 PB = -m_ratio * impulse * uB;
+
+ cA += m_invMassA * PA;
+ aA += m_invIA * b2Cross(rA, PA);
+ cB += m_invMassB * PB;
+ aB += m_invIB * b2Cross(rB, PB);
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+
+ return linearError < b2_linearSlop;
+}
+
+b2Vec2 b2PulleyJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2PulleyJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2PulleyJoint::GetReactionForce(float32 inv_dt) const
+{
+ b2Vec2 P = m_impulse * m_uB;
+ return inv_dt * P;
+}
+
+float32 b2PulleyJoint::GetReactionTorque(float32 inv_dt) const
+{
+ B2_NOT_USED(inv_dt);
+ return 0.0f;
+}
+
+b2Vec2 b2PulleyJoint::GetGroundAnchorA() const
+{
+ return m_groundAnchorA;
+}
+
+b2Vec2 b2PulleyJoint::GetGroundAnchorB() const
+{
+ return m_groundAnchorB;
+}
+
+float32 b2PulleyJoint::GetLengthA() const
+{
+ return m_lengthA;
+}
+
+float32 b2PulleyJoint::GetLengthB() const
+{
+ return m_lengthB;
+}
+
+float32 b2PulleyJoint::GetRatio() const
+{
+ return m_ratio;
+}
+
+float32 b2PulleyJoint::GetCurrentLengthA() const
+{
+ b2Vec2 p = m_bodyA->GetWorldPoint(m_localAnchorA);
+ b2Vec2 s = m_groundAnchorA;
+ b2Vec2 d = p - s;
+ return d.Length();
+}
+
+float32 b2PulleyJoint::GetCurrentLengthB() const
+{
+ b2Vec2 p = m_bodyB->GetWorldPoint(m_localAnchorB);
+ b2Vec2 s = m_groundAnchorB;
+ b2Vec2 d = p - s;
+ return d.Length();
+}
+
+void b2PulleyJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2PulleyJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.groundAnchorA.Set(%.15lef, %.15lef);\n", m_groundAnchorA.x, m_groundAnchorA.y);
+ b2Log(" jd.groundAnchorB.Set(%.15lef, %.15lef);\n", m_groundAnchorB.x, m_groundAnchorB.y);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.lengthA = %.15lef;\n", m_lengthA);
+ b2Log(" jd.lengthB = %.15lef;\n", m_lengthB);
+ b2Log(" jd.ratio = %.15lef;\n", m_ratio);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
+
+void b2PulleyJoint::ShiftOrigin(const b2Vec2& newOrigin)
+{
+ m_groundAnchorA -= newOrigin;
+ m_groundAnchorB -= newOrigin;
+}
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PulleyJoint.h b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PulleyJoint.h
new file mode 100644
index 0000000..71c759b
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2PulleyJoint.h
@@ -0,0 +1,152 @@
+/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.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 B2_PULLEY_JOINT_H
+#define B2_PULLEY_JOINT_H
+
+#include "Box2D/Dynamics/Joints/b2Joint.h"
+
+const float32 b2_minPulleyLength = 2.0f;
+
+/// Pulley joint definition. This requires two ground anchors,
+/// two dynamic body anchor points, and a pulley ratio.
+struct b2PulleyJointDef : public b2JointDef
+{
+ b2PulleyJointDef()
+ {
+ type = e_pulleyJoint;
+ groundAnchorA.Set(-1.0f, 1.0f);
+ groundAnchorB.Set(1.0f, 1.0f);
+ localAnchorA.Set(-1.0f, 0.0f);
+ localAnchorB.Set(1.0f, 0.0f);
+ lengthA = 0.0f;
+ lengthB = 0.0f;
+ ratio = 1.0f;
+ collideConnected = true;
+ }
+
+ /// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors.
+ void Initialize(b2Body* bodyA, b2Body* bodyB,
+ const b2Vec2& groundAnchorA, const b2Vec2& groundAnchorB,
+ const b2Vec2& anchorA, const b2Vec2& anchorB,
+ float32 ratio);
+
+ /// The first ground anchor in world coordinates. This point never moves.
+ b2Vec2 groundAnchorA;
+
+ /// The second ground anchor in world coordinates. This point never moves.
+ b2Vec2 groundAnchorB;
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The a reference length for the segment attached to bodyA.
+ float32 lengthA;
+
+ /// The a reference length for the segment attached to bodyB.
+ float32 lengthB;
+
+ /// The pulley ratio, used to simulate a block-and-tackle.
+ float32 ratio;
+};
+
+/// The pulley joint is connected to two bodies and two fixed ground points.
+/// The pulley supports a ratio such that:
+/// length1 + ratio * length2 <= constant
+/// Yes, the force transmitted is scaled by the ratio.
+/// Warning: the pulley joint can get a bit squirrelly by itself. They often
+/// work better when combined with prismatic joints. You should also cover the
+/// the anchor points with static shapes to prevent one side from going to
+/// zero length.
+class b2PulleyJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const override;
+ b2Vec2 GetAnchorB() const override;
+
+ b2Vec2 GetReactionForce(float32 inv_dt) const override;
+ float32 GetReactionTorque(float32 inv_dt) const override;
+
+ /// Get the first ground anchor.
+ b2Vec2 GetGroundAnchorA() const;
+
+ /// Get the second ground anchor.
+ b2Vec2 GetGroundAnchorB() const;
+
+ /// Get the current length of the segment attached to bodyA.
+ float32 GetLengthA() const;
+
+ /// Get the current length of the segment attached to bodyB.
+ float32 GetLengthB() const;
+
+ /// Get the pulley ratio.
+ float32 GetRatio() const;
+
+ /// Get the current length of the segment attached to bodyA.
+ float32 GetCurrentLengthA() const;
+
+ /// Get the current length of the segment attached to bodyB.
+ float32 GetCurrentLengthB() const;
+
+ /// Dump joint to dmLog
+ void Dump() override;
+
+ /// Implement b2Joint::ShiftOrigin
+ void ShiftOrigin(const b2Vec2& newOrigin) override;
+
+protected:
+
+ friend class b2Joint;
+ b2PulleyJoint(const b2PulleyJointDef* data);
+
+ void InitVelocityConstraints(const b2SolverData& data) override;
+ void SolveVelocityConstraints(const b2SolverData& data) override;
+ bool SolvePositionConstraints(const b2SolverData& data) override;
+
+ b2Vec2 m_groundAnchorA;
+ b2Vec2 m_groundAnchorB;
+ float32 m_lengthA;
+ float32 m_lengthB;
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ float32 m_constant;
+ float32 m_ratio;
+ float32 m_impulse;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_uA;
+ b2Vec2 m_uB;
+ b2Vec2 m_rA;
+ b2Vec2 m_rB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+ float32 m_mass;
+};
+
+#endif
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp
new file mode 100644
index 0000000..b3f7ee5
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp
@@ -0,0 +1,511 @@
+/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.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 "Box2D/Dynamics/Joints/b2RevoluteJoint.h"
+#include "Box2D/Dynamics/b2Body.h"
+#include "Box2D/Dynamics/b2TimeStep.h"
+
+// Point-to-point constraint
+// C = p2 - p1
+// Cdot = v2 - v1
+// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
+// J = [-I -r1_skew I r2_skew ]
+// Identity used:
+// w k % (rx i + ry j) = w * (-ry i + rx j)
+
+// Motor constraint
+// Cdot = w2 - w1
+// J = [0 0 -1 0 0 1]
+// K = invI1 + invI2
+
+void b2RevoluteJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)
+{
+ bodyA = bA;
+ bodyB = bB;
+ localAnchorA = bodyA->GetLocalPoint(anchor);
+ localAnchorB = bodyB->GetLocalPoint(anchor);
+ referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
+}
+
+b2RevoluteJoint::b2RevoluteJoint(const b2RevoluteJointDef* def)
+: b2Joint(def)
+{
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+ m_referenceAngle = def->referenceAngle;
+
+ m_impulse.SetZero();
+ m_motorImpulse = 0.0f;
+
+ m_lowerAngle = def->lowerAngle;
+ m_upperAngle = def->upperAngle;
+ m_maxMotorTorque = def->maxMotorTorque;
+ m_motorSpeed = def->motorSpeed;
+ m_enableLimit = def->enableLimit;
+ m_enableMotor = def->enableMotor;
+ m_limitState = e_inactiveLimit;
+}
+
+void b2RevoluteJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ // J = [-I -r1_skew I r2_skew]
+ // [ 0 -1 0 1]
+ // r_skew = [-ry; rx]
+
+ // Matlab
+ // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
+ // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
+ // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ bool fixedRotation = (iA + iB == 0.0f);
+
+ m_mass.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB;
+ m_mass.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB;
+ m_mass.ez.x = -m_rA.y * iA - m_rB.y * iB;
+ m_mass.ex.y = m_mass.ey.x;
+ m_mass.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB;
+ m_mass.ez.y = m_rA.x * iA + m_rB.x * iB;
+ m_mass.ex.z = m_mass.ez.x;
+ m_mass.ey.z = m_mass.ez.y;
+ m_mass.ez.z = iA + iB;
+
+ m_motorMass = iA + iB;
+ if (m_motorMass > 0.0f)
+ {
+ m_motorMass = 1.0f / m_motorMass;
+ }
+
+ if (m_enableMotor == false || fixedRotation)
+ {
+ m_motorImpulse = 0.0f;
+ }
+
+ if (m_enableLimit && fixedRotation == false)
+ {
+ float32 jointAngle = aB - aA - m_referenceAngle;
+ if (b2Abs(m_upperAngle - m_lowerAngle) < 2.0f * b2_angularSlop)
+ {
+ m_limitState = e_equalLimits;
+ }
+ else if (jointAngle <= m_lowerAngle)
+ {
+ if (m_limitState != e_atLowerLimit)
+ {
+ m_impulse.z = 0.0f;
+ }
+ m_limitState = e_atLowerLimit;
+ }
+ else if (jointAngle >= m_upperAngle)
+ {
+ if (m_limitState != e_atUpperLimit)
+ {
+ m_impulse.z = 0.0f;
+ }
+ m_limitState = e_atUpperLimit;
+ }
+ else
+ {
+ m_limitState = e_inactiveLimit;
+ m_impulse.z = 0.0f;
+ }
+ }
+ else
+ {
+ m_limitState = e_inactiveLimit;
+ }
+
+ if (data.step.warmStarting)
+ {
+ // Scale impulses to support a variable time step.
+ m_impulse *= data.step.dtRatio;
+ m_motorImpulse *= data.step.dtRatio;
+
+ b2Vec2 P(m_impulse.x, m_impulse.y);
+
+ vA -= mA * P;
+ wA -= iA * (b2Cross(m_rA, P) + m_motorImpulse + m_impulse.z);
+
+ vB += mB * P;
+ wB += iB * (b2Cross(m_rB, P) + m_motorImpulse + m_impulse.z);
+ }
+ else
+ {
+ m_impulse.SetZero();
+ m_motorImpulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2RevoluteJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ bool fixedRotation = (iA + iB == 0.0f);
+
+ // Solve motor constraint.
+ if (m_enableMotor && m_limitState != e_equalLimits && fixedRotation == false)
+ {
+ float32 Cdot = wB - wA - m_motorSpeed;
+ float32 impulse = -m_motorMass * Cdot;
+ float32 oldImpulse = m_motorImpulse;
+ float32 maxImpulse = data.step.dt * m_maxMotorTorque;
+ m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
+ impulse = m_motorImpulse - oldImpulse;
+
+ wA -= iA * impulse;
+ wB += iB * impulse;
+ }
+
+ // Solve limit constraint.
+ if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false)
+ {
+ b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
+ float32 Cdot2 = wB - wA;
+ b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
+
+ b2Vec3 impulse = -m_mass.Solve33(Cdot);
+
+ if (m_limitState == e_equalLimits)
+ {
+ m_impulse += impulse;
+ }
+ else if (m_limitState == e_atLowerLimit)
+ {
+ float32 newImpulse = m_impulse.z + impulse.z;
+ if (newImpulse < 0.0f)
+ {
+ b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y);
+ b2Vec2 reduced = m_mass.Solve22(rhs);
+ impulse.x = reduced.x;
+ impulse.y = reduced.y;
+ impulse.z = -m_impulse.z;
+ m_impulse.x += reduced.x;
+ m_impulse.y += reduced.y;
+ m_impulse.z = 0.0f;
+ }
+ else
+ {
+ m_impulse += impulse;
+ }
+ }
+ else if (m_limitState == e_atUpperLimit)
+ {
+ float32 newImpulse = m_impulse.z + impulse.z;
+ if (newImpulse > 0.0f)
+ {
+ b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y);
+ b2Vec2 reduced = m_mass.Solve22(rhs);
+ impulse.x = reduced.x;
+ impulse.y = reduced.y;
+ impulse.z = -m_impulse.z;
+ m_impulse.x += reduced.x;
+ m_impulse.y += reduced.y;
+ m_impulse.z = 0.0f;
+ }
+ else
+ {
+ m_impulse += impulse;
+ }
+ }
+
+ b2Vec2 P(impulse.x, impulse.y);
+
+ vA -= mA * P;
+ wA -= iA * (b2Cross(m_rA, P) + impulse.z);
+
+ vB += mB * P;
+ wB += iB * (b2Cross(m_rB, P) + impulse.z);
+ }
+ else
+ {
+ // Solve point-to-point constraint
+ b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
+ b2Vec2 impulse = m_mass.Solve22(-Cdot);
+
+ m_impulse.x += impulse.x;
+ m_impulse.y += impulse.y;
+
+ vA -= mA * impulse;
+ wA -= iA * b2Cross(m_rA, impulse);
+
+ vB += mB * impulse;
+ wB += iB * b2Cross(m_rB, impulse);
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2RevoluteJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+
+ b2Rot qA(aA), qB(aB);
+
+ float32 angularError = 0.0f;
+ float32 positionError = 0.0f;
+
+ bool fixedRotation = (m_invIA + m_invIB == 0.0f);
+
+ // Solve angular limit constraint.
+ if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false)
+ {
+ float32 angle = aB - aA - m_referenceAngle;
+ float32 limitImpulse = 0.0f;
+
+ if (m_limitState == e_equalLimits)
+ {
+ // Prevent large angular corrections
+ float32 C = b2Clamp(angle - m_lowerAngle, -b2_maxAngularCorrection, b2_maxAngularCorrection);
+ limitImpulse = -m_motorMass * C;
+ angularError = b2Abs(C);
+ }
+ else if (m_limitState == e_atLowerLimit)
+ {
+ float32 C = angle - m_lowerAngle;
+ angularError = -C;
+
+ // Prevent large angular corrections and allow some slop.
+ C = b2Clamp(C + b2_angularSlop, -b2_maxAngularCorrection, 0.0f);
+ limitImpulse = -m_motorMass * C;
+ }
+ else if (m_limitState == e_atUpperLimit)
+ {
+ float32 C = angle - m_upperAngle;
+ angularError = C;
+
+ // Prevent large angular corrections and allow some slop.
+ C = b2Clamp(C - b2_angularSlop, 0.0f, b2_maxAngularCorrection);
+ limitImpulse = -m_motorMass * C;
+ }
+
+ aA -= m_invIA * limitImpulse;
+ aB += m_invIB * limitImpulse;
+ }
+
+ // Solve point-to-point constraint.
+ {
+ qA.Set(aA);
+ qB.Set(aB);
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ b2Vec2 C = cB + rB - cA - rA;
+ positionError = C.Length();
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ b2Mat22 K;
+ K.ex.x = mA + mB + iA * rA.y * rA.y + iB * rB.y * rB.y;
+ K.ex.y = -iA * rA.x * rA.y - iB * rB.x * rB.y;
+ K.ey.x = K.ex.y;
+ K.ey.y = mA + mB + iA * rA.x * rA.x + iB * rB.x * rB.x;
+
+ b2Vec2 impulse = -K.Solve(C);
+
+ cA -= mA * impulse;
+ aA -= iA * b2Cross(rA, impulse);
+
+ cB += mB * impulse;
+ aB += iB * b2Cross(rB, impulse);
+ }
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+
+ return positionError <= b2_linearSlop && angularError <= b2_angularSlop;
+}
+
+b2Vec2 b2RevoluteJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2RevoluteJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2RevoluteJoint::GetReactionForce(float32 inv_dt) const
+{
+ b2Vec2 P(m_impulse.x, m_impulse.y);
+ return inv_dt * P;
+}
+
+float32 b2RevoluteJoint::GetReactionTorque(float32 inv_dt) const
+{
+ return inv_dt * m_impulse.z;
+}
+
+float32 b2RevoluteJoint::GetJointAngle() const
+{
+ b2Body* bA = m_bodyA;
+ b2Body* bB = m_bodyB;
+ return bB->m_sweep.a - bA->m_sweep.a - m_referenceAngle;
+}
+
+float32 b2RevoluteJoint::GetJointSpeed() const
+{
+ b2Body* bA = m_bodyA;
+ b2Body* bB = m_bodyB;
+ return bB->m_angularVelocity - bA->m_angularVelocity;
+}
+
+bool b2RevoluteJoint::IsMotorEnabled() const
+{
+ return m_enableMotor;
+}
+
+void b2RevoluteJoint::EnableMotor(bool flag)
+{
+ if (flag != m_enableMotor)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_enableMotor = flag;
+ }
+}
+
+float32 b2RevoluteJoint::GetMotorTorque(float32 inv_dt) const
+{
+ return inv_dt * m_motorImpulse;
+}
+
+void b2RevoluteJoint::SetMotorSpeed(float32 speed)
+{
+ if (speed != m_motorSpeed)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_motorSpeed = speed;
+ }
+}
+
+void b2RevoluteJoint::SetMaxMotorTorque(float32 torque)
+{
+ if (torque != m_maxMotorTorque)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_maxMotorTorque = torque;
+ }
+}
+
+bool b2RevoluteJoint::IsLimitEnabled() const
+{
+ return m_enableLimit;
+}
+
+void b2RevoluteJoint::EnableLimit(bool flag)
+{
+ if (flag != m_enableLimit)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_enableLimit = flag;
+ m_impulse.z = 0.0f;
+ }
+}
+
+float32 b2RevoluteJoint::GetLowerLimit() const
+{
+ return m_lowerAngle;
+}
+
+float32 b2RevoluteJoint::GetUpperLimit() const
+{
+ return m_upperAngle;
+}
+
+void b2RevoluteJoint::SetLimits(float32 lower, float32 upper)
+{
+ b2Assert(lower <= upper);
+
+ if (lower != m_lowerAngle || upper != m_upperAngle)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_impulse.z = 0.0f;
+ m_lowerAngle = lower;
+ m_upperAngle = upper;
+ }
+}
+
+void b2RevoluteJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2RevoluteJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle);
+ b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit);
+ b2Log(" jd.lowerAngle = %.15lef;\n", m_lowerAngle);
+ b2Log(" jd.upperAngle = %.15lef;\n", m_upperAngle);
+ b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor);
+ b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed);
+ b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RevoluteJoint.h b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RevoluteJoint.h
new file mode 100644
index 0000000..06b1455
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RevoluteJoint.h
@@ -0,0 +1,204 @@
+/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.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 B2_REVOLUTE_JOINT_H
+#define B2_REVOLUTE_JOINT_H
+
+#include "Box2D/Dynamics/Joints/b2Joint.h"
+
+/// Revolute joint definition. This requires defining an
+/// anchor point where the bodies are joined. The definition
+/// uses local anchor points so that the initial configuration
+/// can violate the constraint slightly. You also need to
+/// specify the initial relative angle for joint limits. This
+/// helps when saving and loading a game.
+/// The local anchor points are measured from the body's origin
+/// rather than the center of mass because:
+/// 1. you might not know where the center of mass will be.
+/// 2. if you add/remove shapes from a body and recompute the mass,
+/// the joints will be broken.
+struct b2RevoluteJointDef : public b2JointDef
+{
+ b2RevoluteJointDef()
+ {
+ type = e_revoluteJoint;
+ localAnchorA.Set(0.0f, 0.0f);
+ localAnchorB.Set(0.0f, 0.0f);
+ referenceAngle = 0.0f;
+ lowerAngle = 0.0f;
+ upperAngle = 0.0f;
+ maxMotorTorque = 0.0f;
+ motorSpeed = 0.0f;
+ enableLimit = false;
+ enableMotor = false;
+ }
+
+ /// Initialize the bodies, anchors, and reference angle using a world
+ /// anchor point.
+ void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The bodyB angle minus bodyA angle in the reference state (radians).
+ float32 referenceAngle;
+
+ /// A flag to enable joint limits.
+ bool enableLimit;
+
+ /// The lower angle for the joint limit (radians).
+ float32 lowerAngle;
+
+ /// The upper angle for the joint limit (radians).
+ float32 upperAngle;
+
+ /// A flag to enable the joint motor.
+ bool enableMotor;
+
+ /// The desired motor speed. Usually in radians per second.
+ float32 motorSpeed;
+
+ /// The maximum motor torque used to achieve the desired motor speed.
+ /// Usually in N-m.
+ float32 maxMotorTorque;
+};
+
+/// A revolute joint constrains two bodies to share a common point while they
+/// are free to rotate about the point. The relative rotation about the shared
+/// point is the joint angle. You can limit the relative rotation with
+/// a joint limit that specifies a lower and upper angle. You can use a motor
+/// to drive the relative rotation about the shared point. A maximum motor torque
+/// is provided so that infinite forces are not generated.
+class b2RevoluteJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const override;
+ b2Vec2 GetAnchorB() const override;
+
+ /// The local anchor point relative to bodyA's origin.
+ const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
+
+ /// The local anchor point relative to bodyB's origin.
+ const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
+
+ /// Get the reference angle.
+ float32 GetReferenceAngle() const { return m_referenceAngle; }
+
+ /// Get the current joint angle in radians.
+ float32 GetJointAngle() const;
+
+ /// Get the current joint angle speed in radians per second.
+ float32 GetJointSpeed() const;
+
+ /// Is the joint limit enabled?
+ bool IsLimitEnabled() const;
+
+ /// Enable/disable the joint limit.
+ void EnableLimit(bool flag);
+
+ /// Get the lower joint limit in radians.
+ float32 GetLowerLimit() const;
+
+ /// Get the upper joint limit in radians.
+ float32 GetUpperLimit() const;
+
+ /// Set the joint limits in radians.
+ void SetLimits(float32 lower, float32 upper);
+
+ /// Is the joint motor enabled?
+ bool IsMotorEnabled() const;
+
+ /// Enable/disable the joint motor.
+ void EnableMotor(bool flag);
+
+ /// Set the motor speed in radians per second.
+ void SetMotorSpeed(float32 speed);
+
+ /// Get the motor speed in radians per second.
+ float32 GetMotorSpeed() const;
+
+ /// Set the maximum motor torque, usually in N-m.
+ void SetMaxMotorTorque(float32 torque);
+ float32 GetMaxMotorTorque() const { return m_maxMotorTorque; }
+
+ /// Get the reaction force given the inverse time step.
+ /// Unit is N.
+ b2Vec2 GetReactionForce(float32 inv_dt) const override;
+
+ /// Get the reaction torque due to the joint limit given the inverse time step.
+ /// Unit is N*m.
+ float32 GetReactionTorque(float32 inv_dt) const override;
+
+ /// Get the current motor torque given the inverse time step.
+ /// Unit is N*m.
+ float32 GetMotorTorque(float32 inv_dt) const;
+
+ /// Dump to b2Log.
+ void Dump() override;
+
+protected:
+
+ friend class b2Joint;
+ friend class b2GearJoint;
+
+ b2RevoluteJoint(const b2RevoluteJointDef* def);
+
+ void InitVelocityConstraints(const b2SolverData& data) override;
+ void SolveVelocityConstraints(const b2SolverData& data) override;
+ bool SolvePositionConstraints(const b2SolverData& data) override;
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ b2Vec3 m_impulse;
+ float32 m_motorImpulse;
+
+ bool m_enableMotor;
+ float32 m_maxMotorTorque;
+ float32 m_motorSpeed;
+
+ bool m_enableLimit;
+ float32 m_referenceAngle;
+ float32 m_lowerAngle;
+ float32 m_upperAngle;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_rA;
+ b2Vec2 m_rB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+ b2Mat33 m_mass; // effective mass for point-to-point constraint.
+ float32 m_motorMass; // effective mass for motor/limit angular constraint.
+ b2LimitState m_limitState;
+};
+
+inline float32 b2RevoluteJoint::GetMotorSpeed() const
+{
+ return m_motorSpeed;
+}
+
+#endif
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RopeJoint.cpp b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RopeJoint.cpp
new file mode 100644
index 0000000..86d27e7
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RopeJoint.cpp
@@ -0,0 +1,241 @@
+/*
+* Copyright (c) 2007-2011 Erin Catto http://www.box2d.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 "Box2D/Dynamics/Joints/b2RopeJoint.h"
+#include "Box2D/Dynamics/b2Body.h"
+#include "Box2D/Dynamics/b2TimeStep.h"
+
+
+// Limit:
+// C = norm(pB - pA) - L
+// u = (pB - pA) / norm(pB - pA)
+// Cdot = dot(u, vB + cross(wB, rB) - vA - cross(wA, rA))
+// J = [-u -cross(rA, u) u cross(rB, u)]
+// K = J * invM * JT
+// = invMassA + invIA * cross(rA, u)^2 + invMassB + invIB * cross(rB, u)^2
+
+b2RopeJoint::b2RopeJoint(const b2RopeJointDef* def)
+: b2Joint(def)
+{
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+
+ m_maxLength = def->maxLength;
+
+ m_mass = 0.0f;
+ m_impulse = 0.0f;
+ m_state = e_inactiveLimit;
+ m_length = 0.0f;
+}
+
+void b2RopeJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ m_u = cB + m_rB - cA - m_rA;
+
+ m_length = m_u.Length();
+
+ float32 C = m_length - m_maxLength;
+ if (C > 0.0f)
+ {
+ m_state = e_atUpperLimit;
+ }
+ else
+ {
+ m_state = e_inactiveLimit;
+ }
+
+ if (m_length > b2_linearSlop)
+ {
+ m_u *= 1.0f / m_length;
+ }
+ else
+ {
+ m_u.SetZero();
+ m_mass = 0.0f;
+ m_impulse = 0.0f;
+ return;
+ }
+
+ // Compute effective mass.
+ float32 crA = b2Cross(m_rA, m_u);
+ float32 crB = b2Cross(m_rB, m_u);
+ float32 invMass = m_invMassA + m_invIA * crA * crA + m_invMassB + m_invIB * crB * crB;
+
+ m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
+
+ if (data.step.warmStarting)
+ {
+ // Scale the impulse to support a variable time step.
+ m_impulse *= data.step.dtRatio;
+
+ b2Vec2 P = m_impulse * m_u;
+ vA -= m_invMassA * P;
+ wA -= m_invIA * b2Cross(m_rA, P);
+ vB += m_invMassB * P;
+ wB += m_invIB * b2Cross(m_rB, P);
+ }
+ else
+ {
+ m_impulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2RopeJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ // Cdot = dot(u, v + cross(w, r))
+ b2Vec2 vpA = vA + b2Cross(wA, m_rA);
+ b2Vec2 vpB = vB + b2Cross(wB, m_rB);
+ float32 C = m_length - m_maxLength;
+ float32 Cdot = b2Dot(m_u, vpB - vpA);
+
+ // Predictive constraint.
+ if (C < 0.0f)
+ {
+ Cdot += data.step.inv_dt * C;
+ }
+
+ float32 impulse = -m_mass * Cdot;
+ float32 oldImpulse = m_impulse;
+ m_impulse = b2Min(0.0f, m_impulse + impulse);
+ impulse = m_impulse - oldImpulse;
+
+ b2Vec2 P = impulse * m_u;
+ vA -= m_invMassA * P;
+ wA -= m_invIA * b2Cross(m_rA, P);
+ vB += m_invMassB * P;
+ wB += m_invIB * b2Cross(m_rB, P);
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2RopeJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+
+ b2Rot qA(aA), qB(aB);
+
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ b2Vec2 u = cB + rB - cA - rA;
+
+ float32 length = u.Normalize();
+ float32 C = length - m_maxLength;
+
+ C = b2Clamp(C, 0.0f, b2_maxLinearCorrection);
+
+ float32 impulse = -m_mass * C;
+ b2Vec2 P = impulse * u;
+
+ cA -= m_invMassA * P;
+ aA -= m_invIA * b2Cross(rA, P);
+ cB += m_invMassB * P;
+ aB += m_invIB * b2Cross(rB, P);
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+
+ return length - m_maxLength < b2_linearSlop;
+}
+
+b2Vec2 b2RopeJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2RopeJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2RopeJoint::GetReactionForce(float32 inv_dt) const
+{
+ b2Vec2 F = (inv_dt * m_impulse) * m_u;
+ return F;
+}
+
+float32 b2RopeJoint::GetReactionTorque(float32 inv_dt) const
+{
+ B2_NOT_USED(inv_dt);
+ return 0.0f;
+}
+
+float32 b2RopeJoint::GetMaxLength() const
+{
+ return m_maxLength;
+}
+
+b2LimitState b2RopeJoint::GetLimitState() const
+{
+ return m_state;
+}
+
+void b2RopeJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2RopeJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.maxLength = %.15lef;\n", m_maxLength);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RopeJoint.h b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RopeJoint.h
new file mode 100644
index 0000000..ef5d6f7
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2RopeJoint.h
@@ -0,0 +1,114 @@
+/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.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 B2_ROPE_JOINT_H
+#define B2_ROPE_JOINT_H
+
+#include "Box2D/Dynamics/Joints/b2Joint.h"
+
+/// Rope joint definition. This requires two body anchor points and
+/// a maximum lengths.
+/// Note: by default the connected objects will not collide.
+/// see collideConnected in b2JointDef.
+struct b2RopeJointDef : public b2JointDef
+{
+ b2RopeJointDef()
+ {
+ type = e_ropeJoint;
+ localAnchorA.Set(-1.0f, 0.0f);
+ localAnchorB.Set(1.0f, 0.0f);
+ maxLength = 0.0f;
+ }
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The maximum length of the rope.
+ /// Warning: this must be larger than b2_linearSlop or
+ /// the joint will have no effect.
+ float32 maxLength;
+};
+
+/// A rope joint enforces a maximum distance between two points
+/// on two bodies. It has no other effect.
+/// Warning: if you attempt to change the maximum length during
+/// the simulation you will get some non-physical behavior.
+/// A model that would allow you to dynamically modify the length
+/// would have some sponginess, so I chose not to implement it
+/// that way. See b2DistanceJoint if you want to dynamically
+/// control length.
+class b2RopeJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const override;
+ b2Vec2 GetAnchorB() const override;
+
+ b2Vec2 GetReactionForce(float32 inv_dt) const override;
+ float32 GetReactionTorque(float32 inv_dt) const override;
+
+ /// The local anchor point relative to bodyA's origin.
+ const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
+
+ /// The local anchor point relative to bodyB's origin.
+ const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
+
+ /// Set/Get the maximum length of the rope.
+ void SetMaxLength(float32 length) { m_maxLength = length; }
+ float32 GetMaxLength() const;
+
+ b2LimitState GetLimitState() const;
+
+ /// Dump joint to dmLog
+ void Dump() override;
+
+protected:
+
+ friend class b2Joint;
+ b2RopeJoint(const b2RopeJointDef* data);
+
+ void InitVelocityConstraints(const b2SolverData& data) override;
+ void SolveVelocityConstraints(const b2SolverData& data) override;
+ bool SolvePositionConstraints(const b2SolverData& data) override;
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ float32 m_maxLength;
+ float32 m_length;
+ float32 m_impulse;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_u;
+ b2Vec2 m_rA;
+ b2Vec2 m_rB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+ float32 m_mass;
+ b2LimitState m_state;
+};
+
+#endif
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WeldJoint.cpp b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WeldJoint.cpp
new file mode 100644
index 0000000..b10cee8
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WeldJoint.cpp
@@ -0,0 +1,344 @@
+/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.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 "Box2D/Dynamics/Joints/b2WeldJoint.h"
+#include "Box2D/Dynamics/b2Body.h"
+#include "Box2D/Dynamics/b2TimeStep.h"
+
+// Point-to-point constraint
+// C = p2 - p1
+// Cdot = v2 - v1
+// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
+// J = [-I -r1_skew I r2_skew ]
+// Identity used:
+// w k % (rx i + ry j) = w * (-ry i + rx j)
+
+// Angle constraint
+// C = angle2 - angle1 - referenceAngle
+// Cdot = w2 - w1
+// J = [0 0 -1 0 0 1]
+// K = invI1 + invI2
+
+void b2WeldJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)
+{
+ bodyA = bA;
+ bodyB = bB;
+ localAnchorA = bodyA->GetLocalPoint(anchor);
+ localAnchorB = bodyB->GetLocalPoint(anchor);
+ referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
+}
+
+b2WeldJoint::b2WeldJoint(const b2WeldJointDef* def)
+: b2Joint(def)
+{
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+ m_referenceAngle = def->referenceAngle;
+ m_frequencyHz = def->frequencyHz;
+ m_dampingRatio = def->dampingRatio;
+
+ m_impulse.SetZero();
+}
+
+void b2WeldJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ // J = [-I -r1_skew I r2_skew]
+ // [ 0 -1 0 1]
+ // r_skew = [-ry; rx]
+
+ // Matlab
+ // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
+ // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
+ // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ b2Mat33 K;
+ K.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB;
+ K.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB;
+ K.ez.x = -m_rA.y * iA - m_rB.y * iB;
+ K.ex.y = K.ey.x;
+ K.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB;
+ K.ez.y = m_rA.x * iA + m_rB.x * iB;
+ K.ex.z = K.ez.x;
+ K.ey.z = K.ez.y;
+ K.ez.z = iA + iB;
+
+ if (m_frequencyHz > 0.0f)
+ {
+ K.GetInverse22(&m_mass);
+
+ float32 invM = iA + iB;
+ float32 m = invM > 0.0f ? 1.0f / invM : 0.0f;
+
+ float32 C = aB - aA - m_referenceAngle;
+
+ // Frequency
+ float32 omega = 2.0f * b2_pi * m_frequencyHz;
+
+ // Damping coefficient
+ float32 d = 2.0f * m * m_dampingRatio * omega;
+
+ // Spring stiffness
+ float32 k = m * omega * omega;
+
+ // magic formulas
+ float32 h = data.step.dt;
+ m_gamma = h * (d + h * k);
+ m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f;
+ m_bias = C * h * k * m_gamma;
+
+ invM += m_gamma;
+ m_mass.ez.z = invM != 0.0f ? 1.0f / invM : 0.0f;
+ }
+ else if (K.ez.z == 0.0f)
+ {
+ K.GetInverse22(&m_mass);
+ m_gamma = 0.0f;
+ m_bias = 0.0f;
+ }
+ else
+ {
+ K.GetSymInverse33(&m_mass);
+ m_gamma = 0.0f;
+ m_bias = 0.0f;
+ }
+
+ if (data.step.warmStarting)
+ {
+ // Scale impulses to support a variable time step.
+ m_impulse *= data.step.dtRatio;
+
+ b2Vec2 P(m_impulse.x, m_impulse.y);
+
+ vA -= mA * P;
+ wA -= iA * (b2Cross(m_rA, P) + m_impulse.z);
+
+ vB += mB * P;
+ wB += iB * (b2Cross(m_rB, P) + m_impulse.z);
+ }
+ else
+ {
+ m_impulse.SetZero();
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2WeldJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ if (m_frequencyHz > 0.0f)
+ {
+ float32 Cdot2 = wB - wA;
+
+ float32 impulse2 = -m_mass.ez.z * (Cdot2 + m_bias + m_gamma * m_impulse.z);
+ m_impulse.z += impulse2;
+
+ wA -= iA * impulse2;
+ wB += iB * impulse2;
+
+ b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
+
+ b2Vec2 impulse1 = -b2Mul22(m_mass, Cdot1);
+ m_impulse.x += impulse1.x;
+ m_impulse.y += impulse1.y;
+
+ b2Vec2 P = impulse1;
+
+ vA -= mA * P;
+ wA -= iA * b2Cross(m_rA, P);
+
+ vB += mB * P;
+ wB += iB * b2Cross(m_rB, P);
+ }
+ else
+ {
+ b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
+ float32 Cdot2 = wB - wA;
+ b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
+
+ b2Vec3 impulse = -b2Mul(m_mass, Cdot);
+ m_impulse += impulse;
+
+ b2Vec2 P(impulse.x, impulse.y);
+
+ vA -= mA * P;
+ wA -= iA * (b2Cross(m_rA, P) + impulse.z);
+
+ vB += mB * P;
+ wB += iB * (b2Cross(m_rB, P) + impulse.z);
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2WeldJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+
+ b2Rot qA(aA), qB(aB);
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+
+ float32 positionError, angularError;
+
+ b2Mat33 K;
+ K.ex.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
+ K.ey.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;
+ K.ez.x = -rA.y * iA - rB.y * iB;
+ K.ex.y = K.ey.x;
+ K.ey.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
+ K.ez.y = rA.x * iA + rB.x * iB;
+ K.ex.z = K.ez.x;
+ K.ey.z = K.ez.y;
+ K.ez.z = iA + iB;
+
+ if (m_frequencyHz > 0.0f)
+ {
+ b2Vec2 C1 = cB + rB - cA - rA;
+
+ positionError = C1.Length();
+ angularError = 0.0f;
+
+ b2Vec2 P = -K.Solve22(C1);
+
+ cA -= mA * P;
+ aA -= iA * b2Cross(rA, P);
+
+ cB += mB * P;
+ aB += iB * b2Cross(rB, P);
+ }
+ else
+ {
+ b2Vec2 C1 = cB + rB - cA - rA;
+ float32 C2 = aB - aA - m_referenceAngle;
+
+ positionError = C1.Length();
+ angularError = b2Abs(C2);
+
+ b2Vec3 C(C1.x, C1.y, C2);
+
+ b2Vec3 impulse;
+ if (K.ez.z > 0.0f)
+ {
+ impulse = -K.Solve33(C);
+ }
+ else
+ {
+ b2Vec2 impulse2 = -K.Solve22(C1);
+ impulse.Set(impulse2.x, impulse2.y, 0.0f);
+ }
+
+ b2Vec2 P(impulse.x, impulse.y);
+
+ cA -= mA * P;
+ aA -= iA * (b2Cross(rA, P) + impulse.z);
+
+ cB += mB * P;
+ aB += iB * (b2Cross(rB, P) + impulse.z);
+ }
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+
+ return positionError <= b2_linearSlop && angularError <= b2_angularSlop;
+}
+
+b2Vec2 b2WeldJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2WeldJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2WeldJoint::GetReactionForce(float32 inv_dt) const
+{
+ b2Vec2 P(m_impulse.x, m_impulse.y);
+ return inv_dt * P;
+}
+
+float32 b2WeldJoint::GetReactionTorque(float32 inv_dt) const
+{
+ return inv_dt * m_impulse.z;
+}
+
+void b2WeldJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2WeldJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle);
+ b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz);
+ b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WeldJoint.h b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WeldJoint.h
new file mode 100644
index 0000000..81ba235
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WeldJoint.h
@@ -0,0 +1,126 @@
+/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.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 B2_WELD_JOINT_H
+#define B2_WELD_JOINT_H
+
+#include "Box2D/Dynamics/Joints/b2Joint.h"
+
+/// Weld joint definition. You need to specify local anchor points
+/// where they are attached and the relative body angle. The position
+/// of the anchor points is important for computing the reaction torque.
+struct b2WeldJointDef : public b2JointDef
+{
+ b2WeldJointDef()
+ {
+ type = e_weldJoint;
+ localAnchorA.Set(0.0f, 0.0f);
+ localAnchorB.Set(0.0f, 0.0f);
+ referenceAngle = 0.0f;
+ frequencyHz = 0.0f;
+ dampingRatio = 0.0f;
+ }
+
+ /// Initialize the bodies, anchors, and reference angle using a world
+ /// anchor point.
+ void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The bodyB angle minus bodyA angle in the reference state (radians).
+ float32 referenceAngle;
+
+ /// The mass-spring-damper frequency in Hertz. Rotation only.
+ /// Disable softness with a value of 0.
+ float32 frequencyHz;
+
+ /// The damping ratio. 0 = no damping, 1 = critical damping.
+ float32 dampingRatio;
+};
+
+/// A weld joint essentially glues two bodies together. A weld joint may
+/// distort somewhat because the island constraint solver is approximate.
+class b2WeldJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const override;
+ b2Vec2 GetAnchorB() const override;
+
+ b2Vec2 GetReactionForce(float32 inv_dt) const override;
+ float32 GetReactionTorque(float32 inv_dt) const override;
+
+ /// The local anchor point relative to bodyA's origin.
+ const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
+
+ /// The local anchor point relative to bodyB's origin.
+ const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
+
+ /// Get the reference angle.
+ float32 GetReferenceAngle() const { return m_referenceAngle; }
+
+ /// Set/get frequency in Hz.
+ void SetFrequency(float32 hz) { m_frequencyHz = hz; }
+ float32 GetFrequency() const { return m_frequencyHz; }
+
+ /// Set/get damping ratio.
+ void SetDampingRatio(float32 ratio) { m_dampingRatio = ratio; }
+ float32 GetDampingRatio() const { return m_dampingRatio; }
+
+ /// Dump to b2Log
+ void Dump() override;
+
+protected:
+
+ friend class b2Joint;
+
+ b2WeldJoint(const b2WeldJointDef* def);
+
+ void InitVelocityConstraints(const b2SolverData& data) override;
+ void SolveVelocityConstraints(const b2SolverData& data) override;
+ bool SolvePositionConstraints(const b2SolverData& data) override;
+
+ float32 m_frequencyHz;
+ float32 m_dampingRatio;
+ float32 m_bias;
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ float32 m_referenceAngle;
+ float32 m_gamma;
+ b2Vec3 m_impulse;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_rA;
+ b2Vec2 m_rB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+ b2Mat33 m_mass;
+};
+
+#endif
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WheelJoint.cpp b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WheelJoint.cpp
new file mode 100644
index 0000000..a95311e
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WheelJoint.cpp
@@ -0,0 +1,456 @@
+/*
+* Copyright (c) 2006-2007 Erin Catto http://www.box2d.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 "Box2D/Dynamics/Joints/b2WheelJoint.h"
+#include "Box2D/Dynamics/b2Body.h"
+#include "Box2D/Dynamics/b2TimeStep.h"
+
+// Linear constraint (point-to-line)
+// d = pB - pA = xB + rB - xA - rA
+// C = dot(ay, d)
+// Cdot = dot(d, cross(wA, ay)) + dot(ay, vB + cross(wB, rB) - vA - cross(wA, rA))
+// = -dot(ay, vA) - dot(cross(d + rA, ay), wA) + dot(ay, vB) + dot(cross(rB, ay), vB)
+// J = [-ay, -cross(d + rA, ay), ay, cross(rB, ay)]
+
+// Spring linear constraint
+// C = dot(ax, d)
+// Cdot = = -dot(ax, vA) - dot(cross(d + rA, ax), wA) + dot(ax, vB) + dot(cross(rB, ax), vB)
+// J = [-ax -cross(d+rA, ax) ax cross(rB, ax)]
+
+// Motor rotational constraint
+// Cdot = wB - wA
+// J = [0 0 -1 0 0 1]
+
+void b2WheelJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis)
+{
+ bodyA = bA;
+ bodyB = bB;
+ localAnchorA = bodyA->GetLocalPoint(anchor);
+ localAnchorB = bodyB->GetLocalPoint(anchor);
+ localAxisA = bodyA->GetLocalVector(axis);
+}
+
+b2WheelJoint::b2WheelJoint(const b2WheelJointDef* def)
+: b2Joint(def)
+{
+ m_localAnchorA = def->localAnchorA;
+ m_localAnchorB = def->localAnchorB;
+ m_localXAxisA = def->localAxisA;
+ m_localYAxisA = b2Cross(1.0f, m_localXAxisA);
+
+ m_mass = 0.0f;
+ m_impulse = 0.0f;
+ m_motorMass = 0.0f;
+ m_motorImpulse = 0.0f;
+ m_springMass = 0.0f;
+ m_springImpulse = 0.0f;
+
+ m_maxMotorTorque = def->maxMotorTorque;
+ m_motorSpeed = def->motorSpeed;
+ m_enableMotor = def->enableMotor;
+
+ m_frequencyHz = def->frequencyHz;
+ m_dampingRatio = def->dampingRatio;
+
+ m_bias = 0.0f;
+ m_gamma = 0.0f;
+
+ m_ax.SetZero();
+ m_ay.SetZero();
+}
+
+void b2WheelJoint::InitVelocityConstraints(const b2SolverData& data)
+{
+ m_indexA = m_bodyA->m_islandIndex;
+ m_indexB = m_bodyB->m_islandIndex;
+ m_localCenterA = m_bodyA->m_sweep.localCenter;
+ m_localCenterB = m_bodyB->m_sweep.localCenter;
+ m_invMassA = m_bodyA->m_invMass;
+ m_invMassB = m_bodyB->m_invMass;
+ m_invIA = m_bodyA->m_invI;
+ m_invIB = m_bodyB->m_invI;
+
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ b2Rot qA(aA), qB(aB);
+
+ // Compute the effective masses.
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ b2Vec2 d = cB + rB - cA - rA;
+
+ // Point to line constraint
+ {
+ m_ay = b2Mul(qA, m_localYAxisA);
+ m_sAy = b2Cross(d + rA, m_ay);
+ m_sBy = b2Cross(rB, m_ay);
+
+ m_mass = mA + mB + iA * m_sAy * m_sAy + iB * m_sBy * m_sBy;
+
+ if (m_mass > 0.0f)
+ {
+ m_mass = 1.0f / m_mass;
+ }
+ }
+
+ // Spring constraint
+ m_springMass = 0.0f;
+ m_bias = 0.0f;
+ m_gamma = 0.0f;
+ if (m_frequencyHz > 0.0f)
+ {
+ m_ax = b2Mul(qA, m_localXAxisA);
+ m_sAx = b2Cross(d + rA, m_ax);
+ m_sBx = b2Cross(rB, m_ax);
+
+ float32 invMass = mA + mB + iA * m_sAx * m_sAx + iB * m_sBx * m_sBx;
+
+ if (invMass > 0.0f)
+ {
+ m_springMass = 1.0f / invMass;
+
+ float32 C = b2Dot(d, m_ax);
+
+ // Frequency
+ float32 omega = 2.0f * b2_pi * m_frequencyHz;
+
+ // Damping coefficient
+ float32 damp = 2.0f * m_springMass * m_dampingRatio * omega;
+
+ // Spring stiffness
+ float32 k = m_springMass * omega * omega;
+
+ // magic formulas
+ float32 h = data.step.dt;
+ m_gamma = h * (damp + h * k);
+ if (m_gamma > 0.0f)
+ {
+ m_gamma = 1.0f / m_gamma;
+ }
+
+ m_bias = C * h * k * m_gamma;
+
+ m_springMass = invMass + m_gamma;
+ if (m_springMass > 0.0f)
+ {
+ m_springMass = 1.0f / m_springMass;
+ }
+ }
+ }
+ else
+ {
+ m_springImpulse = 0.0f;
+ }
+
+ // Rotational motor
+ if (m_enableMotor)
+ {
+ m_motorMass = iA + iB;
+ if (m_motorMass > 0.0f)
+ {
+ m_motorMass = 1.0f / m_motorMass;
+ }
+ }
+ else
+ {
+ m_motorMass = 0.0f;
+ m_motorImpulse = 0.0f;
+ }
+
+ if (data.step.warmStarting)
+ {
+ // Account for variable time step.
+ m_impulse *= data.step.dtRatio;
+ m_springImpulse *= data.step.dtRatio;
+ m_motorImpulse *= data.step.dtRatio;
+
+ b2Vec2 P = m_impulse * m_ay + m_springImpulse * m_ax;
+ float32 LA = m_impulse * m_sAy + m_springImpulse * m_sAx + m_motorImpulse;
+ float32 LB = m_impulse * m_sBy + m_springImpulse * m_sBx + m_motorImpulse;
+
+ vA -= m_invMassA * P;
+ wA -= m_invIA * LA;
+
+ vB += m_invMassB * P;
+ wB += m_invIB * LB;
+ }
+ else
+ {
+ m_impulse = 0.0f;
+ m_springImpulse = 0.0f;
+ m_motorImpulse = 0.0f;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+void b2WheelJoint::SolveVelocityConstraints(const b2SolverData& data)
+{
+ float32 mA = m_invMassA, mB = m_invMassB;
+ float32 iA = m_invIA, iB = m_invIB;
+
+ b2Vec2 vA = data.velocities[m_indexA].v;
+ float32 wA = data.velocities[m_indexA].w;
+ b2Vec2 vB = data.velocities[m_indexB].v;
+ float32 wB = data.velocities[m_indexB].w;
+
+ // Solve spring constraint
+ {
+ float32 Cdot = b2Dot(m_ax, vB - vA) + m_sBx * wB - m_sAx * wA;
+ float32 impulse = -m_springMass * (Cdot + m_bias + m_gamma * m_springImpulse);
+ m_springImpulse += impulse;
+
+ b2Vec2 P = impulse * m_ax;
+ float32 LA = impulse * m_sAx;
+ float32 LB = impulse * m_sBx;
+
+ vA -= mA * P;
+ wA -= iA * LA;
+
+ vB += mB * P;
+ wB += iB * LB;
+ }
+
+ // Solve rotational motor constraint
+ {
+ float32 Cdot = wB - wA - m_motorSpeed;
+ float32 impulse = -m_motorMass * Cdot;
+
+ float32 oldImpulse = m_motorImpulse;
+ float32 maxImpulse = data.step.dt * m_maxMotorTorque;
+ m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
+ impulse = m_motorImpulse - oldImpulse;
+
+ wA -= iA * impulse;
+ wB += iB * impulse;
+ }
+
+ // Solve point to line constraint
+ {
+ float32 Cdot = b2Dot(m_ay, vB - vA) + m_sBy * wB - m_sAy * wA;
+ float32 impulse = -m_mass * Cdot;
+ m_impulse += impulse;
+
+ b2Vec2 P = impulse * m_ay;
+ float32 LA = impulse * m_sAy;
+ float32 LB = impulse * m_sBy;
+
+ vA -= mA * P;
+ wA -= iA * LA;
+
+ vB += mB * P;
+ wB += iB * LB;
+ }
+
+ data.velocities[m_indexA].v = vA;
+ data.velocities[m_indexA].w = wA;
+ data.velocities[m_indexB].v = vB;
+ data.velocities[m_indexB].w = wB;
+}
+
+bool b2WheelJoint::SolvePositionConstraints(const b2SolverData& data)
+{
+ b2Vec2 cA = data.positions[m_indexA].c;
+ float32 aA = data.positions[m_indexA].a;
+ b2Vec2 cB = data.positions[m_indexB].c;
+ float32 aB = data.positions[m_indexB].a;
+
+ b2Rot qA(aA), qB(aB);
+
+ b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
+ b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
+ b2Vec2 d = (cB - cA) + rB - rA;
+
+ b2Vec2 ay = b2Mul(qA, m_localYAxisA);
+
+ float32 sAy = b2Cross(d + rA, ay);
+ float32 sBy = b2Cross(rB, ay);
+
+ float32 C = b2Dot(d, ay);
+
+ float32 k = m_invMassA + m_invMassB + m_invIA * m_sAy * m_sAy + m_invIB * m_sBy * m_sBy;
+
+ float32 impulse;
+ if (k != 0.0f)
+ {
+ impulse = - C / k;
+ }
+ else
+ {
+ impulse = 0.0f;
+ }
+
+ b2Vec2 P = impulse * ay;
+ float32 LA = impulse * sAy;
+ float32 LB = impulse * sBy;
+
+ cA -= m_invMassA * P;
+ aA -= m_invIA * LA;
+ cB += m_invMassB * P;
+ aB += m_invIB * LB;
+
+ data.positions[m_indexA].c = cA;
+ data.positions[m_indexA].a = aA;
+ data.positions[m_indexB].c = cB;
+ data.positions[m_indexB].a = aB;
+
+ return b2Abs(C) <= b2_linearSlop;
+}
+
+b2Vec2 b2WheelJoint::GetAnchorA() const
+{
+ return m_bodyA->GetWorldPoint(m_localAnchorA);
+}
+
+b2Vec2 b2WheelJoint::GetAnchorB() const
+{
+ return m_bodyB->GetWorldPoint(m_localAnchorB);
+}
+
+b2Vec2 b2WheelJoint::GetReactionForce(float32 inv_dt) const
+{
+ return inv_dt * (m_impulse * m_ay + m_springImpulse * m_ax);
+}
+
+float32 b2WheelJoint::GetReactionTorque(float32 inv_dt) const
+{
+ return inv_dt * m_motorImpulse;
+}
+
+float32 b2WheelJoint::GetJointTranslation() const
+{
+ b2Body* bA = m_bodyA;
+ b2Body* bB = m_bodyB;
+
+ b2Vec2 pA = bA->GetWorldPoint(m_localAnchorA);
+ b2Vec2 pB = bB->GetWorldPoint(m_localAnchorB);
+ b2Vec2 d = pB - pA;
+ b2Vec2 axis = bA->GetWorldVector(m_localXAxisA);
+
+ float32 translation = b2Dot(d, axis);
+ return translation;
+}
+
+float32 b2WheelJoint::GetJointLinearSpeed() const
+{
+ b2Body* bA = m_bodyA;
+ b2Body* bB = m_bodyB;
+
+ b2Vec2 rA = b2Mul(bA->m_xf.q, m_localAnchorA - bA->m_sweep.localCenter);
+ b2Vec2 rB = b2Mul(bB->m_xf.q, m_localAnchorB - bB->m_sweep.localCenter);
+ b2Vec2 p1 = bA->m_sweep.c + rA;
+ b2Vec2 p2 = bB->m_sweep.c + rB;
+ b2Vec2 d = p2 - p1;
+ b2Vec2 axis = b2Mul(bA->m_xf.q, m_localXAxisA);
+
+ b2Vec2 vA = bA->m_linearVelocity;
+ b2Vec2 vB = bB->m_linearVelocity;
+ float32 wA = bA->m_angularVelocity;
+ float32 wB = bB->m_angularVelocity;
+
+ float32 speed = b2Dot(d, b2Cross(wA, axis)) + b2Dot(axis, vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA));
+ return speed;
+}
+
+float32 b2WheelJoint::GetJointAngle() const
+{
+ b2Body* bA = m_bodyA;
+ b2Body* bB = m_bodyB;
+ return bB->m_sweep.a - bA->m_sweep.a;
+}
+
+float32 b2WheelJoint::GetJointAngularSpeed() const
+{
+ float32 wA = m_bodyA->m_angularVelocity;
+ float32 wB = m_bodyB->m_angularVelocity;
+ return wB - wA;
+}
+
+bool b2WheelJoint::IsMotorEnabled() const
+{
+ return m_enableMotor;
+}
+
+void b2WheelJoint::EnableMotor(bool flag)
+{
+ if (flag != m_enableMotor)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_enableMotor = flag;
+ }
+}
+
+void b2WheelJoint::SetMotorSpeed(float32 speed)
+{
+ if (speed != m_motorSpeed)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_motorSpeed = speed;
+ }
+}
+
+void b2WheelJoint::SetMaxMotorTorque(float32 torque)
+{
+ if (torque != m_maxMotorTorque)
+ {
+ m_bodyA->SetAwake(true);
+ m_bodyB->SetAwake(true);
+ m_maxMotorTorque = torque;
+ }
+}
+
+float32 b2WheelJoint::GetMotorTorque(float32 inv_dt) const
+{
+ return inv_dt * m_motorImpulse;
+}
+
+void b2WheelJoint::Dump()
+{
+ int32 indexA = m_bodyA->m_islandIndex;
+ int32 indexB = m_bodyB->m_islandIndex;
+
+ b2Log(" b2WheelJointDef jd;\n");
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
+ b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y);
+ b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor);
+ b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed);
+ b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque);
+ b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz);
+ b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio);
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
+}
diff --git a/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WheelJoint.h b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WheelJoint.h
new file mode 100644
index 0000000..be7ad66
--- /dev/null
+++ b/src/libjin/3rdparty/Box2D/Dynamics/Joints/b2WheelJoint.h
@@ -0,0 +1,216 @@
+/*
+* Copyright (c) 2006-2011 Erin Catto http://www.box2d.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 B2_WHEEL_JOINT_H
+#define B2_WHEEL_JOINT_H
+
+#include "Box2D/Dynamics/Joints/b2Joint.h"
+
+/// Wheel joint definition. This requires defining a line of
+/// motion using an axis and an anchor point. The definition uses local
+/// anchor points and a local axis so that the initial configuration
+/// can violate the constraint slightly. The joint translation is zero
+/// when the local anchor points coincide in world space. Using local
+/// anchors and a local axis helps when saving and loading a game.
+struct b2WheelJointDef : public b2JointDef
+{
+ b2WheelJointDef()
+ {
+ type = e_wheelJoint;
+ localAnchorA.SetZero();
+ localAnchorB.SetZero();
+ localAxisA.Set(1.0f, 0.0f);
+ enableMotor = false;
+ maxMotorTorque = 0.0f;
+ motorSpeed = 0.0f;
+ frequencyHz = 2.0f;
+ dampingRatio = 0.7f;
+ }
+
+ /// Initialize the bodies, anchors, axis, and reference angle using the world
+ /// anchor and world axis.
+ void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis);
+
+ /// The local anchor point relative to bodyA's origin.
+ b2Vec2 localAnchorA;
+
+ /// The local anchor point relative to bodyB's origin.
+ b2Vec2 localAnchorB;
+
+ /// The local translation axis in bodyA.
+ b2Vec2 localAxisA;
+
+ /// Enable/disable the joint motor.
+ bool enableMotor;
+
+ /// The maximum motor torque, usually in N-m.
+ float32 maxMotorTorque;
+
+ /// The desired motor speed in radians per second.
+ float32 motorSpeed;
+
+ /// Suspension frequency, zero indicates no suspension
+ float32 frequencyHz;
+
+ /// Suspension damping ratio, one indicates critical damping
+ float32 dampingRatio;
+};
+
+/// A wheel joint. This joint provides two degrees of freedom: translation
+/// along an axis fixed in bodyA and rotation in the plane. In other words, it is a point to
+/// line constraint with a rotational motor and a linear spring/damper.
+/// This joint is designed for vehicle suspensions.
+class b2WheelJoint : public b2Joint
+{
+public:
+ b2Vec2 GetAnchorA() const override;
+ b2Vec2 GetAnchorB() const override;
+
+ b2Vec2 GetReactionForce(float32 inv_dt) const override;
+ float32 GetReactionTorque(float32 inv_dt) const override;
+
+ /// The local anchor point relative to bodyA's origin.
+ const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
+
+ /// The local anchor point relative to bodyB's origin.
+ const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
+
+ /// The local joint axis relative to bodyA.
+ const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; }
+
+ /// Get the current joint translation, usually in meters.
+ float32 GetJointTranslation() const;
+
+ /// Get the current joint linear speed, usually in meters per second.
+ float32 GetJointLinearSpeed() const;
+
+ /// Get the current joint angle in radians.
+ float32 GetJointAngle() const;
+
+ /// Get the current joint angular speed in radians per second.
+ float32 GetJointAngularSpeed() const;
+
+ /// Is the joint motor enabled?
+ bool IsMotorEnabled() const;
+
+ /// Enable/disable the joint motor.
+ void EnableMotor(bool flag);
+
+ /// Set the motor speed, usually in radians per second.
+ void SetMotorSpeed(float32 speed);
+
+ /// Get the motor speed, usually in radians per second.
+ float32 GetMotorSpeed() const;
+
+ /// Set/Get the maximum motor force, usually in N-m.
+ void SetMaxMotorTorque(float32 torque);
+ float32 GetMaxMotorTorque() const;
+
+ /// Get the current motor torque given the inverse time step, usually in N-m.
+ float32 GetMotorTorque(float32 inv_dt) const;
+
+ /// Set/Get the spring frequency in hertz. Setting the frequency to zero disables the spring.
+ void SetSpringFrequencyHz(float32 hz);
+ float32 GetSpringFrequencyHz() const;
+
+ /// Set/Get the spring damping ratio
+ void SetSpringDampingRatio(float32 ratio);
+ float32 GetSpringDampingRatio() const;
+
+ /// Dump to b2Log
+ void Dump() override;
+
+protected:
+
+ friend class b2Joint;
+ b2WheelJoint(const b2WheelJointDef* def);
+
+ void InitVelocityConstraints(const b2SolverData& data) override;
+ void SolveVelocityConstraints(const b2SolverData& data) override;
+ bool SolvePositionConstraints(const b2SolverData& data) override;
+
+ float32 m_frequencyHz;
+ float32 m_dampingRatio;
+
+ // Solver shared
+ b2Vec2 m_localAnchorA;
+ b2Vec2 m_localAnchorB;
+ b2Vec2 m_localXAxisA;
+ b2Vec2 m_localYAxisA;
+
+ float32 m_impulse;
+ float32 m_motorImpulse;
+ float32 m_springImpulse;
+
+ float32 m_maxMotorTorque;
+ float32 m_motorSpeed;
+ bool m_enableMotor;
+
+ // Solver temp
+ int32 m_indexA;
+ int32 m_indexB;
+ b2Vec2 m_localCenterA;
+ b2Vec2 m_localCenterB;
+ float32 m_invMassA;
+ float32 m_invMassB;
+ float32 m_invIA;
+ float32 m_invIB;
+
+ b2Vec2 m_ax, m_ay;
+ float32 m_sAx, m_sBx;
+ float32 m_sAy, m_sBy;
+
+ float32 m_mass;
+ float32 m_motorMass;
+ float32 m_springMass;
+
+ float32 m_bias;
+ float32 m_gamma;
+};
+
+inline float32 b2WheelJoint::GetMotorSpeed() const
+{
+ return m_motorSpeed;
+}
+
+inline float32 b2WheelJoint::GetMaxMotorTorque() const
+{
+ return m_maxMotorTorque;
+}
+
+inline void b2WheelJoint::SetSpringFrequencyHz(float32 hz)
+{
+ m_frequencyHz = hz;
+}
+
+inline float32 b2WheelJoint::GetSpringFrequencyHz() const
+{
+ return m_frequencyHz;
+}
+
+inline void b2WheelJoint::SetSpringDampingRatio(float32 ratio)
+{
+ m_dampingRatio = ratio;
+}
+
+inline float32 b2WheelJoint::GetSpringDampingRatio() const
+{
+ return m_dampingRatio;
+}
+
+#endif