#include "body.h"
#include "core.h"
#include "joint.h"
#include "math_internal.h"
#include "physics_world.h"
#include "solver.h"
#include "solver_set.h"
#include "recording.h"
#include "box3d/box3d.h"
void b3PrismaticJoint_EnableLimit( b3JointId jointId, bool enableLimit )
{
b3World* world = b3GetWorld( jointId.world0 );
B3_REC( world, PrismaticJointEnableLimit, jointId, enableLimit );
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
if ( enableLimit != base->prismaticJoint.enableLimit )
{
base->prismaticJoint.lowerImpulse = 0.0f;
base->prismaticJoint.upperImpulse = 0.0f;
}
base->prismaticJoint.enableLimit = enableLimit;
}
bool b3PrismaticJoint_IsLimitEnabled( b3JointId jointId )
{
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
return base->prismaticJoint.enableLimit;
}
float b3PrismaticJoint_GetLowerLimit( b3JointId jointId )
{
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
return base->prismaticJoint.lowerTranslation;
}
float b3PrismaticJoint_GetUpperLimit( b3JointId jointId )
{
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
return base->prismaticJoint.upperTranslation;
}
void b3PrismaticJoint_SetLimits( b3JointId jointId, float lower, float upper )
{
B3_ASSERT( b3IsValidFloat( lower ) && b3IsValidFloat( upper ) );
b3World* world = b3GetWorld( jointId.world0 );
B3_REC( world, PrismaticJointSetLimits, jointId, lower, upper );
float lowerAngle = b3MinFloat( lower, upper );
float upperAngle = b3MaxFloat( lower, upper );
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
base->prismaticJoint.lowerTranslation = lowerAngle;
base->prismaticJoint.upperTranslation = upperAngle;
}
float b3PrismaticJoint_GetTranslation( b3JointId jointId )
{
b3World* world = b3GetWorld( jointId.world0 );
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
b3WorldTransform transformA = b3GetBodyTransform( world, base->bodyIdA );
b3WorldTransform transformB = b3GetBodyTransform( world, base->bodyIdB );
b3Vec3 jointAxis = b3RotateVector( base->localFrameA.q, b3Vec3_axisX );
jointAxis = b3RotateVector( transformA.q, jointAxis );
b3Vec3 anchorA = b3RotateVector( transformA.q, base->localFrameA.p );
b3Vec3 anchorB = b3RotateVector( transformB.q, base->localFrameB.p );
b3Vec3 d = b3Add( b3SubPos( transformB.p, transformA.p ), b3Sub( anchorB, anchorA ) );
float translation = b3Dot( d, jointAxis );
return translation;
}
void b3PrismaticJoint_EnableSpring( b3JointId jointId, bool enableSpring )
{
b3World* world = b3GetWorld( jointId.world0 );
B3_REC( world, PrismaticJointEnableSpring, jointId, enableSpring );
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
if ( enableSpring != base->prismaticJoint.enableSpring )
{
base->prismaticJoint.springImpulse = 0.0f;
}
base->prismaticJoint.enableSpring = enableSpring;
}
bool b3PrismaticJoint_IsSpringEnabled( b3JointId jointId )
{
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
return base->prismaticJoint.enableSpring;
}
void b3PrismaticJoint_SetTargetTranslation( b3JointId jointId, float targetTranslation )
{
B3_ASSERT( b3IsValidFloat( targetTranslation ) );
b3World* world = b3GetWorld( jointId.world0 );
B3_REC( world, PrismaticJointSetTargetTranslation, jointId, targetTranslation );
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
base->prismaticJoint.targetTranslation = targetTranslation;
}
float b3PrismaticJoint_GetTargetTranslation( b3JointId jointId )
{
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
return base->prismaticJoint.targetTranslation;
}
void b3PrismaticJoint_SetSpringHertz( b3JointId jointId, float hertz )
{
B3_ASSERT( b3IsValidFloat( hertz ) && hertz >= 0.0f );
b3World* world = b3GetWorld( jointId.world0 );
B3_REC( world, PrismaticJointSetSpringHertz, jointId, hertz );
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
base->prismaticJoint.hertz = hertz;
}
float b3PrismaticJoint_GetSpringHertz( b3JointId jointId )
{
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
return base->prismaticJoint.hertz;
}
void b3PrismaticJoint_SetSpringDampingRatio( b3JointId jointId, float dampingRatio )
{
B3_ASSERT( b3IsValidFloat( dampingRatio ) && dampingRatio >= 0.0f );
b3World* world = b3GetWorld( jointId.world0 );
B3_REC( world, PrismaticJointSetSpringDampingRatio, jointId, dampingRatio );
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
base->prismaticJoint.dampingRatio = dampingRatio;
}
float b3PrismaticJoint_GetSpringDampingRatio( b3JointId jointId )
{
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
return base->prismaticJoint.dampingRatio;
}
void b3PrismaticJoint_EnableMotor( b3JointId jointId, bool enableMotor )
{
b3World* world = b3GetWorld( jointId.world0 );
B3_REC( world, PrismaticJointEnableMotor, jointId, enableMotor );
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
if ( enableMotor != base->prismaticJoint.enableMotor )
{
base->prismaticJoint.motorImpulse = 0.0f;
}
base->prismaticJoint.enableMotor = enableMotor;
}
bool b3PrismaticJoint_IsMotorEnabled( b3JointId jointId )
{
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
return base->prismaticJoint.enableMotor;
}
void b3PrismaticJoint_SetMotorSpeed( b3JointId jointId, float motorSpeed )
{
B3_ASSERT( b3IsValidFloat( motorSpeed ) );
b3World* world = b3GetWorld( jointId.world0 );
B3_REC( world, PrismaticJointSetMotorSpeed, jointId, motorSpeed );
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
base->prismaticJoint.motorSpeed = motorSpeed;
}
float b3PrismaticJoint_GetMotorSpeed( b3JointId jointId )
{
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
return base->prismaticJoint.motorSpeed;
}
void b3PrismaticJoint_SetMaxMotorForce( b3JointId jointId, float maxForce )
{
B3_ASSERT( b3IsValidFloat( maxForce ) && maxForce >= 0.0f );
b3World* world = b3GetWorld( jointId.world0 );
B3_REC( world, PrismaticJointSetMaxMotorForce, jointId, maxForce );
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
base->prismaticJoint.maxMotorForce = maxForce;
}
float b3PrismaticJoint_GetMaxMotorForce( b3JointId jointId )
{
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
return base->prismaticJoint.maxMotorForce;
}
float b3PrismaticJoint_GetMotorForce( b3JointId jointId )
{
b3World* world = b3GetWorld( jointId.world0 );
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
return world->inv_h * base->prismaticJoint.motorImpulse;
}
float b3PrismaticJoint_GetSpeed( b3JointId jointId )
{
b3World* world = b3GetWorld( jointId.world0 );
b3JointSim* base = b3GetJointSimCheckType( jointId, b3_prismaticJoint );
b3Body* bodyA = b3Array_Get( world->bodies, base->bodyIdA );
b3Body* bodyB = b3Array_Get( world->bodies, base->bodyIdB );
b3BodySim* bodySimA = b3GetBodySim( world, bodyA );
b3BodySim* bodySimB = b3GetBodySim( world, bodyB );
b3BodyState* stateA = b3GetBodyState( world, bodyA );
b3BodyState* stateB = b3GetBodyState( world, bodyB );
b3Quat qA = bodySimA->transform.q;
b3Quat qB = bodySimB->transform.q;
b3Vec3 axisA = b3RotateVector( qA, b3RotateVector( base->localFrameA.q, b3Vec3_axisX ) );
b3Vec3 rA = b3RotateVector( qA, b3Sub( base->localFrameA.p, bodySimA->localCenter ) );
b3Vec3 rB = b3RotateVector( qB, b3Sub( base->localFrameB.p, bodySimB->localCenter ) );
b3Vec3 d = b3Add( b3SubPos( bodySimB->center, bodySimA->center ), b3Sub( rB, rA ) );
b3Vec3 vA = stateA ? stateA->linearVelocity : b3Vec3_zero;
b3Vec3 vB = stateB ? stateB->linearVelocity : b3Vec3_zero;
b3Vec3 wA = stateA ? stateA->angularVelocity : b3Vec3_zero;
b3Vec3 wB = stateB ? stateB->angularVelocity : b3Vec3_zero;
b3Vec3 vRel = b3Sub( b3Add( vB, b3Cross( wB, rB ) ), b3Add( vA, b3Cross( wA, rA ) ) );
float speed = b3Dot( d, b3Cross( wA, axisA ) ) + b3Dot( axisA, vRel );
return speed;
}
b3Vec3 b3GetPrismaticJointForce( b3World* world, b3JointSim* base )
{
b3WorldTransform transformA = b3GetBodyTransform( world, base->bodyIdA );
b3PrismaticJoint* joint = &base->prismaticJoint;
b3Vec3 impulse = {
joint->perpImpulse.x,
joint->perpImpulse.y,
joint->motorImpulse + joint->lowerImpulse + joint->upperImpulse + joint->springImpulse,
};
b3Vec3 force = b3MulSV( world->inv_h, impulse );
force = b3RotateVector( base->localFrameA.q, force );
force = b3RotateVector( transformA.q, force );
return force;
}
b3Vec3 b3GetPrismaticJointTorque( b3World* world, b3JointSim* base )
{
b3WorldTransform transformA = b3GetBodyTransform( world, base->bodyIdA );
b3PrismaticJoint* joint = &base->prismaticJoint;
b3Vec3 torque = b3MulSV( world->inv_h, joint->angularImpulse );
torque = b3RotateVector( base->localFrameA.q, torque );
torque = b3RotateVector( transformA.q, torque );
return torque;
}
void b3PreparePrismaticJoint( b3JointSim* base, b3StepContext* context )
{
B3_ASSERT( base->type == b3_prismaticJoint );
b3World* world = context->world;
b3Body* bodyA = b3Array_Get( world->bodies, base->bodyIdA );
b3Body* bodyB = b3Array_Get( world->bodies, base->bodyIdB );
B3_ASSERT( bodyB->setIndex == b3_awakeSet );
b3SolverSet* setA = b3Array_Get( world->solverSets, bodyA->setIndex );
b3SolverSet* setB = b3Array_Get( world->solverSets, bodyB->setIndex );
int localIndexA = bodyA->localIndex;
int localIndexB = bodyB->localIndex;
b3BodySim* bodySimA = b3Array_Get( setA->bodySims, localIndexA );
b3BodySim* bodySimB = b3Array_Get( setB->bodySims, localIndexB );
base->invMassA = bodySimA->invMass;
base->invMassB = bodySimB->invMass;
base->invIA = bodySimA->invInertiaWorld;
base->invIB = bodySimB->invInertiaWorld;
b3Matrix3 invInertiaSum = b3AddMM( base->invIA, base->invIB );
base->fixedRotation = b3Det( invInertiaSum ) < 1000.0f * FLT_MIN;
b3PrismaticJoint* joint = &base->prismaticJoint;
joint->indexA = bodyA->setIndex == b3_awakeSet ? localIndexA : B3_NULL_INDEX;
joint->indexB = bodyB->setIndex == b3_awakeSet ? localIndexB : B3_NULL_INDEX;
joint->frameA.q = b3MulQuat( bodySimA->transform.q, base->localFrameA.q );
joint->frameA.p = b3RotateVector( bodySimA->transform.q, b3Sub( base->localFrameA.p, bodySimA->localCenter ) );
joint->frameB.q = b3MulQuat( bodySimB->transform.q, base->localFrameB.q );
joint->frameB.p = b3RotateVector( bodySimB->transform.q, b3Sub( base->localFrameB.p, bodySimB->localCenter ) );
joint->deltaCenter = b3SubPos( bodySimB->center, bodySimA->center );
joint->rotationMass = b3InvertMatrix( invInertiaSum );
b3Matrix3 matrixA = b3MakeMatrixFromQuat( joint->frameA.q );
joint->jointAxis = matrixA.cx;
joint->perpAxisY = matrixA.cy;
joint->perpAxisZ = matrixA.cz;
joint->springSoftness = b3MakeSoft( joint->hertz, joint->dampingRatio, context->h );
if ( context->enableWarmStarting == false )
{
joint->perpImpulse = (b3Vec2){ 0.0f, 0.0f };
joint->angularImpulse = (b3Vec3){ 0.0f, 0.0f, 0.0f };
joint->motorImpulse = 0.0f;
joint->springImpulse = 0.0f;
joint->lowerImpulse = 0.0f;
joint->upperImpulse = 0.0f;
}
}
void b3WarmStartPrismaticJoint( b3JointSim* base, b3StepContext* context )
{
B3_ASSERT( base->type == b3_prismaticJoint );
float mA = base->invMassA;
float mB = base->invMassB;
b3Matrix3 iA = base->invIA;
b3Matrix3 iB = base->invIB;
b3BodyState dummyState = b3_identityBodyState;
b3PrismaticJoint* joint = &base->prismaticJoint;
b3BodyState* stateA = joint->indexA == B3_NULL_INDEX ? &dummyState : context->states + joint->indexA;
b3BodyState* stateB = joint->indexB == B3_NULL_INDEX ? &dummyState : context->states + joint->indexB;
b3Vec3 rA = b3RotateVector( stateA->deltaRotation, joint->frameA.p );
b3Vec3 rB = b3RotateVector( stateB->deltaRotation, joint->frameB.p );
b3Vec3 d = b3Add( b3Add( b3Sub( stateB->deltaPosition, stateA->deltaPosition ), joint->deltaCenter ), b3Sub( rB, rA ) );
b3Vec3 jointAxis = b3RotateVector( stateA->deltaRotation, joint->jointAxis );
b3Vec3 sAx = b3Cross( b3Add( rA, d ), jointAxis );
b3Vec3 sBx = b3Cross( rB, jointAxis );
b3Vec3 perpY = b3RotateVector( stateA->deltaRotation, joint->perpAxisY );
b3Vec3 perpZ = b3RotateVector( stateA->deltaRotation, joint->perpAxisZ );
b3Vec3 sAy = b3Cross( b3Add( rA, d ), perpY );
b3Vec3 sBy = b3Cross( rB, perpY );
b3Vec3 sAz = b3Cross( b3Add( rA, d ), perpZ );
b3Vec3 sBz = b3Cross( rB, perpZ );
float axialImpulse = joint->springImpulse + joint->motorImpulse + joint->lowerImpulse - joint->upperImpulse;
b3Vec2 perpImpulse = joint->perpImpulse;
b3Vec3 P = b3Blend3( axialImpulse, jointAxis, perpImpulse.x, perpY, perpImpulse.y, perpZ );
b3Vec3 LA = b3Add( b3Blend3( axialImpulse, sAx, perpImpulse.x, sAy, perpImpulse.y, sAz ), joint->angularImpulse );
b3Vec3 LB = b3Add( b3Blend3( axialImpulse, sBx, perpImpulse.x, sBy, perpImpulse.y, sBz ), joint->angularImpulse );
b3Vec3 vA = stateA->linearVelocity;
b3Vec3 wA = stateA->angularVelocity;
b3Vec3 vB = stateB->linearVelocity;
b3Vec3 wB = stateB->angularVelocity;
vA = b3MulSub( vA, mA, P );
wA = b3Sub( wA, b3MulMV( iA, LA ) );
vB = b3MulAdd( vB, mB, P );
wB = b3Add( wB, b3MulMV( iB, LB ) );
if ( stateA->flags & b3_dynamicFlag )
{
stateA->linearVelocity = vA;
stateA->angularVelocity = wA;
}
if ( stateB->flags & b3_dynamicFlag )
{
stateB->linearVelocity = vB;
stateB->angularVelocity = wB;
}
}
void b3SolvePrismaticJoint( b3JointSim* base, b3StepContext* context, bool useBias )
{
float mA = base->invMassA;
float mB = base->invMassB;
b3Matrix3 iA = base->invIA;
b3Matrix3 iB = base->invIB;
b3BodyState dummyState = b3_identityBodyState;
b3PrismaticJoint* joint = &base->prismaticJoint;
b3BodyState* stateA = joint->indexA == B3_NULL_INDEX ? &dummyState : context->states + joint->indexA;
b3BodyState* stateB = joint->indexB == B3_NULL_INDEX ? &dummyState : context->states + joint->indexB;
b3Vec3 vA = stateA->linearVelocity;
b3Vec3 wA = stateA->angularVelocity;
b3Vec3 vB = stateB->linearVelocity;
b3Vec3 wB = stateB->angularVelocity;
bool fixedRotation = base->fixedRotation;
b3Vec3 rA = b3RotateVector( stateA->deltaRotation, joint->frameA.p );
b3Vec3 rB = b3RotateVector( stateB->deltaRotation, joint->frameB.p );
b3Vec3 dcA = stateA->deltaPosition;
b3Vec3 dcB = stateB->deltaPosition;
b3Vec3 d = b3Add( b3Add( b3Sub( dcB, dcA ), joint->deltaCenter ), b3Sub( rB, rA ) );
b3Vec3 jointAxis = b3RotateVector( stateA->deltaRotation, joint->jointAxis );
b3Vec3 sAx = b3Cross( b3Add( rA, d ), jointAxis );
b3Vec3 sBx = b3Cross( rB, jointAxis );
float jointTranslation = b3Dot( d, jointAxis );
float targetTranslation = joint->targetTranslation;
float ka = mA + mB + b3Dot( sAx, b3MulMV( iA, sAx ) ) + b3Dot( sBx, b3MulMV( iB, sBx ) );
float axialMass = ka > 0.0f ? 1.0f / ka : 0.0f;
if ( joint->enableSpring && fixedRotation == false )
{
float c = jointTranslation - targetTranslation;
float bias = joint->springSoftness.biasRate * c;
float massScale = joint->springSoftness.massScale;
float impulseScale = joint->springSoftness.impulseScale;
b3Vec3 vRel = b3Sub( b3Sub( b3Add( vB, b3Cross( wB, rB ) ), vA ), b3Cross( wA, b3Add( rA, d ) ) );
float cdot = b3Dot( vRel, jointAxis );
float deltaImpulse = -massScale * axialMass * ( cdot + bias ) - impulseScale * joint->springImpulse;
joint->springImpulse += deltaImpulse;
b3Vec3 P = b3MulSV( deltaImpulse, jointAxis );
b3Vec3 LA = b3MulSV( deltaImpulse, sAx );
b3Vec3 LB = b3MulSV( deltaImpulse, sBx );
vA = b3MulSub( vA, mA, P );
wA = b3Sub( wA, b3MulMV( iA, LA ) );
vB = b3MulAdd( vB, mB, P );
wB = b3Add( wB, b3MulMV( iB, LB ) );
}
if ( joint->enableMotor && fixedRotation == false )
{
b3Vec3 vRel = b3Sub( b3Sub( b3Add( vB, b3Cross( wB, rB ) ), vA ), b3Cross( wA, b3Add( rA, d ) ) );
float cdot = b3Dot( vRel, jointAxis ) - joint->motorSpeed;
float deltaImpulse = -axialMass * cdot;
float newImpulse = joint->motorImpulse + deltaImpulse;
float maxImpulse = joint->maxMotorForce * context->h;
newImpulse = b3ClampFloat( newImpulse, -maxImpulse, maxImpulse );
deltaImpulse = newImpulse - joint->motorImpulse;
joint->motorImpulse = newImpulse;
b3Vec3 P = b3MulSV( deltaImpulse, jointAxis );
b3Vec3 LA = b3MulSV( deltaImpulse, sAx );
b3Vec3 LB = b3MulSV( deltaImpulse, sBx );
vA = b3MulSub( vA, mA, P );
wA = b3Sub( wA, b3MulMV( iA, LA ) );
vB = b3MulAdd( vB, mB, P );
wB = b3Add( wB, b3MulMV( iB, LB ) );
}
if ( joint->enableLimit && fixedRotation == false )
{
float speculativeDistance = 0.25f * ( joint->upperTranslation - joint->lowerTranslation );
{
float C = jointTranslation - joint->lowerTranslation;
if ( C < speculativeDistance )
{
float bias = 0.0f;
float massScale = 1.0f;
float impulseScale = 0.0f;
if ( C > 0.0f )
{
bias = C * context->inv_h;
}
else if ( useBias )
{
bias = base->constraintSoftness.biasRate * C;
massScale = base->constraintSoftness.massScale;
impulseScale = base->constraintSoftness.impulseScale;
}
b3Vec3 vRel = b3Sub( b3Sub( b3Add( vB, b3Cross( wB, rB ) ), vA ), b3Cross( wA, b3Add( rA, d ) ) );
float cdot = b3Dot( vRel, jointAxis );
float oldImpulse = joint->lowerImpulse;
float deltaImpulse = -massScale * axialMass * ( cdot + bias ) - impulseScale * oldImpulse;
joint->lowerImpulse = b3MaxFloat( oldImpulse + deltaImpulse, 0.0f );
deltaImpulse = joint->lowerImpulse - oldImpulse;
b3Vec3 P = b3MulSV( deltaImpulse, jointAxis );
b3Vec3 LA = b3MulSV( deltaImpulse, sAx );
b3Vec3 LB = b3MulSV( deltaImpulse, sBx );
vA = b3MulSub( vA, mA, P );
wA = b3Sub( wA, b3MulMV( iA, LA ) );
vB = b3MulAdd( vB, mB, P );
wB = b3Add( wB, b3MulMV( iB, LB ) );
}
else
{
joint->lowerImpulse = 0.0f;
}
}
{
float C = joint->upperTranslation - jointTranslation;
if ( C < speculativeDistance )
{
float bias = 0.0f;
float massScale = 1.0f;
float impulseScale = 0.0f;
if ( C > 0.0f )
{
bias = C * context->inv_h;
}
else if ( useBias )
{
bias = base->constraintSoftness.biasRate * C;
massScale = base->constraintSoftness.massScale;
impulseScale = base->constraintSoftness.impulseScale;
}
b3Vec3 vRel = b3Sub( b3Sub( b3Add( vB, b3Cross( wB, rB ) ), vA ), b3Cross( wA, b3Add( rA, d ) ) );
float cdot = -b3Dot( vRel, jointAxis );
float oldImpulse = joint->upperImpulse;
float deltaImpulse = -massScale * axialMass * ( cdot + bias ) - impulseScale * oldImpulse;
joint->upperImpulse = b3MaxFloat( oldImpulse + deltaImpulse, 0.0f );
float negDeltaImpulse = oldImpulse - joint->upperImpulse;
b3Vec3 P = b3MulSV( negDeltaImpulse, jointAxis );
b3Vec3 LA = b3MulSV( negDeltaImpulse, sAx );
b3Vec3 LB = b3MulSV( negDeltaImpulse, sBx );
vA = b3MulSub( vA, mA, P );
wA = b3Sub( wA, b3MulMV( iA, LA ) );
vB = b3MulAdd( vB, mB, P );
wB = b3Add( wB, b3MulMV( iB, LB ) );
}
else
{
joint->upperImpulse = 0.0f;
}
}
}
if ( fixedRotation == false )
{
b3Vec3 bias = { 0.0f, 0.0f, 0.0f };
float massScale = 1.0f;
float impulseScale = 0.0f;
if ( useBias )
{
b3Quat quatA = b3MulQuat( stateA->deltaRotation, joint->frameA.q );
b3Quat quatB = b3MulQuat( stateB->deltaRotation, joint->frameB.q );
b3Quat relQ = b3InvMulQuat( quatA, quatB );
b3Quat targetQuat = b3Quat_identity;
b3Vec3 deltaRotation = b3DeltaQuatToRotation( relQ, targetQuat );
b3Vec3 c = b3Neg( b3RotateVector( quatA, deltaRotation ) );
bias = b3MulSV( base->constraintSoftness.biasRate, c );
massScale = base->constraintSoftness.massScale;
impulseScale = base->constraintSoftness.impulseScale;
}
b3Vec3 cdot = b3Sub( wB, wA );
b3Vec3 impulse = b3Sub(
b3MulSV( -massScale, b3MulMV( joint->rotationMass, b3Add( cdot, bias ) ) ),
b3MulSV( impulseScale, joint->angularImpulse ) );
joint->angularImpulse = b3Add( joint->angularImpulse, impulse );
wA = b3Sub( wA, b3MulMV( iA, impulse ) );
wB = b3Add( wB, b3MulMV( iB, impulse ) );
}
{
b3Vec3 perpY = b3RotateVector( stateA->deltaRotation, joint->perpAxisY );
b3Vec3 perpZ = b3RotateVector( stateA->deltaRotation, joint->perpAxisZ );
b3Vec2 bias = { 0.0f, 0.0f };
float massScale = 1.0f;
float impulseScale = 0.0f;
if ( useBias )
{
b3Vec2 c = { b3Dot( perpY, d ), b3Dot( perpZ, d ) };
bias = b3MulSV2( base->constraintSoftness.biasRate, c );
massScale = base->constraintSoftness.massScale;
impulseScale = base->constraintSoftness.impulseScale;
}
b3Vec3 vRel = b3Sub( b3Sub( b3Add( vB, b3Cross( wB, rB ) ), vA ), b3Cross( wA, b3Add( rA, d ) ) );
b3Vec2 cdot = { b3Dot( perpY, vRel ), b3Dot( perpZ, vRel ) };
b3Vec3 sAy = b3Cross( b3Add( rA, d ), perpY );
b3Vec3 sBy = b3Cross( rB, perpY );
b3Vec3 sAz = b3Cross( b3Add( rA, d ), perpZ );
b3Vec3 sBz = b3Cross( rB, perpZ );
float kyy = mA + mB + b3Dot( sAy, b3MulMV( iA, sAy ) ) + b3Dot( sBy, b3MulMV( iB, sBy ) );
float kyz = b3Dot( sAy, b3MulMV( iA, sAz ) ) + b3Dot( sBy, b3MulMV( iB, sBz ) );
float kzz = mA + mB + b3Dot( sAz, b3MulMV( iA, sAz ) ) + b3Dot( sBz, b3MulMV( iB, sBz ) );
b3Matrix2 K = { { kyy, kyz }, { kyz, kzz } };
b3Vec2 oldImpulse = joint->perpImpulse;
b3Vec2 sol = b3Solve2( K, b3Add2( cdot, bias ) );
b3Vec2 deltaImpulse = b3Sub2( b3MulSV2( -massScale, sol ), b3MulSV2( impulseScale, oldImpulse ) );
joint->perpImpulse = b3Add2( oldImpulse, deltaImpulse );
b3Vec3 P = b3Blend2( deltaImpulse.x, perpY, deltaImpulse.y, perpZ );
vA = b3MulSub( vA, mA, P );
wA = b3Sub( wA, b3MulMV( iA, b3Blend2( deltaImpulse.x, sAy, deltaImpulse.y, sAz ) ) );
vB = b3MulAdd( vB, mB, P );
wB = b3Add( wB, b3MulMV( iB, b3Blend2( deltaImpulse.x, sBy, deltaImpulse.y, sBz ) ) );
}
B3_ASSERT( b3IsValidVec3( vA ) );
B3_ASSERT( b3IsValidVec3( wA ) );
B3_ASSERT( b3IsValidVec3( vB ) );
B3_ASSERT( b3IsValidVec3( wB ) );
if ( stateA->flags & b3_dynamicFlag )
{
stateA->linearVelocity = vA;
stateA->angularVelocity = wA;
}
if ( stateB->flags & b3_dynamicFlag )
{
stateB->linearVelocity = vB;
stateB->angularVelocity = wB;
}
}
void b3DrawPrismaticJoint( b3DebugDraw* draw, b3JointSim* base, b3WorldTransform transformA, b3WorldTransform transformB, float scale )
{
b3WorldTransform frameA = b3MulWorldTransforms( transformA, base->localFrameA );
b3WorldTransform frameB = b3MulWorldTransforms( transformB, base->localFrameB );
b3Matrix3 R = b3MakeMatrixFromQuat( frameA.q );
b3Vec3 axis = R.cx;
b3Vec3 perpY = R.cy;
b3Vec3 perpZ = R.cz;
float s = 0.2f * scale;
draw->DrawSegmentFcn( frameA.p, b3OffsetPos( frameA.p, b3MulSV( s, perpY ) ), b3_colorGreen, draw->context );
draw->DrawSegmentFcn( frameA.p, b3OffsetPos( frameA.p, b3MulSV( s, perpZ ) ), b3_colorBlue, draw->context );
b3PrismaticJoint* joint = &base->prismaticJoint;
if ( joint->enableLimit )
{
b3Pos p1 = b3OffsetPos( frameA.p, b3MulSV( joint->lowerTranslation, axis ) );
b3Pos p2 = b3OffsetPos( frameA.p, b3MulSV( joint->upperTranslation, axis ) );
draw->DrawSegmentFcn( p1, p2, b3_colorOrange, draw->context );
draw->DrawPointFcn( p1, 10.0f, b3_colorGreen, draw->context );
draw->DrawPointFcn( p2, 10.0f, b3_colorRed, draw->context );
}
else
{
b3Pos p1 = b3OffsetPos( frameA.p, b3MulSV( -0.5f * scale, axis ) );
b3Pos p2 = b3OffsetPos( frameA.p, b3MulSV( 0.5f * scale, axis ) );
draw->DrawSegmentFcn( p1, p2, b3_colorOrange, draw->context );
}
draw->DrawPointFcn( frameB.p, 8.0f, b3_colorViolet, draw->context );
}