/*
* Copyright (c) 2006-2007 Erin Catto http:
*
* 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, and must not be
* misrepresented the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
/**
* A rigid body. Internal computation are done in terms
* of the center of mass position. The center of mass may
* be offset from the body's origin.
*
* @class b2Body
* @constructor
* @param bd
* @param world
*/
var b2Body = function (bd, world) {
// initialize instance variables for references
this.sMat0 = new b2Mat22();
this.m_position = new b2Vec2();
this.m_R = new b2Mat22(0);
this.m_position0 = new b2Vec2();
//
var i = 0;
var sd;
var massData;
this.m_flags = 0;
this.m_position.SetV( bd.position );
this.m_rotation = bd.rotation;
this.m_R.Set(this.m_rotation);
this.m_position0.SetV(this.m_position);
this.m_rotation0 = this.m_rotation;
this.m_world = world;
this.m_linearDamping = b2Math.b2Clamp(1.0 - bd.linearDamping, 0.0, 1.0);
this.m_angularDamping = b2Math.b2Clamp(1.0 - bd.angularDamping, 0.0, 1.0);
this.m_force = new b2Vec2(0.0, 0.0);
this.m_torque = 0.0;
this.m_mass = 0.0;
var massDatas = new Array(b2Settings.b2_maxShapesPerBody);
for (i = 0; i < b2Settings.b2_maxShapesPerBody; i++){
massDatas[i] = new b2MassData();
}
// Compute the shape mass properties, the bodies total mass and COM.
this.m_shapeCount = 0;
this.m_center = new b2Vec2(0.0, 0.0);
for (i = 0; i < b2Settings.b2_maxShapesPerBody; ++i)
{
sd = bd.shapes[i];
if (sd == null) break;
massData = massDatas[ i ];
sd.ComputeMass(massData);
this.m_mass += massData.mass;
//this.m_center += massData->mass * (sd->localPosition + massData->center);
this.m_center.x += massData.mass * (sd.localPosition.x + massData.center.x);
this.m_center.y += massData.mass * (sd.localPosition.y + massData.center.y);
++this.m_shapeCount;
}
// Compute center of mass, and shift the origin to the COM.
if (this.m_mass > 0.0)
{
this.m_center.Multiply( 1.0 / this.m_mass );
this.m_position.Add( b2Math.b2MulMV(this.m_R, this.m_center) );
}
else
{
this.m_flags |= b2Body.e_staticFlag;
}
// Compute the moment of inertia.
this.m_I = 0.0;
for (i = 0; i < this.m_shapeCount; ++i)
{
sd = bd.shapes[i];
massData = massDatas[ i ];
this.m_I += massData.I;
var r = b2Math.SubtractVV( b2Math.AddVV(sd.localPosition, massData.center), this.m_center );
this.m_I += massData.mass * b2Math.b2Dot(r, r);
}
if (this.m_mass > 0.0)
{
this.m_invMass = 1.0 / this.m_mass;
}
else
{
this.m_invMass = 0.0;
}
if (this.m_I > 0.0 && bd.preventRotation == false)
{
this.m_invI = 1.0 / this.m_I;
}
else
{
this.m_I = 0.0;
this.m_invI = 0.0;
}
// Compute the center of mass velocity.
this.m_linearVelocity = b2Math.AddVV(bd.linearVelocity, b2Math.b2CrossFV(bd.angularVelocity, this.m_center));
this.m_angularVelocity = bd.angularVelocity;
this.m_jointList = null;
this.m_contactList = null;
this.m_prev = null;
this.m_next = null;
// Create the shapes.
this.m_shapeList = null;
for (i = 0; i < this.m_shapeCount; ++i)
{
sd = bd.shapes[i];
var shape = b2Shape.Create(sd, this, this.m_center);
shape.m_next = this.m_shapeList;
this.m_shapeList = shape;
}
this.m_sleepTime = 0.0;
if (bd.allowSleep)
{
this.m_flags |= b2Body.e_allowSleepFlag;
}
if (bd.isSleeping)
{
this.m_flags |= b2Body.e_sleepFlag;
}
if ((this.m_flags & b2Body.e_sleepFlag) || this.m_invMass == 0.0)
{
this.m_linearVelocity.Set(0.0, 0.0);
this.m_angularVelocity = 0.0;
}
this.m_userData = bd.userData;
};
b2Body.prototype =
{
// Set the position of the body's origin and rotation (radians).
// This breaks any contacts and wakes the other bodies.
SetOriginPosition: function(position, rotation){
if (this.IsFrozen())
{
return;
}
this.m_rotation = rotation;
this.m_R.Set(this.m_rotation);
this.m_position = b2Math.AddVV(position , b2Math.b2MulMV(this.m_R, this.m_center));
this.m_position0.SetV(this.m_position);
this.m_rotation0 = this.m_rotation;
for (var s = this.m_shapeList; s != null; s = s.m_next)
{
s.Synchronize(this.m_position, this.m_R, this.m_position, this.m_R);
}
this.m_world.m_broadPhase.Commit();
},
// Get the position of the body's origin. The body's origin does not
// necessarily coincide with the center of mass. It depends on how the
// shapes are created.
GetOriginPosition: function(){
return b2Math.SubtractVV(this.m_position, b2Math.b2MulMV(this.m_R, this.m_center));
},
// Set the position of the body's center of mass and rotation (radians).
// This breaks any contacts and wakes the other bodies.
SetCenterPosition: function(position, rotation){
if (this.IsFrozen())
{
return;
}
this.m_rotation = rotation;
this.m_R.Set(this.m_rotation);
this.m_position.SetV( position );
this.m_position0.SetV(this.m_position);
this.m_rotation0 = this.m_rotation;
for (var s = this.m_shapeList; s != null; s = s.m_next)
{
s.Synchronize(this.m_position, this.m_R, this.m_position, this.m_R);
}
this.m_world.m_broadPhase.Commit();
},
// Get the position of the body's center of mass. The body's center of mass
// does not necessarily coincide with the body's origin. It depends on how the
// shapes are created.
GetCenterPosition: function(){
return this.m_position;
},
// Get the rotation in radians.
GetRotation: function(){
return this.m_rotation;
},
GetRotationMatrix: function(){
return this.m_R;
},
// Set/Get the linear velocity of the center of mass.
SetLinearVelocity: function(v){
this.m_linearVelocity.SetV(v);
},
GetLinearVelocity: function(){
return this.m_linearVelocity;
},
// Set/Get the angular velocity.
SetAngularVelocity: function(w){
this.m_angularVelocity = w;
},
GetAngularVelocity: function(){
return this.m_angularVelocity;
},
// Apply a force at a world point. Additive.
ApplyForce: function(force, point)
{
if (this.IsSleeping() == false)
{
this.m_force.Add( force );
this.m_torque += b2Math.b2CrossVV(b2Math.SubtractVV(point, this.m_position), force);
}
},
// Apply a torque. Additive.
ApplyTorque: function(torque)
{
if (this.IsSleeping() == false)
{
this.m_torque += torque;
}
},
// Apply an impulse at a point. This immediately modifies the velocity.
ApplyImpulse: function(impulse, point)
{
if (this.IsSleeping() == false)
{
this.m_linearVelocity.Add( b2Math.MulFV(this.m_invMass, impulse) );
this.m_angularVelocity += ( this.m_invI * b2Math.b2CrossVV( b2Math.SubtractVV(point, this.m_position), impulse) );
}
},
GetMass: function(){
return this.m_mass;
},
GetInertia: function(){
return this.m_I;
},
// Get the world coordinates of a point give the local coordinates
// relative to the body's center of mass.
GetWorldPoint: function(localPoint){
return b2Math.AddVV(this.m_position , b2Math.b2MulMV(this.m_R, localPoint));
},
// Get the world coordinates of a vector given the local coordinates.
GetWorldVector: function(localVector){
return b2Math.b2MulMV(this.m_R, localVector);
},
// Returns a local point relative to the center of mass given a world point.
GetLocalPoint: function(worldPoint){
return b2Math.b2MulTMV(this.m_R, b2Math.SubtractVV(worldPoint, this.m_position));
},
// Returns a local vector given a world vector.
GetLocalVector: function(worldVector){
return b2Math.b2MulTMV(this.m_R, worldVector);
},
// Is this body static (immovable)?
IsStatic: function(){
return (this.m_flags & b2Body.e_staticFlag) == b2Body.e_staticFlag;
},
IsFrozen: function()
{
return (this.m_flags & b2Body.e_frozenFlag) == b2Body.e_frozenFlag;
},
// Is this body sleeping (not simulating).
IsSleeping: function(){
return (this.m_flags & b2Body.e_sleepFlag) == b2Body.e_sleepFlag;
},
// You can disable sleeping on this particular body.
AllowSleeping: function(flag)
{
if (flag)
{
this.m_flags |= b2Body.e_allowSleepFlag;
}
else
{
this.m_flags &= ~b2Body.e_allowSleepFlag;
this.WakeUp();
}
},
// Wake up this body so it will begin simulating.
WakeUp: function(){
this.m_flags &= ~b2Body.e_sleepFlag;
this.m_sleepTime = 0.0;
},
// Get the list of all shapes attached to this body.
GetShapeList: function(){
return this.m_shapeList;
},
GetContactList: function()
{
return this.m_contactList;
},
GetJointList: function()
{
return this.m_jointList;
},
// Get the next body in the world's body list.
GetNext: function(){
return this.m_next;
},
GetUserData: function(){
return this.m_userData;
},
//--------------- Internals Below -------------------
// does not support destructors
/*~b2Body(){
b2Shape* s = this.m_shapeList;
while (s)
{
b2Shape* s0 = s;
s = s->this.m_next;
b2Shape::this.Destroy(s0);
}
}*/
Destroy: function(){
var s = this.m_shapeList;
while (s)
{
var s0 = s;
s = s.m_next;
b2Shape.Destroy(s0);
}
},
// Temp mat
sMat0: new b2Mat22(),
SynchronizeShapes: function(){
//b2Mat22 R0(this.m_rotation0);
this.sMat0.Set(this.m_rotation0);
for (var s = this.m_shapeList; s != null; s = s.m_next)
{
s.Synchronize(this.m_position0, this.sMat0, this.m_position, this.m_R);
}
},
QuickSyncShapes: function(){
for (var s = this.m_shapeList; s != null; s = s.m_next)
{
s.QuickSync(this.m_position, this.m_R);
}
},
// This is used to prevent connected bodies from colliding.
// It may lie, depending on the collideConnected flag.
IsConnected: function(other){
for (var jn = this.m_jointList; jn != null; jn = jn.next)
{
if (jn.other == other)
return jn.joint.m_collideConnected == false;
}
return false;
},
Freeze: function(){
this.m_flags |= b2Body.e_frozenFlag;
this.m_linearVelocity.SetZero();
this.m_angularVelocity = 0.0;
for (var s = this.m_shapeList; s != null; s = s.m_next)
{
s.DestroyProxy();
}
},
m_flags: 0,
m_position: new b2Vec2(),
m_rotation: null,
m_R: new b2Mat22(0),
// Conservative advancement data.
m_position0: new b2Vec2(),
m_rotation0: null,
m_linearVelocity: null,
m_angularVelocity: null,
m_force: null,
m_torque: null,
m_center: null,
m_world: null,
m_prev: null,
m_next: null,
m_shapeList: null,
m_shapeCount: 0,
m_jointList: null,
m_contactList: null,
m_mass: null,
m_invMass: null,
m_I: null,
m_invI: null,
m_linearDamping: null,
m_angularDamping: null,
m_sleepTime: null,
m_userData: null
};
b2Body.e_staticFlag = 0x0001;
b2Body.e_frozenFlag = 0x0002;
b2Body.e_islandFlag = 0x0004;
b2Body.e_sleepFlag = 0x0008;
b2Body.e_allowSleepFlag = 0x0010;
b2Body.e_destroyFlag = 0x0020;