mirror of
https://github.com/love2d/love.git
synced 2026-08-15 07:41:11 +02:00
Initial Mercurial commit.
This commit is contained in:
@@ -0,0 +1,286 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "Body.h"
|
||||
|
||||
#include <common/math.h>
|
||||
|
||||
#include "World.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
Body::Body(World * world, b2Vec2 p, float m, float i)
|
||||
: world(world)
|
||||
{
|
||||
world->retain();
|
||||
b2BodyDef def;
|
||||
def.position = world->scaleDown(p);
|
||||
def.massData.mass = m;
|
||||
def.massData.I = i;
|
||||
body = world->world->CreateBody(&def);
|
||||
}
|
||||
|
||||
Body::~Body()
|
||||
{
|
||||
world->world->DestroyBody(body);
|
||||
world->release();
|
||||
body = 0;
|
||||
}
|
||||
|
||||
float Body::getX()
|
||||
{
|
||||
return world->scaleUp(body->GetPosition().x);
|
||||
}
|
||||
|
||||
float Body::getY()
|
||||
{
|
||||
return world->scaleUp(body->GetPosition().y);
|
||||
}
|
||||
|
||||
int Body::getPosition(lua_State * L)
|
||||
{
|
||||
return pushVector(L, world->scaleUp(body->GetPosition()));
|
||||
}
|
||||
|
||||
int Body::getVelocity(lua_State * L)
|
||||
{
|
||||
return pushVector(L, world->scaleUp(body->GetLinearVelocity()));
|
||||
}
|
||||
|
||||
float Body::getAngle()
|
||||
{
|
||||
return body->GetAngle();
|
||||
}
|
||||
|
||||
int Body::getWorldCenter(lua_State * L)
|
||||
{
|
||||
return pushVector(L, world->scaleUp(body->GetWorldCenter()));
|
||||
}
|
||||
|
||||
int Body::getLocalCenter(lua_State * L)
|
||||
{
|
||||
return pushVector(L, world->scaleUp(body->GetLocalCenter()));
|
||||
}
|
||||
|
||||
float Body::getSpin() const
|
||||
{
|
||||
return body->GetAngularVelocity();
|
||||
}
|
||||
|
||||
float Body::getMass() const
|
||||
{
|
||||
return body->GetMass();
|
||||
}
|
||||
|
||||
float Body::getInertia() const
|
||||
{
|
||||
return body->GetInertia();
|
||||
}
|
||||
|
||||
float Body::getAngularDamping() const
|
||||
{
|
||||
return body->m_angularDamping;
|
||||
}
|
||||
|
||||
float Body::getDamping() const
|
||||
{
|
||||
return body->m_linearDamping;
|
||||
}
|
||||
|
||||
void Body::applyImpulse(float jx, float jy)
|
||||
{
|
||||
body->ApplyImpulse(b2Vec2(jx, jy), world->scaleDown(body->GetWorldCenter()));
|
||||
}
|
||||
|
||||
void Body::applyImpulse(float jx, float jy, float rx, float ry)
|
||||
{
|
||||
body->ApplyImpulse(b2Vec2(jx, jy), world->scaleDown(b2Vec2(rx, ry)));
|
||||
}
|
||||
|
||||
void Body::applyTorque(float t)
|
||||
{
|
||||
body->ApplyTorque(t);
|
||||
}
|
||||
|
||||
void Body::applyForce(float fx, float fy, float rx, float ry)
|
||||
{
|
||||
body->ApplyForce(b2Vec2(fx, fy), world->scaleDown(b2Vec2(rx, ry)));
|
||||
}
|
||||
|
||||
void Body::applyForce(float fx, float fy)
|
||||
{
|
||||
body->ApplyForce(b2Vec2(fx, fy), world->scaleDown(body->GetWorldCenter()));
|
||||
}
|
||||
|
||||
void Body::setX(float x)
|
||||
{
|
||||
body->SetXForm(world->scaleDown(b2Vec2(x, getY())), getAngle());
|
||||
}
|
||||
|
||||
void Body::setY(float y)
|
||||
{
|
||||
body->SetXForm(world->scaleDown(b2Vec2(getX(), y)), getAngle());
|
||||
}
|
||||
|
||||
void Body::setVelocity(float x, float y)
|
||||
{
|
||||
body->SetLinearVelocity(world->scaleDown(b2Vec2(x, y)));
|
||||
}
|
||||
|
||||
void Body::setAngle(float d)
|
||||
{
|
||||
body->SetXForm(body->GetPosition(), d);
|
||||
}
|
||||
|
||||
void Body::setSpin(float r)
|
||||
{
|
||||
body->SetAngularVelocity(r);
|
||||
}
|
||||
|
||||
void Body::setPosition(float x, float y)
|
||||
{
|
||||
body->SetXForm(world->scaleDown(b2Vec2(x, y)), body->GetAngle());
|
||||
}
|
||||
|
||||
void Body::setAngularDamping(float d)
|
||||
{
|
||||
body->m_angularDamping = d;
|
||||
}
|
||||
|
||||
void Body::setDamping(float d)
|
||||
{
|
||||
body->m_linearDamping = d;
|
||||
}
|
||||
|
||||
void Body::setMassFromShapes()
|
||||
{
|
||||
body->SetMassFromShapes();
|
||||
}
|
||||
|
||||
void Body::setMass(float x, float y, float m, float i)
|
||||
{
|
||||
b2MassData massData;
|
||||
massData.center = world->scaleDown(b2Vec2(x, y));
|
||||
massData.mass = m;
|
||||
massData.I = i;
|
||||
body->SetMass(&massData);
|
||||
}
|
||||
|
||||
int Body::getWorldPoint(lua_State * L)
|
||||
{
|
||||
b2Vec2 v = world->scaleDown(getVector(L));
|
||||
return pushVector(L, world->scaleUp(body->GetWorldPoint(v)));
|
||||
}
|
||||
|
||||
int Body::getWorldVector(lua_State * L)
|
||||
{
|
||||
b2Vec2 v = world->scaleDown(getVector(L));
|
||||
return pushVector(L, world->scaleUp(body->GetWorldVector(v)));
|
||||
}
|
||||
|
||||
int Body::getLocalPoint(lua_State * L)
|
||||
{
|
||||
b2Vec2 v = world->scaleDown(getVector(L));
|
||||
return pushVector(L, world->scaleUp(body->GetLocalPoint(v)));
|
||||
}
|
||||
|
||||
int Body::getLocalVector(lua_State * L)
|
||||
{
|
||||
b2Vec2 v = world->scaleDown(getVector(L));
|
||||
return pushVector(L, world->scaleUp(body->GetLocalVector(v)));
|
||||
}
|
||||
|
||||
int Body::getVelocityWorldPoint(lua_State * L)
|
||||
{
|
||||
b2Vec2 v = world->scaleDown(getVector(L));
|
||||
return pushVector(L, world->scaleUp(body->GetLinearVelocityFromWorldPoint(v)));
|
||||
}
|
||||
|
||||
int Body::getVelocityLocalPoint(lua_State * L)
|
||||
{
|
||||
b2Vec2 v = world->scaleDown(getVector(L));
|
||||
return pushVector(L, world->scaleUp(body->GetLinearVelocityFromLocalPoint(v)));
|
||||
}
|
||||
|
||||
bool Body::isBullet() const
|
||||
{
|
||||
return body->IsBullet();
|
||||
}
|
||||
|
||||
void Body::setBullet(bool bullet)
|
||||
{
|
||||
return body->SetBullet(bullet);
|
||||
}
|
||||
|
||||
bool Body::isStatic() const
|
||||
{
|
||||
return body->IsStatic();
|
||||
}
|
||||
|
||||
bool Body::isDynamic() const
|
||||
{
|
||||
return body->IsDynamic();
|
||||
}
|
||||
|
||||
bool Body::isFrozen() const
|
||||
{
|
||||
return body->IsFrozen();
|
||||
}
|
||||
|
||||
bool Body::isSleeping() const
|
||||
{
|
||||
return body->IsSleeping();
|
||||
}
|
||||
|
||||
void Body::setAllowSleep(bool allow)
|
||||
{
|
||||
body->AllowSleeping(true);
|
||||
}
|
||||
|
||||
void Body::setSleep(bool sleep)
|
||||
{
|
||||
if(sleep)
|
||||
body->PutToSleep();
|
||||
else
|
||||
body->WakeUp();
|
||||
}
|
||||
|
||||
b2Vec2 Body::getVector(lua_State * L)
|
||||
{
|
||||
love::luax_assert_argc(L, 2, 2);
|
||||
b2Vec2 v((float)lua_tonumber(L, 1), (float)lua_tonumber(L, 2));
|
||||
lua_pop(L, 2);
|
||||
return v;
|
||||
}
|
||||
|
||||
int Body::pushVector(lua_State * L, const b2Vec2 & v)
|
||||
{
|
||||
lua_pushnumber(L, v.x);
|
||||
lua_pushnumber(L, v.y);
|
||||
return 2;
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,349 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_BODY_H
|
||||
#define LOVE_PHYSICS_BOX2D_BODY_H
|
||||
|
||||
// LOVE
|
||||
#include <common/runtime.h>
|
||||
#include <common/Object.h>
|
||||
|
||||
|
||||
// Box2D
|
||||
#include "Include/Box2D.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
// Forward declarations.
|
||||
class World;
|
||||
|
||||
/**
|
||||
* A Body is an entity which has position and orientation
|
||||
* in world space. A Body does have collision geometry
|
||||
* by itself, but depend on an arbitrary number of child Shape objects
|
||||
* which together constitute the final geometry for the Body.
|
||||
**/
|
||||
class Body : public Object
|
||||
{
|
||||
// Friends.
|
||||
friend class Joint;
|
||||
friend class DistanceJoint;
|
||||
friend class MouseJoint;
|
||||
friend class CircleShape;
|
||||
friend class PolygonShape;
|
||||
friend class Shape;
|
||||
|
||||
private:
|
||||
|
||||
// We need a shared_ptr to the parent World,
|
||||
// because World can not be destroyed as long as
|
||||
// bodies exists in it.
|
||||
//
|
||||
// This ensures that a World only can be destroyed
|
||||
// once all bodies have been destroyed too.
|
||||
World * world;
|
||||
|
||||
public:
|
||||
|
||||
// The Box2D body. (Should not be public?)
|
||||
b2Body * body;
|
||||
|
||||
/**
|
||||
* Create a Body at position p.
|
||||
**/
|
||||
Body(World * world, b2Vec2 p, float m, float i);
|
||||
|
||||
~Body();
|
||||
|
||||
/**
|
||||
* Gets the current x-position of the Body.
|
||||
**/
|
||||
float getX();
|
||||
|
||||
/**
|
||||
* Gets the current y-position of the Body.
|
||||
**/
|
||||
float getY();
|
||||
|
||||
/**
|
||||
* Gets the current angle (deg) of the Body.
|
||||
**/
|
||||
float getAngle();
|
||||
|
||||
/**
|
||||
* Gets the current position of the Body.
|
||||
* @returns The current x-position.
|
||||
* @returns The current y-position.
|
||||
**/
|
||||
int getPosition(lua_State * L);
|
||||
|
||||
/**
|
||||
* Gets the velocity in the current center of mass.
|
||||
* @returns The x-component of the velocity.
|
||||
* @returns The y-component of the velocity.
|
||||
**/
|
||||
int getVelocity(lua_State * L);
|
||||
|
||||
/**
|
||||
* The current center of mass for the Body in world
|
||||
* coordinates.
|
||||
* @returns The x-component of the point.
|
||||
* @returns The y-component of the point.
|
||||
**/
|
||||
int getWorldCenter(lua_State * L);
|
||||
|
||||
/**
|
||||
* The current center of mass for the Body in local
|
||||
* coordinates.
|
||||
* @returns The x-component of the point.
|
||||
* @returns The y-component of the point.
|
||||
**/
|
||||
int getLocalCenter(lua_State * L);
|
||||
|
||||
/**
|
||||
* Get the current Body spin. (Angular velocity).
|
||||
**/
|
||||
float getSpin() const;
|
||||
|
||||
/**
|
||||
* Gets the Body's mass.
|
||||
**/
|
||||
float getMass() const;
|
||||
|
||||
/**
|
||||
* Gets the Body's intertia.
|
||||
**/
|
||||
float getInertia() const;
|
||||
|
||||
/**
|
||||
* Gets the Body's angular damping.
|
||||
**/
|
||||
float getAngularDamping() const;
|
||||
|
||||
/**
|
||||
* Gets the Body's linear damping.
|
||||
**/
|
||||
float getDamping() const;
|
||||
|
||||
/**
|
||||
* Apply an impulse (jx, jy) with offset (0, 0).
|
||||
**/
|
||||
void applyImpulse(float jx, float jy);
|
||||
|
||||
/**
|
||||
* Apply an impulse (jx, jy) with offset (rx, ry).
|
||||
**/
|
||||
void applyImpulse(float jx, float jy, float rx, float ry);
|
||||
|
||||
/**
|
||||
* Apply torque (t).
|
||||
**/
|
||||
void applyTorque(float t);
|
||||
|
||||
/**
|
||||
* Apply force (fx, fy) with offset (0, 0).
|
||||
**/
|
||||
void applyForce(float fx, float fy);
|
||||
|
||||
/**
|
||||
* Apply force (fx, fy) with offset (rx, ry).
|
||||
**/
|
||||
void applyForce(float fx, float fy, float rx, float ry);
|
||||
|
||||
/**
|
||||
* Sets the x-position of the Body.
|
||||
**/
|
||||
void setX(float x);
|
||||
|
||||
/**
|
||||
* Sets the Y-position of the Body.
|
||||
**/
|
||||
void setY(float y);
|
||||
|
||||
/**
|
||||
* Sets the current velocity of the Body.
|
||||
**/
|
||||
void setVelocity(float x, float y);
|
||||
|
||||
/**
|
||||
* Sets the angle of the Body.
|
||||
**/
|
||||
void setAngle(float d);
|
||||
|
||||
/**
|
||||
* Sets the current spin of the Body.
|
||||
**/
|
||||
void setSpin(float r);
|
||||
|
||||
/**
|
||||
* Sets the current position of the Body.
|
||||
**/
|
||||
void setPosition(float x, float y);
|
||||
|
||||
/**
|
||||
* Sets the mass from the currently attatched shapes.
|
||||
**/
|
||||
void setMassFromShapes();
|
||||
|
||||
/**
|
||||
* Sets mass properties.
|
||||
* @param x The x-coordinate for the local center of mass.
|
||||
* @param y The y-coordinate for the local center of mass.
|
||||
* @param m The mass.
|
||||
* @param i The inertia.
|
||||
**/
|
||||
void setMass(float x, float y, float m, float i);
|
||||
|
||||
/**
|
||||
* Sets the Body's angular damping.
|
||||
**/
|
||||
void setAngularDamping(float d);
|
||||
|
||||
/**
|
||||
* Sets the Body's linear damping.
|
||||
**/
|
||||
void setDamping(float d);
|
||||
|
||||
/**
|
||||
* Transforms a point (x, y) from local coordinates
|
||||
* to world coordinates.
|
||||
* @param x The x-coordinate of the local point.
|
||||
* @param y The y-coordinate of the local point.
|
||||
* @returns The x-coordinate of the point in world coordinates.
|
||||
* @returns The y-coordinate of the point in world coordinates.
|
||||
**/
|
||||
int getWorldPoint(lua_State * L);
|
||||
|
||||
/**
|
||||
* Transforms a vector (x, y) from local coordinates
|
||||
* to world coordinates.
|
||||
* @param x The x-coordinate of the local vector.
|
||||
* @param y The y-coordinate of the local vector.
|
||||
* @returns The x-coordinate of the vector in world coordinates.
|
||||
* @returns The y-coordinate of the vector in world coordinates.
|
||||
**/
|
||||
int getWorldVector(lua_State * L);
|
||||
|
||||
/**
|
||||
* Transforms a point (x, y) from world coordinates
|
||||
* to local coordinates.
|
||||
* @param x The x-coordinate of the world point.
|
||||
* @param y The y-coordinate of the world point.
|
||||
* @returns The x-coordinate of the point in local coordinates.
|
||||
* @returns The y-coordinate of the point in local coordinates.
|
||||
**/
|
||||
int getLocalPoint(lua_State * L);
|
||||
|
||||
/**
|
||||
* Transforms a vector (x, y) from world coordinates
|
||||
* to local coordinates.
|
||||
* @param x The x-coordinate of the world vector.
|
||||
* @param y The y-coordinate of the world vector.
|
||||
* @returns The x-coordinate of the vector in local coordinates.
|
||||
* @returns The y-coordinate of the vector in local coordinates.
|
||||
**/
|
||||
int getLocalVector(lua_State * L);
|
||||
|
||||
/**
|
||||
* Gets the velocity on the Body for the given world point.
|
||||
* @param x The x-coordinate of the world point.
|
||||
* @param y The y-coordinate of the world point.
|
||||
* @returns The x-component of the velocity vector.
|
||||
* @returns The y-component of the velocity vector.
|
||||
**/
|
||||
int getVelocityWorldPoint(lua_State * L);
|
||||
|
||||
/**
|
||||
* Gets the velocity on the Body for the given local point.
|
||||
* @param x The x-coordinate of the local point.
|
||||
* @param y The y-coordinate of the local point.
|
||||
* @returns The x-component of the velocity vector.
|
||||
* @returns The y-component of the velocity vector.
|
||||
**/
|
||||
int getVelocityLocalPoint(lua_State * L);
|
||||
|
||||
/**
|
||||
* Returns true if the Body is a bullet, false otherwise.
|
||||
**/
|
||||
bool isBullet() const;
|
||||
|
||||
/**
|
||||
* Set whether this Body should be treated as a bullet.
|
||||
* Bullets require more processing power than normal shapes.
|
||||
**/
|
||||
void setBullet(bool bullet);
|
||||
|
||||
/**
|
||||
* Checks whether a Body is static or not, i.e. terrain
|
||||
* or not.
|
||||
**/
|
||||
bool isStatic() const;
|
||||
|
||||
/**
|
||||
* The opposite of isStatic.
|
||||
**/
|
||||
bool isDynamic() const;
|
||||
|
||||
/**
|
||||
* Checks whether a Body is frozen or not.
|
||||
* A Body will freeze if hits the world bounding box.
|
||||
**/
|
||||
bool isFrozen() const;
|
||||
|
||||
/**
|
||||
* Checks whether a Body is sleeping or nor. A Body
|
||||
* will fall to sleep if nothing happens to it for while.
|
||||
**/
|
||||
bool isSleeping() const;
|
||||
|
||||
/**
|
||||
* Controls whether this Body should be allowed to sleep.
|
||||
**/
|
||||
void setAllowSleep(bool allow);
|
||||
|
||||
/**
|
||||
* Controls the Body's sleep.
|
||||
* @param sleep True to put to sleep, false to wake up.
|
||||
**/
|
||||
void setSleep(bool sleep);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Gets a 2d vector from the arguments on the stack.
|
||||
**/
|
||||
b2Vec2 getVector(lua_State * L);
|
||||
|
||||
/**
|
||||
* Pushed the x- and y-components of a vector on
|
||||
* the stack.
|
||||
**/
|
||||
int pushVector(lua_State * L, const b2Vec2 & v);
|
||||
};
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_BODY_H
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "CircleShape.h"
|
||||
|
||||
// Module
|
||||
#include "Body.h"
|
||||
#include "World.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
CircleShape::CircleShape(Body * body, b2CircleDef * def)
|
||||
: Shape(body), radius(def->radius)
|
||||
{
|
||||
def->localPosition = body->world->scaleDown(def->localPosition);
|
||||
def->radius = body->world->scaleDown(def->radius);
|
||||
radius = def->radius;
|
||||
shape = body->body->CreateShape(def);
|
||||
shape->SetUserData((void*)data);
|
||||
}
|
||||
|
||||
CircleShape::~CircleShape()
|
||||
{
|
||||
body->body->DestroyShape(shape);
|
||||
shape = 0;
|
||||
}
|
||||
|
||||
float CircleShape::getRadius() const
|
||||
{
|
||||
return body->world->scaleUp(radius);
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_CIRCLE_SHAPE_H
|
||||
#define LOVE_PHYSICS_BOX2D_CIRCLE_SHAPE_H
|
||||
|
||||
// Module
|
||||
#include "Shape.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
/**
|
||||
* A CircleShape represent a Circle which can
|
||||
* be used for collision detection and physics.
|
||||
*
|
||||
* The CircleShape is much faster than the PolygonShape,
|
||||
* and should generally be used where possible.
|
||||
**/
|
||||
class CircleShape : public Shape
|
||||
{
|
||||
private:
|
||||
// The radius of the circle. We need to store this because
|
||||
// Box2D has no built-in method for getting the radius.
|
||||
float radius;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create a new CircleShape from the parent body and a
|
||||
* Box2D CircleShape definition.
|
||||
* @param body The parent body.
|
||||
* @param def The CircleShape definition.
|
||||
**/
|
||||
CircleShape(Body * body, b2CircleDef * def);
|
||||
|
||||
virtual ~CircleShape();
|
||||
|
||||
/**
|
||||
* Gets the radius for the circle.
|
||||
**/
|
||||
float getRadius() const;
|
||||
|
||||
// There is no support for setting the radius.
|
||||
};
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_CIRCLE_SHAPE_H
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "Contact.h"
|
||||
#include "World.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
Contact::Contact(World * world, const b2ContactPoint * point)
|
||||
: point(*point), world(world)
|
||||
{
|
||||
world->retain();
|
||||
}
|
||||
|
||||
Contact::~Contact()
|
||||
{
|
||||
world->release();
|
||||
}
|
||||
|
||||
int Contact::getPosition(lua_State * L)
|
||||
{
|
||||
love::luax_assert_argc(L, 0, 0);
|
||||
lua_pushnumber(L, world->scaleUp(point.position.x));
|
||||
lua_pushnumber(L, world->scaleUp(point.position.y));
|
||||
return 2;
|
||||
}
|
||||
|
||||
int Contact::getVelocity(lua_State * L)
|
||||
{
|
||||
love::luax_assert_argc(L, 0, 0);
|
||||
lua_pushnumber(L, world->scaleUp(point.velocity.x));
|
||||
lua_pushnumber(L, world->scaleUp(point.velocity.y));
|
||||
return 2;
|
||||
}
|
||||
|
||||
int Contact::getNormal(lua_State * L)
|
||||
{
|
||||
love::luax_assert_argc(L, 0, 0);
|
||||
lua_pushnumber(L, world->scaleUp(point.normal.x));
|
||||
lua_pushnumber(L, world->scaleUp(point.normal.y));
|
||||
return 2;
|
||||
}
|
||||
|
||||
float Contact::getSeparation() const
|
||||
{
|
||||
return world->scaleUp(point.separation);
|
||||
}
|
||||
|
||||
float Contact::getFriction() const
|
||||
{
|
||||
return point.friction;
|
||||
}
|
||||
|
||||
float Contact::getRestitution() const
|
||||
{
|
||||
return point.restitution;
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_CONTACT_H
|
||||
#define LOVE_PHYSICS_BOX2D_CONTACT_H
|
||||
|
||||
// LOVE
|
||||
#include <common/Object.h>
|
||||
#include <common/runtime.h>
|
||||
|
||||
// Box2D
|
||||
#include "Include/Box2D.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
class World;
|
||||
|
||||
/**
|
||||
* A Contact represents a collision point between
|
||||
* two shapes.
|
||||
**/
|
||||
class Contact : public Object
|
||||
{
|
||||
// Friends.
|
||||
friend class World;
|
||||
|
||||
private:
|
||||
|
||||
// The Box2D contact point.
|
||||
b2ContactPoint point;
|
||||
|
||||
// The parent world. Needed for scaling.
|
||||
World * world;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a new Contact by copying a Box2D contact
|
||||
* point. It does not store the pointer, but copy the
|
||||
* data pointed to.
|
||||
* @param point Pointer to the Box2D contact.
|
||||
**/
|
||||
Contact(World * world, const b2ContactPoint * point);
|
||||
|
||||
~Contact();
|
||||
|
||||
/**
|
||||
* Gets the position of the Contact.
|
||||
* @return The position along the x-axis.
|
||||
* @return The position along the y-axis.
|
||||
**/
|
||||
int getPosition(lua_State * L);
|
||||
|
||||
/**
|
||||
* Gets the linear impact velocity.
|
||||
* @return The velocity along the x-axis.
|
||||
* @return The velocity along the y-axis.
|
||||
**/
|
||||
int getVelocity(lua_State * L);
|
||||
|
||||
/**
|
||||
* Gets the collision normal.
|
||||
* @return The x-component of the normal.
|
||||
* @return The y-component of the normal.
|
||||
**/
|
||||
int getNormal(lua_State * L);
|
||||
|
||||
/**
|
||||
* How far apart the shapes are. If they are intersecting
|
||||
* this value is negative.
|
||||
**/
|
||||
float getSeparation() const;
|
||||
|
||||
/**
|
||||
* The mixed friction between the two shapes at
|
||||
* the point of impact.
|
||||
**/
|
||||
float getFriction() const;
|
||||
|
||||
/**
|
||||
* The mixed restitution of the two shapes
|
||||
* at the point of impact.
|
||||
**/
|
||||
float getRestitution() const;
|
||||
|
||||
};
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_CONTACT_H
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "DistanceJoint.h"
|
||||
|
||||
// Module
|
||||
#include "Body.h"
|
||||
#include "World.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
DistanceJoint::DistanceJoint(Body * body1, Body * body2, float x1, float y1, float x2, float y2)
|
||||
: Joint(body1, body2)
|
||||
{
|
||||
b2DistanceJointDef def;
|
||||
def.Initialize(body1->body, body2->body, world->scaleDown(b2Vec2(x1,y1)), world->scaleDown(b2Vec2(x2,y2)));
|
||||
joint = (b2DistanceJoint*)createJoint(&def);
|
||||
}
|
||||
|
||||
DistanceJoint::~DistanceJoint()
|
||||
{
|
||||
destroyJoint(joint);
|
||||
joint = 0;
|
||||
}
|
||||
|
||||
void DistanceJoint::setLength(float length)
|
||||
{
|
||||
joint->m_length = world->scaleDown(length);
|
||||
}
|
||||
|
||||
float DistanceJoint::getLength() const
|
||||
{
|
||||
return world->scaleUp(joint->m_length);
|
||||
}
|
||||
|
||||
void DistanceJoint::setFrequency(float hz)
|
||||
{
|
||||
joint->m_frequencyHz = hz;
|
||||
}
|
||||
|
||||
float DistanceJoint::getFrequency() const
|
||||
{
|
||||
return joint->m_frequencyHz;
|
||||
}
|
||||
|
||||
void DistanceJoint::setDamping(float d)
|
||||
{
|
||||
joint->m_dampingRatio = d;
|
||||
}
|
||||
|
||||
float DistanceJoint::getDamping() const
|
||||
{
|
||||
return joint->m_dampingRatio;
|
||||
}
|
||||
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_DISTANCE_JOINT_H
|
||||
#define LOVE_PHYSICS_BOX2D_DISTANCE_JOINT_H
|
||||
|
||||
// Module
|
||||
#include "Joint.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
/**
|
||||
* The DistanceJoint keeps Bodies at a fixed distance
|
||||
* from eachother.
|
||||
**/
|
||||
class DistanceJoint : public Joint
|
||||
{
|
||||
private:
|
||||
// The Box2D DistanceJoint object.
|
||||
b2DistanceJoint * joint;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a DistanceJoint connecting body1 to body2.
|
||||
**/
|
||||
DistanceJoint(Body * body1, Body * body2, float x1, float y1, float x2, float y2);
|
||||
|
||||
virtual ~DistanceJoint();
|
||||
|
||||
/**
|
||||
* Sets the equilibrium distance between the two bodies.
|
||||
**/
|
||||
void setLength(float length);
|
||||
|
||||
/**
|
||||
* Gets the equilibrium distance between the two bodies.
|
||||
**/
|
||||
float getLength() const;
|
||||
|
||||
/**
|
||||
* Sets the response speed.
|
||||
**/
|
||||
void setFrequency(float hz);
|
||||
|
||||
/**
|
||||
* Gets the response speed.
|
||||
**/
|
||||
float getFrequency() const;
|
||||
|
||||
/**
|
||||
* Sets the damping ratio.
|
||||
* 0 = no damping, 1 = critical damping.
|
||||
**/
|
||||
void setDamping(float d);
|
||||
|
||||
/**
|
||||
* Gets the damping ratio.
|
||||
* 0 = no damping, 1 = critical damping.
|
||||
**/
|
||||
float getDamping() const;
|
||||
|
||||
};
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_DISTANCE_JOINT_H
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "GearJoint.h"
|
||||
|
||||
// Module
|
||||
#include "Body.h"
|
||||
#include "World.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
GearJoint::GearJoint(Joint * joint1, Joint * joint2, float ratio)
|
||||
: Joint(joint1->body2, joint2->body2)
|
||||
{
|
||||
b2GearJointDef def;
|
||||
def.joint1 = joint1->joint;
|
||||
def.joint2 = joint2->joint;
|
||||
def.body1 = joint1->body2->body;
|
||||
def.body2 = joint2->body2->body;
|
||||
def.ratio = ratio;
|
||||
|
||||
joint = (b2GearJoint*)createJoint(&def);
|
||||
}
|
||||
|
||||
GearJoint::~GearJoint()
|
||||
{
|
||||
destroyJoint(joint);
|
||||
joint = 0;
|
||||
}
|
||||
|
||||
void GearJoint::setRatio(float ratio)
|
||||
{
|
||||
joint->m_ratio = ratio;
|
||||
}
|
||||
|
||||
float GearJoint::getRatio() const
|
||||
{
|
||||
return joint->m_ratio;
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_GEAR_JOINT_H
|
||||
#define LOVE_PHYSICS_BOX2D_GEAR_JOINT_H
|
||||
|
||||
// Module
|
||||
#include "Joint.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
/**
|
||||
* 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: The revolute and prismatic joints must be attached to
|
||||
* fixed bodies (which must be body1 on those joints).
|
||||
**/
|
||||
class GearJoint : public Joint
|
||||
{
|
||||
private:
|
||||
// The Box2D GearJoint object.
|
||||
b2GearJoint * joint;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a GearJoint connecting joint1 to joint2.
|
||||
**/
|
||||
GearJoint(Joint * joint1, Joint * joint2, float ratio);
|
||||
|
||||
virtual ~GearJoint();
|
||||
|
||||
/**
|
||||
* Sets the ratio.
|
||||
**/
|
||||
void setRatio(float ratio);
|
||||
|
||||
/**
|
||||
* Gets the ratio.
|
||||
**/
|
||||
float getRatio() const;
|
||||
|
||||
};
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_GEAR_JOINT_H
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef BOX2D_H
|
||||
#define BOX2D_H
|
||||
|
||||
/**
|
||||
\mainpage Box2D API Documentation
|
||||
|
||||
\section intro_sec Getting Started
|
||||
|
||||
For tutorials please see http://www.box2d.org/manual.html
|
||||
|
||||
For discussion please visit http://www.box2d.org/forum
|
||||
*/
|
||||
|
||||
// These include files constitute the main Box2D API
|
||||
|
||||
#include "../Source/Common/b2Settings.h"
|
||||
|
||||
#include "../Source/Collision/Shapes/b2CircleShape.h"
|
||||
#include "../Source/Collision/Shapes/b2PolygonShape.h"
|
||||
#include "../Source/Collision/b2BroadPhase.h"
|
||||
#include "../Source/Dynamics/b2WorldCallbacks.h"
|
||||
#include "../Source/Dynamics/b2World.h"
|
||||
#include "../Source/Dynamics/b2Body.h"
|
||||
|
||||
#include "../Source/Dynamics/Contacts/b2Contact.h"
|
||||
|
||||
#include "../Source/Dynamics/Joints/b2DistanceJoint.h"
|
||||
#include "../Source/Dynamics/Joints/b2MouseJoint.h"
|
||||
#include "../Source/Dynamics/Joints/b2PrismaticJoint.h"
|
||||
#include "../Source/Dynamics/Joints/b2RevoluteJoint.h"
|
||||
#include "../Source/Dynamics/Joints/b2PulleyJoint.h"
|
||||
#include "../Source/Dynamics/Joints/b2GearJoint.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "Joint.h"
|
||||
|
||||
// STD
|
||||
#include <bitset>
|
||||
|
||||
// Module
|
||||
#include "Body.h"
|
||||
#include "World.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
Joint::Joint(Body * body1)
|
||||
: body1(body1), body2(0), world(body1->world)
|
||||
{
|
||||
body1->retain();
|
||||
}
|
||||
|
||||
Joint::Joint(Body * body1, Body * body2)
|
||||
: body1(body1), body2(body2), world(body1->world)
|
||||
{
|
||||
body1->retain();
|
||||
body2->retain();
|
||||
}
|
||||
|
||||
Joint::~Joint()
|
||||
{
|
||||
if(body1 != 0)
|
||||
body1->release();
|
||||
if(body2 != 0)
|
||||
body2->release();
|
||||
|
||||
joint = 0;
|
||||
}
|
||||
|
||||
int Joint::getType() const
|
||||
{
|
||||
switch(joint->GetType())
|
||||
{
|
||||
case e_revoluteJoint:
|
||||
return love::JOINT_REVOLUTE;
|
||||
case e_prismaticJoint:
|
||||
return love::JOINT_PRISMATIC;
|
||||
case e_distanceJoint:
|
||||
return love::JOINT_DISTANCE;
|
||||
case e_pulleyJoint:
|
||||
return love::JOINT_PULLEY;
|
||||
case e_mouseJoint:
|
||||
return love::JOINT_MOUSE;
|
||||
case e_gearJoint:
|
||||
return love::JOINT_GEAR;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int Joint::getAnchors(lua_State * L)
|
||||
{
|
||||
lua_pushnumber(L, world->scaleUp(joint->GetAnchor1().x));
|
||||
lua_pushnumber(L, world->scaleUp(joint->GetAnchor1().y));
|
||||
lua_pushnumber(L, world->scaleUp(joint->GetAnchor2().x));
|
||||
lua_pushnumber(L, world->scaleUp(joint->GetAnchor2().y));
|
||||
return 4;
|
||||
}
|
||||
|
||||
int Joint::getReactionForce(lua_State * L)
|
||||
{
|
||||
b2Vec2 v = joint->GetReactionForce();
|
||||
lua_pushnumber(L, v.x);
|
||||
lua_pushnumber(L, v.y);
|
||||
return 2;
|
||||
}
|
||||
|
||||
float Joint::getReactionTorque()
|
||||
{
|
||||
return joint->GetReactionTorque();
|
||||
}
|
||||
|
||||
void Joint::setCollideConnected(bool collide)
|
||||
{
|
||||
joint->m_collideConnected = collide;
|
||||
}
|
||||
|
||||
bool Joint::getCollideConnected() const
|
||||
{
|
||||
return joint->m_collideConnected;
|
||||
}
|
||||
|
||||
b2Joint * Joint::createJoint(b2JointDef * def)
|
||||
{
|
||||
joint = world->world->CreateJoint(def);
|
||||
return joint;
|
||||
}
|
||||
|
||||
void Joint::destroyJoint(b2Joint * joint)
|
||||
{
|
||||
world->world->DestroyJoint(joint);
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_JOINT_H
|
||||
#define LOVE_PHYSICS_BOX2D_JOINT_H
|
||||
|
||||
// LOVE
|
||||
#include <common/runtime.h>
|
||||
#include <common/Object.h>
|
||||
#include <common/constants.h>
|
||||
|
||||
// Box2D
|
||||
#include "Include/Box2D.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
// Forward declarations.
|
||||
class Body;
|
||||
class World;
|
||||
|
||||
/**
|
||||
* A Joint acts as positioning constraints on Bodies.
|
||||
* A Joint can be used to prevent Bodies from going to
|
||||
* far apart, or coming too close together.
|
||||
**/
|
||||
class Joint : public Object
|
||||
{
|
||||
friend class GearJoint;
|
||||
|
||||
private:
|
||||
|
||||
// A Joint must be destroyed *before* the bodies it acts upon,
|
||||
// and the world they reside in. We therefore need refs
|
||||
// parents and associations to prevent wrong destruction order.
|
||||
Body * body1, * body2;
|
||||
|
||||
|
||||
// The Box2D joint object.
|
||||
b2Joint * joint;
|
||||
|
||||
protected:
|
||||
World * world;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* This constructor will connect one end of the joint to body1,
|
||||
* and the other one to the default ground body.
|
||||
*
|
||||
* This constructor is mainly used by MouseJoint.
|
||||
**/
|
||||
Joint(Body * body1);
|
||||
|
||||
/**
|
||||
* Create a joint between body1 and body2.
|
||||
**/
|
||||
Joint(Body * body1, Body * body2);
|
||||
|
||||
virtual ~Joint();
|
||||
|
||||
/**
|
||||
* Gets the type of joint.
|
||||
**/
|
||||
int getType() const;
|
||||
|
||||
/**
|
||||
* Gets the anchor positions of the Joint in world
|
||||
* coordinates. This is useful for debugdrawing the joint.
|
||||
**/
|
||||
int getAnchors(lua_State * L);
|
||||
|
||||
/**
|
||||
* Gets the reaction force on body2 at the joint anchor.
|
||||
**/
|
||||
int getReactionForce(lua_State * L);
|
||||
|
||||
/**
|
||||
* Gets the reaction torque on body2.
|
||||
**/
|
||||
float getReactionTorque();
|
||||
|
||||
/**
|
||||
* Sets whether connected bodies should collide
|
||||
* or not. Default is false.
|
||||
**/
|
||||
void setCollideConnected(bool collide);
|
||||
|
||||
/**
|
||||
* Gets whether connected bodies should collide
|
||||
* or not.
|
||||
**/
|
||||
bool getCollideConnected() const;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Joints require pointers to a Box2D joint objects at
|
||||
* different polymorphic levels, which is why these function
|
||||
* were created.
|
||||
**/
|
||||
|
||||
/**
|
||||
* Creates a Joint, and ensures that the parent class
|
||||
* gets a copy of the pointer.
|
||||
**/
|
||||
b2Joint * createJoint(b2JointDef * def);
|
||||
|
||||
/**
|
||||
* Destroys the joint. This function was created just to
|
||||
* get some cinsistency.
|
||||
**/
|
||||
void destroyJoint(b2Joint * joint);
|
||||
};
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_JOINT_H
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "MouseJoint.h"
|
||||
|
||||
// Module
|
||||
#include "Body.h"
|
||||
#include "World.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
MouseJoint::MouseJoint(Body * body1, float x, float y)
|
||||
: Joint(body1)
|
||||
{
|
||||
b2MouseJointDef def;
|
||||
|
||||
def.body1 = body1->world->world->GetGroundBody();
|
||||
def.body2 = body1->body;
|
||||
def.maxForce = 1000.0f * body1->body->GetMass();
|
||||
def.target = body1->world->scaleDown(b2Vec2(x,y));
|
||||
joint = (b2MouseJoint*)createJoint(&def);
|
||||
}
|
||||
|
||||
MouseJoint::~MouseJoint()
|
||||
{
|
||||
destroyJoint(joint);
|
||||
joint = 0;
|
||||
}
|
||||
|
||||
void MouseJoint::setTarget(float x, float y)
|
||||
{
|
||||
joint->SetTarget(world->scaleDown(b2Vec2(x, y)));
|
||||
}
|
||||
|
||||
int MouseJoint::getTarget(lua_State * L)
|
||||
{
|
||||
lua_pushnumber(L, world->scaleUp(joint->m_target.x));
|
||||
lua_pushnumber(L, world->scaleUp(joint->m_target.y));
|
||||
return 2;
|
||||
}
|
||||
|
||||
void MouseJoint::setMaxForce(float force)
|
||||
{
|
||||
joint->m_maxForce = force;
|
||||
}
|
||||
|
||||
float MouseJoint::getMaxForce() const
|
||||
{
|
||||
return joint->m_maxForce;
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_MOUSE_JOINT_H
|
||||
#define LOVE_PHYSICS_BOX2D_MOUSE_JOINT_H
|
||||
|
||||
// Module
|
||||
#include "Joint.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
/**
|
||||
* The MouseJoint is a joint type that
|
||||
* is suitable for controlling objects with the mouse.
|
||||
*
|
||||
* One end is anchored in the dynamic body, and the other id
|
||||
* anchor to a static ground body. The anchor offset can then be
|
||||
* moved to the current mouse position.
|
||||
**/
|
||||
class MouseJoint : public Joint
|
||||
{
|
||||
private:
|
||||
// The Box2D MouseJoint object.
|
||||
b2MouseJoint * joint;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a MouseJoint which connects body1 to the target point.
|
||||
**/
|
||||
MouseJoint(Body * body1, float x, float y);
|
||||
|
||||
virtual ~MouseJoint();
|
||||
|
||||
/**
|
||||
* Sets the target of anchor2. (You usually want
|
||||
* to set this to the current mouse.)
|
||||
**/
|
||||
void setTarget(float x, float y);
|
||||
|
||||
/**
|
||||
* Gets the current anchor2 target.
|
||||
**/
|
||||
int getTarget(lua_State * L);
|
||||
|
||||
/**
|
||||
* Sets the maximum constraint force that can be exerted
|
||||
* to move the candidate body.
|
||||
**/
|
||||
void setMaxForce(float force);
|
||||
|
||||
/**
|
||||
* Gets the maximum constraint force that can be exerted
|
||||
* to move the candidate body.
|
||||
**/
|
||||
float getMaxForce() const;
|
||||
};
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_MOUSE_JOINT_H
|
||||
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "Physics.h"
|
||||
|
||||
// Convex Hull Scan
|
||||
#include "graham/GrahamScanConvexHull.h"
|
||||
|
||||
// LOVE
|
||||
#include <common/math.h>
|
||||
#include "wrap_Body.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
|
||||
const char * Physics::getName() const
|
||||
{
|
||||
return "love.physics.box2d";
|
||||
}
|
||||
|
||||
World * Physics::newWorld(float lx, float ly, float ux, float uy, float gx, float gy, bool sleep)
|
||||
{
|
||||
b2AABB aabb;
|
||||
aabb.lowerBound.Set(lx, ly);
|
||||
aabb.upperBound.Set(ux, uy);
|
||||
return new World(aabb, b2Vec2(gx, gy), sleep);
|
||||
}
|
||||
|
||||
World * Physics::newWorld(float w, float h)
|
||||
{
|
||||
return newWorld(-w, -h, w, h, 0, 0, true);
|
||||
}
|
||||
|
||||
Body * Physics::newBody(World * world, float x, float y, float mass, float i)
|
||||
{
|
||||
return new Body(world, b2Vec2(x, y), mass, i);
|
||||
}
|
||||
|
||||
Body * Physics::newBody(World * world, float x, float y)
|
||||
{
|
||||
return new Body(world, b2Vec2(x, y), 1, 1);
|
||||
}
|
||||
|
||||
Body * Physics::newBody(World * world)
|
||||
{
|
||||
return new Body(world, b2Vec2(0, 0), 1, 1);
|
||||
}
|
||||
|
||||
CircleShape * Physics::newCircleShape(Body * body, float radius)
|
||||
{
|
||||
return newCircleShape(body, 0, 0, radius);
|
||||
}
|
||||
|
||||
CircleShape * Physics::newCircleShape(Body * body, float x, float y, float radius)
|
||||
{
|
||||
b2CircleDef def;
|
||||
def.density = 1.0f;
|
||||
def.localPosition.Set(x, y);
|
||||
def.friction = 0.5f;
|
||||
def.restitution = 0.1f;
|
||||
def.radius = radius;
|
||||
return new CircleShape(body, &def);
|
||||
}
|
||||
|
||||
PolygonShape * Physics::newRectangleShape(Body * body, float w, float h)
|
||||
{
|
||||
return newRectangleShape(body, 0, 0, w, h, 0);
|
||||
}
|
||||
|
||||
PolygonShape * Physics::newRectangleShape(Body * body, float x, float y, float w, float h)
|
||||
{
|
||||
return newRectangleShape(body, x, y, w, h, 0);
|
||||
}
|
||||
|
||||
PolygonShape * Physics::newRectangleShape(Body * body, float x, float y, float w, float h, float angle)
|
||||
{
|
||||
b2PolygonDef def;
|
||||
def.friction = 0.5f;
|
||||
def.restitution = 0.1f;
|
||||
def.density = 1.0f;
|
||||
def.SetAsBox(w/2.0f, h/2.0f, b2Vec2(x, y), angle);
|
||||
return new PolygonShape(body, &def);
|
||||
}
|
||||
|
||||
int Physics::newPolygonShape(lua_State * L)
|
||||
{
|
||||
int argc = lua_gettop(L);
|
||||
int vcount = (int)(argc-1)/2;
|
||||
// 1 body + 3 vertices
|
||||
love::luax_assert_argc(L, 1 + (2 * 3));
|
||||
|
||||
Body * b = luax_checkbody(L, 1);
|
||||
|
||||
b2PolygonDef def;
|
||||
def.friction = 0.5f;
|
||||
def.restitution = 0.1f;
|
||||
def.density = 1.0f;
|
||||
|
||||
std::vector<point2d> points(def.vertexCount);
|
||||
std::vector<point2d> convex_hull;
|
||||
|
||||
for(int i = 0;i<vcount;i++)
|
||||
{
|
||||
float x = (float)lua_tonumber(L, -2);
|
||||
float y = (float)lua_tonumber(L, -1);
|
||||
point2d tmp(x, y);
|
||||
points.push_back(tmp);
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
|
||||
// Compute convex hull.
|
||||
GrahamScanConvexHull()(points, convex_hull);
|
||||
|
||||
def.vertexCount = (int32)convex_hull.size();
|
||||
|
||||
if(def.vertexCount < 3)
|
||||
return luaL_error(L, "Polygon degenerated to less than three points.");
|
||||
|
||||
for(int i = 0;i<def.vertexCount;i++)
|
||||
def.vertices[def.vertexCount-i-1].Set((float)convex_hull[i].x, (float)convex_hull[i].y);
|
||||
|
||||
PolygonShape * p = new PolygonShape(b, &def);
|
||||
|
||||
luax_newtype(L, "PolygonShape", LOVE_PHYSICS_POLYGON_SHAPE_BITS, (void*)p);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
DistanceJoint * Physics::newDistanceJoint(Body * body1, Body * body2, float x1, float y1, float x2, float y2)
|
||||
{
|
||||
return new DistanceJoint(body1, body2, x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
MouseJoint * Physics::newMouseJoint(Body * body, float x, float y)
|
||||
{
|
||||
return new MouseJoint(body, x, y);
|
||||
}
|
||||
|
||||
RevoluteJoint * Physics::newRevoluteJoint(Body * body1, Body * body2, float x, float y)
|
||||
{
|
||||
return new RevoluteJoint(body1, body2, x, y);
|
||||
}
|
||||
|
||||
PrismaticJoint * Physics::newPrismaticJoint(Body * body1, Body * body2, float x, float y, float ax, float ay)
|
||||
{
|
||||
return new PrismaticJoint(body1, body2, x, y, ax, ay);
|
||||
}
|
||||
|
||||
PulleyJoint * Physics::newPulleyJoint(Body * body1, Body * body2, b2Vec2 groundAnchor1, b2Vec2 groundAnchor2, b2Vec2 anchor1, b2Vec2 anchor2, float ratio)
|
||||
{
|
||||
return new PulleyJoint(body1, body2, groundAnchor1, groundAnchor2, anchor1, anchor2, ratio);
|
||||
}
|
||||
|
||||
GearJoint * Physics::newGearJoint(Joint * joint1, Joint * joint2, float ratio)
|
||||
{
|
||||
return new GearJoint(joint1, joint2, ratio);
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_PHYSICS_H
|
||||
#define LOVE_PHYSICS_BOX2D_PHYSICS_H
|
||||
|
||||
// LOVE
|
||||
#include <common/Module.h>
|
||||
#include "World.h"
|
||||
#include "Contact.h"
|
||||
#include "Body.h"
|
||||
#include "Shape.h"
|
||||
#include "CircleShape.h"
|
||||
#include "PolygonShape.h"
|
||||
#include "Joint.h"
|
||||
#include "MouseJoint.h"
|
||||
#include "DistanceJoint.h"
|
||||
#include "PrismaticJoint.h"
|
||||
#include "RevoluteJoint.h"
|
||||
#include "PulleyJoint.h"
|
||||
#include "GearJoint.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
class Physics : public Module
|
||||
{
|
||||
public:
|
||||
|
||||
// Implements Module.
|
||||
const char * getName() const;
|
||||
|
||||
/**
|
||||
* Creates a new World.
|
||||
* @param lx Lower bound on the x-axis.
|
||||
* @param ly Lower bound on the y-axis.
|
||||
* @param ux Upper bound on the x-axis.
|
||||
* @param uy Upper bound on the y-axis.
|
||||
* @param gx Gravity along x-axis.
|
||||
* @param gy Gravity along y-axis.
|
||||
* @param sleep Whether the World allows sleep.
|
||||
**/
|
||||
World * newWorld(float lx, float ly, float ux, float uy, float gx, float gy, bool sleep);
|
||||
|
||||
/**
|
||||
* Creates a new World with with size (w,h).
|
||||
* @param w The width of the world.
|
||||
* @param h The height of the world.
|
||||
**/
|
||||
World * newWorld(float w, float h);
|
||||
|
||||
/**
|
||||
* Creates a new Body at the specified position.
|
||||
* @param world The world to create the Body in.
|
||||
* @param x The position along the x-axis.
|
||||
* @param x The position along the y-axis.
|
||||
* @param m The mass.
|
||||
* @param i The rotational inertia.
|
||||
**/
|
||||
Body * newBody(World * world, float x, float y, float m, float i);
|
||||
|
||||
/**
|
||||
* Creates a new Body at the specified position.
|
||||
* @param world The world to create the Body in.
|
||||
* @param x The position along the x-axis.
|
||||
* @param x The position along the y-axis.
|
||||
**/
|
||||
Body * newBody(World * world, float x, float y);
|
||||
|
||||
/**
|
||||
* Creates a new Body at (0, 0)
|
||||
* @param world The world to create the Body in.
|
||||
**/
|
||||
Body * newBody(World * world);
|
||||
|
||||
/**
|
||||
* Creates a new CircleShape at the Body origin.
|
||||
* @param body The Body to create the Shape on.
|
||||
* @param radius The radius of the circle.
|
||||
**/
|
||||
CircleShape * newCircleShape(Body * body, float radius);
|
||||
|
||||
/**
|
||||
* Creates a new CircleShape at (x,y) in local coorinates.
|
||||
* @param body The Body to create the Shape on.
|
||||
* @param x The offset along the x-axis.
|
||||
* @param y The offset along the y-axis.
|
||||
* @param radius The radius of the circle.
|
||||
**/
|
||||
CircleShape * newCircleShape(Body * body, float x, float y, float radius);
|
||||
|
||||
/**
|
||||
* Shorthand for creating rectangluar PolygonShapes. The rectangle
|
||||
* will be created at the local origin.
|
||||
* @param w The width of the rectangle.
|
||||
* @param h The height of the rectangle.
|
||||
**/
|
||||
PolygonShape * newRectangleShape(Body * body, float w, float h);
|
||||
|
||||
/**
|
||||
* Shorthand for creating rectangluar PolygonShapes. The rectangle
|
||||
* will be created at (x,y) in local coordinates.
|
||||
* @param x The offset along the x-axis.
|
||||
* @param y The offset along the y-axis.
|
||||
* @param w The width of the rectangle.
|
||||
* @param h The height of the rectangle.
|
||||
**/
|
||||
PolygonShape * newRectangleShape(Body * body, float x, float y, float w, float h);
|
||||
|
||||
/**
|
||||
* Shorthand for creating rectangluar PolygonShapes. The rectangle
|
||||
* will be created at (x,y) in local coordinates.
|
||||
* @param x The offset along the x-axis.
|
||||
* @param y The offset along the y-axis.
|
||||
* @param w The width of the rectangle.
|
||||
* @param h The height of the rectangle.
|
||||
* @param angle The angle of the rectangle. (deg)
|
||||
**/
|
||||
PolygonShape * newRectangleShape(Body * body, float x, float y, float w, float h, float angle);
|
||||
|
||||
/**
|
||||
* Creates a new PolygonShape.
|
||||
* @param body The body to create this shape on.
|
||||
* @param ... A variable number of vertices.
|
||||
**/
|
||||
int newPolygonShape(lua_State * L);
|
||||
|
||||
/**
|
||||
* Creates a new DistanceJoint connecting body1 with body2.
|
||||
* @param x1 Anchor1 along the x-axis. (World coordinates)
|
||||
* @param y1 Anchor1 along the y-axis. (World coordinates)
|
||||
* @param x2 Anchor2 along the x-axis. (World coordinates)
|
||||
* @param y2 Anchor2 along the y-axis. (World coordinates)
|
||||
**/
|
||||
DistanceJoint * newDistanceJoint(Body * body1, Body * body2, float x1, float y1, float x2, float y2);
|
||||
|
||||
/**
|
||||
* Creates a new MouseJoint connecting the body with an arbitrary point.
|
||||
* @param x Anchor along the x-axis. (World coordinates)
|
||||
* @param y Anchor along the y-axis. (World coordinates)
|
||||
**/
|
||||
MouseJoint * newMouseJoint(Body * body, float x, float y);
|
||||
|
||||
/**
|
||||
* Creates a new RevoluteJoint connecting body1 with body2.
|
||||
* @param x Anchor along the x-axis. (World coordinates)
|
||||
* @param y Anchor along the y-axis. (World coordinates)
|
||||
**/
|
||||
RevoluteJoint * newRevoluteJoint(Body * body1, Body * body2, float x, float y);
|
||||
|
||||
/**
|
||||
* Creates a new PrismaticJoint connecting body1 with body2.
|
||||
* @param x World-anchor along the x-axis.
|
||||
* @param y World-anchor along the y-axis.
|
||||
* @param ax The x-component of the world-axis.
|
||||
* @param ay The y-component of the world-axis.
|
||||
**/
|
||||
PrismaticJoint * newPrismaticJoint(Body * body1, Body * body2, float x, float y, float ax, float ay);
|
||||
|
||||
/**
|
||||
* Creates a new PulleyJoint connecting body1 with body2.
|
||||
* @param groundAnchor1 World ground-anchor for body1.
|
||||
* @param groundAnchor2 World ground-anchor for body2.
|
||||
* @param anchor1 World anchor on body1.
|
||||
* @param anchor2 World anchor on body2.
|
||||
* @param ratio The pulley ratio.
|
||||
**/
|
||||
PulleyJoint * newPulleyJoint(Body * body1, Body * body2, b2Vec2 groundAnchor1, b2Vec2 groundAnchor2, b2Vec2 anchor1, b2Vec2 anchor2, float ratio);
|
||||
|
||||
/**
|
||||
* Creates a new GearJoint connecting joint1 with joint2.
|
||||
* @param joint1 The first joint.
|
||||
* @param joint2 The second joint.
|
||||
* @param ratio The gear ratio.
|
||||
**/
|
||||
GearJoint * newGearJoint(Joint * joint1, Joint * joint2, float ratio);
|
||||
|
||||
|
||||
}; // Physics
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_PHYSICS_H
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "PolygonShape.h"
|
||||
|
||||
// Module
|
||||
#include "Body.h"
|
||||
#include "World.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
PolygonShape::PolygonShape(Body * body, b2PolygonDef * def)
|
||||
: Shape(body)
|
||||
{
|
||||
for(int i = 0; i<def->vertexCount; i++)
|
||||
def->vertices[i] = body->world->scaleDown(def->vertices[i]);
|
||||
|
||||
shape = body->body->CreateShape(def);
|
||||
shape->SetUserData((void*)data);
|
||||
}
|
||||
|
||||
PolygonShape::~PolygonShape()
|
||||
{
|
||||
body->body->DestroyShape(shape);
|
||||
shape = 0;
|
||||
}
|
||||
|
||||
int PolygonShape::getPoints(lua_State * L)
|
||||
{
|
||||
love::luax_assert_argc(L, 0);
|
||||
b2PolygonShape * p = (b2PolygonShape *)shape;
|
||||
const b2Vec2 * vertices = p->GetVertices();
|
||||
int count = p->GetVertexCount();
|
||||
for(int i = 0;i<count; i++)
|
||||
{
|
||||
b2Vec2 v = body->world->scaleUp(body->body->GetWorldPoint(vertices[i]));
|
||||
lua_pushnumber(L, v.x);
|
||||
lua_pushnumber(L, v.y);
|
||||
}
|
||||
return count*2;
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_POLYGON_SHAPE_H
|
||||
#define LOVE_PHYSICS_BOX2D_POLYGON_SHAPE_H
|
||||
|
||||
// Module
|
||||
#include "Shape.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
/**
|
||||
* You should know what a Polygon is. :)
|
||||
*
|
||||
* This class is needed so that we can easily get
|
||||
* the transformed points in Lua. By calling shape:getPoints(),
|
||||
* the result can be passed directly to love.graphics.polygon().
|
||||
**/
|
||||
class PolygonShape : public Shape
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create a new PolygonShape from the parent Body and
|
||||
* a Box2D polygon definition.
|
||||
* @param body The parent Body.
|
||||
* @param def The polygon definition.
|
||||
**/
|
||||
PolygonShape(Body * body, b2PolygonDef * def);
|
||||
|
||||
virtual ~PolygonShape();
|
||||
|
||||
/**
|
||||
* Returns the transformed points of the polygon.
|
||||
* This function is useful for debug drawing and such.
|
||||
*
|
||||
* The result can be directly passed into love.graphics.polygon().
|
||||
**/
|
||||
int getPoints(lua_State * L);
|
||||
};
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_POLYGON_SHAPE_H
|
||||
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "PrismaticJoint.h"
|
||||
|
||||
// Module
|
||||
#include "Body.h"
|
||||
#include "World.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
PrismaticJoint::PrismaticJoint(Body * body1, Body * body2, float x, float y, float ax, float ay)
|
||||
: Joint(body1, body2)
|
||||
{
|
||||
b2PrismaticJointDef def;
|
||||
|
||||
def.Initialize(body1->body, body2->body, world->scaleDown(b2Vec2(x,y)), b2Vec2(ax,ay));
|
||||
def.lowerTranslation = 0.0f;
|
||||
def.upperTranslation = 100.0f;
|
||||
def.enableLimit = true;
|
||||
joint = (b2PrismaticJoint*)createJoint(&def);
|
||||
}
|
||||
|
||||
PrismaticJoint::~PrismaticJoint()
|
||||
{
|
||||
destroyJoint(joint);
|
||||
joint = 0;
|
||||
}
|
||||
|
||||
float PrismaticJoint::getTranslation() const
|
||||
{
|
||||
return world->scaleDown(joint->GetJointTranslation());
|
||||
}
|
||||
|
||||
float PrismaticJoint::getSpeed() const
|
||||
{
|
||||
return world->scaleDown(joint->GetJointSpeed());
|
||||
}
|
||||
|
||||
void PrismaticJoint::setMotorEnabled(bool motor)
|
||||
{
|
||||
return joint->EnableMotor(true);
|
||||
}
|
||||
|
||||
bool PrismaticJoint::isMotorEnabled() const
|
||||
{
|
||||
return joint->IsMotorEnabled();
|
||||
}
|
||||
|
||||
void PrismaticJoint::setMaxMotorForce(float force)
|
||||
{
|
||||
joint->SetMaxMotorForce(force);
|
||||
}
|
||||
|
||||
float PrismaticJoint::getMaxMotorForce() const
|
||||
{
|
||||
return joint->GetMotorForce();
|
||||
}
|
||||
|
||||
void PrismaticJoint::setMotorSpeed(float speed)
|
||||
{
|
||||
joint->SetMotorSpeed(speed);
|
||||
}
|
||||
|
||||
float PrismaticJoint::getMotorSpeed() const
|
||||
{
|
||||
return joint->GetMotorSpeed();
|
||||
}
|
||||
|
||||
float PrismaticJoint::getMotorForce() const
|
||||
{
|
||||
return joint->GetMotorForce();
|
||||
}
|
||||
|
||||
void PrismaticJoint::setLimitsEnabled(bool limit)
|
||||
{
|
||||
joint->EnableLimit(limit);
|
||||
}
|
||||
|
||||
bool PrismaticJoint::isLimitsEnabled() const
|
||||
{
|
||||
return joint->IsLimitEnabled();
|
||||
}
|
||||
|
||||
void PrismaticJoint::setUpperLimit(float limit)
|
||||
{
|
||||
joint->SetLimits(joint->GetLowerLimit(), world->scaleDown(limit));
|
||||
}
|
||||
|
||||
void PrismaticJoint::setLowerLimit(float limit)
|
||||
{
|
||||
joint->SetLimits(world->scaleDown(limit), joint->GetUpperLimit());
|
||||
}
|
||||
|
||||
void PrismaticJoint::setLimits(float lower, float upper)
|
||||
{
|
||||
joint->SetLimits(world->scaleDown(lower), world->scaleDown(upper));
|
||||
}
|
||||
|
||||
float PrismaticJoint::getLowerLimit() const
|
||||
{
|
||||
return world->scaleUp(joint->GetLowerLimit());
|
||||
}
|
||||
|
||||
float PrismaticJoint::getUpperLimit() const
|
||||
{
|
||||
return world->scaleUp(joint->GetUpperLimit());
|
||||
}
|
||||
|
||||
int PrismaticJoint::getLimits(lua_State * L)
|
||||
{
|
||||
lua_pushnumber(L, world->scaleUp(joint->GetLowerLimit()));
|
||||
lua_pushnumber(L, world->scaleUp(joint->GetUpperLimit()));
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_PRISMATIC_JOINT_H
|
||||
#define LOVE_PHYSICS_BOX2D_PRISMATIC_JOINT_H
|
||||
|
||||
// Module
|
||||
#include "Joint.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
/**
|
||||
* PrismaticJoints allow shapes to move in relation to eachother
|
||||
* along a defined axis.
|
||||
**/
|
||||
class PrismaticJoint : public Joint
|
||||
{
|
||||
private:
|
||||
|
||||
// The Box2D prismatic joint object.
|
||||
b2PrismaticJoint * joint;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a new PrismaticJoint connecting body1 and body2.
|
||||
**/
|
||||
PrismaticJoint(Body * body1, Body * body2, float x, float y, float ax, float ay);
|
||||
|
||||
virtual ~PrismaticJoint();
|
||||
|
||||
/**
|
||||
* Get the current joint translation, usually in meters.
|
||||
**/
|
||||
float getTranslation() const;
|
||||
|
||||
/**
|
||||
* Get the current joint translation speed, usually in meters per second.
|
||||
**/
|
||||
float getSpeed() const;
|
||||
|
||||
/**
|
||||
* Enable/disable the joint motor.
|
||||
**/
|
||||
void setMotorEnabled(bool motor);
|
||||
|
||||
/**
|
||||
* Checks whether the motor is enabled.
|
||||
**/
|
||||
bool isMotorEnabled() const;
|
||||
|
||||
/**
|
||||
* Set the maximum motor force, usually in N.
|
||||
**/
|
||||
void setMaxMotorForce(float force);
|
||||
|
||||
/**
|
||||
* Get the current motor force, usually in N.
|
||||
**/
|
||||
float getMaxMotorForce() const;
|
||||
|
||||
/**
|
||||
* Set the motor speed, usually in meters per second.
|
||||
**/
|
||||
void setMotorSpeed(float speed);
|
||||
|
||||
/**
|
||||
* Get the motor speed, usually in meters per second.
|
||||
**/
|
||||
float getMotorSpeed() const;
|
||||
|
||||
/**
|
||||
* Get the current motor force, usually in N.
|
||||
**/
|
||||
float getMotorForce() const;
|
||||
|
||||
/**
|
||||
* Enable/disable the joint limit.
|
||||
**/
|
||||
void setLimitsEnabled(bool limit);
|
||||
|
||||
/**
|
||||
* Checks whether limits are enabled.
|
||||
**/
|
||||
bool isLimitsEnabled() const;
|
||||
|
||||
/**
|
||||
* Sets the upper limit, usually in meters.
|
||||
**/
|
||||
void setUpperLimit(float limit);
|
||||
|
||||
/**
|
||||
* Sets the lower limit, usually in meters.
|
||||
**/
|
||||
void setLowerLimit(float limit);
|
||||
|
||||
/**
|
||||
* Sets the limits, usually in meters.
|
||||
**/
|
||||
void setLimits(float lower, float upper);
|
||||
|
||||
/**
|
||||
* Gets the lower limit, usually in meters.
|
||||
**/
|
||||
float getLowerLimit() const;
|
||||
|
||||
/**
|
||||
* Gets the upper limit, usually in meters.
|
||||
**/
|
||||
float getUpperLimit() const;
|
||||
|
||||
/**
|
||||
* Gets the limits, usually in meters.
|
||||
* @returns The upper limit.
|
||||
* @returns The lower limit.
|
||||
**/
|
||||
int getLimits(lua_State * L);
|
||||
|
||||
};
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_PRISMATIC_JOINT_H
|
||||
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "PulleyJoint.h"
|
||||
|
||||
// Module
|
||||
#include "Body.h"
|
||||
#include "World.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
PulleyJoint::PulleyJoint(Body * body1, Body * body2, b2Vec2 groundAnchor1, b2Vec2 groundAnchor2, b2Vec2 anchor1, b2Vec2 anchor2, float ratio)
|
||||
: Joint(body1, body2)
|
||||
{
|
||||
b2PulleyJointDef def;
|
||||
def.Initialize(body1->body, body2->body, world->scaleDown(groundAnchor1), world->scaleDown(groundAnchor2), \
|
||||
world->scaleDown(anchor1), world->scaleDown(anchor2), ratio);
|
||||
|
||||
joint = (b2PulleyJoint*)createJoint(&def);
|
||||
}
|
||||
|
||||
PulleyJoint::~PulleyJoint()
|
||||
{
|
||||
destroyJoint(joint);
|
||||
joint = 0;
|
||||
}
|
||||
|
||||
int PulleyJoint::getGroundAnchors(lua_State * L)
|
||||
{
|
||||
lua_pushnumber(L, world->scaleUp(joint->GetGroundAnchor1().x));
|
||||
lua_pushnumber(L, world->scaleUp(joint->GetGroundAnchor1().y));
|
||||
lua_pushnumber(L, world->scaleUp(joint->GetGroundAnchor2().x));
|
||||
lua_pushnumber(L, world->scaleUp(joint->GetGroundAnchor2().y));
|
||||
return 4;
|
||||
}
|
||||
|
||||
void PulleyJoint::setMaxLengths(float maxlength1, float maxlength2)
|
||||
{
|
||||
// Apply Box2D's maximum lengths too. They know better.
|
||||
|
||||
if (maxlength1 > 0)
|
||||
{
|
||||
joint->m_maxLength1 = b2Min(world->scaleDown(maxlength1), joint->m_constant - joint->m_ratio * b2_minPulleyLength);
|
||||
}
|
||||
|
||||
if (maxlength2 > 0)
|
||||
{
|
||||
joint->m_maxLength2 = b2Min(world->scaleDown(maxlength2), (joint->m_constant - b2_minPulleyLength) / joint->m_ratio);
|
||||
}
|
||||
}
|
||||
|
||||
int PulleyJoint::getMaxLengths(lua_State * L)
|
||||
{
|
||||
lua_pushnumber(L, world->scaleUp(joint->m_maxLength1));
|
||||
lua_pushnumber(L, world->scaleUp(joint->m_maxLength2));
|
||||
return 2;
|
||||
}
|
||||
|
||||
void PulleyJoint::setConstant(float constant)
|
||||
{
|
||||
joint->m_constant = world->scaleDown(constant);
|
||||
|
||||
// Update the max lengths, as does Box2D
|
||||
joint->m_maxLength1 = joint->m_constant - joint->m_ratio * b2_minPulleyLength;
|
||||
joint->m_maxLength2 = (joint->m_constant - b2_minPulleyLength) / joint->m_ratio;
|
||||
}
|
||||
|
||||
float PulleyJoint::getConstant() const
|
||||
{
|
||||
return world->scaleUp(joint->m_constant);
|
||||
}
|
||||
|
||||
float PulleyJoint::getLength1() const
|
||||
{
|
||||
return world->scaleUp(joint->GetLength1());
|
||||
}
|
||||
|
||||
float PulleyJoint::getLength2() const
|
||||
{
|
||||
return world->scaleUp(joint->GetLength2());
|
||||
}
|
||||
|
||||
void PulleyJoint::setRatio(float ratio)
|
||||
{
|
||||
joint->m_ratio = ratio;
|
||||
}
|
||||
|
||||
float PulleyJoint::getRatio() const
|
||||
{
|
||||
return joint->m_ratio;
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_PULLEY_JOINT_H
|
||||
#define LOVE_PHYSICS_BOX2D_PULLEY_JOINT_H
|
||||
|
||||
// Module
|
||||
#include "Joint.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
/**
|
||||
* The PulleyJoint The pulley connects two bodies to ground and
|
||||
* to each other. As one body goes up, the other goes down. The
|
||||
* total length of the pulley rope is conserved according to the
|
||||
* initial configuration: length1 + ratio * length2 <= constant.
|
||||
**/
|
||||
class PulleyJoint : public Joint
|
||||
{
|
||||
private:
|
||||
// The Box2D DistanceJoint object.
|
||||
b2PulleyJoint * joint;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a PulleyJoint connecting body1 to body2.
|
||||
**/
|
||||
PulleyJoint(Body * body1, Body * body2, b2Vec2 groundAnchor1, b2Vec2 groundAnchor2, b2Vec2 anchor1, b2Vec2 anchor2, float ratio);
|
||||
|
||||
virtual ~PulleyJoint();
|
||||
|
||||
/**
|
||||
* Gets the ground anchors position in world
|
||||
* coordinates.
|
||||
**/
|
||||
int getGroundAnchors(lua_State * L);
|
||||
|
||||
/**
|
||||
* Sets the max rope lengths (a value of zero keeps it
|
||||
* unchanged). Beware that Box2D also imposes a maximum,
|
||||
* so the smallest of these is actually set.
|
||||
**/
|
||||
void setMaxLengths(float maxlength1, float maxlength2);
|
||||
|
||||
/**
|
||||
* Gets the max rope lengths.
|
||||
**/
|
||||
int getMaxLengths(lua_State * L);
|
||||
|
||||
/**
|
||||
* Sets the total length of the rope and updates the
|
||||
* MaxLengths values accordingly.
|
||||
**/
|
||||
void setConstant(float length);
|
||||
|
||||
/**
|
||||
* Gets the total length of the rope.
|
||||
**/
|
||||
float getConstant() const;
|
||||
|
||||
/**
|
||||
* Gets the current length of the segment attached to body1.
|
||||
**/
|
||||
float getLength1() const;
|
||||
|
||||
/**
|
||||
* Gets the current length of the segment attached to body2.
|
||||
**/
|
||||
float getLength2() const;
|
||||
|
||||
/**
|
||||
* Sets the pulley ratio.
|
||||
**/
|
||||
void setRatio(float ratio);
|
||||
|
||||
/**
|
||||
* Gets the pulley ratio.
|
||||
**/
|
||||
float getRatio() const;
|
||||
|
||||
};
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_PULLEY_JOINT_H
|
||||
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "RevoluteJoint.h"
|
||||
|
||||
#include <common/math.h>
|
||||
|
||||
// Module
|
||||
#include "Body.h"
|
||||
#include "World.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
RevoluteJoint::RevoluteJoint(Body * body1, Body * body2, float x, float y)
|
||||
: Joint(body1, body2)
|
||||
{
|
||||
b2RevoluteJointDef def;
|
||||
def.Initialize(body1->body, body2->body, world->scaleDown(b2Vec2(x,y)));
|
||||
joint = (b2RevoluteJoint*)createJoint(&def);
|
||||
}
|
||||
|
||||
RevoluteJoint::~RevoluteJoint()
|
||||
{
|
||||
destroyJoint(joint);
|
||||
joint = 0;
|
||||
}
|
||||
|
||||
float RevoluteJoint::getAngle() const
|
||||
{
|
||||
return joint->GetJointAngle();
|
||||
}
|
||||
|
||||
float RevoluteJoint::getSpeed() const
|
||||
{
|
||||
return joint->GetJointSpeed();
|
||||
}
|
||||
|
||||
void RevoluteJoint::setMotorEnabled(bool motor)
|
||||
{
|
||||
return joint->EnableMotor(motor);
|
||||
}
|
||||
|
||||
bool RevoluteJoint::isMotorEnabled() const
|
||||
{
|
||||
return joint->IsMotorEnabled();
|
||||
}
|
||||
|
||||
void RevoluteJoint::setMaxMotorTorque(float torque)
|
||||
{
|
||||
joint->SetMaxMotorTorque(torque);
|
||||
}
|
||||
|
||||
float RevoluteJoint::getMaxMotorTorque() const
|
||||
{
|
||||
return joint->GetMotorTorque();
|
||||
}
|
||||
|
||||
void RevoluteJoint::setMotorSpeed(float speed)
|
||||
{
|
||||
joint->SetMotorSpeed(speed);
|
||||
}
|
||||
|
||||
float RevoluteJoint::getMotorSpeed() const
|
||||
{
|
||||
return joint->GetMotorSpeed();
|
||||
}
|
||||
|
||||
float RevoluteJoint::getMotorTorque() const
|
||||
{
|
||||
return joint->GetMotorTorque();
|
||||
}
|
||||
|
||||
void RevoluteJoint::setLimitsEnabled(bool limit)
|
||||
{
|
||||
joint->EnableLimit(limit);
|
||||
}
|
||||
|
||||
bool RevoluteJoint::isLimitsEnabled() const
|
||||
{
|
||||
return joint->IsLimitEnabled();
|
||||
}
|
||||
|
||||
void RevoluteJoint::setUpperLimit(float limit)
|
||||
{
|
||||
joint->SetLimits(joint->GetLowerLimit(), limit);
|
||||
}
|
||||
|
||||
void RevoluteJoint::setLowerLimit(float limit)
|
||||
{
|
||||
joint->SetLimits(limit, joint->GetUpperLimit());
|
||||
}
|
||||
|
||||
void RevoluteJoint::setLimits(float lower, float upper)
|
||||
{
|
||||
joint->SetLimits(lower, upper);
|
||||
}
|
||||
|
||||
float RevoluteJoint::getLowerLimit() const
|
||||
{
|
||||
return joint->GetLowerLimit();
|
||||
}
|
||||
|
||||
float RevoluteJoint::getUpperLimit() const
|
||||
{
|
||||
return joint->GetUpperLimit();
|
||||
}
|
||||
|
||||
int RevoluteJoint::getLimits(lua_State * L)
|
||||
{
|
||||
lua_pushnumber(L, joint->GetLowerLimit());
|
||||
lua_pushnumber(L, joint->GetUpperLimit());
|
||||
return 2;
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_REVOLUTE_JOINT_H
|
||||
#define LOVE_PHYSICS_BOX2D_REVOLUTE_JOINT_H
|
||||
|
||||
// Module
|
||||
#include "Joint.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
/**
|
||||
* A RevoluteJoint allows two bodies relative rotation
|
||||
* around a single point.
|
||||
**/
|
||||
class RevoluteJoint : public Joint
|
||||
{
|
||||
private:
|
||||
|
||||
// The Box2D revolute joint object.
|
||||
b2RevoluteJoint * joint;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a new RevoluteJoint connecting body1 and body2.
|
||||
**/
|
||||
RevoluteJoint(Body * body1, Body * body2, float x, float y);
|
||||
|
||||
virtual ~RevoluteJoint();
|
||||
|
||||
/**
|
||||
* Get the current joint angle in degrees.
|
||||
**/
|
||||
float getAngle() const;
|
||||
|
||||
/**
|
||||
* Get the current joint angle speed in degrees per second.
|
||||
**/
|
||||
float getSpeed() const;
|
||||
|
||||
/**
|
||||
* Enable/disable the joint motor.
|
||||
**/
|
||||
void setMotorEnabled(bool motor);
|
||||
|
||||
/**
|
||||
* Checks whether the motor is enabled.
|
||||
**/
|
||||
bool isMotorEnabled() const;
|
||||
|
||||
/**
|
||||
* Set the maximum motor torque, usually in N-m.
|
||||
**/
|
||||
void setMaxMotorTorque(float torque);
|
||||
|
||||
/**
|
||||
* Gets the maximum motor torque, usually in N-m.
|
||||
**/
|
||||
float getMaxMotorTorque() const;
|
||||
|
||||
/**
|
||||
* Sets the motor speed in degrees per second.
|
||||
**/
|
||||
void setMotorSpeed(float speed);
|
||||
|
||||
/**
|
||||
* Gets the motor speed in degrees per second.
|
||||
**/
|
||||
float getMotorSpeed() const;
|
||||
|
||||
/**
|
||||
* Get the current motor torque, usually in N-m.
|
||||
**/
|
||||
float getMotorTorque() const;
|
||||
|
||||
/**
|
||||
* Enable/disable the joint limit.
|
||||
**/
|
||||
void setLimitsEnabled(bool limit);
|
||||
|
||||
/**
|
||||
* Checks whether limits are enabled.
|
||||
**/
|
||||
bool isLimitsEnabled() const;
|
||||
|
||||
/**
|
||||
* Sets the upper limit in degrees.
|
||||
**/
|
||||
void setUpperLimit(float limit);
|
||||
|
||||
/**
|
||||
* Sets the lower limit in degrees.
|
||||
**/
|
||||
void setLowerLimit(float limit);
|
||||
|
||||
/**
|
||||
* Sets the limits in degrees.
|
||||
**/
|
||||
void setLimits(float lower, float upper);
|
||||
|
||||
/**
|
||||
* Gets the lower limit in degrees.
|
||||
**/
|
||||
float getLowerLimit() const;
|
||||
|
||||
/**
|
||||
* Gets the upper limit in degrees.
|
||||
**/
|
||||
float getUpperLimit() const;
|
||||
|
||||
/**
|
||||
* Gets the limits in degrees.
|
||||
* @returns The lower limit.
|
||||
* @returns The upper limit.
|
||||
**/
|
||||
int getLimits(lua_State * L);
|
||||
|
||||
};
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_REVOLUTE_JOINT_H
|
||||
@@ -0,0 +1,259 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "Shape.h"
|
||||
|
||||
// Module
|
||||
#include "Body.h"
|
||||
#include "World.h"
|
||||
|
||||
// STD
|
||||
#include <bitset>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
Shape::Shape(Body * body)
|
||||
: body(body)
|
||||
{
|
||||
body->retain();
|
||||
data = new shapeudata();
|
||||
data->ref = 0;
|
||||
}
|
||||
|
||||
Shape::~Shape()
|
||||
{
|
||||
if(data->ref != 0)
|
||||
delete data->ref;
|
||||
|
||||
delete data;
|
||||
data = 0;
|
||||
}
|
||||
|
||||
int Shape::getType() const
|
||||
{
|
||||
switch(shape->GetType())
|
||||
{
|
||||
case e_circleShape:
|
||||
return SHAPE_CIRCLE;
|
||||
case e_polygonShape:
|
||||
return SHAPE_POLYGON;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void Shape::setFriction(float friction)
|
||||
{
|
||||
shape->m_friction = friction;
|
||||
}
|
||||
|
||||
void Shape::setRestitution(float restitution)
|
||||
{
|
||||
shape->m_restitution = restitution;
|
||||
}
|
||||
|
||||
void Shape::setDensity(float density)
|
||||
{
|
||||
shape->m_density = density;
|
||||
}
|
||||
|
||||
void Shape::setSensor(bool sensor)
|
||||
{
|
||||
shape->m_isSensor = sensor;
|
||||
}
|
||||
|
||||
float Shape::getFriction() const
|
||||
{
|
||||
return shape->GetFriction();
|
||||
}
|
||||
|
||||
float Shape::getRestituion() const
|
||||
{
|
||||
return shape->GetRestitution();
|
||||
}
|
||||
|
||||
float Shape::getDensity() const
|
||||
{
|
||||
return shape->m_density;
|
||||
}
|
||||
|
||||
bool Shape::isSensor() const
|
||||
{
|
||||
return shape->IsSensor();
|
||||
}
|
||||
|
||||
Body * Shape::getBody() const
|
||||
{
|
||||
return body;
|
||||
}
|
||||
|
||||
bool Shape::testPoint(float x, float y) const
|
||||
{
|
||||
return shape->TestPoint(shape->GetBody()->GetXForm(), body->world->scaleDown(b2Vec2(x, y)));
|
||||
}
|
||||
|
||||
int Shape::testSegment(lua_State * L)
|
||||
{
|
||||
love::luax_assert_argc(L, 4, 4);
|
||||
|
||||
b2Segment s;
|
||||
|
||||
s.p1.x = (float)lua_tonumber(L, 1);
|
||||
s.p1.y = (float)lua_tonumber(L, 2);
|
||||
s.p2.x = (float)lua_tonumber(L, 3);
|
||||
s.p2.y = (float)lua_tonumber(L, 4);
|
||||
|
||||
s.p1 = body->world->scaleDown(s.p1);
|
||||
s.p2 = body->world->scaleDown(s.p2);
|
||||
|
||||
float lambda;
|
||||
b2Vec2 normal;
|
||||
|
||||
if(shape->TestSegment(shape->GetBody()->GetXForm(), &lambda, &normal, s, 1.0f))
|
||||
{
|
||||
lua_pushnumber(L, lambda);
|
||||
normal = body->world->scaleUp(normal);
|
||||
lua_pushnumber(L, normal.x);
|
||||
lua_pushnumber(L, normal.y);
|
||||
return 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Shape::setCategory(lua_State * L)
|
||||
{
|
||||
b2FilterData f = shape->GetFilterData();
|
||||
f.categoryBits = (uint16)getBits(L);
|
||||
shape->SetFilterData(f);
|
||||
shape->GetBody()->GetWorld()->Refilter(shape);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Shape::setMask(lua_State * L)
|
||||
{
|
||||
b2FilterData f = shape->GetFilterData();
|
||||
f.maskBits = ~(uint16)getBits(L);
|
||||
shape->SetFilterData(f);
|
||||
shape->GetBody()->GetWorld()->Refilter(shape);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Shape::getCategory(lua_State * L)
|
||||
{
|
||||
return pushBits(L, shape->GetFilterData().categoryBits);
|
||||
}
|
||||
|
||||
int Shape::getMask(lua_State * L)
|
||||
{
|
||||
return pushBits(L, ~(shape->GetFilterData().maskBits));
|
||||
}
|
||||
|
||||
int Shape::setData(lua_State * L)
|
||||
{
|
||||
love::luax_assert_argc(L, 1, 1);
|
||||
|
||||
if(data->ref != 0)
|
||||
{
|
||||
delete data->ref;
|
||||
data->ref = 0;
|
||||
}
|
||||
|
||||
data->ref = new Reference(L);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Shape::getData(lua_State * L)
|
||||
{
|
||||
love::luax_assert_argc(L, 0, 0);
|
||||
if(data->ref != 0)
|
||||
data->ref->push();
|
||||
else
|
||||
lua_pushnil(L);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Shape::getBoundingBox(lua_State * L)
|
||||
{
|
||||
love::luax_assert_argc(L, 0, 0);
|
||||
b2AABB bb;
|
||||
shape->ComputeAABB(&bb, shape->GetBody()->GetXForm());
|
||||
bb = body->world->scaleUp(bb);
|
||||
|
||||
// Top left.
|
||||
lua_pushnumber(L, bb.lowerBound.x);
|
||||
lua_pushnumber(L, bb.upperBound.y);
|
||||
|
||||
// Bottom left.
|
||||
lua_pushnumber(L, bb.lowerBound.x);
|
||||
lua_pushnumber(L, bb.lowerBound.y);
|
||||
|
||||
// Bottom right.
|
||||
lua_pushnumber(L, bb.upperBound.x);
|
||||
lua_pushnumber(L, bb.lowerBound.y);
|
||||
|
||||
// Top right.
|
||||
lua_pushnumber(L, bb.upperBound.x);
|
||||
lua_pushnumber(L, bb.upperBound.y);
|
||||
|
||||
return 8;
|
||||
}
|
||||
|
||||
uint16 Shape::getBits(lua_State * L)
|
||||
{
|
||||
// Get number of args.
|
||||
int argc = lua_gettop(L);
|
||||
|
||||
// The new bitset.
|
||||
std::bitset<16> b;
|
||||
|
||||
for(int i = 1;i<=argc;i++)
|
||||
{
|
||||
size_t bpos = (size_t)(lua_tointeger(L, i)-1);
|
||||
if(bpos < 0 || bpos > 16)
|
||||
return luaL_error(L, "Values must be in range 1-16.");
|
||||
b.set(bpos, true);
|
||||
}
|
||||
|
||||
return (uint16)b.to_ulong();
|
||||
}
|
||||
|
||||
int Shape::pushBits(lua_State * L, uint16 bits)
|
||||
{
|
||||
// Create a bitset.
|
||||
std::bitset<16> b((unsigned long)bits);
|
||||
|
||||
// Push all set bits.
|
||||
for(int i = 0;i<16;i++)
|
||||
if(b.test(i))
|
||||
lua_pushinteger(L, i+1);
|
||||
|
||||
// Count number of set bits.
|
||||
return (int)b.count();
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,235 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_SHAPE_H
|
||||
#define LOVE_PHYSICS_BOX2D_SHAPE_H
|
||||
|
||||
// LOVE
|
||||
#include <common/Object.h>
|
||||
#include <common/Reference.h>
|
||||
#include <common/constants.h>
|
||||
|
||||
// Box2D
|
||||
#include "Include/Box2D.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
// Forward declarations.
|
||||
class Body;
|
||||
|
||||
/**
|
||||
* This struct is stored in a void pointer
|
||||
* in the Box2D Shape class. For now, all we
|
||||
* need is a Lua reference to arbitrary data,
|
||||
* but we might need more later.
|
||||
**/
|
||||
struct shapeudata
|
||||
{
|
||||
// Reference to arbitrary data.
|
||||
Reference * ref;
|
||||
};
|
||||
|
||||
/**
|
||||
* A Shape is geometry attached to a Body.
|
||||
* A Body has position and orientation, and
|
||||
* a Shape's geometry will be affected by the parent
|
||||
* body's transformation.
|
||||
**/
|
||||
class Shape : public Object
|
||||
{
|
||||
protected:
|
||||
|
||||
// A pointer to the parent Body. If the Body
|
||||
// is destroyed, all child shapes are destroyed as well.
|
||||
// This ensures that all child shapes are always destroyed
|
||||
// *before* the parent Body.
|
||||
Body * body;
|
||||
|
||||
// The Box2D shape.
|
||||
b2Shape * shape;
|
||||
|
||||
// Our shape data, to be stored in
|
||||
// the Box2D shape.
|
||||
shapeudata * data;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a Shape attatched to the specified
|
||||
* Body.
|
||||
**/
|
||||
Shape(Body * body);
|
||||
|
||||
virtual ~Shape();
|
||||
|
||||
/**
|
||||
* Gets the type of Shape. Useful for
|
||||
* debug drawing.
|
||||
**/
|
||||
int getType() const;
|
||||
|
||||
/**
|
||||
* Sets the friction of the Shape.
|
||||
* @param friction The new friction.
|
||||
**/
|
||||
void setFriction(float friction);
|
||||
|
||||
/**
|
||||
* Sets the restitution for the Shape.
|
||||
* @param restitution The restitution.
|
||||
**/
|
||||
void setRestitution(float restitution);
|
||||
|
||||
/**
|
||||
* Sets the density of the Shape.
|
||||
* @param density The density of the Shape.
|
||||
**/
|
||||
void setDensity(float density);
|
||||
|
||||
/**
|
||||
* Set whether this shape should be a sensor or not.
|
||||
* @param sensor True if sensor, false if not.
|
||||
**/
|
||||
void setSensor(bool sensor);
|
||||
|
||||
/**
|
||||
* Gets the friction of the Shape.
|
||||
* @returns The friction.
|
||||
**/
|
||||
float getFriction() const;
|
||||
|
||||
/**
|
||||
* Gets the restitution of the Shape.
|
||||
* @return The restitution of the Shape.
|
||||
**/
|
||||
float getRestituion() const;
|
||||
|
||||
/**
|
||||
* Gets the density of the Shape.
|
||||
* @return The density.
|
||||
**/
|
||||
float getDensity() const;
|
||||
|
||||
/**
|
||||
* Checks whether this Shape acts as a sensor.
|
||||
* @return True if sensor, false otherwise.
|
||||
**/
|
||||
bool isSensor() const;
|
||||
|
||||
/**
|
||||
* Get the body attatched to this Shape.
|
||||
* @return The parent Body.
|
||||
**/
|
||||
Body * getBody() const;
|
||||
|
||||
/**
|
||||
* Checks if a point is inside the Shape.
|
||||
* @param x The x-component of the Shape.
|
||||
* @param y The y-component of the Shape.
|
||||
**/
|
||||
bool testPoint(float x, float y) const;
|
||||
|
||||
/**
|
||||
* Tests whether a line segment intersects a Shape.
|
||||
**/
|
||||
int testSegment(lua_State * L);
|
||||
|
||||
/**
|
||||
* With this function, you can easily set the categories
|
||||
* a Shape is a member of.
|
||||
*
|
||||
* The function accepts 1-16 arguments. Each argument must
|
||||
* be a number from 1-16, and must be unique in the list.
|
||||
**/
|
||||
int setCategory(lua_State * L);
|
||||
|
||||
/**
|
||||
* Returns the categories this Shape is
|
||||
* a member of. So if the Shape is a member
|
||||
* of 5 categories, this function returns five
|
||||
* values.
|
||||
**/
|
||||
int getCategory(lua_State * L);
|
||||
|
||||
/**
|
||||
* Sets which categories this Shape should *not*
|
||||
* collide with.
|
||||
*
|
||||
* The function works the same was as setCategory, but
|
||||
* each entry here represents a 0 in the bit string, not
|
||||
* a 1 like setCategory.
|
||||
**/
|
||||
int setMask(lua_State * L);
|
||||
|
||||
/**
|
||||
* Returns the current masked categories.
|
||||
* If there are 5 masked categories, then this
|
||||
* function will have 5 return values.
|
||||
**/
|
||||
int getMask(lua_State * L);
|
||||
|
||||
/**
|
||||
* This function stores an in-C reference to
|
||||
* arbitrary Lua data in the Box2D shape object.
|
||||
*
|
||||
* The data set here will be passed to the collision
|
||||
* handler when collisions occur.
|
||||
**/
|
||||
int setData(lua_State * L);
|
||||
|
||||
/**
|
||||
* Gets the data set with setData. If no
|
||||
* data is set, nil is returned.
|
||||
**/
|
||||
int getData(lua_State * L);
|
||||
|
||||
/**
|
||||
* Gets the bounding box for this Shape.
|
||||
* The function returns eight values which can be
|
||||
* passed directly to love.graphics.polygon.
|
||||
**/
|
||||
int getBoundingBox(lua_State * L);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Gets a 16-integer from the current stack top.
|
||||
* @param The 16-bit integer.
|
||||
**/
|
||||
uint16 getBits(lua_State * L);
|
||||
|
||||
/**
|
||||
* Push each set bit in a 16-bit integer as
|
||||
* a list of integer indices. That is, if the bits are
|
||||
* set to 0000 0000 0011 0001, then this function will
|
||||
* push (1, 5, 6) on the stack.
|
||||
**/
|
||||
int pushBits(lua_State * L, uint16 bits);
|
||||
};
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_SHAPE_H
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2CircleShape.h"
|
||||
|
||||
b2CircleShape::b2CircleShape(const b2ShapeDef* def)
|
||||
: b2Shape(def)
|
||||
{
|
||||
b2Assert(def->type == e_circleShape);
|
||||
const b2CircleDef* circleDef = (const b2CircleDef*)def;
|
||||
|
||||
m_type = e_circleShape;
|
||||
m_localPosition = circleDef->localPosition;
|
||||
m_radius = circleDef->radius;
|
||||
}
|
||||
|
||||
void b2CircleShape::UpdateSweepRadius(const b2Vec2& center)
|
||||
{
|
||||
// Update the sweep radius (maximum radius) as measured from
|
||||
// a local center point.
|
||||
b2Vec2 d = m_localPosition - center;
|
||||
m_sweepRadius = d.Length() + m_radius - b2_toiSlop;
|
||||
}
|
||||
|
||||
bool b2CircleShape::TestPoint(const b2XForm& transform, const b2Vec2& p) const
|
||||
{
|
||||
b2Vec2 center = transform.position + b2Mul(transform.R, m_localPosition);
|
||||
b2Vec2 d = p - center;
|
||||
return b2Dot(d, d) <= m_radius * m_radius;
|
||||
}
|
||||
|
||||
// Collision Detection in Interactive 3D Environments by Gino van den Bergen
|
||||
// From Section 3.1.2
|
||||
// x = s + a * r
|
||||
// norm(x) = radius
|
||||
bool b2CircleShape::TestSegment(const b2XForm& transform,
|
||||
float32* lambda,
|
||||
b2Vec2* normal,
|
||||
const b2Segment& segment,
|
||||
float32 maxLambda) const
|
||||
{
|
||||
b2Vec2 position = transform.position + b2Mul(transform.R, m_localPosition);
|
||||
b2Vec2 s = segment.p1 - position;
|
||||
float32 b = b2Dot(s, s) - m_radius * m_radius;
|
||||
|
||||
// Does the segment start inside the circle?
|
||||
if (b < 0.0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Solve quadratic equation.
|
||||
b2Vec2 r = segment.p2 - segment.p1;
|
||||
float32 c = b2Dot(s, r);
|
||||
float32 rr = b2Dot(r, r);
|
||||
float32 sigma = c * c - rr * b;
|
||||
|
||||
// Check for negative discriminant and short segment.
|
||||
if (sigma < 0.0f || rr < B2_FLT_EPSILON)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the point of intersection of the line with the circle.
|
||||
float32 a = -(c + b2Sqrt(sigma));
|
||||
|
||||
// Is the intersection point on the segment?
|
||||
if (0.0f <= a && a <= maxLambda * rr)
|
||||
{
|
||||
a /= rr;
|
||||
*lambda = a;
|
||||
*normal = s + a * r;
|
||||
normal->Normalize();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void b2CircleShape::ComputeAABB(b2AABB* aabb, const b2XForm& transform) const
|
||||
{
|
||||
b2Vec2 p = transform.position + b2Mul(transform.R, m_localPosition);
|
||||
aabb->lowerBound.Set(p.x - m_radius, p.y - m_radius);
|
||||
aabb->upperBound.Set(p.x + m_radius, p.y + m_radius);
|
||||
}
|
||||
|
||||
void b2CircleShape::ComputeSweptAABB(b2AABB* aabb, const b2XForm& transform1, const b2XForm& transform2) const
|
||||
{
|
||||
b2Vec2 p1 = transform1.position + b2Mul(transform1.R, m_localPosition);
|
||||
b2Vec2 p2 = transform2.position + b2Mul(transform2.R, m_localPosition);
|
||||
b2Vec2 lower = b2Min(p1, p2);
|
||||
b2Vec2 upper = b2Max(p1, p2);
|
||||
|
||||
aabb->lowerBound.Set(lower.x - m_radius, lower.y - m_radius);
|
||||
aabb->upperBound.Set(upper.x + m_radius, upper.y + m_radius);
|
||||
}
|
||||
|
||||
void b2CircleShape::ComputeMass(b2MassData* massData) const
|
||||
{
|
||||
massData->mass = m_density * b2_pi * m_radius * m_radius;
|
||||
massData->center = m_localPosition;
|
||||
|
||||
// inertia about the local origin
|
||||
massData->I = massData->mass * (0.5f * m_radius * m_radius + b2Dot(m_localPosition, m_localPosition));
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_CIRCLE_SHAPE_H
|
||||
#define B2_CIRCLE_SHAPE_H
|
||||
|
||||
#include "b2Shape.h"
|
||||
|
||||
/// This structure is used to build circle shapes.
|
||||
struct b2CircleDef : public b2ShapeDef
|
||||
{
|
||||
b2CircleDef()
|
||||
{
|
||||
type = e_circleShape;
|
||||
localPosition.SetZero();
|
||||
radius = 1.0f;
|
||||
}
|
||||
|
||||
b2Vec2 localPosition;
|
||||
float32 radius;
|
||||
};
|
||||
|
||||
/// A circle shape.
|
||||
class b2CircleShape : public b2Shape
|
||||
{
|
||||
public:
|
||||
/// @see b2Shape::TestPoint
|
||||
bool TestPoint(const b2XForm& transform, const b2Vec2& p) const;
|
||||
|
||||
/// @see b2Shape::TestSegment
|
||||
bool TestSegment( const b2XForm& transform,
|
||||
float32* lambda,
|
||||
b2Vec2* normal,
|
||||
const b2Segment& segment,
|
||||
float32 maxLambda) const;
|
||||
|
||||
/// @see b2Shape::ComputeAABB
|
||||
void ComputeAABB(b2AABB* aabb, const b2XForm& transform) const;
|
||||
|
||||
/// @see b2Shape::ComputeSweptAABB
|
||||
void ComputeSweptAABB( b2AABB* aabb,
|
||||
const b2XForm& transform1,
|
||||
const b2XForm& transform2) const;
|
||||
|
||||
/// @see b2Shape::ComputeMass
|
||||
void ComputeMass(b2MassData* massData) const;
|
||||
|
||||
/// Get the local position of this circle in its parent body.
|
||||
const b2Vec2& GetLocalPosition() const;
|
||||
|
||||
/// Get the radius of this circle.
|
||||
float32 GetRadius() const;
|
||||
|
||||
private:
|
||||
|
||||
friend class b2Shape;
|
||||
|
||||
b2CircleShape(const b2ShapeDef* def);
|
||||
|
||||
void UpdateSweepRadius(const b2Vec2& center);
|
||||
|
||||
// Local position in parent body
|
||||
b2Vec2 m_localPosition;
|
||||
float32 m_radius;
|
||||
};
|
||||
|
||||
inline const b2Vec2& b2CircleShape::GetLocalPosition() const
|
||||
{
|
||||
return m_localPosition;
|
||||
}
|
||||
|
||||
inline float32 b2CircleShape::GetRadius() const
|
||||
{
|
||||
return m_radius;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,449 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2PolygonShape.h"
|
||||
|
||||
void b2PolygonDef::SetAsBox(float32 hx, float32 hy)
|
||||
{
|
||||
vertexCount = 4;
|
||||
vertices[0].Set(-hx, -hy);
|
||||
vertices[1].Set( hx, -hy);
|
||||
vertices[2].Set( hx, hy);
|
||||
vertices[3].Set(-hx, hy);
|
||||
}
|
||||
|
||||
void b2PolygonDef::SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle)
|
||||
{
|
||||
SetAsBox(hx, hy);
|
||||
b2XForm xf;
|
||||
xf.position = center;
|
||||
xf.R.Set(angle);
|
||||
|
||||
for (int32 i = 0; i < vertexCount; ++i)
|
||||
{
|
||||
vertices[i] = b2Mul(xf, vertices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count)
|
||||
{
|
||||
b2Assert(count >= 3);
|
||||
|
||||
b2Vec2 c; c.Set(0.0f, 0.0f);
|
||||
float32 area = 0.0f;
|
||||
|
||||
// pRef is the reference point for forming triangles.
|
||||
// It's location doesn't change the result (except for rounding error).
|
||||
b2Vec2 pRef(0.0f, 0.0f);
|
||||
#if 0
|
||||
// This code would put the reference point inside the polygon.
|
||||
for (int32 i = 0; i < count; ++i)
|
||||
{
|
||||
pRef += vs[i];
|
||||
}
|
||||
pRef *= 1.0f / count;
|
||||
#endif
|
||||
|
||||
const float32 inv3 = 1.0f / 3.0f;
|
||||
|
||||
for (int32 i = 0; i < count; ++i)
|
||||
{
|
||||
// Triangle vertices.
|
||||
b2Vec2 p1 = pRef;
|
||||
b2Vec2 p2 = vs[i];
|
||||
b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0];
|
||||
|
||||
b2Vec2 e1 = p2 - p1;
|
||||
b2Vec2 e2 = p3 - p1;
|
||||
|
||||
float32 D = b2Cross(e1, e2);
|
||||
|
||||
float32 triangleArea = 0.5f * D;
|
||||
area += triangleArea;
|
||||
|
||||
// Area weighted centroid
|
||||
c += triangleArea * inv3 * (p1 + p2 + p3);
|
||||
}
|
||||
|
||||
// Centroid
|
||||
b2Assert(area > B2_FLT_EPSILON);
|
||||
c *= 1.0f / area;
|
||||
return c;
|
||||
}
|
||||
|
||||
// http://www.geometrictools.com/Documentation/MinimumAreaRectangle.pdf
|
||||
static void ComputeOBB(b2OBB* obb, const b2Vec2* vs, int32 count)
|
||||
{
|
||||
b2Assert(count <= b2_maxPolygonVertices);
|
||||
b2Vec2 p[b2_maxPolygonVertices + 1];
|
||||
for (int32 i = 0; i < count; ++i)
|
||||
{
|
||||
p[i] = vs[i];
|
||||
}
|
||||
p[count] = p[0];
|
||||
|
||||
float32 minArea = B2_FLT_MAX;
|
||||
|
||||
for (int32 i = 1; i <= count; ++i)
|
||||
{
|
||||
b2Vec2 root = p[i-1];
|
||||
b2Vec2 ux = p[i] - root;
|
||||
float32 length = ux.Normalize();
|
||||
b2Assert(length > B2_FLT_EPSILON);
|
||||
b2Vec2 uy(-ux.y, ux.x);
|
||||
b2Vec2 lower(B2_FLT_MAX, B2_FLT_MAX);
|
||||
b2Vec2 upper(-B2_FLT_MAX, -B2_FLT_MAX);
|
||||
|
||||
for (int32 j = 0; j < count; ++j)
|
||||
{
|
||||
b2Vec2 d = p[j] - root;
|
||||
b2Vec2 r;
|
||||
r.x = b2Dot(ux, d);
|
||||
r.y = b2Dot(uy, d);
|
||||
lower = b2Min(lower, r);
|
||||
upper = b2Max(upper, r);
|
||||
}
|
||||
|
||||
float32 area = (upper.x - lower.x) * (upper.y - lower.y);
|
||||
if (area < 0.95f * minArea)
|
||||
{
|
||||
minArea = area;
|
||||
obb->R.col1 = ux;
|
||||
obb->R.col2 = uy;
|
||||
b2Vec2 center = 0.5f * (lower + upper);
|
||||
obb->center = root + b2Mul(obb->R, center);
|
||||
obb->extents = 0.5f * (upper - lower);
|
||||
}
|
||||
}
|
||||
|
||||
b2Assert(minArea < B2_FLT_MAX);
|
||||
}
|
||||
|
||||
b2PolygonShape::b2PolygonShape(const b2ShapeDef* def)
|
||||
: b2Shape(def)
|
||||
{
|
||||
b2Assert(def->type == e_polygonShape);
|
||||
m_type = e_polygonShape;
|
||||
const b2PolygonDef* poly = (const b2PolygonDef*)def;
|
||||
|
||||
// Get the vertices transformed into the body frame.
|
||||
m_vertexCount = poly->vertexCount;
|
||||
b2Assert(3 <= m_vertexCount && m_vertexCount <= b2_maxPolygonVertices);
|
||||
|
||||
// Copy vertices.
|
||||
for (int32 i = 0; i < m_vertexCount; ++i)
|
||||
{
|
||||
m_vertices[i] = poly->vertices[i];
|
||||
}
|
||||
|
||||
// Compute normals. Ensure the edges have non-zero length.
|
||||
for (int32 i = 0; i < m_vertexCount; ++i)
|
||||
{
|
||||
int32 i1 = i;
|
||||
int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0;
|
||||
b2Vec2 edge = m_vertices[i2] - m_vertices[i1];
|
||||
b2Assert(edge.LengthSquared() > B2_FLT_EPSILON * B2_FLT_EPSILON);
|
||||
m_normals[i] = b2Cross(edge, 1.0f);
|
||||
m_normals[i].Normalize();
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Ensure the polygon is convex.
|
||||
for (int32 i = 0; i < m_vertexCount; ++i)
|
||||
{
|
||||
for (int32 j = 0; j < m_vertexCount; ++j)
|
||||
{
|
||||
// Don't check vertices on the current edge.
|
||||
if (j == i || j == (i + 1) % m_vertexCount)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Your polygon is non-convex (it has an indentation).
|
||||
// Or your polygon is too skinny.
|
||||
float32 s = b2Dot(m_normals[i], m_vertices[j] - m_vertices[i]);
|
||||
b2Assert(s < -b2_linearSlop);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the polygon is counter-clockwise.
|
||||
for (int32 i = 1; i < m_vertexCount; ++i)
|
||||
{
|
||||
float32 cross = b2Cross(m_normals[i-1], m_normals[i]);
|
||||
|
||||
// Keep asinf happy.
|
||||
cross = b2Clamp(cross, -1.0f, 1.0f);
|
||||
|
||||
// You have consecutive edges that are almost parallel on your polygon.
|
||||
float32 angle = asinf(cross);
|
||||
b2Assert(angle > b2_angularSlop);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Compute the polygon centroid.
|
||||
m_centroid = ComputeCentroid(poly->vertices, poly->vertexCount);
|
||||
|
||||
// Compute the oriented bounding box.
|
||||
ComputeOBB(&m_obb, m_vertices, m_vertexCount);
|
||||
|
||||
// Create core polygon shape by shifting edges inward.
|
||||
// Also compute the min/max radius for CCD.
|
||||
for (int32 i = 0; i < m_vertexCount; ++i)
|
||||
{
|
||||
int32 i1 = i - 1 >= 0 ? i - 1 : m_vertexCount - 1;
|
||||
int32 i2 = i;
|
||||
|
||||
b2Vec2 n1 = m_normals[i1];
|
||||
b2Vec2 n2 = m_normals[i2];
|
||||
b2Vec2 v = m_vertices[i] - m_centroid;;
|
||||
|
||||
b2Vec2 d;
|
||||
d.x = b2Dot(n1, v) - b2_toiSlop;
|
||||
d.y = b2Dot(n2, v) - b2_toiSlop;
|
||||
|
||||
// Shifting the edge inward by b2_toiSlop should
|
||||
// not cause the plane to pass the centroid.
|
||||
|
||||
// Your shape has a radius/extent less than b2_toiSlop.
|
||||
b2Assert(d.x >= 0.0f);
|
||||
b2Assert(d.y >= 0.0f);
|
||||
b2Mat22 A;
|
||||
A.col1.x = n1.x; A.col2.x = n1.y;
|
||||
A.col1.y = n2.x; A.col2.y = n2.y;
|
||||
m_coreVertices[i] = A.Solve(d) + m_centroid;
|
||||
}
|
||||
}
|
||||
|
||||
void b2PolygonShape::UpdateSweepRadius(const b2Vec2& center)
|
||||
{
|
||||
// Update the sweep radius (maximum radius) as measured from
|
||||
// a local center point.
|
||||
m_sweepRadius = 0.0f;
|
||||
for (int32 i = 0; i < m_vertexCount; ++i)
|
||||
{
|
||||
b2Vec2 d = m_coreVertices[i] - center;
|
||||
m_sweepRadius = b2Max(m_sweepRadius, d.Length());
|
||||
}
|
||||
}
|
||||
|
||||
bool b2PolygonShape::TestPoint(const b2XForm& xf, const b2Vec2& p) const
|
||||
{
|
||||
b2Vec2 pLocal = b2MulT(xf.R, p - xf.position);
|
||||
|
||||
for (int32 i = 0; i < m_vertexCount; ++i)
|
||||
{
|
||||
float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]);
|
||||
if (dot > 0.0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool b2PolygonShape::TestSegment(
|
||||
const b2XForm& xf,
|
||||
float32* lambda,
|
||||
b2Vec2* normal,
|
||||
const b2Segment& segment,
|
||||
float32 maxLambda) const
|
||||
{
|
||||
float32 lower = 0.0f, upper = maxLambda;
|
||||
|
||||
b2Vec2 p1 = b2MulT(xf.R, segment.p1 - xf.position);
|
||||
b2Vec2 p2 = b2MulT(xf.R, segment.p2 - xf.position);
|
||||
b2Vec2 d = p2 - p1;
|
||||
int32 index = -1;
|
||||
|
||||
for (int32 i = 0; i < m_vertexCount; ++i)
|
||||
{
|
||||
// p = p1 + a * d
|
||||
// dot(normal, p - v) = 0
|
||||
// dot(normal, p1 - v) + a * dot(normal, d) = 0
|
||||
float32 numerator = b2Dot(m_normals[i], m_vertices[i] - p1);
|
||||
float32 denominator = b2Dot(m_normals[i], d);
|
||||
|
||||
// Note: we want this predicate without division:
|
||||
// lower < numerator / denominator, where denominator < 0
|
||||
// Since denominator < 0, we have to flip the inequality:
|
||||
// lower < numerator / denominator <==> denominator * lower > numerator.
|
||||
|
||||
if (denominator < 0.0f && numerator < lower * denominator)
|
||||
{
|
||||
// Increase lower.
|
||||
// The segment enters this half-space.
|
||||
lower = numerator / denominator;
|
||||
index = i;
|
||||
}
|
||||
else if (denominator > 0.0f && numerator < upper * denominator)
|
||||
{
|
||||
// Decrease upper.
|
||||
// The segment exits this half-space.
|
||||
upper = numerator / denominator;
|
||||
}
|
||||
|
||||
if (upper < lower)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
b2Assert(0.0f <= lower && lower <= maxLambda);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
*lambda = lower;
|
||||
*normal = b2Mul(xf.R, m_normals[index]);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2XForm& xf) const
|
||||
{
|
||||
b2Mat22 R = b2Mul(xf.R, m_obb.R);
|
||||
b2Mat22 absR = b2Abs(R);
|
||||
b2Vec2 h = b2Mul(absR, m_obb.extents);
|
||||
b2Vec2 position = xf.position + b2Mul(xf.R, m_obb.center);
|
||||
aabb->lowerBound = position - h;
|
||||
aabb->upperBound = position + h;
|
||||
}
|
||||
|
||||
void b2PolygonShape::ComputeSweptAABB(b2AABB* aabb,
|
||||
const b2XForm& transform1,
|
||||
const b2XForm& transform2) const
|
||||
{
|
||||
b2AABB aabb1, aabb2;
|
||||
ComputeAABB(&aabb1, transform1);
|
||||
ComputeAABB(&aabb2, transform2);
|
||||
aabb->lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound);
|
||||
aabb->upperBound = b2Max(aabb1.upperBound, aabb2.upperBound);
|
||||
}
|
||||
|
||||
void b2PolygonShape::ComputeMass(b2MassData* massData) const
|
||||
{
|
||||
// Polygon mass, centroid, and inertia.
|
||||
// Let rho be the polygon density in mass per unit area.
|
||||
// Then:
|
||||
// mass = rho * int(dA)
|
||||
// centroid.x = (1/mass) * rho * int(x * dA)
|
||||
// centroid.y = (1/mass) * rho * int(y * dA)
|
||||
// I = rho * int((x*x + y*y) * dA)
|
||||
//
|
||||
// We can compute these integrals by summing all the integrals
|
||||
// for each triangle of the polygon. To evaluate the integral
|
||||
// for a single triangle, we make a change of variables to
|
||||
// the (u,v) coordinates of the triangle:
|
||||
// x = x0 + e1x * u + e2x * v
|
||||
// y = y0 + e1y * u + e2y * v
|
||||
// where 0 <= u && 0 <= v && u + v <= 1.
|
||||
//
|
||||
// We integrate u from [0,1-v] and then v from [0,1].
|
||||
// We also need to use the Jacobian of the transformation:
|
||||
// D = cross(e1, e2)
|
||||
//
|
||||
// Simplification: triangle centroid = (1/3) * (p1 + p2 + p3)
|
||||
//
|
||||
// The rest of the derivation is handled by computer algebra.
|
||||
|
||||
b2Assert(m_vertexCount >= 3);
|
||||
|
||||
b2Vec2 center; center.Set(0.0f, 0.0f);
|
||||
float32 area = 0.0f;
|
||||
float32 I = 0.0f;
|
||||
|
||||
// pRef is the reference point for forming triangles.
|
||||
// It's location doesn't change the result (except for rounding error).
|
||||
b2Vec2 pRef(0.0f, 0.0f);
|
||||
#if 0
|
||||
// This code would put the reference point inside the polygon.
|
||||
for (int32 i = 0; i < m_vertexCount; ++i)
|
||||
{
|
||||
pRef += m_vertices[i];
|
||||
}
|
||||
pRef *= 1.0f / count;
|
||||
#endif
|
||||
|
||||
const float32 k_inv3 = 1.0f / 3.0f;
|
||||
|
||||
for (int32 i = 0; i < m_vertexCount; ++i)
|
||||
{
|
||||
// Triangle vertices.
|
||||
b2Vec2 p1 = pRef;
|
||||
b2Vec2 p2 = m_vertices[i];
|
||||
b2Vec2 p3 = i + 1 < m_vertexCount ? m_vertices[i+1] : m_vertices[0];
|
||||
|
||||
b2Vec2 e1 = p2 - p1;
|
||||
b2Vec2 e2 = p3 - p1;
|
||||
|
||||
float32 D = b2Cross(e1, e2);
|
||||
|
||||
float32 triangleArea = 0.5f * D;
|
||||
area += triangleArea;
|
||||
|
||||
// Area weighted centroid
|
||||
center += triangleArea * k_inv3 * (p1 + p2 + p3);
|
||||
|
||||
float32 px = p1.x, py = p1.y;
|
||||
float32 ex1 = e1.x, ey1 = e1.y;
|
||||
float32 ex2 = e2.x, ey2 = e2.y;
|
||||
|
||||
float32 intx2 = k_inv3 * (0.25f * (ex1*ex1 + ex2*ex1 + ex2*ex2) + (px*ex1 + px*ex2)) + 0.5f*px*px;
|
||||
float32 inty2 = k_inv3 * (0.25f * (ey1*ey1 + ey2*ey1 + ey2*ey2) + (py*ey1 + py*ey2)) + 0.5f*py*py;
|
||||
|
||||
I += D * (intx2 + inty2);
|
||||
}
|
||||
|
||||
// Total mass
|
||||
massData->mass = m_density * area;
|
||||
|
||||
// Center of mass
|
||||
b2Assert(area > B2_FLT_EPSILON);
|
||||
center *= 1.0f / area;
|
||||
massData->center = center;
|
||||
|
||||
// Inertia tensor relative to the local origin.
|
||||
massData->I = m_density * I;
|
||||
}
|
||||
|
||||
b2Vec2 b2PolygonShape::Centroid(const b2XForm& xf) const
|
||||
{
|
||||
return b2Mul(xf, m_centroid);
|
||||
}
|
||||
|
||||
b2Vec2 b2PolygonShape::Support(const b2XForm& xf, const b2Vec2& d) const
|
||||
{
|
||||
b2Vec2 dLocal = b2MulT(xf.R, d);
|
||||
|
||||
int32 bestIndex = 0;
|
||||
float32 bestValue = b2Dot(m_coreVertices[0], dLocal);
|
||||
for (int32 i = 1; i < m_vertexCount; ++i)
|
||||
{
|
||||
float32 value = b2Dot(m_coreVertices[i], dLocal);
|
||||
if (value > bestValue)
|
||||
{
|
||||
bestIndex = i;
|
||||
bestValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
return b2Mul(xf, m_coreVertices[bestIndex]);
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_POLYGON_SHAPE_H
|
||||
#define B2_POLYGON_SHAPE_H
|
||||
|
||||
#include "b2Shape.h"
|
||||
|
||||
/// Convex polygon. The vertices must be in CCW order for a right-handed
|
||||
/// coordinate system with the z-axis coming out of the screen.
|
||||
struct b2PolygonDef : public b2ShapeDef
|
||||
{
|
||||
b2PolygonDef()
|
||||
{
|
||||
type = e_polygonShape;
|
||||
vertexCount = 0;
|
||||
}
|
||||
|
||||
/// Build vertices to represent an axis-aligned box.
|
||||
/// @param hx the half-width.
|
||||
/// @param hy the half-height.
|
||||
void SetAsBox(float32 hx, float32 hy);
|
||||
|
||||
/// Build vertices to represent an oriented box.
|
||||
/// @param hx the half-width.
|
||||
/// @param hy the half-height.
|
||||
/// @param center the center of the box in local coordinates.
|
||||
/// @param angle the rotation of the box in local coordinates.
|
||||
void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle);
|
||||
|
||||
/// The polygon vertices in local coordinates.
|
||||
b2Vec2 vertices[b2_maxPolygonVertices];
|
||||
|
||||
/// The number of polygon vertices.
|
||||
int32 vertexCount;
|
||||
};
|
||||
|
||||
|
||||
/// A convex polygon.
|
||||
class b2PolygonShape : public b2Shape
|
||||
{
|
||||
public:
|
||||
/// @see b2Shape::TestPoint
|
||||
bool TestPoint(const b2XForm& transform, const b2Vec2& p) const;
|
||||
|
||||
/// @see b2Shape::TestSegment
|
||||
bool TestSegment( const b2XForm& transform,
|
||||
float32* lambda,
|
||||
b2Vec2* normal,
|
||||
const b2Segment& segment,
|
||||
float32 maxLambda) const;
|
||||
|
||||
/// @see b2Shape::ComputeAABB
|
||||
void ComputeAABB(b2AABB* aabb, const b2XForm& transform) const;
|
||||
|
||||
/// @see b2Shape::ComputeSweptAABB
|
||||
void ComputeSweptAABB( b2AABB* aabb,
|
||||
const b2XForm& transform1,
|
||||
const b2XForm& transform2) const;
|
||||
|
||||
/// @see b2Shape::ComputeMass
|
||||
void ComputeMass(b2MassData* massData) const;
|
||||
|
||||
/// Get the oriented bounding box relative to the parent body.
|
||||
const b2OBB& GetOBB() const;
|
||||
|
||||
/// Get local centroid relative to the parent body.
|
||||
const b2Vec2& GetCentroid() const;
|
||||
|
||||
/// Get the vertex count.
|
||||
int32 GetVertexCount() const;
|
||||
|
||||
/// Get the vertices in local coordinates.
|
||||
const b2Vec2* GetVertices() const;
|
||||
|
||||
/// Get the core vertices in local coordinates. These vertices
|
||||
/// represent a smaller polygon that is used for time of impact
|
||||
/// computations.
|
||||
const b2Vec2* GetCoreVertices() const;
|
||||
|
||||
/// Get the edge normal vectors. There is one for each vertex.
|
||||
const b2Vec2* GetNormals() const;
|
||||
|
||||
/// Get the first vertex and apply the supplied transform.
|
||||
b2Vec2 GetFirstVertex(const b2XForm& xf) const;
|
||||
|
||||
/// Get the centroid and apply the supplied transform.
|
||||
b2Vec2 Centroid(const b2XForm& xf) const;
|
||||
|
||||
/// Get the support point in the given world direction.
|
||||
/// Use the supplied transform.
|
||||
b2Vec2 Support(const b2XForm& xf, const b2Vec2& d) const;
|
||||
|
||||
private:
|
||||
|
||||
friend class b2Shape;
|
||||
|
||||
b2PolygonShape(const b2ShapeDef* def);
|
||||
|
||||
void UpdateSweepRadius(const b2Vec2& center);
|
||||
|
||||
// Local position of the polygon centroid.
|
||||
b2Vec2 m_centroid;
|
||||
|
||||
b2OBB m_obb;
|
||||
|
||||
b2Vec2 m_vertices[b2_maxPolygonVertices];
|
||||
b2Vec2 m_normals[b2_maxPolygonVertices];
|
||||
b2Vec2 m_coreVertices[b2_maxPolygonVertices];
|
||||
int32 m_vertexCount;
|
||||
};
|
||||
|
||||
inline b2Vec2 b2PolygonShape::GetFirstVertex(const b2XForm& xf) const
|
||||
{
|
||||
return b2Mul(xf, m_coreVertices[0]);
|
||||
}
|
||||
|
||||
inline const b2OBB& b2PolygonShape::GetOBB() const
|
||||
{
|
||||
return m_obb;
|
||||
}
|
||||
|
||||
inline const b2Vec2& b2PolygonShape::GetCentroid() const
|
||||
{
|
||||
return m_centroid;
|
||||
}
|
||||
|
||||
inline int32 b2PolygonShape::GetVertexCount() const
|
||||
{
|
||||
return m_vertexCount;
|
||||
}
|
||||
|
||||
inline const b2Vec2* b2PolygonShape::GetVertices() const
|
||||
{
|
||||
return m_vertices;
|
||||
}
|
||||
|
||||
inline const b2Vec2* b2PolygonShape::GetCoreVertices() const
|
||||
{
|
||||
return m_coreVertices;
|
||||
}
|
||||
|
||||
inline const b2Vec2* b2PolygonShape::GetNormals() const
|
||||
{
|
||||
return m_normals;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2Shape.h"
|
||||
#include "b2CircleShape.h"
|
||||
#include "b2PolygonShape.h"
|
||||
#include "../b2Collision.h"
|
||||
#include "../b2BroadPhase.h"
|
||||
#include "../../Common/b2BlockAllocator.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
b2Shape* b2Shape::Create(const b2ShapeDef* def, b2BlockAllocator* allocator)
|
||||
{
|
||||
switch (def->type)
|
||||
{
|
||||
case e_circleShape:
|
||||
{
|
||||
void* mem = allocator->Allocate(sizeof(b2CircleShape));
|
||||
return new (mem) b2CircleShape(def);
|
||||
}
|
||||
|
||||
case e_polygonShape:
|
||||
{
|
||||
void* mem = allocator->Allocate(sizeof(b2PolygonShape));
|
||||
return new (mem) b2PolygonShape(def);
|
||||
}
|
||||
|
||||
default:
|
||||
b2Assert(false);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void b2Shape::Destroy(b2Shape* s, b2BlockAllocator* allocator)
|
||||
{
|
||||
switch (s->GetType())
|
||||
{
|
||||
case e_circleShape:
|
||||
s->~b2Shape();
|
||||
allocator->Free(s, sizeof(b2CircleShape));
|
||||
break;
|
||||
|
||||
case e_polygonShape:
|
||||
s->~b2Shape();
|
||||
allocator->Free(s, sizeof(b2PolygonShape));
|
||||
break;
|
||||
|
||||
default:
|
||||
b2Assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
b2Shape::b2Shape(const b2ShapeDef* def)
|
||||
{
|
||||
m_userData = def->userData;
|
||||
m_friction = def->friction;
|
||||
m_restitution = def->restitution;
|
||||
m_density = def->density;
|
||||
m_body = NULL;
|
||||
m_sweepRadius = 0.0f;
|
||||
|
||||
m_next = NULL;
|
||||
|
||||
m_proxyId = b2_nullProxy;
|
||||
|
||||
m_filter = def->filter;
|
||||
|
||||
m_isSensor = def->isSensor;
|
||||
}
|
||||
|
||||
b2Shape::~b2Shape()
|
||||
{
|
||||
b2Assert(m_proxyId == b2_nullProxy);
|
||||
}
|
||||
|
||||
void b2Shape::CreateProxy(b2BroadPhase* broadPhase, const b2XForm& transform)
|
||||
{
|
||||
b2Assert(m_proxyId == b2_nullProxy);
|
||||
|
||||
b2AABB aabb;
|
||||
ComputeAABB(&aabb, transform);
|
||||
|
||||
bool inRange = broadPhase->InRange(aabb);
|
||||
|
||||
// You are creating a shape outside the world box.
|
||||
b2Assert(inRange);
|
||||
|
||||
if (inRange)
|
||||
{
|
||||
m_proxyId = broadPhase->CreateProxy(aabb, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_proxyId = b2_nullProxy;
|
||||
}
|
||||
}
|
||||
|
||||
void b2Shape::DestroyProxy(b2BroadPhase* broadPhase)
|
||||
{
|
||||
if (m_proxyId != b2_nullProxy)
|
||||
{
|
||||
broadPhase->DestroyProxy(m_proxyId);
|
||||
m_proxyId = b2_nullProxy;
|
||||
}
|
||||
}
|
||||
|
||||
bool b2Shape::Synchronize(b2BroadPhase* broadPhase, const b2XForm& transform1, const b2XForm& transform2)
|
||||
{
|
||||
if (m_proxyId == b2_nullProxy)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute an AABB that covers the swept shape (may miss some rotation effect).
|
||||
b2AABB aabb;
|
||||
ComputeSweptAABB(&aabb, transform1, transform2);
|
||||
|
||||
if (broadPhase->InRange(aabb))
|
||||
{
|
||||
broadPhase->MoveProxy(m_proxyId, aabb);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void b2Shape::RefilterProxy(b2BroadPhase* broadPhase, const b2XForm& transform)
|
||||
{
|
||||
if (m_proxyId == b2_nullProxy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
broadPhase->DestroyProxy(m_proxyId);
|
||||
|
||||
b2AABB aabb;
|
||||
ComputeAABB(&aabb, transform);
|
||||
|
||||
bool inRange = broadPhase->InRange(aabb);
|
||||
|
||||
if (inRange)
|
||||
{
|
||||
m_proxyId = broadPhase->CreateProxy(aabb, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_proxyId = b2_nullProxy;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_SHAPE_H
|
||||
#define B2_SHAPE_H
|
||||
|
||||
#include "../../Common/b2Math.h"
|
||||
#include "../b2Collision.h"
|
||||
|
||||
class b2BlockAllocator;
|
||||
class b2Body;
|
||||
class b2BroadPhase;
|
||||
|
||||
/// This holds the mass data computed for a shape.
|
||||
struct b2MassData
|
||||
{
|
||||
/// The mass of the shape, usually in kilograms.
|
||||
float32 mass;
|
||||
|
||||
/// The position of the shape's centroid relative to the shape's origin.
|
||||
b2Vec2 center;
|
||||
|
||||
/// The rotational inertia of the shape.
|
||||
float32 I;
|
||||
};
|
||||
|
||||
/// This holds contact filtering data.
|
||||
struct b2FilterData
|
||||
{
|
||||
/// The collision category bits. Normally you would just set one bit.
|
||||
uint16 categoryBits;
|
||||
|
||||
/// The collision mask bits. This states the categories that this
|
||||
/// shape would accept for collision.
|
||||
uint16 maskBits;
|
||||
|
||||
/// Collision groups allow a certain group of objects to never collide (negative)
|
||||
/// or always collide (positive). Zero means no collision group. Non-zero group
|
||||
/// filtering always wins against the mask bits.
|
||||
int16 groupIndex;
|
||||
};
|
||||
|
||||
/// The various collision shape types supported by Box2D.
|
||||
enum b2ShapeType
|
||||
{
|
||||
e_unknownShape = -1,
|
||||
e_circleShape,
|
||||
e_polygonShape,
|
||||
e_shapeTypeCount,
|
||||
};
|
||||
|
||||
/// A shape definition is used to construct a shape. This class defines an
|
||||
/// abstract shape definition. You can reuse shape definitions safely.
|
||||
struct b2ShapeDef
|
||||
{
|
||||
/// The constructor sets the default shape definition values.
|
||||
b2ShapeDef()
|
||||
{
|
||||
type = e_unknownShape;
|
||||
userData = NULL;
|
||||
friction = 0.2f;
|
||||
restitution = 0.0f;
|
||||
density = 0.0f;
|
||||
filter.categoryBits = 0x0001;
|
||||
filter.maskBits = 0xFFFF;
|
||||
filter.groupIndex = 0;
|
||||
isSensor = false;
|
||||
}
|
||||
|
||||
virtual ~b2ShapeDef() {}
|
||||
|
||||
/// Holds the shape type for down-casting.
|
||||
b2ShapeType type;
|
||||
|
||||
/// Use this to store application specify shape data.
|
||||
void* userData;
|
||||
|
||||
/// The shape's friction coefficient, usually in the range [0,1].
|
||||
float32 friction;
|
||||
|
||||
/// The shape's restitution (elasticity) usually in the range [0,1].
|
||||
float32 restitution;
|
||||
|
||||
/// The shape's density, usually in kg/m^2.
|
||||
float32 density;
|
||||
|
||||
/// A sensor shape collects contact information but never generates a collision
|
||||
/// response.
|
||||
bool isSensor;
|
||||
|
||||
/// Contact filtering data.
|
||||
b2FilterData filter;
|
||||
};
|
||||
|
||||
/// A shape is used for collision detection. Shapes are created in b2World.
|
||||
/// You can use shape for collision detection before they are attached to the world.
|
||||
/// @warning you cannot reuse shapes.
|
||||
class b2Shape
|
||||
{
|
||||
public:
|
||||
/// Get the type of this shape. You can use this to down cast to the concrete shape.
|
||||
/// @return the shape type.
|
||||
b2ShapeType GetType() const;
|
||||
|
||||
/// Is this shape a sensor (non-solid)?
|
||||
/// @return the true if the shape is a sensor.
|
||||
bool IsSensor() const;
|
||||
|
||||
/// Set the contact filtering data. You must call b2World::Refilter to correct
|
||||
/// existing contacts/non-contacts.
|
||||
void SetFilterData(const b2FilterData& filter);
|
||||
|
||||
/// Get the contact filtering data.
|
||||
const b2FilterData& GetFilterData() const;
|
||||
|
||||
/// Get the parent body of this shape. This is NULL if the shape is not attached.
|
||||
/// @return the parent body.
|
||||
b2Body* GetBody();
|
||||
|
||||
/// Get the next shape in the parent body's shape list.
|
||||
/// @return the next shape.
|
||||
b2Shape* GetNext();
|
||||
|
||||
/// Get the user data that was assigned in the shape definition. Use this to
|
||||
/// store your application specific data.
|
||||
void* GetUserData();
|
||||
|
||||
/// Set the user data. Use this to store your application specific data.
|
||||
void SetUserData(void* data);
|
||||
|
||||
/// Test a point for containment in this shape. This only works for convex shapes.
|
||||
/// @param xf the shape world transform.
|
||||
/// @param p a point in world coordinates.
|
||||
virtual bool TestPoint(const b2XForm& xf, const b2Vec2& p) const = 0;
|
||||
|
||||
/// Perform a ray cast against this shape.
|
||||
/// @param xf the shape world transform.
|
||||
/// @param lambda returns the hit fraction. You can use this to compute the contact point
|
||||
/// p = (1 - lambda) * segment.p1 + lambda * segment.p2.
|
||||
/// @param normal returns the normal at the contact point. If there is no intersection, the normal
|
||||
/// is not set.
|
||||
/// @param segment defines the begin and end point of the ray cast.
|
||||
/// @param maxLambda a number typically in the range [0,1].
|
||||
/// @return true if there was an intersection.
|
||||
virtual bool TestSegment( const b2XForm& xf,
|
||||
float32* lambda,
|
||||
b2Vec2* normal,
|
||||
const b2Segment& segment,
|
||||
float32 maxLambda) const = 0;
|
||||
|
||||
/// Given a transform, compute the associated axis aligned bounding box for this shape.
|
||||
/// @param aabb returns the axis aligned box.
|
||||
/// @param xf the world transform of the shape.
|
||||
virtual void ComputeAABB(b2AABB* aabb, const b2XForm& xf) const = 0;
|
||||
|
||||
/// Given two transforms, compute the associated swept axis aligned bounding box for this shape.
|
||||
/// @param aabb returns the axis aligned box.
|
||||
/// @param xf1 the starting shape world transform.
|
||||
/// @param xf2 the ending shape world transform.
|
||||
virtual void ComputeSweptAABB( b2AABB* aabb,
|
||||
const b2XForm& xf1,
|
||||
const b2XForm& xf2) const = 0;
|
||||
|
||||
/// Compute the mass properties of this shape using its dimensions and density.
|
||||
/// The inertia tensor is computed about the local origin, not the centroid.
|
||||
/// @param massData returns the mass data for this shape.
|
||||
virtual void ComputeMass(b2MassData* massData) const = 0;
|
||||
|
||||
/// Get the maximum radius about the parent body's center of mass.
|
||||
float32 GetSweepRadius() const;
|
||||
|
||||
/// Get the coefficient of friction.
|
||||
float32 GetFriction() const;
|
||||
|
||||
/// Get the coefficient of restitution.
|
||||
float32 GetRestitution() const;
|
||||
|
||||
float32 m_density;
|
||||
float32 m_friction;
|
||||
float32 m_restitution;
|
||||
bool m_isSensor;
|
||||
|
||||
protected:
|
||||
|
||||
friend class b2Body;
|
||||
friend class b2World;
|
||||
|
||||
static b2Shape* Create(const b2ShapeDef* def, b2BlockAllocator* allocator);
|
||||
static void Destroy(b2Shape* shape, b2BlockAllocator* allocator);
|
||||
|
||||
b2Shape(const b2ShapeDef* def);
|
||||
virtual ~b2Shape();
|
||||
|
||||
void CreateProxy(b2BroadPhase* broadPhase, const b2XForm& xf);
|
||||
void DestroyProxy(b2BroadPhase* broadPhase);
|
||||
bool Synchronize(b2BroadPhase* broadPhase, const b2XForm& xf1, const b2XForm& xf2);
|
||||
void RefilterProxy(b2BroadPhase* broadPhase, const b2XForm& xf);
|
||||
|
||||
virtual void UpdateSweepRadius(const b2Vec2& center) = 0;
|
||||
|
||||
b2ShapeType m_type;
|
||||
b2Shape* m_next;
|
||||
b2Body* m_body;
|
||||
|
||||
// Sweep radius relative to the parent body's center of mass.
|
||||
float32 m_sweepRadius;
|
||||
|
||||
uint16 m_proxyId;
|
||||
b2FilterData m_filter;
|
||||
|
||||
|
||||
|
||||
void* m_userData;
|
||||
};
|
||||
|
||||
inline b2ShapeType b2Shape::GetType() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
inline bool b2Shape::IsSensor() const
|
||||
{
|
||||
return m_isSensor;
|
||||
}
|
||||
|
||||
inline void b2Shape::SetFilterData(const b2FilterData& filter)
|
||||
{
|
||||
m_filter = filter;
|
||||
}
|
||||
|
||||
inline const b2FilterData& b2Shape::GetFilterData() const
|
||||
{
|
||||
return m_filter;
|
||||
}
|
||||
|
||||
inline void* b2Shape::GetUserData()
|
||||
{
|
||||
return m_userData;
|
||||
}
|
||||
|
||||
inline void b2Shape::SetUserData(void* data)
|
||||
{
|
||||
m_userData = data;
|
||||
}
|
||||
|
||||
inline b2Body* b2Shape::GetBody()
|
||||
{
|
||||
return m_body;
|
||||
}
|
||||
|
||||
inline b2Shape* b2Shape::GetNext()
|
||||
{
|
||||
return m_next;
|
||||
}
|
||||
|
||||
inline float32 b2Shape::GetSweepRadius() const
|
||||
{
|
||||
return m_sweepRadius;
|
||||
}
|
||||
|
||||
inline float32 b2Shape::GetFriction() const
|
||||
{
|
||||
return m_friction;
|
||||
}
|
||||
|
||||
inline float32 b2Shape::GetRestitution() const
|
||||
{
|
||||
return m_restitution;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,668 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2BroadPhase.h"
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
|
||||
// Notes:
|
||||
// - we use bound arrays instead of linked lists for cache coherence.
|
||||
// - we use quantized integral values for fast compares.
|
||||
// - we use short indices rather than pointers to save memory.
|
||||
// - we use a stabbing count for fast overlap queries (less than order N).
|
||||
// - we also use a time stamp on each proxy to speed up the registration of
|
||||
// overlap query results.
|
||||
// - where possible, we compare bound indices instead of values to reduce
|
||||
// cache misses (TODO_ERIN).
|
||||
// - no broadphase is perfect and neither is this one: it is not great for huge
|
||||
// worlds (use a multi-SAP instead), it is not great for large objects.
|
||||
|
||||
bool b2BroadPhase::s_validate = false;
|
||||
|
||||
struct b2BoundValues
|
||||
{
|
||||
uint16 lowerValues[2];
|
||||
uint16 upperValues[2];
|
||||
};
|
||||
|
||||
static int32 BinarySearch(b2Bound* bounds, int32 count, uint16 value)
|
||||
{
|
||||
int32 low = 0;
|
||||
int32 high = count - 1;
|
||||
while (low <= high)
|
||||
{
|
||||
int32 mid = (low + high) >> 1;
|
||||
if (bounds[mid].value > value)
|
||||
{
|
||||
high = mid - 1;
|
||||
}
|
||||
else if (bounds[mid].value < value)
|
||||
{
|
||||
low = mid + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (uint16)mid;
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
b2BroadPhase::b2BroadPhase(const b2AABB& worldAABB, b2PairCallback* callback)
|
||||
{
|
||||
m_pairManager.Initialize(this, callback);
|
||||
|
||||
b2Assert(worldAABB.IsValid());
|
||||
m_worldAABB = worldAABB;
|
||||
m_proxyCount = 0;
|
||||
|
||||
b2Vec2 d = worldAABB.upperBound - worldAABB.lowerBound;
|
||||
m_quantizationFactor.x = float32(B2BROADPHASE_MAX) / d.x;
|
||||
m_quantizationFactor.y = float32(B2BROADPHASE_MAX) / d.y;
|
||||
|
||||
for (uint16 i = 0; i < b2_maxProxies - 1; ++i)
|
||||
{
|
||||
m_proxyPool[i].SetNext(i + 1);
|
||||
m_proxyPool[i].timeStamp = 0;
|
||||
m_proxyPool[i].overlapCount = b2_invalid;
|
||||
m_proxyPool[i].userData = NULL;
|
||||
}
|
||||
m_proxyPool[b2_maxProxies-1].SetNext(b2_nullProxy);
|
||||
m_proxyPool[b2_maxProxies-1].timeStamp = 0;
|
||||
m_proxyPool[b2_maxProxies-1].overlapCount = b2_invalid;
|
||||
m_proxyPool[b2_maxProxies-1].userData = NULL;
|
||||
m_freeProxy = 0;
|
||||
|
||||
m_timeStamp = 1;
|
||||
m_queryResultCount = 0;
|
||||
}
|
||||
|
||||
b2BroadPhase::~b2BroadPhase()
|
||||
{
|
||||
}
|
||||
|
||||
// This one is only used for validation.
|
||||
bool b2BroadPhase::TestOverlap(b2Proxy* p1, b2Proxy* p2)
|
||||
{
|
||||
for (int32 axis = 0; axis < 2; ++axis)
|
||||
{
|
||||
b2Bound* bounds = m_bounds[axis];
|
||||
|
||||
b2Assert(p1->lowerBounds[axis] < 2 * m_proxyCount);
|
||||
b2Assert(p1->upperBounds[axis] < 2 * m_proxyCount);
|
||||
b2Assert(p2->lowerBounds[axis] < 2 * m_proxyCount);
|
||||
b2Assert(p2->upperBounds[axis] < 2 * m_proxyCount);
|
||||
|
||||
if (bounds[p1->lowerBounds[axis]].value > bounds[p2->upperBounds[axis]].value)
|
||||
return false;
|
||||
|
||||
if (bounds[p1->upperBounds[axis]].value < bounds[p2->lowerBounds[axis]].value)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool b2BroadPhase::TestOverlap(const b2BoundValues& b, b2Proxy* p)
|
||||
{
|
||||
for (int32 axis = 0; axis < 2; ++axis)
|
||||
{
|
||||
b2Bound* bounds = m_bounds[axis];
|
||||
|
||||
b2Assert(p->lowerBounds[axis] < 2 * m_proxyCount);
|
||||
b2Assert(p->upperBounds[axis] < 2 * m_proxyCount);
|
||||
|
||||
if (b.lowerValues[axis] > bounds[p->upperBounds[axis]].value)
|
||||
return false;
|
||||
|
||||
if (b.upperValues[axis] < bounds[p->lowerBounds[axis]].value)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void b2BroadPhase::ComputeBounds(uint16* lowerValues, uint16* upperValues, const b2AABB& aabb)
|
||||
{
|
||||
b2Assert(aabb.upperBound.x > aabb.lowerBound.x);
|
||||
b2Assert(aabb.upperBound.y > aabb.lowerBound.y);
|
||||
|
||||
b2Vec2 minVertex = b2Clamp(aabb.lowerBound, m_worldAABB.lowerBound, m_worldAABB.upperBound);
|
||||
b2Vec2 maxVertex = b2Clamp(aabb.upperBound, m_worldAABB.lowerBound, m_worldAABB.upperBound);
|
||||
|
||||
// Bump lower bounds downs and upper bounds up. This ensures correct sorting of
|
||||
// lower/upper bounds that would have equal values.
|
||||
// TODO_ERIN implement fast float to uint16 conversion.
|
||||
lowerValues[0] = (uint16)(m_quantizationFactor.x * (minVertex.x - m_worldAABB.lowerBound.x)) & (B2BROADPHASE_MAX - 1);
|
||||
upperValues[0] = (uint16)(m_quantizationFactor.x * (maxVertex.x - m_worldAABB.lowerBound.x)) | 1;
|
||||
|
||||
lowerValues[1] = (uint16)(m_quantizationFactor.y * (minVertex.y - m_worldAABB.lowerBound.y)) & (B2BROADPHASE_MAX - 1);
|
||||
upperValues[1] = (uint16)(m_quantizationFactor.y * (maxVertex.y - m_worldAABB.lowerBound.y)) | 1;
|
||||
}
|
||||
|
||||
void b2BroadPhase::IncrementTimeStamp()
|
||||
{
|
||||
if (m_timeStamp == B2BROADPHASE_MAX)
|
||||
{
|
||||
for (uint16 i = 0; i < b2_maxProxies; ++i)
|
||||
{
|
||||
m_proxyPool[i].timeStamp = 0;
|
||||
}
|
||||
m_timeStamp = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
++m_timeStamp;
|
||||
}
|
||||
}
|
||||
|
||||
void b2BroadPhase::IncrementOverlapCount(int32 proxyId)
|
||||
{
|
||||
b2Proxy* proxy = m_proxyPool + proxyId;
|
||||
if (proxy->timeStamp < m_timeStamp)
|
||||
{
|
||||
proxy->timeStamp = m_timeStamp;
|
||||
proxy->overlapCount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
proxy->overlapCount = 2;
|
||||
b2Assert(m_queryResultCount < b2_maxProxies);
|
||||
m_queryResults[m_queryResultCount] = (uint16)proxyId;
|
||||
++m_queryResultCount;
|
||||
}
|
||||
}
|
||||
|
||||
void b2BroadPhase::Query(int32* lowerQueryOut, int32* upperQueryOut,
|
||||
uint16 lowerValue, uint16 upperValue,
|
||||
b2Bound* bounds, int32 boundCount, int32 axis)
|
||||
{
|
||||
int32 lowerQuery = BinarySearch(bounds, boundCount, lowerValue);
|
||||
int32 upperQuery = BinarySearch(bounds, boundCount, upperValue);
|
||||
|
||||
// Easy case: lowerQuery <= lowerIndex(i) < upperQuery
|
||||
// Solution: search query range for min bounds.
|
||||
for (int32 i = lowerQuery; i < upperQuery; ++i)
|
||||
{
|
||||
if (bounds[i].IsLower())
|
||||
{
|
||||
IncrementOverlapCount(bounds[i].proxyId);
|
||||
}
|
||||
}
|
||||
|
||||
// Hard case: lowerIndex(i) < lowerQuery < upperIndex(i)
|
||||
// Solution: use the stabbing count to search down the bound array.
|
||||
if (lowerQuery > 0)
|
||||
{
|
||||
int32 i = lowerQuery - 1;
|
||||
int32 s = bounds[i].stabbingCount;
|
||||
|
||||
// Find the s overlaps.
|
||||
while (s)
|
||||
{
|
||||
b2Assert(i >= 0);
|
||||
|
||||
if (bounds[i].IsLower())
|
||||
{
|
||||
b2Proxy* proxy = m_proxyPool + bounds[i].proxyId;
|
||||
if (lowerQuery <= proxy->upperBounds[axis])
|
||||
{
|
||||
IncrementOverlapCount(bounds[i].proxyId);
|
||||
--s;
|
||||
}
|
||||
}
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
*lowerQueryOut = lowerQuery;
|
||||
*upperQueryOut = upperQuery;
|
||||
}
|
||||
|
||||
uint16 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData)
|
||||
{
|
||||
b2Assert(m_proxyCount < b2_maxProxies);
|
||||
b2Assert(m_freeProxy != b2_nullProxy);
|
||||
|
||||
uint16 proxyId = m_freeProxy;
|
||||
b2Proxy* proxy = m_proxyPool + proxyId;
|
||||
m_freeProxy = proxy->GetNext();
|
||||
|
||||
proxy->overlapCount = 0;
|
||||
proxy->userData = userData;
|
||||
|
||||
int32 boundCount = 2 * m_proxyCount;
|
||||
|
||||
uint16 lowerValues[2], upperValues[2];
|
||||
ComputeBounds(lowerValues, upperValues, aabb);
|
||||
|
||||
for (int32 axis = 0; axis < 2; ++axis)
|
||||
{
|
||||
b2Bound* bounds = m_bounds[axis];
|
||||
int32 lowerIndex, upperIndex;
|
||||
Query(&lowerIndex, &upperIndex, lowerValues[axis], upperValues[axis], bounds, boundCount, axis);
|
||||
|
||||
memmove(bounds + upperIndex + 2, bounds + upperIndex, (boundCount - upperIndex) * sizeof(b2Bound));
|
||||
memmove(bounds + lowerIndex + 1, bounds + lowerIndex, (upperIndex - lowerIndex) * sizeof(b2Bound));
|
||||
|
||||
// The upper index has increased because of the lower bound insertion.
|
||||
++upperIndex;
|
||||
|
||||
// Copy in the new bounds.
|
||||
bounds[lowerIndex].value = lowerValues[axis];
|
||||
bounds[lowerIndex].proxyId = proxyId;
|
||||
bounds[upperIndex].value = upperValues[axis];
|
||||
bounds[upperIndex].proxyId = proxyId;
|
||||
|
||||
bounds[lowerIndex].stabbingCount = lowerIndex == 0 ? 0 : bounds[lowerIndex-1].stabbingCount;
|
||||
bounds[upperIndex].stabbingCount = bounds[upperIndex-1].stabbingCount;
|
||||
|
||||
// Adjust the stabbing count between the new bounds.
|
||||
for (int32 index = lowerIndex; index < upperIndex; ++index)
|
||||
{
|
||||
++bounds[index].stabbingCount;
|
||||
}
|
||||
|
||||
// Adjust the all the affected bound indices.
|
||||
for (int32 index = lowerIndex; index < boundCount + 2; ++index)
|
||||
{
|
||||
b2Proxy* proxy = m_proxyPool + bounds[index].proxyId;
|
||||
if (bounds[index].IsLower())
|
||||
{
|
||||
proxy->lowerBounds[axis] = (uint16)index;
|
||||
}
|
||||
else
|
||||
{
|
||||
proxy->upperBounds[axis] = (uint16)index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++m_proxyCount;
|
||||
|
||||
b2Assert(m_queryResultCount < b2_maxProxies);
|
||||
|
||||
// Create pairs if the AABB is in range.
|
||||
for (int32 i = 0; i < m_queryResultCount; ++i)
|
||||
{
|
||||
b2Assert(m_queryResults[i] < b2_maxProxies);
|
||||
b2Assert(m_proxyPool[m_queryResults[i]].IsValid());
|
||||
|
||||
m_pairManager.AddBufferedPair(proxyId, m_queryResults[i]);
|
||||
}
|
||||
|
||||
m_pairManager.Commit();
|
||||
|
||||
if (s_validate)
|
||||
{
|
||||
Validate();
|
||||
}
|
||||
|
||||
// Prepare for next query.
|
||||
m_queryResultCount = 0;
|
||||
IncrementTimeStamp();
|
||||
|
||||
return proxyId;
|
||||
}
|
||||
|
||||
void b2BroadPhase::DestroyProxy(int32 proxyId)
|
||||
{
|
||||
b2Assert(0 < m_proxyCount && m_proxyCount <= b2_maxProxies);
|
||||
b2Proxy* proxy = m_proxyPool + proxyId;
|
||||
b2Assert(proxy->IsValid());
|
||||
|
||||
int32 boundCount = 2 * m_proxyCount;
|
||||
|
||||
for (int32 axis = 0; axis < 2; ++axis)
|
||||
{
|
||||
b2Bound* bounds = m_bounds[axis];
|
||||
|
||||
int32 lowerIndex = proxy->lowerBounds[axis];
|
||||
int32 upperIndex = proxy->upperBounds[axis];
|
||||
uint16 lowerValue = bounds[lowerIndex].value;
|
||||
uint16 upperValue = bounds[upperIndex].value;
|
||||
|
||||
memmove(bounds + lowerIndex, bounds + lowerIndex + 1, (upperIndex - lowerIndex - 1) * sizeof(b2Bound));
|
||||
memmove(bounds + upperIndex-1, bounds + upperIndex + 1, (boundCount - upperIndex - 1) * sizeof(b2Bound));
|
||||
|
||||
// Fix bound indices.
|
||||
for (int32 index = lowerIndex; index < boundCount - 2; ++index)
|
||||
{
|
||||
b2Proxy* proxy = m_proxyPool + bounds[index].proxyId;
|
||||
if (bounds[index].IsLower())
|
||||
{
|
||||
proxy->lowerBounds[axis] = (uint16)index;
|
||||
}
|
||||
else
|
||||
{
|
||||
proxy->upperBounds[axis] = (uint16)index;
|
||||
}
|
||||
}
|
||||
|
||||
// Fix stabbing count.
|
||||
for (int32 index = lowerIndex; index < upperIndex - 1; ++index)
|
||||
{
|
||||
--bounds[index].stabbingCount;
|
||||
}
|
||||
|
||||
// Query for pairs to be removed. lowerIndex and upperIndex are not needed.
|
||||
Query(&lowerIndex, &upperIndex, lowerValue, upperValue, bounds, boundCount - 2, axis);
|
||||
}
|
||||
|
||||
b2Assert(m_queryResultCount < b2_maxProxies);
|
||||
|
||||
for (int32 i = 0; i < m_queryResultCount; ++i)
|
||||
{
|
||||
b2Assert(m_proxyPool[m_queryResults[i]].IsValid());
|
||||
m_pairManager.RemoveBufferedPair(proxyId, m_queryResults[i]);
|
||||
}
|
||||
|
||||
m_pairManager.Commit();
|
||||
|
||||
// Prepare for next query.
|
||||
m_queryResultCount = 0;
|
||||
IncrementTimeStamp();
|
||||
|
||||
// Return the proxy to the pool.
|
||||
proxy->userData = NULL;
|
||||
proxy->overlapCount = b2_invalid;
|
||||
proxy->lowerBounds[0] = b2_invalid;
|
||||
proxy->lowerBounds[1] = b2_invalid;
|
||||
proxy->upperBounds[0] = b2_invalid;
|
||||
proxy->upperBounds[1] = b2_invalid;
|
||||
|
||||
proxy->SetNext(m_freeProxy);
|
||||
m_freeProxy = (uint16)proxyId;
|
||||
--m_proxyCount;
|
||||
|
||||
if (s_validate)
|
||||
{
|
||||
Validate();
|
||||
}
|
||||
}
|
||||
|
||||
void b2BroadPhase::MoveProxy(int32 proxyId, const b2AABB& aabb)
|
||||
{
|
||||
if (proxyId == b2_nullProxy || b2_maxProxies <= proxyId)
|
||||
{
|
||||
b2Assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aabb.IsValid() == false)
|
||||
{
|
||||
b2Assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
int32 boundCount = 2 * m_proxyCount;
|
||||
|
||||
b2Proxy* proxy = m_proxyPool + proxyId;
|
||||
|
||||
// Get new bound values
|
||||
b2BoundValues newValues;
|
||||
ComputeBounds(newValues.lowerValues, newValues.upperValues, aabb);
|
||||
|
||||
// Get old bound values
|
||||
b2BoundValues oldValues;
|
||||
for (int32 axis = 0; axis < 2; ++axis)
|
||||
{
|
||||
oldValues.lowerValues[axis] = m_bounds[axis][proxy->lowerBounds[axis]].value;
|
||||
oldValues.upperValues[axis] = m_bounds[axis][proxy->upperBounds[axis]].value;
|
||||
}
|
||||
|
||||
for (int32 axis = 0; axis < 2; ++axis)
|
||||
{
|
||||
b2Bound* bounds = m_bounds[axis];
|
||||
|
||||
int32 lowerIndex = proxy->lowerBounds[axis];
|
||||
int32 upperIndex = proxy->upperBounds[axis];
|
||||
|
||||
uint16 lowerValue = newValues.lowerValues[axis];
|
||||
uint16 upperValue = newValues.upperValues[axis];
|
||||
|
||||
int32 deltaLower = lowerValue - bounds[lowerIndex].value;
|
||||
int32 deltaUpper = upperValue - bounds[upperIndex].value;
|
||||
|
||||
bounds[lowerIndex].value = lowerValue;
|
||||
bounds[upperIndex].value = upperValue;
|
||||
|
||||
//
|
||||
// Expanding adds overlaps
|
||||
//
|
||||
|
||||
// Should we move the lower bound down?
|
||||
if (deltaLower < 0)
|
||||
{
|
||||
int32 index = lowerIndex;
|
||||
while (index > 0 && lowerValue < bounds[index-1].value)
|
||||
{
|
||||
b2Bound* bound = bounds + index;
|
||||
b2Bound* prevBound = bound - 1;
|
||||
|
||||
int32 prevProxyId = prevBound->proxyId;
|
||||
b2Proxy* prevProxy = m_proxyPool + prevBound->proxyId;
|
||||
|
||||
++prevBound->stabbingCount;
|
||||
|
||||
if (prevBound->IsUpper() == true)
|
||||
{
|
||||
if (TestOverlap(newValues, prevProxy))
|
||||
{
|
||||
m_pairManager.AddBufferedPair(proxyId, prevProxyId);
|
||||
}
|
||||
|
||||
++prevProxy->upperBounds[axis];
|
||||
++bound->stabbingCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
++prevProxy->lowerBounds[axis];
|
||||
--bound->stabbingCount;
|
||||
}
|
||||
|
||||
--proxy->lowerBounds[axis];
|
||||
b2Swap(*bound, *prevBound);
|
||||
--index;
|
||||
}
|
||||
}
|
||||
|
||||
// Should we move the upper bound up?
|
||||
if (deltaUpper > 0)
|
||||
{
|
||||
int32 index = upperIndex;
|
||||
while (index < boundCount-1 && bounds[index+1].value <= upperValue)
|
||||
{
|
||||
b2Bound* bound = bounds + index;
|
||||
b2Bound* nextBound = bound + 1;
|
||||
int32 nextProxyId = nextBound->proxyId;
|
||||
b2Proxy* nextProxy = m_proxyPool + nextProxyId;
|
||||
|
||||
++nextBound->stabbingCount;
|
||||
|
||||
if (nextBound->IsLower() == true)
|
||||
{
|
||||
if (TestOverlap(newValues, nextProxy))
|
||||
{
|
||||
m_pairManager.AddBufferedPair(proxyId, nextProxyId);
|
||||
}
|
||||
|
||||
--nextProxy->lowerBounds[axis];
|
||||
++bound->stabbingCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
--nextProxy->upperBounds[axis];
|
||||
--bound->stabbingCount;
|
||||
}
|
||||
|
||||
++proxy->upperBounds[axis];
|
||||
b2Swap(*bound, *nextBound);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Shrinking removes overlaps
|
||||
//
|
||||
|
||||
// Should we move the lower bound up?
|
||||
if (deltaLower > 0)
|
||||
{
|
||||
int32 index = lowerIndex;
|
||||
while (index < boundCount-1 && bounds[index+1].value <= lowerValue)
|
||||
{
|
||||
b2Bound* bound = bounds + index;
|
||||
b2Bound* nextBound = bound + 1;
|
||||
|
||||
int32 nextProxyId = nextBound->proxyId;
|
||||
b2Proxy* nextProxy = m_proxyPool + nextProxyId;
|
||||
|
||||
--nextBound->stabbingCount;
|
||||
|
||||
if (nextBound->IsUpper())
|
||||
{
|
||||
if (TestOverlap(oldValues, nextProxy))
|
||||
{
|
||||
m_pairManager.RemoveBufferedPair(proxyId, nextProxyId);
|
||||
}
|
||||
|
||||
--nextProxy->upperBounds[axis];
|
||||
--bound->stabbingCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
--nextProxy->lowerBounds[axis];
|
||||
++bound->stabbingCount;
|
||||
}
|
||||
|
||||
++proxy->lowerBounds[axis];
|
||||
b2Swap(*bound, *nextBound);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
// Should we move the upper bound down?
|
||||
if (deltaUpper < 0)
|
||||
{
|
||||
int32 index = upperIndex;
|
||||
while (index > 0 && upperValue < bounds[index-1].value)
|
||||
{
|
||||
b2Bound* bound = bounds + index;
|
||||
b2Bound* prevBound = bound - 1;
|
||||
|
||||
int32 prevProxyId = prevBound->proxyId;
|
||||
b2Proxy* prevProxy = m_proxyPool + prevProxyId;
|
||||
|
||||
--prevBound->stabbingCount;
|
||||
|
||||
if (prevBound->IsLower() == true)
|
||||
{
|
||||
if (TestOverlap(oldValues, prevProxy))
|
||||
{
|
||||
m_pairManager.RemoveBufferedPair(proxyId, prevProxyId);
|
||||
}
|
||||
|
||||
++prevProxy->lowerBounds[axis];
|
||||
--bound->stabbingCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
++prevProxy->upperBounds[axis];
|
||||
++bound->stabbingCount;
|
||||
}
|
||||
|
||||
--proxy->upperBounds[axis];
|
||||
b2Swap(*bound, *prevBound);
|
||||
--index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (s_validate)
|
||||
{
|
||||
Validate();
|
||||
}
|
||||
}
|
||||
|
||||
void b2BroadPhase::Commit()
|
||||
{
|
||||
m_pairManager.Commit();
|
||||
}
|
||||
|
||||
int32 b2BroadPhase::Query(const b2AABB& aabb, void** userData, int32 maxCount)
|
||||
{
|
||||
uint16 lowerValues[2];
|
||||
uint16 upperValues[2];
|
||||
ComputeBounds(lowerValues, upperValues, aabb);
|
||||
|
||||
int32 lowerIndex, upperIndex;
|
||||
|
||||
Query(&lowerIndex, &upperIndex, lowerValues[0], upperValues[0], m_bounds[0], 2*m_proxyCount, 0);
|
||||
Query(&lowerIndex, &upperIndex, lowerValues[1], upperValues[1], m_bounds[1], 2*m_proxyCount, 1);
|
||||
|
||||
b2Assert(m_queryResultCount < b2_maxProxies);
|
||||
|
||||
int32 count = 0;
|
||||
for (int32 i = 0; i < m_queryResultCount && count < maxCount; ++i, ++count)
|
||||
{
|
||||
b2Assert(m_queryResults[i] < b2_maxProxies);
|
||||
b2Proxy* proxy = m_proxyPool + m_queryResults[i];
|
||||
b2Assert(proxy->IsValid());
|
||||
userData[i] = proxy->userData;
|
||||
}
|
||||
|
||||
// Prepare for next query.
|
||||
m_queryResultCount = 0;
|
||||
IncrementTimeStamp();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void b2BroadPhase::Validate()
|
||||
{
|
||||
for (int32 axis = 0; axis < 2; ++axis)
|
||||
{
|
||||
b2Bound* bounds = m_bounds[axis];
|
||||
|
||||
int32 boundCount = 2 * m_proxyCount;
|
||||
uint16 stabbingCount = 0;
|
||||
|
||||
for (int32 i = 0; i < boundCount; ++i)
|
||||
{
|
||||
b2Bound* bound = bounds + i;
|
||||
b2Assert(i == 0 || bounds[i-1].value <= bound->value);
|
||||
b2Assert(bound->proxyId != b2_nullProxy);
|
||||
b2Assert(m_proxyPool[bound->proxyId].IsValid());
|
||||
|
||||
if (bound->IsLower() == true)
|
||||
{
|
||||
b2Assert(m_proxyPool[bound->proxyId].lowerBounds[axis] == i);
|
||||
++stabbingCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
b2Assert(m_proxyPool[bound->proxyId].upperBounds[axis] == i);
|
||||
--stabbingCount;
|
||||
}
|
||||
|
||||
b2Assert(bound->stabbingCount == stabbingCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_BROAD_PHASE_H
|
||||
#define B2_BROAD_PHASE_H
|
||||
|
||||
/*
|
||||
This broad phase uses the Sweep and Prune algorithm as described in:
|
||||
Collision Detection in Interactive 3D Environments by Gino van den Bergen
|
||||
Also, some ideas, such as using integral values for fast compares comes from
|
||||
Bullet (http:/www.bulletphysics.com).
|
||||
*/
|
||||
|
||||
#include "../Common/b2Settings.h"
|
||||
#include "b2Collision.h"
|
||||
#include "b2PairManager.h"
|
||||
#include <climits>
|
||||
|
||||
#ifdef TARGET_FLOAT32_IS_FIXED
|
||||
#define B2BROADPHASE_MAX (USHRT_MAX/2)
|
||||
#else
|
||||
#define B2BROADPHASE_MAX USHRT_MAX
|
||||
|
||||
#endif
|
||||
|
||||
const uint16 b2_invalid = B2BROADPHASE_MAX;
|
||||
const uint16 b2_nullEdge = B2BROADPHASE_MAX;
|
||||
struct b2BoundValues;
|
||||
|
||||
struct b2Bound
|
||||
{
|
||||
bool IsLower() const { return (value & 1) == 0; }
|
||||
bool IsUpper() const { return (value & 1) == 1; }
|
||||
|
||||
uint16 value;
|
||||
uint16 proxyId;
|
||||
uint16 stabbingCount;
|
||||
};
|
||||
|
||||
struct b2Proxy
|
||||
{
|
||||
uint16 GetNext() const { return lowerBounds[0]; }
|
||||
void SetNext(uint16 next) { lowerBounds[0] = next; }
|
||||
bool IsValid() const { return overlapCount != b2_invalid; }
|
||||
|
||||
uint16 lowerBounds[2], upperBounds[2];
|
||||
uint16 overlapCount;
|
||||
uint16 timeStamp;
|
||||
void* userData;
|
||||
};
|
||||
|
||||
class b2BroadPhase
|
||||
{
|
||||
public:
|
||||
b2BroadPhase(const b2AABB& worldAABB, b2PairCallback* callback);
|
||||
~b2BroadPhase();
|
||||
|
||||
// Use this to see if your proxy is in range. If it is not in range,
|
||||
// it should be destroyed. Otherwise you may get O(m^2) pairs, where m
|
||||
// is the number of proxies that are out of range.
|
||||
bool InRange(const b2AABB& aabb) const;
|
||||
|
||||
// Create and destroy proxies. These call Flush first.
|
||||
uint16 CreateProxy(const b2AABB& aabb, void* userData);
|
||||
void DestroyProxy(int32 proxyId);
|
||||
|
||||
// Call MoveProxy as many times as you like, then when you are done
|
||||
// call Commit to finalized the proxy pairs (for your time step).
|
||||
void MoveProxy(int32 proxyId, const b2AABB& aabb);
|
||||
void Commit();
|
||||
|
||||
// Get a single proxy. Returns NULL if the id is invalid.
|
||||
b2Proxy* GetProxy(int32 proxyId);
|
||||
|
||||
// Query an AABB for overlapping proxies, returns the user data and
|
||||
// the count, up to the supplied maximum count.
|
||||
int32 Query(const b2AABB& aabb, void** userData, int32 maxCount);
|
||||
|
||||
void Validate();
|
||||
void ValidatePairs();
|
||||
|
||||
private:
|
||||
void ComputeBounds(uint16* lowerValues, uint16* upperValues, const b2AABB& aabb);
|
||||
|
||||
bool TestOverlap(b2Proxy* p1, b2Proxy* p2);
|
||||
bool TestOverlap(const b2BoundValues& b, b2Proxy* p);
|
||||
|
||||
void Query(int32* lowerIndex, int32* upperIndex, uint16 lowerValue, uint16 upperValue,
|
||||
b2Bound* bounds, int32 boundCount, int32 axis);
|
||||
void IncrementOverlapCount(int32 proxyId);
|
||||
void IncrementTimeStamp();
|
||||
|
||||
public:
|
||||
friend class b2PairManager;
|
||||
|
||||
b2PairManager m_pairManager;
|
||||
|
||||
b2Proxy m_proxyPool[b2_maxProxies];
|
||||
uint16 m_freeProxy;
|
||||
|
||||
b2Bound m_bounds[2][2*b2_maxProxies];
|
||||
|
||||
uint16 m_queryResults[b2_maxProxies];
|
||||
int32 m_queryResultCount;
|
||||
|
||||
b2AABB m_worldAABB;
|
||||
b2Vec2 m_quantizationFactor;
|
||||
int32 m_proxyCount;
|
||||
uint16 m_timeStamp;
|
||||
|
||||
static bool s_validate;
|
||||
};
|
||||
|
||||
|
||||
inline bool b2BroadPhase::InRange(const b2AABB& aabb) const
|
||||
{
|
||||
b2Vec2 d = b2Max(aabb.lowerBound - m_worldAABB.upperBound, m_worldAABB.lowerBound - aabb.upperBound);
|
||||
return b2Max(d.x, d.y) < 0.0f;
|
||||
}
|
||||
|
||||
inline b2Proxy* b2BroadPhase::GetProxy(int32 proxyId)
|
||||
{
|
||||
if (proxyId == b2_nullProxy || m_proxyPool[proxyId].IsValid() == false)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_proxyPool + proxyId;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2Collision.h"
|
||||
#include "Shapes/b2CircleShape.h"
|
||||
#include "Shapes/b2PolygonShape.h"
|
||||
|
||||
void b2CollideCircles(
|
||||
b2Manifold* manifold,
|
||||
const b2CircleShape* circle1, const b2XForm& xf1,
|
||||
const b2CircleShape* circle2, const b2XForm& xf2)
|
||||
{
|
||||
manifold->pointCount = 0;
|
||||
|
||||
b2Vec2 p1 = b2Mul(xf1, circle1->GetLocalPosition());
|
||||
b2Vec2 p2 = b2Mul(xf2, circle2->GetLocalPosition());
|
||||
|
||||
b2Vec2 d = p2 - p1;
|
||||
float32 distSqr = b2Dot(d, d);
|
||||
float32 r1 = circle1->GetRadius();
|
||||
float32 r2 = circle2->GetRadius();
|
||||
float32 radiusSum = r1 + r2;
|
||||
if (distSqr > radiusSum * radiusSum)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float32 separation;
|
||||
if (distSqr < B2_FLT_EPSILON)
|
||||
{
|
||||
separation = -radiusSum;
|
||||
manifold->normal.Set(0.0f, 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
float32 dist = b2Sqrt(distSqr);
|
||||
separation = dist - radiusSum;
|
||||
float32 a = 1.0f / dist;
|
||||
manifold->normal.x = a * d.x;
|
||||
manifold->normal.y = a * d.y;
|
||||
}
|
||||
|
||||
manifold->pointCount = 1;
|
||||
manifold->points[0].id.key = 0;
|
||||
manifold->points[0].separation = separation;
|
||||
|
||||
p1 += r1 * manifold->normal;
|
||||
p2 -= r2 * manifold->normal;
|
||||
|
||||
b2Vec2 p = 0.5f * (p1 + p2);
|
||||
|
||||
manifold->points[0].localPoint1 = b2MulT(xf1, p);
|
||||
manifold->points[0].localPoint2 = b2MulT(xf2, p);
|
||||
}
|
||||
|
||||
void b2CollidePolygonAndCircle(
|
||||
b2Manifold* manifold,
|
||||
const b2PolygonShape* polygon, const b2XForm& xf1,
|
||||
const b2CircleShape* circle, const b2XForm& xf2)
|
||||
{
|
||||
manifold->pointCount = 0;
|
||||
|
||||
// Compute circle position in the frame of the polygon.
|
||||
b2Vec2 c = b2Mul(xf2, circle->GetLocalPosition());
|
||||
b2Vec2 cLocal = b2MulT(xf1, c);
|
||||
|
||||
// Find the min separating edge.
|
||||
int32 normalIndex = 0;
|
||||
float32 separation = -B2_FLT_MAX;
|
||||
float32 radius = circle->GetRadius();
|
||||
int32 vertexCount = polygon->GetVertexCount();
|
||||
const b2Vec2* vertices = polygon->GetVertices();
|
||||
const b2Vec2* normals = polygon->GetNormals();
|
||||
|
||||
for (int32 i = 0; i < vertexCount; ++i)
|
||||
{
|
||||
float32 s = b2Dot(normals[i], cLocal - vertices[i]);
|
||||
|
||||
if (s > radius)
|
||||
{
|
||||
// Early out.
|
||||
return;
|
||||
}
|
||||
|
||||
if (s > separation)
|
||||
{
|
||||
separation = s;
|
||||
normalIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
// If the center is inside the polygon ...
|
||||
if (separation < B2_FLT_EPSILON)
|
||||
{
|
||||
manifold->pointCount = 1;
|
||||
manifold->normal = b2Mul(xf1.R, normals[normalIndex]);
|
||||
manifold->points[0].id.features.incidentEdge = (uint8)normalIndex;
|
||||
manifold->points[0].id.features.incidentVertex = b2_nullFeature;
|
||||
manifold->points[0].id.features.referenceEdge = 0;
|
||||
manifold->points[0].id.features.flip = 0;
|
||||
b2Vec2 position = c - radius * manifold->normal;
|
||||
manifold->points[0].localPoint1 = b2MulT(xf1, position);
|
||||
manifold->points[0].localPoint2 = b2MulT(xf2, position);
|
||||
manifold->points[0].separation = separation - radius;
|
||||
return;
|
||||
}
|
||||
|
||||
// Project the circle center onto the edge segment.
|
||||
int32 vertIndex1 = normalIndex;
|
||||
int32 vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0;
|
||||
b2Vec2 e = vertices[vertIndex2] - vertices[vertIndex1];
|
||||
|
||||
float32 length = e.Normalize();
|
||||
b2Assert(length > B2_FLT_EPSILON);
|
||||
|
||||
// Project the center onto the edge.
|
||||
float32 u = b2Dot(cLocal - vertices[vertIndex1], e);
|
||||
b2Vec2 p;
|
||||
if (u <= 0.0f)
|
||||
{
|
||||
p = vertices[vertIndex1];
|
||||
manifold->points[0].id.features.incidentEdge = b2_nullFeature;
|
||||
manifold->points[0].id.features.incidentVertex = (uint8)vertIndex1;
|
||||
}
|
||||
else if (u >= length)
|
||||
{
|
||||
p = vertices[vertIndex2];
|
||||
manifold->points[0].id.features.incidentEdge = b2_nullFeature;
|
||||
manifold->points[0].id.features.incidentVertex = (uint8)vertIndex2;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = vertices[vertIndex1] + u * e;
|
||||
manifold->points[0].id.features.incidentEdge = (uint8)normalIndex;
|
||||
manifold->points[0].id.features.incidentVertex = 0;
|
||||
}
|
||||
|
||||
b2Vec2 d = cLocal - p;
|
||||
float32 dist = d.Normalize();
|
||||
if (dist > radius)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
manifold->pointCount = 1;
|
||||
manifold->normal = b2Mul(xf1.R, d);
|
||||
b2Vec2 position = c - radius * manifold->normal;
|
||||
manifold->points[0].localPoint1 = b2MulT(xf1, position);
|
||||
manifold->points[0].localPoint2 = b2MulT(xf2, position);
|
||||
manifold->points[0].separation = dist - radius;
|
||||
manifold->points[0].id.features.referenceEdge = 0;
|
||||
manifold->points[0].id.features.flip = 0;
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2Collision.h"
|
||||
#include "Shapes/b2PolygonShape.h"
|
||||
|
||||
struct ClipVertex
|
||||
{
|
||||
b2Vec2 v;
|
||||
b2ContactID id;
|
||||
};
|
||||
|
||||
static int32 ClipSegmentToLine(ClipVertex vOut[2], ClipVertex vIn[2],
|
||||
const b2Vec2& normal, float32 offset)
|
||||
{
|
||||
// Start with no output points
|
||||
int32 numOut = 0;
|
||||
|
||||
// Calculate the distance of end points to the line
|
||||
float32 distance0 = b2Dot(normal, vIn[0].v) - offset;
|
||||
float32 distance1 = b2Dot(normal, vIn[1].v) - offset;
|
||||
|
||||
// If the points are behind the plane
|
||||
if (distance0 <= 0.0f) vOut[numOut++] = vIn[0];
|
||||
if (distance1 <= 0.0f) vOut[numOut++] = vIn[1];
|
||||
|
||||
// If the points are on different sides of the plane
|
||||
if (distance0 * distance1 < 0.0f)
|
||||
{
|
||||
// Find intersection point of edge and plane
|
||||
float32 interp = distance0 / (distance0 - distance1);
|
||||
vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v);
|
||||
if (distance0 > 0.0f)
|
||||
{
|
||||
vOut[numOut].id = vIn[0].id;
|
||||
}
|
||||
else
|
||||
{
|
||||
vOut[numOut].id = vIn[1].id;
|
||||
}
|
||||
++numOut;
|
||||
}
|
||||
|
||||
return numOut;
|
||||
}
|
||||
|
||||
// Find the separation between poly1 and poly2 for a give edge normal on poly1.
|
||||
static float32 EdgeSeparation(const b2PolygonShape* poly1, const b2XForm& xf1, int32 edge1,
|
||||
const b2PolygonShape* poly2, const b2XForm& xf2)
|
||||
{
|
||||
int32 count1 = poly1->GetVertexCount();
|
||||
const b2Vec2* vertices1 = poly1->GetVertices();
|
||||
const b2Vec2* normals1 = poly1->GetNormals();
|
||||
|
||||
int32 count2 = poly2->GetVertexCount();
|
||||
const b2Vec2* vertices2 = poly2->GetVertices();
|
||||
|
||||
b2Assert(0 <= edge1 && edge1 < count1);
|
||||
|
||||
// Convert normal from poly1's frame into poly2's frame.
|
||||
b2Vec2 normal1World = b2Mul(xf1.R, normals1[edge1]);
|
||||
b2Vec2 normal1 = b2MulT(xf2.R, normal1World);
|
||||
|
||||
// Find support vertex on poly2 for -normal.
|
||||
int32 index = 0;
|
||||
float32 minDot = B2_FLT_MAX;
|
||||
|
||||
for (int32 i = 0; i < count2; ++i)
|
||||
{
|
||||
float32 dot = b2Dot(vertices2[i], normal1);
|
||||
if (dot < minDot)
|
||||
{
|
||||
minDot = dot;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
b2Vec2 v1 = b2Mul(xf1, vertices1[edge1]);
|
||||
b2Vec2 v2 = b2Mul(xf2, vertices2[index]);
|
||||
float32 separation = b2Dot(v2 - v1, normal1World);
|
||||
return separation;
|
||||
}
|
||||
|
||||
// Find the max separation between poly1 and poly2 using edge normals from poly1.
|
||||
static float32 FindMaxSeparation(int32* edgeIndex,
|
||||
const b2PolygonShape* poly1, const b2XForm& xf1,
|
||||
const b2PolygonShape* poly2, const b2XForm& xf2)
|
||||
{
|
||||
int32 count1 = poly1->GetVertexCount();
|
||||
const b2Vec2* normals1 = poly1->GetNormals();
|
||||
|
||||
// Vector pointing from the centroid of poly1 to the centroid of poly2.
|
||||
b2Vec2 d = b2Mul(xf2, poly2->GetCentroid()) - b2Mul(xf1, poly1->GetCentroid());
|
||||
b2Vec2 dLocal1 = b2MulT(xf1.R, d);
|
||||
|
||||
// Find edge normal on poly1 that has the largest projection onto d.
|
||||
int32 edge = 0;
|
||||
float32 maxDot = -B2_FLT_MAX;
|
||||
for (int32 i = 0; i < count1; ++i)
|
||||
{
|
||||
float32 dot = b2Dot(normals1[i], dLocal1);
|
||||
if (dot > maxDot)
|
||||
{
|
||||
maxDot = dot;
|
||||
edge = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the separation for the edge normal.
|
||||
float32 s = EdgeSeparation(poly1, xf1, edge, poly2, xf2);
|
||||
if (s > 0.0f)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
// Check the separation for the previous edge normal.
|
||||
int32 prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1;
|
||||
float32 sPrev = EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2);
|
||||
if (sPrev > 0.0f)
|
||||
{
|
||||
return sPrev;
|
||||
}
|
||||
|
||||
// Check the separation for the next edge normal.
|
||||
int32 nextEdge = edge + 1 < count1 ? edge + 1 : 0;
|
||||
float32 sNext = EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2);
|
||||
if (sNext > 0.0f)
|
||||
{
|
||||
return sNext;
|
||||
}
|
||||
|
||||
// Find the best edge and the search direction.
|
||||
int32 bestEdge;
|
||||
float32 bestSeparation;
|
||||
int32 increment;
|
||||
if (sPrev > s && sPrev > sNext)
|
||||
{
|
||||
increment = -1;
|
||||
bestEdge = prevEdge;
|
||||
bestSeparation = sPrev;
|
||||
}
|
||||
else if (sNext > s)
|
||||
{
|
||||
increment = 1;
|
||||
bestEdge = nextEdge;
|
||||
bestSeparation = sNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
*edgeIndex = edge;
|
||||
return s;
|
||||
}
|
||||
|
||||
// Perform a local search for the best edge normal.
|
||||
for ( ; ; )
|
||||
{
|
||||
if (increment == -1)
|
||||
edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1;
|
||||
else
|
||||
edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0;
|
||||
|
||||
s = EdgeSeparation(poly1, xf1, edge, poly2, xf2);
|
||||
if (s > 0.0f)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
if (s > bestSeparation)
|
||||
{
|
||||
bestEdge = edge;
|
||||
bestSeparation = s;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*edgeIndex = bestEdge;
|
||||
return bestSeparation;
|
||||
}
|
||||
|
||||
static void FindIncidentEdge(ClipVertex c[2],
|
||||
const b2PolygonShape* poly1, const b2XForm& xf1, int32 edge1,
|
||||
const b2PolygonShape* poly2, const b2XForm& xf2)
|
||||
{
|
||||
int32 count1 = poly1->GetVertexCount();
|
||||
const b2Vec2* normals1 = poly1->GetNormals();
|
||||
|
||||
int32 count2 = poly2->GetVertexCount();
|
||||
const b2Vec2* vertices2 = poly2->GetVertices();
|
||||
const b2Vec2* normals2 = poly2->GetNormals();
|
||||
|
||||
b2Assert(0 <= edge1 && edge1 < count1);
|
||||
|
||||
// Get the normal of the reference edge in poly2's frame.
|
||||
b2Vec2 normal1 = b2MulT(xf2.R, b2Mul(xf1.R, normals1[edge1]));
|
||||
|
||||
// Find the incident edge on poly2.
|
||||
int32 index = 0;
|
||||
float32 minDot = B2_FLT_MAX;
|
||||
for (int32 i = 0; i < count2; ++i)
|
||||
{
|
||||
float32 dot = b2Dot(normal1, normals2[i]);
|
||||
if (dot < minDot)
|
||||
{
|
||||
minDot = dot;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Build the clip vertices for the incident edge.
|
||||
int32 i1 = index;
|
||||
int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0;
|
||||
|
||||
c[0].v = b2Mul(xf2, vertices2[i1]);
|
||||
c[0].id.features.referenceEdge = (uint8)edge1;
|
||||
c[0].id.features.incidentEdge = (uint8)i1;
|
||||
c[0].id.features.incidentVertex = 0;
|
||||
|
||||
c[1].v = b2Mul(xf2, vertices2[i2]);
|
||||
c[1].id.features.referenceEdge = (uint8)edge1;
|
||||
c[1].id.features.incidentEdge = (uint8)i2;
|
||||
c[1].id.features.incidentVertex = 1;
|
||||
}
|
||||
|
||||
// Find edge normal of max separation on A - return if separating axis is found
|
||||
// Find edge normal of max separation on B - return if separation axis is found
|
||||
// Choose reference edge as min(minA, minB)
|
||||
// Find incident edge
|
||||
// Clip
|
||||
|
||||
// The normal points from 1 to 2
|
||||
void b2CollidePolygons(b2Manifold* manifold,
|
||||
const b2PolygonShape* polyA, const b2XForm& xfA,
|
||||
const b2PolygonShape* polyB, const b2XForm& xfB)
|
||||
{
|
||||
manifold->pointCount = 0;
|
||||
|
||||
int32 edgeA = 0;
|
||||
float32 separationA = FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB);
|
||||
if (separationA > 0.0f)
|
||||
return;
|
||||
|
||||
int32 edgeB = 0;
|
||||
float32 separationB = FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA);
|
||||
if (separationB > 0.0f)
|
||||
return;
|
||||
|
||||
const b2PolygonShape* poly1; // reference poly
|
||||
const b2PolygonShape* poly2; // incident poly
|
||||
b2XForm xf1, xf2;
|
||||
int32 edge1; // reference edge
|
||||
uint8 flip;
|
||||
const float32 k_relativeTol = 0.98f;
|
||||
const float32 k_absoluteTol = 0.001f;
|
||||
|
||||
// TODO_ERIN use "radius" of poly for absolute tolerance.
|
||||
if (separationB > k_relativeTol * separationA + k_absoluteTol)
|
||||
{
|
||||
poly1 = polyB;
|
||||
poly2 = polyA;
|
||||
xf1 = xfB;
|
||||
xf2 = xfA;
|
||||
edge1 = edgeB;
|
||||
flip = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
poly1 = polyA;
|
||||
poly2 = polyB;
|
||||
xf1 = xfA;
|
||||
xf2 = xfB;
|
||||
edge1 = edgeA;
|
||||
flip = 0;
|
||||
}
|
||||
|
||||
ClipVertex incidentEdge[2];
|
||||
FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2);
|
||||
|
||||
int32 count1 = poly1->GetVertexCount();
|
||||
const b2Vec2* vertices1 = poly1->GetVertices();
|
||||
|
||||
b2Vec2 v11 = vertices1[edge1];
|
||||
b2Vec2 v12 = edge1 + 1 < count1 ? vertices1[edge1+1] : vertices1[0];
|
||||
|
||||
b2Vec2 dv = v12 - v11;
|
||||
b2Vec2 sideNormal = b2Mul(xf1.R, v12 - v11);
|
||||
sideNormal.Normalize();
|
||||
b2Vec2 frontNormal = b2Cross(sideNormal, 1.0f);
|
||||
|
||||
v11 = b2Mul(xf1, v11);
|
||||
v12 = b2Mul(xf1, v12);
|
||||
|
||||
float32 frontOffset = b2Dot(frontNormal, v11);
|
||||
float32 sideOffset1 = -b2Dot(sideNormal, v11);
|
||||
float32 sideOffset2 = b2Dot(sideNormal, v12);
|
||||
|
||||
// Clip incident edge against extruded edge1 side edges.
|
||||
ClipVertex clipPoints1[2];
|
||||
ClipVertex clipPoints2[2];
|
||||
int np;
|
||||
|
||||
// Clip to box side 1
|
||||
np = ClipSegmentToLine(clipPoints1, incidentEdge, -sideNormal, sideOffset1);
|
||||
|
||||
if (np < 2)
|
||||
return;
|
||||
|
||||
// Clip to negative box side 1
|
||||
np = ClipSegmentToLine(clipPoints2, clipPoints1, sideNormal, sideOffset2);
|
||||
|
||||
if (np < 2)
|
||||
return;
|
||||
|
||||
// Now clipPoints2 contains the clipped points.
|
||||
manifold->normal = flip ? -frontNormal : frontNormal;
|
||||
|
||||
int32 pointCount = 0;
|
||||
for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
|
||||
{
|
||||
float32 separation = b2Dot(frontNormal, clipPoints2[i].v) - frontOffset;
|
||||
|
||||
if (separation <= 0.0f)
|
||||
{
|
||||
b2ManifoldPoint* cp = manifold->points + pointCount;
|
||||
cp->separation = separation;
|
||||
cp->localPoint1 = b2MulT(xfA, clipPoints2[i].v);
|
||||
cp->localPoint2 = b2MulT(xfB, clipPoints2[i].v);
|
||||
cp->id = clipPoints2[i].id;
|
||||
cp->id.features.flip = flip;
|
||||
++pointCount;
|
||||
}
|
||||
}
|
||||
|
||||
manifold->pointCount = pointCount;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2Collision.h"
|
||||
|
||||
// Collision Detection in Interactive 3D Environments by Gino van den Bergen
|
||||
// From Section 3.4.1
|
||||
// x = mu1 * p1 + mu2 * p2
|
||||
// mu1 + mu2 = 1 && mu1 >= 0 && mu2 >= 0
|
||||
// mu1 = 1 - mu2;
|
||||
// x = (1 - mu2) * p1 + mu2 * p2
|
||||
// = p1 + mu2 * (p2 - p1)
|
||||
// x = s + a * r (s := start, r := end - start)
|
||||
// s + a * r = p1 + mu2 * d (d := p2 - p1)
|
||||
// -a * r + mu2 * d = b (b := s - p1)
|
||||
// [-r d] * [a; mu2] = b
|
||||
// Cramer's rule:
|
||||
// denom = det[-r d]
|
||||
// a = det[b d] / denom
|
||||
// mu2 = det[-r b] / denom
|
||||
bool b2Segment::TestSegment(float32* lambda, b2Vec2* normal, const b2Segment& segment, float32 maxLambda) const
|
||||
{
|
||||
b2Vec2 s = segment.p1;
|
||||
b2Vec2 r = segment.p2 - s;
|
||||
b2Vec2 d = p2 - p1;
|
||||
b2Vec2 n = b2Cross(d, 1.0f);
|
||||
|
||||
const float32 k_slop = 100.0f * B2_FLT_EPSILON;
|
||||
float32 denom = -b2Dot(r, n);
|
||||
|
||||
// Cull back facing collision and ignore parallel segments.
|
||||
if (denom > k_slop)
|
||||
{
|
||||
// Does the segment intersect the infinite line associated with this segment?
|
||||
b2Vec2 b = s - p1;
|
||||
float32 a = b2Dot(b, n);
|
||||
|
||||
if (0.0f <= a && a <= maxLambda * denom)
|
||||
{
|
||||
float32 mu2 = -r.x * b.y + r.y * b.x;
|
||||
|
||||
// Does the segment intersect this segment?
|
||||
if (-k_slop * denom <= mu2 && mu2 <= denom * (1.0f + k_slop))
|
||||
{
|
||||
a /= denom;
|
||||
n.Normalize();
|
||||
*lambda = a;
|
||||
*normal = n;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_COLLISION_H
|
||||
#define B2_COLLISION_H
|
||||
|
||||
#include "../Common/b2Math.h"
|
||||
#include <climits>
|
||||
|
||||
/// @file
|
||||
/// Structures and functions used for computing contact points, distance
|
||||
/// queries, and TOI queries.
|
||||
|
||||
class b2Shape;
|
||||
class b2CircleShape;
|
||||
class b2PolygonShape;
|
||||
|
||||
const uint8 b2_nullFeature = UCHAR_MAX;
|
||||
|
||||
/// Contact ids to facilitate warm starting.
|
||||
union b2ContactID
|
||||
{
|
||||
/// The features that intersect to form the contact point
|
||||
struct Features
|
||||
{
|
||||
uint8 referenceEdge; ///< The edge that defines the outward contact normal.
|
||||
uint8 incidentEdge; ///< The edge most anti-parallel to the reference edge.
|
||||
uint8 incidentVertex; ///< The vertex (0 or 1) on the incident edge that was clipped.
|
||||
uint8 flip; ///< A value of 1 indicates that the reference edge is on shape2.
|
||||
} features;
|
||||
uint32 key; ///< Used to quickly compare contact ids.
|
||||
};
|
||||
|
||||
/// A manifold point is a contact point belonging to a contact
|
||||
/// manifold. It holds details related to the geometry and dynamics
|
||||
/// of the contact points.
|
||||
/// The point is stored in local coordinates because CCD
|
||||
/// requires sub-stepping in which the separation is stale.
|
||||
struct b2ManifoldPoint
|
||||
{
|
||||
b2Vec2 localPoint1; ///< local position of the contact point in body1
|
||||
b2Vec2 localPoint2; ///< local position of the contact point in body2
|
||||
float32 separation; ///< the separation of the shapes along the normal vector
|
||||
float32 normalImpulse; ///< the non-penetration impulse
|
||||
float32 tangentImpulse; ///< the friction impulse
|
||||
b2ContactID id; ///< uniquely identifies a contact point between two shapes
|
||||
};
|
||||
|
||||
/// A manifold for two touching convex shapes.
|
||||
struct b2Manifold
|
||||
{
|
||||
b2ManifoldPoint points[b2_maxManifoldPoints]; ///< the points of contact
|
||||
b2Vec2 normal; ///< the shared unit normal vector
|
||||
int32 pointCount; ///< the number of manifold points
|
||||
};
|
||||
|
||||
/// A line segment.
|
||||
struct b2Segment
|
||||
{
|
||||
/// Ray cast against this segment with another segment.
|
||||
bool TestSegment(float32* lambda, b2Vec2* normal, const b2Segment& segment, float32 maxLambda) const;
|
||||
|
||||
b2Vec2 p1; ///< the starting point
|
||||
b2Vec2 p2; ///< the ending point
|
||||
};
|
||||
|
||||
/// An axis aligned bounding box.
|
||||
struct b2AABB
|
||||
{
|
||||
/// Verify that the bounds are sorted.
|
||||
bool IsValid() const;
|
||||
|
||||
b2Vec2 lowerBound; ///< the lower vertex
|
||||
b2Vec2 upperBound; ///< the upper vertex
|
||||
};
|
||||
|
||||
/// An oriented bounding box.
|
||||
struct b2OBB
|
||||
{
|
||||
b2Mat22 R; ///< the rotation matrix
|
||||
b2Vec2 center; ///< the local centroid
|
||||
b2Vec2 extents; ///< the half-widths
|
||||
};
|
||||
|
||||
/// Compute the collision manifold between two circles.
|
||||
void b2CollideCircles(b2Manifold* manifold,
|
||||
const b2CircleShape* circle1, const b2XForm& xf1,
|
||||
const b2CircleShape* circle2, const b2XForm& xf2);
|
||||
|
||||
/// Compute the collision manifold between a polygon and a circle.
|
||||
void b2CollidePolygonAndCircle(b2Manifold* manifold,
|
||||
const b2PolygonShape* polygon, const b2XForm& xf1,
|
||||
const b2CircleShape* circle, const b2XForm& xf2);
|
||||
|
||||
/// Compute the collision manifold between two circles.
|
||||
void b2CollidePolygons(b2Manifold* manifold,
|
||||
const b2PolygonShape* polygon1, const b2XForm& xf1,
|
||||
const b2PolygonShape* polygon2, const b2XForm& xf2);
|
||||
|
||||
/// Compute the distance between two shapes and the closest points.
|
||||
/// @return the distance between the shapes or zero if they are overlapped/touching.
|
||||
float32 b2Distance(b2Vec2* x1, b2Vec2* x2,
|
||||
const b2Shape* shape1, const b2XForm& xf1,
|
||||
const b2Shape* shape2, const b2XForm& xf2);
|
||||
|
||||
/// Compute the time when two shapes begin to touch or touch at a closer distance.
|
||||
/// @warning the sweeps must have the same time interval.
|
||||
/// @return the fraction between [0,1] in which the shapes first touch.
|
||||
/// fraction=0 means the shapes begin touching/overlapped, and fraction=1 means the shapes don't touch.
|
||||
float32 b2TimeOfImpact(const b2Shape* shape1, const b2Sweep& sweep1,
|
||||
const b2Shape* shape2, const b2Sweep& sweep2);
|
||||
|
||||
|
||||
// ---------------- Inline Functions ------------------------------------------
|
||||
|
||||
inline bool b2AABB::IsValid() const
|
||||
{
|
||||
b2Vec2 d = upperBound - lowerBound;
|
||||
bool valid = d.x >= 0.0f && d.y >= 0.0f;
|
||||
valid = valid && lowerBound.IsValid() && upperBound.IsValid();
|
||||
return valid;
|
||||
}
|
||||
|
||||
inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b)
|
||||
{
|
||||
b2Vec2 d1, d2;
|
||||
d1 = b.lowerBound - a.upperBound;
|
||||
d2 = a.lowerBound - b.upperBound;
|
||||
|
||||
if (d1.x > 0.0f || d1.y > 0.0f)
|
||||
return false;
|
||||
|
||||
if (d2.x > 0.0f || d2.y > 0.0f)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2Collision.h"
|
||||
#include "Shapes/b2CircleShape.h"
|
||||
#include "Shapes/b2PolygonShape.h"
|
||||
|
||||
int32 g_GJK_Iterations = 0;
|
||||
|
||||
// GJK using Voronoi regions (Christer Ericson) and region selection
|
||||
// optimizations (Casey Muratori).
|
||||
|
||||
// The origin is either in the region of points[1] or in the edge region. The origin is
|
||||
// not in region of points[0] because that is the old point.
|
||||
static int32 ProcessTwo(b2Vec2* x1, b2Vec2* x2, b2Vec2* p1s, b2Vec2* p2s, b2Vec2* points)
|
||||
{
|
||||
// If in point[1] region
|
||||
b2Vec2 r = -points[1];
|
||||
b2Vec2 d = points[0] - points[1];
|
||||
float32 length = d.Normalize();
|
||||
float32 lambda = b2Dot(r, d);
|
||||
if (lambda <= 0.0f || length < B2_FLT_EPSILON)
|
||||
{
|
||||
// The simplex is reduced to a point.
|
||||
*x1 = p1s[1];
|
||||
*x2 = p2s[1];
|
||||
p1s[0] = p1s[1];
|
||||
p2s[0] = p2s[1];
|
||||
points[0] = points[1];
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Else in edge region
|
||||
lambda /= length;
|
||||
*x1 = p1s[1] + lambda * (p1s[0] - p1s[1]);
|
||||
*x2 = p2s[1] + lambda * (p2s[0] - p2s[1]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Possible regions:
|
||||
// - points[2]
|
||||
// - edge points[0]-points[2]
|
||||
// - edge points[1]-points[2]
|
||||
// - inside the triangle
|
||||
static int32 ProcessThree(b2Vec2* x1, b2Vec2* x2, b2Vec2* p1s, b2Vec2* p2s, b2Vec2* points)
|
||||
{
|
||||
b2Vec2 a = points[0];
|
||||
b2Vec2 b = points[1];
|
||||
b2Vec2 c = points[2];
|
||||
|
||||
b2Vec2 ab = b - a;
|
||||
b2Vec2 ac = c - a;
|
||||
b2Vec2 bc = c - b;
|
||||
|
||||
float32 sn = -b2Dot(a, ab), sd = b2Dot(b, ab);
|
||||
float32 tn = -b2Dot(a, ac), td = b2Dot(c, ac);
|
||||
float32 un = -b2Dot(b, bc), ud = b2Dot(c, bc);
|
||||
|
||||
// In vertex c region?
|
||||
if (td <= 0.0f && ud <= 0.0f)
|
||||
{
|
||||
// Single point
|
||||
*x1 = p1s[2];
|
||||
*x2 = p2s[2];
|
||||
p1s[0] = p1s[2];
|
||||
p2s[0] = p2s[2];
|
||||
points[0] = points[2];
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Should not be in vertex a or b region.
|
||||
B2_NOT_USED(sd);
|
||||
B2_NOT_USED(sn);
|
||||
b2Assert(sn > 0.0f || tn > 0.0f);
|
||||
b2Assert(sd > 0.0f || un > 0.0f);
|
||||
|
||||
float32 n = b2Cross(ab, ac);
|
||||
|
||||
#ifdef TARGET_FLOAT32_IS_FIXED
|
||||
n = (n < 0.0)? -1.0 : ((n > 0.0)? 1.0 : 0.0);
|
||||
#endif
|
||||
|
||||
// Should not be in edge ab region.
|
||||
float32 vc = n * b2Cross(a, b);
|
||||
b2Assert(vc > 0.0f || sn > 0.0f || sd > 0.0f);
|
||||
|
||||
// In edge bc region?
|
||||
float32 va = n * b2Cross(b, c);
|
||||
if (va <= 0.0f && un >= 0.0f && ud >= 0.0f && (un+ud) > 0.0f)
|
||||
{
|
||||
b2Assert(un + ud > 0.0f);
|
||||
float32 lambda = un / (un + ud);
|
||||
*x1 = p1s[1] + lambda * (p1s[2] - p1s[1]);
|
||||
*x2 = p2s[1] + lambda * (p2s[2] - p2s[1]);
|
||||
p1s[0] = p1s[2];
|
||||
p2s[0] = p2s[2];
|
||||
points[0] = points[2];
|
||||
return 2;
|
||||
}
|
||||
|
||||
// In edge ac region?
|
||||
float32 vb = n * b2Cross(c, a);
|
||||
if (vb <= 0.0f && tn >= 0.0f && td >= 0.0f && (tn+td) > 0.0f)
|
||||
{
|
||||
b2Assert(tn + td > 0.0f);
|
||||
float32 lambda = tn / (tn + td);
|
||||
*x1 = p1s[0] + lambda * (p1s[2] - p1s[0]);
|
||||
*x2 = p2s[0] + lambda * (p2s[2] - p2s[0]);
|
||||
p1s[1] = p1s[2];
|
||||
p2s[1] = p2s[2];
|
||||
points[1] = points[2];
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Inside the triangle, compute barycentric coordinates
|
||||
float32 denom = va + vb + vc;
|
||||
b2Assert(denom > 0.0f);
|
||||
denom = 1.0f / denom;
|
||||
|
||||
#ifdef TARGET_FLOAT32_IS_FIXED
|
||||
*x1 = denom * (va * p1s[0] + vb * p1s[1] + vc * p1s[2]);
|
||||
*x2 = denom * (va * p2s[0] + vb * p2s[1] + vc * p2s[2]);
|
||||
#else
|
||||
float32 u = va * denom;
|
||||
float32 v = vb * denom;
|
||||
float32 w = 1.0f - u - v;
|
||||
*x1 = u * p1s[0] + v * p1s[1] + w * p1s[2];
|
||||
*x2 = u * p2s[0] + v * p2s[1] + w * p2s[2];
|
||||
#endif
|
||||
return 3;
|
||||
}
|
||||
|
||||
static bool InPoints(const b2Vec2& w, const b2Vec2* points, int32 pointCount)
|
||||
{
|
||||
const float32 k_tolerance = 100.0f * B2_FLT_EPSILON;
|
||||
for (int32 i = 0; i < pointCount; ++i)
|
||||
{
|
||||
b2Vec2 d = b2Abs(w - points[i]);
|
||||
b2Vec2 m = b2Max(b2Abs(w), b2Abs(points[i]));
|
||||
|
||||
if (d.x < k_tolerance * (m.x + 1.0f) &&
|
||||
d.y < k_tolerance * (m.y + 1.0f))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
float32 DistanceGeneric(b2Vec2* x1, b2Vec2* x2,
|
||||
const T1* shape1, const b2XForm& xf1,
|
||||
const T2* shape2, const b2XForm& xf2)
|
||||
{
|
||||
b2Vec2 p1s[3], p2s[3];
|
||||
b2Vec2 points[3];
|
||||
int32 pointCount = 0;
|
||||
|
||||
*x1 = shape1->GetFirstVertex(xf1);
|
||||
*x2 = shape2->GetFirstVertex(xf2);
|
||||
|
||||
float32 vSqr = 0.0f;
|
||||
const int32 maxIterations = 20;
|
||||
for (int32 iter = 0; iter < maxIterations; ++iter)
|
||||
{
|
||||
b2Vec2 v = *x2 - *x1;
|
||||
b2Vec2 w1 = shape1->Support(xf1, v);
|
||||
b2Vec2 w2 = shape2->Support(xf2, -v);
|
||||
|
||||
vSqr = b2Dot(v, v);
|
||||
b2Vec2 w = w2 - w1;
|
||||
float32 vw = b2Dot(v, w);
|
||||
if (vSqr - vw <= 0.01f * vSqr || InPoints(w, points, pointCount)) // or w in points
|
||||
{
|
||||
if (pointCount == 0)
|
||||
{
|
||||
*x1 = w1;
|
||||
*x2 = w2;
|
||||
}
|
||||
g_GJK_Iterations = iter;
|
||||
return b2Sqrt(vSqr);
|
||||
}
|
||||
|
||||
switch (pointCount)
|
||||
{
|
||||
case 0:
|
||||
p1s[0] = w1;
|
||||
p2s[0] = w2;
|
||||
points[0] = w;
|
||||
*x1 = p1s[0];
|
||||
*x2 = p2s[0];
|
||||
++pointCount;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
p1s[1] = w1;
|
||||
p2s[1] = w2;
|
||||
points[1] = w;
|
||||
pointCount = ProcessTwo(x1, x2, p1s, p2s, points);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
p1s[2] = w1;
|
||||
p2s[2] = w2;
|
||||
points[2] = w;
|
||||
pointCount = ProcessThree(x1, x2, p1s, p2s, points);
|
||||
break;
|
||||
}
|
||||
|
||||
// If we have three points, then the origin is in the corresponding triangle.
|
||||
if (pointCount == 3)
|
||||
{
|
||||
g_GJK_Iterations = iter;
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float32 maxSqr = -B2_FLT_MAX;
|
||||
for (int32 i = 0; i < pointCount; ++i)
|
||||
{
|
||||
maxSqr = b2Max(maxSqr, b2Dot(points[i], points[i]));
|
||||
}
|
||||
|
||||
#ifdef TARGET_FLOAT32_IS_FIXED
|
||||
if (pointCount == 3 || vSqr <= 5.0*B2_FLT_EPSILON * maxSqr)
|
||||
#else
|
||||
if (pointCount == 3 || vSqr <= 100.0f * B2_FLT_EPSILON * maxSqr)
|
||||
#endif
|
||||
{
|
||||
g_GJK_Iterations = iter;
|
||||
v = *x2 - *x1;
|
||||
vSqr = b2Dot(v, v);
|
||||
return b2Sqrt(vSqr);
|
||||
}
|
||||
}
|
||||
|
||||
g_GJK_Iterations = maxIterations;
|
||||
return b2Sqrt(vSqr);
|
||||
}
|
||||
|
||||
static float32 DistanceCC(
|
||||
b2Vec2* x1, b2Vec2* x2,
|
||||
const b2CircleShape* circle1, const b2XForm& xf1,
|
||||
const b2CircleShape* circle2, const b2XForm& xf2)
|
||||
{
|
||||
b2Vec2 p1 = b2Mul(xf1, circle1->GetLocalPosition());
|
||||
b2Vec2 p2 = b2Mul(xf2, circle2->GetLocalPosition());
|
||||
|
||||
b2Vec2 d = p2 - p1;
|
||||
float32 dSqr = b2Dot(d, d);
|
||||
float32 r1 = circle1->GetRadius() - b2_toiSlop;
|
||||
float32 r2 = circle2->GetRadius() - b2_toiSlop;
|
||||
float32 r = r1 + r2;
|
||||
if (dSqr > r * r)
|
||||
{
|
||||
float32 dLen = d.Normalize();
|
||||
float32 distance = dLen - r;
|
||||
*x1 = p1 + r1 * d;
|
||||
*x2 = p2 - r2 * d;
|
||||
return distance;
|
||||
}
|
||||
else if (dSqr > B2_FLT_EPSILON * B2_FLT_EPSILON)
|
||||
{
|
||||
d.Normalize();
|
||||
*x1 = p1 + r1 * d;
|
||||
*x2 = *x1;
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
*x1 = p1;
|
||||
*x2 = *x1;
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// This is used for polygon-vs-circle distance.
|
||||
struct Point
|
||||
{
|
||||
b2Vec2 Support(const b2XForm&, const b2Vec2&) const
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
b2Vec2 GetFirstVertex(const b2XForm&) const
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
b2Vec2 p;
|
||||
};
|
||||
|
||||
// GJK is more robust with polygon-vs-point than polygon-vs-circle.
|
||||
// So we convert polygon-vs-circle to polygon-vs-point.
|
||||
static float32 DistancePC(
|
||||
b2Vec2* x1, b2Vec2* x2,
|
||||
const b2PolygonShape* polygon, const b2XForm& xf1,
|
||||
const b2CircleShape* circle, const b2XForm& xf2)
|
||||
{
|
||||
Point point;
|
||||
point.p = b2Mul(xf2, circle->GetLocalPosition());
|
||||
|
||||
float32 distance = DistanceGeneric(x1, x2, polygon, xf1, &point, b2XForm_identity);
|
||||
|
||||
float32 r = circle->GetRadius() - b2_toiSlop;
|
||||
|
||||
if (distance > r)
|
||||
{
|
||||
distance -= r;
|
||||
b2Vec2 d = *x2 - *x1;
|
||||
d.Normalize();
|
||||
*x2 -= r * d;
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = 0.0f;
|
||||
*x2 = *x1;
|
||||
}
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
float32 b2Distance(b2Vec2* x1, b2Vec2* x2,
|
||||
const b2Shape* shape1, const b2XForm& xf1,
|
||||
const b2Shape* shape2, const b2XForm& xf2)
|
||||
{
|
||||
b2ShapeType type1 = shape1->GetType();
|
||||
b2ShapeType type2 = shape2->GetType();
|
||||
|
||||
if (type1 == e_circleShape && type2 == e_circleShape)
|
||||
{
|
||||
return DistanceCC(x1, x2, (b2CircleShape*)shape1, xf1, (b2CircleShape*)shape2, xf2);
|
||||
}
|
||||
|
||||
if (type1 == e_polygonShape && type2 == e_circleShape)
|
||||
{
|
||||
return DistancePC(x1, x2, (b2PolygonShape*)shape1, xf1, (b2CircleShape*)shape2, xf2);
|
||||
}
|
||||
|
||||
if (type1 == e_circleShape && type2 == e_polygonShape)
|
||||
{
|
||||
return DistancePC(x2, x1, (b2PolygonShape*)shape2, xf2, (b2CircleShape*)shape1, xf1);
|
||||
}
|
||||
|
||||
if (type1 == e_polygonShape && type2 == e_polygonShape)
|
||||
{
|
||||
return DistanceGeneric(x1, x2, (b2PolygonShape*)shape1, xf1, (b2PolygonShape*)shape2, xf2);
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2PairManager.h"
|
||||
#include "b2BroadPhase.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// Thomas Wang's hash, see: http://www.concentric.net/~Ttwang/tech/inthash.htm
|
||||
// This assumes proxyId1 and proxyId2 are 16-bit.
|
||||
inline uint32 Hash(uint32 proxyId1, uint32 proxyId2)
|
||||
{
|
||||
uint32 key = (proxyId2 << 16) | proxyId1;
|
||||
key = ~key + (key << 15);
|
||||
key = key ^ (key >> 12);
|
||||
key = key + (key << 2);
|
||||
key = key ^ (key >> 4);
|
||||
key = key * 2057;
|
||||
key = key ^ (key >> 16);
|
||||
return key;
|
||||
}
|
||||
|
||||
inline bool Equals(const b2Pair& pair, int32 proxyId1, int32 proxyId2)
|
||||
{
|
||||
return pair.proxyId1 == proxyId1 && pair.proxyId2 == proxyId2;
|
||||
}
|
||||
|
||||
inline bool Equals(const b2BufferedPair& pair1, const b2BufferedPair& pair2)
|
||||
{
|
||||
return pair1.proxyId1 == pair2.proxyId1 && pair1.proxyId2 == pair2.proxyId2;
|
||||
}
|
||||
|
||||
// For sorting.
|
||||
inline bool operator < (const b2BufferedPair& pair1, const b2BufferedPair& pair2)
|
||||
{
|
||||
if (pair1.proxyId1 < pair2.proxyId1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pair1.proxyId1 == pair2.proxyId1)
|
||||
{
|
||||
return pair1.proxyId2 < pair2.proxyId2;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
b2PairManager::b2PairManager()
|
||||
{
|
||||
b2Assert(b2IsPowerOfTwo(b2_tableCapacity) == true);
|
||||
b2Assert(b2_tableCapacity >= b2_maxPairs);
|
||||
for (int32 i = 0; i < b2_tableCapacity; ++i)
|
||||
{
|
||||
m_hashTable[i] = b2_nullPair;
|
||||
}
|
||||
m_freePair = 0;
|
||||
for (int32 i = 0; i < b2_maxPairs; ++i)
|
||||
{
|
||||
m_pairs[i].proxyId1 = b2_nullProxy;
|
||||
m_pairs[i].proxyId2 = b2_nullProxy;
|
||||
m_pairs[i].userData = NULL;
|
||||
m_pairs[i].status = 0;
|
||||
m_pairs[i].next = uint16(i + 1);
|
||||
}
|
||||
m_pairs[b2_maxPairs-1].next = b2_nullPair;
|
||||
m_pairCount = 0;
|
||||
m_pairBufferCount = 0;
|
||||
}
|
||||
|
||||
void b2PairManager::Initialize(b2BroadPhase* broadPhase, b2PairCallback* callback)
|
||||
{
|
||||
m_broadPhase = broadPhase;
|
||||
m_callback = callback;
|
||||
}
|
||||
|
||||
b2Pair* b2PairManager::Find(int32 proxyId1, int32 proxyId2, uint32 hash)
|
||||
{
|
||||
int32 index = m_hashTable[hash];
|
||||
|
||||
while (index != b2_nullPair && Equals(m_pairs[index], proxyId1, proxyId2) == false)
|
||||
{
|
||||
index = m_pairs[index].next;
|
||||
}
|
||||
|
||||
if (index == b2_nullPair)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b2Assert(index < b2_maxPairs);
|
||||
|
||||
return m_pairs + index;
|
||||
}
|
||||
|
||||
b2Pair* b2PairManager::Find(int32 proxyId1, int32 proxyId2)
|
||||
{
|
||||
if (proxyId1 > proxyId2) b2Swap(proxyId1, proxyId2);
|
||||
|
||||
int32 hash = Hash(proxyId1, proxyId2) & b2_tableMask;
|
||||
|
||||
return Find(proxyId1, proxyId2, hash);
|
||||
}
|
||||
|
||||
// Returns existing pair or creates a new one.
|
||||
b2Pair* b2PairManager::AddPair(int32 proxyId1, int32 proxyId2)
|
||||
{
|
||||
if (proxyId1 > proxyId2) b2Swap(proxyId1, proxyId2);
|
||||
|
||||
int32 hash = Hash(proxyId1, proxyId2) & b2_tableMask;
|
||||
|
||||
b2Pair* pair = Find(proxyId1, proxyId2, hash);
|
||||
if (pair != NULL)
|
||||
{
|
||||
return pair;
|
||||
}
|
||||
|
||||
b2Assert(m_pairCount < b2_maxPairs && m_freePair != b2_nullPair);
|
||||
|
||||
uint16 pairIndex = m_freePair;
|
||||
pair = m_pairs + pairIndex;
|
||||
m_freePair = pair->next;
|
||||
|
||||
pair->proxyId1 = (uint16)proxyId1;
|
||||
pair->proxyId2 = (uint16)proxyId2;
|
||||
pair->status = 0;
|
||||
pair->userData = NULL;
|
||||
pair->next = m_hashTable[hash];
|
||||
|
||||
m_hashTable[hash] = pairIndex;
|
||||
|
||||
++m_pairCount;
|
||||
|
||||
return pair;
|
||||
}
|
||||
|
||||
// Removes a pair. The pair must exist.
|
||||
void* b2PairManager::RemovePair(int32 proxyId1, int32 proxyId2)
|
||||
{
|
||||
b2Assert(m_pairCount > 0);
|
||||
|
||||
if (proxyId1 > proxyId2) b2Swap(proxyId1, proxyId2);
|
||||
|
||||
int32 hash = Hash(proxyId1, proxyId2) & b2_tableMask;
|
||||
|
||||
uint16* node = &m_hashTable[hash];
|
||||
while (*node != b2_nullPair)
|
||||
{
|
||||
if (Equals(m_pairs[*node], proxyId1, proxyId2))
|
||||
{
|
||||
uint16 index = *node;
|
||||
*node = m_pairs[*node].next;
|
||||
|
||||
b2Pair* pair = m_pairs + index;
|
||||
void* userData = pair->userData;
|
||||
|
||||
// Scrub
|
||||
pair->next = m_freePair;
|
||||
pair->proxyId1 = b2_nullProxy;
|
||||
pair->proxyId2 = b2_nullProxy;
|
||||
pair->userData = NULL;
|
||||
pair->status = 0;
|
||||
|
||||
m_freePair = index;
|
||||
--m_pairCount;
|
||||
return userData;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = &m_pairs[*node].next;
|
||||
}
|
||||
}
|
||||
|
||||
b2Assert(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
As proxies are created and moved, many pairs are created and destroyed. Even worse, the same
|
||||
pair may be added and removed multiple times in a single time step of the physics engine. To reduce
|
||||
traffic in the pair manager, we try to avoid destroying pairs in the pair manager until the
|
||||
end of the physics step. This is done by buffering all the RemovePair requests. AddPair
|
||||
requests are processed immediately because we need the hash table entry for quick lookup.
|
||||
|
||||
All user user callbacks are delayed until the buffered pairs are confirmed in Commit.
|
||||
This is very important because the user callbacks may be very expensive and client logic
|
||||
may be harmed if pairs are added and removed within the same time step.
|
||||
|
||||
Buffer a pair for addition.
|
||||
We may add a pair that is not in the pair manager or pair buffer.
|
||||
We may add a pair that is already in the pair manager and pair buffer.
|
||||
If the added pair is not a new pair, then it must be in the pair buffer (because RemovePair was called).
|
||||
*/
|
||||
void b2PairManager::AddBufferedPair(int32 id1, int32 id2)
|
||||
{
|
||||
b2Assert(id1 != b2_nullProxy && id2 != b2_nullProxy);
|
||||
b2Assert(m_pairBufferCount < b2_maxPairs);
|
||||
|
||||
b2Pair* pair = AddPair(id1, id2);
|
||||
|
||||
// If this pair is not in the pair buffer ...
|
||||
if (pair->IsBuffered() == false)
|
||||
{
|
||||
// This must be a newly added pair.
|
||||
b2Assert(pair->IsFinal() == false);
|
||||
|
||||
// Add it to the pair buffer.
|
||||
pair->SetBuffered();
|
||||
m_pairBuffer[m_pairBufferCount].proxyId1 = pair->proxyId1;
|
||||
m_pairBuffer[m_pairBufferCount].proxyId2 = pair->proxyId2;
|
||||
++m_pairBufferCount;
|
||||
|
||||
b2Assert(m_pairBufferCount <= m_pairCount);
|
||||
}
|
||||
|
||||
// Confirm this pair for the subsequent call to Commit.
|
||||
pair->ClearRemoved();
|
||||
|
||||
if (b2BroadPhase::s_validate)
|
||||
{
|
||||
ValidateBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
// Buffer a pair for removal.
|
||||
void b2PairManager::RemoveBufferedPair(int32 id1, int32 id2)
|
||||
{
|
||||
b2Assert(id1 != b2_nullProxy && id2 != b2_nullProxy);
|
||||
b2Assert(m_pairBufferCount < b2_maxPairs);
|
||||
|
||||
b2Pair* pair = Find(id1, id2);
|
||||
|
||||
if (pair == NULL)
|
||||
{
|
||||
// The pair never existed. This is legal (due to collision filtering).
|
||||
return;
|
||||
}
|
||||
|
||||
// If this pair is not in the pair buffer ...
|
||||
if (pair->IsBuffered() == false)
|
||||
{
|
||||
// This must be an old pair.
|
||||
b2Assert(pair->IsFinal() == true);
|
||||
|
||||
pair->SetBuffered();
|
||||
m_pairBuffer[m_pairBufferCount].proxyId1 = pair->proxyId1;
|
||||
m_pairBuffer[m_pairBufferCount].proxyId2 = pair->proxyId2;
|
||||
++m_pairBufferCount;
|
||||
|
||||
b2Assert(m_pairBufferCount <= m_pairCount);
|
||||
}
|
||||
|
||||
pair->SetRemoved();
|
||||
|
||||
if (b2BroadPhase::s_validate)
|
||||
{
|
||||
ValidateBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void b2PairManager::Commit()
|
||||
{
|
||||
int32 removeCount = 0;
|
||||
|
||||
b2Proxy* proxies = m_broadPhase->m_proxyPool;
|
||||
|
||||
for (int32 i = 0; i < m_pairBufferCount; ++i)
|
||||
{
|
||||
b2Pair* pair = Find(m_pairBuffer[i].proxyId1, m_pairBuffer[i].proxyId2);
|
||||
b2Assert(pair->IsBuffered());
|
||||
pair->ClearBuffered();
|
||||
|
||||
b2Assert(pair->proxyId1 < b2_maxProxies && pair->proxyId2 < b2_maxProxies);
|
||||
|
||||
b2Proxy* proxy1 = proxies + pair->proxyId1;
|
||||
b2Proxy* proxy2 = proxies + pair->proxyId2;
|
||||
|
||||
b2Assert(proxy1->IsValid());
|
||||
b2Assert(proxy2->IsValid());
|
||||
|
||||
if (pair->IsRemoved())
|
||||
{
|
||||
// It is possible a pair was added then removed before a commit. Therefore,
|
||||
// we should be careful not to tell the user the pair was removed when the
|
||||
// the user didn't receive a matching add.
|
||||
if (pair->IsFinal() == true)
|
||||
{
|
||||
m_callback->PairRemoved(proxy1->userData, proxy2->userData, pair->userData);
|
||||
}
|
||||
|
||||
// Store the ids so we can actually remove the pair below.
|
||||
m_pairBuffer[removeCount].proxyId1 = pair->proxyId1;
|
||||
m_pairBuffer[removeCount].proxyId2 = pair->proxyId2;
|
||||
++removeCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
b2Assert(m_broadPhase->TestOverlap(proxy1, proxy2) == true);
|
||||
|
||||
if (pair->IsFinal() == false)
|
||||
{
|
||||
pair->userData = m_callback->PairAdded(proxy1->userData, proxy2->userData);
|
||||
pair->SetFinal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < removeCount; ++i)
|
||||
{
|
||||
RemovePair(m_pairBuffer[i].proxyId1, m_pairBuffer[i].proxyId2);
|
||||
}
|
||||
|
||||
m_pairBufferCount = 0;
|
||||
|
||||
if (b2BroadPhase::s_validate)
|
||||
{
|
||||
ValidateTable();
|
||||
}
|
||||
}
|
||||
|
||||
void b2PairManager::ValidateBuffer()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
b2Assert(m_pairBufferCount <= m_pairCount);
|
||||
|
||||
std::sort(m_pairBuffer, m_pairBuffer + m_pairBufferCount);
|
||||
|
||||
for (int32 i = 0; i < m_pairBufferCount; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
b2Assert(Equals(m_pairBuffer[i], m_pairBuffer[i-1]) == false);
|
||||
}
|
||||
|
||||
b2Pair* pair = Find(m_pairBuffer[i].proxyId1, m_pairBuffer[i].proxyId2);
|
||||
b2Assert(pair->IsBuffered());
|
||||
|
||||
b2Assert(pair->proxyId1 != pair->proxyId2);
|
||||
b2Assert(pair->proxyId1 < b2_maxProxies);
|
||||
b2Assert(pair->proxyId2 < b2_maxProxies);
|
||||
|
||||
b2Proxy* proxy1 = m_broadPhase->m_proxyPool + pair->proxyId1;
|
||||
b2Proxy* proxy2 = m_broadPhase->m_proxyPool + pair->proxyId2;
|
||||
|
||||
b2Assert(proxy1->IsValid() == true);
|
||||
b2Assert(proxy2->IsValid() == true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void b2PairManager::ValidateTable()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
for (int32 i = 0; i < b2_tableCapacity; ++i)
|
||||
{
|
||||
uint16 index = m_hashTable[i];
|
||||
while (index != b2_nullPair)
|
||||
{
|
||||
b2Pair* pair = m_pairs + index;
|
||||
b2Assert(pair->IsBuffered() == false);
|
||||
b2Assert(pair->IsFinal() == true);
|
||||
b2Assert(pair->IsRemoved() == false);
|
||||
|
||||
b2Assert(pair->proxyId1 != pair->proxyId2);
|
||||
b2Assert(pair->proxyId1 < b2_maxProxies);
|
||||
b2Assert(pair->proxyId2 < b2_maxProxies);
|
||||
|
||||
b2Proxy* proxy1 = m_broadPhase->m_proxyPool + pair->proxyId1;
|
||||
b2Proxy* proxy2 = m_broadPhase->m_proxyPool + pair->proxyId2;
|
||||
|
||||
b2Assert(proxy1->IsValid() == true);
|
||||
b2Assert(proxy2->IsValid() == true);
|
||||
|
||||
b2Assert(m_broadPhase->TestOverlap(proxy1, proxy2) == true);
|
||||
|
||||
index = pair->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
// The pair manager is used by the broad-phase to quickly add/remove/find pairs
|
||||
// of overlapping proxies. It is based closely on code provided by Pierre Terdiman.
|
||||
// http://www.codercorner.com/IncrementalSAP.txt
|
||||
|
||||
#ifndef B2_PAIR_MANAGER_H
|
||||
#define B2_PAIR_MANAGER_H
|
||||
|
||||
#include "../Common/b2Settings.h"
|
||||
#include "../Common/b2Math.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
class b2BroadPhase;
|
||||
struct b2Proxy;
|
||||
|
||||
const uint16 b2_nullPair = USHRT_MAX;
|
||||
const uint16 b2_nullProxy = USHRT_MAX;
|
||||
const int32 b2_tableCapacity = b2_maxPairs; // must be a power of two
|
||||
const int32 b2_tableMask = b2_tableCapacity - 1;
|
||||
|
||||
struct b2Pair
|
||||
{
|
||||
enum
|
||||
{
|
||||
e_pairBuffered = 0x0001,
|
||||
e_pairRemoved = 0x0002,
|
||||
e_pairFinal = 0x0004,
|
||||
};
|
||||
|
||||
void SetBuffered() { status |= e_pairBuffered; }
|
||||
void ClearBuffered() { status &= ~e_pairBuffered; }
|
||||
bool IsBuffered() { return (status & e_pairBuffered) == e_pairBuffered; }
|
||||
|
||||
void SetRemoved() { status |= e_pairRemoved; }
|
||||
void ClearRemoved() { status &= ~e_pairRemoved; }
|
||||
bool IsRemoved() { return (status & e_pairRemoved) == e_pairRemoved; }
|
||||
|
||||
void SetFinal() { status |= e_pairFinal; }
|
||||
bool IsFinal() { return (status & e_pairFinal) == e_pairFinal; }
|
||||
|
||||
void* userData;
|
||||
uint16 proxyId1;
|
||||
uint16 proxyId2;
|
||||
uint16 next;
|
||||
uint16 status;
|
||||
};
|
||||
|
||||
struct b2BufferedPair
|
||||
{
|
||||
uint16 proxyId1;
|
||||
uint16 proxyId2;
|
||||
};
|
||||
|
||||
class b2PairCallback
|
||||
{
|
||||
public:
|
||||
virtual ~b2PairCallback() {}
|
||||
|
||||
// This should return the new pair user data. It is ok if the
|
||||
// user data is null.
|
||||
virtual void* PairAdded(void* proxyUserData1, void* proxyUserData2) = 0;
|
||||
|
||||
// This should free the pair's user data. In extreme circumstances, it is possible
|
||||
// this will be called with null pairUserData because the pair never existed.
|
||||
virtual void PairRemoved(void* proxyUserData1, void* proxyUserData2, void* pairUserData) = 0;
|
||||
};
|
||||
|
||||
class b2PairManager
|
||||
{
|
||||
public:
|
||||
b2PairManager();
|
||||
|
||||
void Initialize(b2BroadPhase* broadPhase, b2PairCallback* callback);
|
||||
|
||||
void AddBufferedPair(int32 proxyId1, int32 proxyId2);
|
||||
void RemoveBufferedPair(int32 proxyId1, int32 proxyId2);
|
||||
|
||||
void Commit();
|
||||
|
||||
private:
|
||||
b2Pair* Find(int32 proxyId1, int32 proxyId2);
|
||||
b2Pair* Find(int32 proxyId1, int32 proxyId2, uint32 hashValue);
|
||||
|
||||
b2Pair* AddPair(int32 proxyId1, int32 proxyId2);
|
||||
void* RemovePair(int32 proxyId1, int32 proxyId2);
|
||||
|
||||
void ValidateBuffer();
|
||||
void ValidateTable();
|
||||
|
||||
public:
|
||||
b2BroadPhase *m_broadPhase;
|
||||
b2PairCallback *m_callback;
|
||||
b2Pair m_pairs[b2_maxPairs];
|
||||
uint16 m_freePair;
|
||||
int32 m_pairCount;
|
||||
|
||||
b2BufferedPair m_pairBuffer[b2_maxPairs];
|
||||
int32 m_pairBufferCount;
|
||||
|
||||
uint16 m_hashTable[b2_tableCapacity];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2Collision.h"
|
||||
#include "Shapes/b2Shape.h"
|
||||
|
||||
// This algorithm uses conservative advancement to compute the time of
|
||||
// impact (TOI) of two shapes.
|
||||
// Refs: Bullet, Young Kim
|
||||
float32 b2TimeOfImpact(const b2Shape* shape1, const b2Sweep& sweep1,
|
||||
const b2Shape* shape2, const b2Sweep& sweep2)
|
||||
{
|
||||
float32 r1 = shape1->GetSweepRadius();
|
||||
float32 r2 = shape2->GetSweepRadius();
|
||||
|
||||
b2Assert(sweep1.t0 == sweep2.t0);
|
||||
b2Assert(1.0f - sweep1.t0 > B2_FLT_EPSILON);
|
||||
|
||||
float32 t0 = sweep1.t0;
|
||||
b2Vec2 v1 = sweep1.c - sweep1.c0;
|
||||
b2Vec2 v2 = sweep2.c - sweep2.c0;
|
||||
float32 omega1 = sweep1.a - sweep1.a0;
|
||||
float32 omega2 = sweep2.a - sweep2.a0;
|
||||
|
||||
float32 alpha = 0.0f;
|
||||
|
||||
b2Vec2 p1, p2;
|
||||
const int32 k_maxIterations = 20; // TODO_ERIN b2Settings
|
||||
int32 iter = 0;
|
||||
b2Vec2 normal = b2Vec2_zero;
|
||||
float32 distance = 0.0f;
|
||||
float32 targetDistance = 0.0f;
|
||||
for(;;)
|
||||
{
|
||||
float32 t = (1.0f - alpha) * t0 + alpha;
|
||||
b2XForm xf1, xf2;
|
||||
sweep1.GetXForm(&xf1, t);
|
||||
sweep2.GetXForm(&xf2, t);
|
||||
|
||||
// Get the distance between shapes.
|
||||
distance = b2Distance(&p1, &p2, shape1, xf1, shape2, xf2);
|
||||
|
||||
if (iter == 0)
|
||||
{
|
||||
// Compute a reasonable target distance to give some breathing room
|
||||
// for conservative advancement.
|
||||
if (distance > 2.0f * b2_toiSlop)
|
||||
{
|
||||
targetDistance = 1.5f * b2_toiSlop;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetDistance = b2Max(0.05f * b2_toiSlop, distance - 0.5f * b2_toiSlop);
|
||||
}
|
||||
}
|
||||
|
||||
if (distance - targetDistance < 0.05f * b2_toiSlop || iter == k_maxIterations)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
normal = p2 - p1;
|
||||
normal.Normalize();
|
||||
|
||||
// Compute upper bound on remaining movement.
|
||||
float32 approachVelocityBound = b2Dot(normal, v1 - v2) + b2Abs(omega1) * r1 + b2Abs(omega2) * r2;
|
||||
if (b2Abs(approachVelocityBound) < B2_FLT_EPSILON)
|
||||
{
|
||||
alpha = 1.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the conservative time increment. Don't advance all the way.
|
||||
float32 dAlpha = (distance - targetDistance) / approachVelocityBound;
|
||||
//float32 dt = (distance - 0.5f * b2_linearSlop) / approachVelocityBound;
|
||||
float32 newAlpha = alpha + dAlpha;
|
||||
|
||||
// The shapes may be moving apart or a safe distance apart.
|
||||
if (newAlpha < 0.0f || 1.0f < newAlpha)
|
||||
{
|
||||
alpha = 1.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
// Ensure significant advancement.
|
||||
if (newAlpha < (1.0f + 100.0f * B2_FLT_EPSILON) * alpha)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
alpha = newAlpha;
|
||||
|
||||
++iter;
|
||||
}
|
||||
|
||||
return alpha;
|
||||
}
|
||||
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
Copyright (c) 2006 Henry Strickland & Ryan Seto
|
||||
2007-2008 Tobias Weyand (modifications and extensions)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
(* http://www.opensource.org/licenses/mit-license.php *)
|
||||
*/
|
||||
|
||||
#ifndef _FIXED_H_
|
||||
#define _FIXED_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef TARGET_IS_NDS
|
||||
|
||||
#include "nds.h"
|
||||
|
||||
#endif
|
||||
|
||||
#define FIXED_BP 16
|
||||
#define FIXED_MAX ((1<<(32-FIXED_BP-1))-1)
|
||||
#define FIXED_MIN (-(1<<(32-FIXED_BP-1)))
|
||||
#define FIXED_EPSILON (Fixed(0.00007f))
|
||||
|
||||
#define G_1_DIV_PI 20861
|
||||
|
||||
class Fixed {
|
||||
|
||||
private:
|
||||
|
||||
int g; // the guts
|
||||
|
||||
const static int BP= FIXED_BP; // how many low bits are right of Binary Point
|
||||
const static int BP2= BP*2; // how many low bits are right of Binary Point
|
||||
const static int BPhalf= BP/2; // how many low bits are right of Binary Point
|
||||
|
||||
double STEP(); // smallest step we can represent
|
||||
|
||||
// for private construction via guts
|
||||
enum FixedRaw { RAW };
|
||||
Fixed(FixedRaw, int guts);
|
||||
|
||||
public:
|
||||
|
||||
Fixed();
|
||||
Fixed(const Fixed &a);
|
||||
Fixed(float a);
|
||||
Fixed(double a);
|
||||
Fixed(int a);
|
||||
Fixed(long a);
|
||||
|
||||
Fixed& operator =(const Fixed a);
|
||||
Fixed& operator =(float a);
|
||||
Fixed& operator =(double a);
|
||||
Fixed& operator =(int a);
|
||||
Fixed& operator =(long a);
|
||||
|
||||
operator float();
|
||||
operator double();
|
||||
operator int();
|
||||
operator long();
|
||||
operator unsigned short();
|
||||
|
||||
operator float() const;
|
||||
|
||||
Fixed operator +() const;
|
||||
Fixed operator -() const;
|
||||
|
||||
Fixed operator +(const Fixed a) const;
|
||||
Fixed operator -(const Fixed a) const;
|
||||
#if 1
|
||||
// more acurate, using long long
|
||||
Fixed operator *(const Fixed a) const;
|
||||
#else
|
||||
// faster, but with only half as many bits right of binary point
|
||||
Fixed operator *(const Fixed a) const;
|
||||
#endif
|
||||
Fixed operator /(const Fixed a) const;
|
||||
|
||||
Fixed operator *(unsigned short a) const;
|
||||
Fixed operator *(int a) const;
|
||||
|
||||
Fixed operator +(float a) const;
|
||||
Fixed operator -(float a) const;
|
||||
Fixed operator *(float a) const;
|
||||
Fixed operator /(float a) const;
|
||||
|
||||
Fixed operator +(double a) const;
|
||||
Fixed operator -(double a) const;
|
||||
Fixed operator *(double a) const;
|
||||
Fixed operator /(double a) const;
|
||||
|
||||
Fixed operator >>(int a) const;
|
||||
Fixed operator <<(int a) const;
|
||||
|
||||
Fixed& operator +=(Fixed a);
|
||||
Fixed& operator -=(Fixed a);
|
||||
Fixed& operator *=(Fixed a);
|
||||
Fixed& operator /=(Fixed a);
|
||||
|
||||
Fixed& operator +=(int a);
|
||||
Fixed& operator -=(int a);
|
||||
Fixed& operator *=(int a);
|
||||
Fixed& operator /=(int a);
|
||||
|
||||
Fixed& operator +=(long a);
|
||||
Fixed& operator -=(long a);
|
||||
Fixed& operator *=(long a);
|
||||
Fixed& operator /=(long a);
|
||||
|
||||
Fixed& operator +=(float a);
|
||||
Fixed& operator -=(float a);
|
||||
Fixed& operator *=(float a);
|
||||
Fixed& operator /=(float a);
|
||||
|
||||
Fixed& operator +=(double a);
|
||||
Fixed& operator -=(double a);
|
||||
Fixed& operator *=(double a);
|
||||
Fixed& operator /=(double a);
|
||||
|
||||
bool operator ==(const Fixed a) const;
|
||||
bool operator !=(const Fixed a) const;
|
||||
bool operator <=(const Fixed a) const;
|
||||
bool operator >=(const Fixed a) const;
|
||||
bool operator <(const Fixed a) const;
|
||||
bool operator >(const Fixed a) const;
|
||||
|
||||
bool operator ==(float a) const;
|
||||
bool operator !=(float a) const;
|
||||
bool operator <=(float a) const;
|
||||
bool operator >=(float a) const;
|
||||
bool operator <(float a) const;
|
||||
bool operator >(float a) const;
|
||||
|
||||
bool operator ==(double a) const;
|
||||
bool operator !=(double a) const;
|
||||
bool operator <=(double a) const;
|
||||
bool operator >=(double a) const;
|
||||
bool operator <(double a) const;
|
||||
bool operator >(double a) const;
|
||||
|
||||
bool operator >(int a) const;
|
||||
bool operator <(int a) const;
|
||||
bool operator >=(int a) const;
|
||||
bool operator <=(int a) const;
|
||||
|
||||
Fixed abs();
|
||||
Fixed sqrt();
|
||||
#ifdef TARGET_IS_NDS
|
||||
Fixed cosf();
|
||||
Fixed sinf();
|
||||
Fixed tanf();
|
||||
#endif
|
||||
};
|
||||
|
||||
//
|
||||
// Implementation
|
||||
//
|
||||
|
||||
inline double Fixed::STEP() { return 1.0 / (1<<BP); } // smallest step we can represent
|
||||
|
||||
// for private construction via guts
|
||||
inline Fixed::Fixed(FixedRaw, int guts) : g(guts) {}
|
||||
|
||||
inline Fixed::Fixed() : g(0) {}
|
||||
inline Fixed::Fixed(const Fixed &a) : g( a.g ) {}
|
||||
inline Fixed::Fixed(float a) : g( int(a * (float)(1<<BP)) ) {}
|
||||
inline Fixed::Fixed(double a) : g( int(a * (double)(1<<BP) ) ) {}
|
||||
inline Fixed::Fixed(int a) : g( a << BP ) {}
|
||||
inline Fixed::Fixed(long a) : g( a << BP ) {}
|
||||
|
||||
inline Fixed& Fixed::operator =(const Fixed a) { g= a.g; return *this; }
|
||||
inline Fixed& Fixed::operator =(float a) { g= Fixed(a).g; return *this; }
|
||||
inline Fixed& Fixed::operator =(double a) { g= Fixed(a).g; return *this; }
|
||||
inline Fixed& Fixed::operator =(int a) { g= Fixed(a).g; return *this; }
|
||||
inline Fixed& Fixed::operator =(long a) { g= Fixed(a).g; return *this; }
|
||||
|
||||
inline Fixed::operator float() { return g * (float)STEP(); }
|
||||
inline Fixed::operator double() { return g * (double)STEP(); }
|
||||
inline Fixed::operator int() { return g>>BP; }
|
||||
inline Fixed::operator long() { return g>>BP; }
|
||||
//#pragma warning(disable: 4244) //HARDWIRE added pragma to prevent VS2005 compilation error
|
||||
inline Fixed::operator unsigned short() { return g>>BP; }
|
||||
inline Fixed::operator float() const { return g / (float)(1<<BP); }
|
||||
|
||||
inline Fixed Fixed::operator +() const { return Fixed(RAW,g); }
|
||||
inline Fixed Fixed::operator -() const { return Fixed(RAW,-g); }
|
||||
|
||||
inline Fixed Fixed::operator +(const Fixed a) const { return Fixed(RAW, g + a.g); }
|
||||
inline Fixed Fixed::operator -(const Fixed a) const { return Fixed(RAW, g - a.g); }
|
||||
|
||||
#if 1
|
||||
// more acurate, using long long
|
||||
inline Fixed Fixed::operator *(const Fixed a) const { return Fixed(RAW, (int)( ((long long)g * (long long)a.g ) >> BP)); }
|
||||
|
||||
#elif 0
|
||||
|
||||
// check for overflow and figure out where. Must specify -rdynamic in linker
|
||||
#include <execinfo.h>
|
||||
#include <signal.h>
|
||||
#include <exception>
|
||||
|
||||
inline Fixed Fixed::operator *(const Fixed a) const {
|
||||
long long x = ((long long)g * (long long)a.g );
|
||||
if(x > 0x7fffffffffffLL || x < -0x7fffffffffffLL) {
|
||||
printf("overflow");
|
||||
void *array[2];
|
||||
int nSize = backtrace(array, 2);
|
||||
char **symbols = backtrace_symbols(array, nSize);
|
||||
for(int i=0; i<nSize; i++) {
|
||||
printf(" %s", symbols[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
return Fixed(RAW, (int)(x>>BP));
|
||||
}
|
||||
|
||||
#else
|
||||
// faster, but with only half as many bits right of binary point
|
||||
inline Fixed Fixed::operator *(const Fixed a) const { return Fixed(RAW, (g>>BPhalf) * (a.g>>BPhalf) ); }
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef TARGET_IS_NDS
|
||||
// Division using the DS's maths coprocessor
|
||||
inline Fixed Fixed::operator /(const Fixed a) const
|
||||
{
|
||||
//printf("%d %d\n", (long long)g << BP, a.g);
|
||||
return Fixed(RAW, int( div64((long long)g << BP, a.g) ) );
|
||||
}
|
||||
#else
|
||||
inline Fixed Fixed::operator /(const Fixed a) const
|
||||
{
|
||||
return Fixed(RAW, int( (((long long)g << BP2) / (long long)(a.g)) >> BP) );
|
||||
//return Fixed(RAW, int( (((long long)g << BP) / (long long)(a.g)) ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline Fixed Fixed::operator *(unsigned short a) const { return operator*(Fixed(a)); }
|
||||
inline Fixed Fixed::operator *(int a) const { return operator*(Fixed(a)); }
|
||||
|
||||
inline Fixed Fixed::operator +(float a) const { return Fixed(RAW, g + Fixed(a).g); }
|
||||
inline Fixed Fixed::operator -(float a) const { return Fixed(RAW, g - Fixed(a).g); }
|
||||
inline Fixed Fixed::operator *(float a) const { return Fixed(RAW, (g>>BPhalf) * (Fixed(a).g>>BPhalf) ); }
|
||||
//inline Fixed Fixed::operator /(float a) const { return Fixed(RAW, int( (((long long)g << BP2) / (long long)(Fixed(a).g)) >> BP) ); }
|
||||
inline Fixed Fixed::operator /(float a) const { return operator/(Fixed(a)); }
|
||||
|
||||
inline Fixed Fixed::operator +(double a) const { return Fixed(RAW, g + Fixed(a).g); }
|
||||
inline Fixed Fixed::operator -(double a) const { return Fixed(RAW, g - Fixed(a).g); }
|
||||
inline Fixed Fixed::operator *(double a) const { return Fixed(RAW, (g>>BPhalf) * (Fixed(a).g>>BPhalf) ); }
|
||||
//inline Fixed Fixed::operator /(double a) const { return Fixed(RAW, int( (((long long)g << BP2) / (long long)(Fixed(a).g)) >> BP) ); }
|
||||
inline Fixed Fixed::operator /(double a) const { return operator/(Fixed(a)); }
|
||||
|
||||
inline Fixed Fixed::operator >>(int a) const { return Fixed(RAW, g >> a); }
|
||||
inline Fixed Fixed::operator <<(int a) const { return Fixed(RAW, g << a); }
|
||||
|
||||
inline Fixed& Fixed::operator +=(Fixed a) { return *this = *this + a; }
|
||||
inline Fixed& Fixed::operator -=(Fixed a) { return *this = *this - a; }
|
||||
inline Fixed& Fixed::operator *=(Fixed a) { return *this = *this * a; }
|
||||
//inline Fixed& Fixed::operator /=(Fixed a) { return *this = *this / a; }
|
||||
inline Fixed& Fixed::operator /=(Fixed a) { return *this = operator/(a); }
|
||||
|
||||
inline Fixed& Fixed::operator +=(int a) { return *this = *this + (Fixed)a; }
|
||||
inline Fixed& Fixed::operator -=(int a) { return *this = *this - (Fixed)a; }
|
||||
inline Fixed& Fixed::operator *=(int a) { return *this = *this * (Fixed)a; }
|
||||
//inline Fixed& Fixed::operator /=(int a) { return *this = *this / (Fixed)a; }
|
||||
inline Fixed& Fixed::operator /=(int a) { return *this = operator/((Fixed)a); }
|
||||
|
||||
inline Fixed& Fixed::operator +=(long a) { return *this = *this + (Fixed)a; }
|
||||
inline Fixed& Fixed::operator -=(long a) { return *this = *this - (Fixed)a; }
|
||||
inline Fixed& Fixed::operator *=(long a) { return *this = *this * (Fixed)a; }
|
||||
//inline Fixed& Fixed::operator /=(long a) { return *this = *this / (Fixed)a; }
|
||||
inline Fixed& Fixed::operator /=(long a) { return *this = operator/((Fixed)a); }
|
||||
|
||||
inline Fixed& Fixed::operator +=(float a) { return *this = *this + a; }
|
||||
inline Fixed& Fixed::operator -=(float a) { return *this = *this - a; }
|
||||
inline Fixed& Fixed::operator *=(float a) { return *this = *this * a; }
|
||||
//inline Fixed& Fixed::operator /=(float a) { return *this = *this / a; }
|
||||
inline Fixed& Fixed::operator /=(float a) { return *this = operator/(a); }
|
||||
|
||||
inline Fixed& Fixed::operator +=(double a) { return *this = *this + a; }
|
||||
inline Fixed& Fixed::operator -=(double a) { return *this = *this - a; }
|
||||
inline Fixed& Fixed::operator *=(double a) { return *this = *this * a; }
|
||||
//inline Fixed& Fixed::operator /=(double a) { return *this = *this / a; }
|
||||
inline Fixed& Fixed::operator /=(double a) { return *this = operator/(a); }
|
||||
|
||||
inline Fixed operator +(int a, const Fixed b) { return Fixed(a)+b; }
|
||||
inline Fixed operator -(int a, const Fixed b) { return Fixed(a)-b; }
|
||||
inline Fixed operator *(int a, const Fixed b) { return Fixed(a)*b; }
|
||||
inline Fixed operator /(int a, const Fixed b) { return Fixed(a)/b; };
|
||||
|
||||
inline Fixed operator +(float a, const Fixed b) { return Fixed(a)+b; }
|
||||
inline Fixed operator -(float a, const Fixed b) { return Fixed(a)-b; }
|
||||
inline Fixed operator *(float a, const Fixed b) { return Fixed(a)*b; }
|
||||
inline Fixed operator /(float a, const Fixed b) { return Fixed(a)/b; }
|
||||
|
||||
inline bool Fixed::operator ==(const Fixed a) const { return g == a.g; }
|
||||
inline bool Fixed::operator !=(const Fixed a) const { return g != a.g; }
|
||||
inline bool Fixed::operator <=(const Fixed a) const { return g <= a.g; }
|
||||
inline bool Fixed::operator >=(const Fixed a) const { return g >= a.g; }
|
||||
inline bool Fixed::operator <(const Fixed a) const { return g < a.g; }
|
||||
inline bool Fixed::operator >(const Fixed a) const { return g > a.g; }
|
||||
|
||||
inline bool Fixed::operator ==(float a) const { return g == Fixed(a).g; }
|
||||
inline bool Fixed::operator !=(float a) const { return g != Fixed(a).g; }
|
||||
inline bool Fixed::operator <=(float a) const { return g <= Fixed(a).g; }
|
||||
inline bool Fixed::operator >=(float a) const { return g >= Fixed(a).g; }
|
||||
inline bool Fixed::operator <(float a) const { return g < Fixed(a).g; }
|
||||
inline bool Fixed::operator >(float a) const { return g > Fixed(a).g; }
|
||||
|
||||
inline bool Fixed::operator ==(double a) const { return g == Fixed(a).g; }
|
||||
inline bool Fixed::operator !=(double a) const { return g != Fixed(a).g; }
|
||||
inline bool Fixed::operator <=(double a) const { return g <= Fixed(a).g; }
|
||||
inline bool Fixed::operator >=(double a) const { return g >= Fixed(a).g; }
|
||||
inline bool Fixed::operator <(double a) const { return g < Fixed(a).g; }
|
||||
inline bool Fixed::operator >(double a) const { return g > Fixed(a).g; }
|
||||
|
||||
inline bool Fixed::operator >(int a) const { return g > Fixed(a).g; }
|
||||
inline bool Fixed::operator <(int a) const { return g < Fixed(a).g; }
|
||||
inline bool Fixed::operator >=(int a) const{ return g >= Fixed(a).g; };
|
||||
inline bool Fixed::operator <=(int a) const{ return g <= Fixed(a).g; };
|
||||
|
||||
inline bool operator ==(float a, const Fixed b) { return Fixed(a) == b; }
|
||||
inline bool operator !=(float a, const Fixed b) { return Fixed(a) != b; }
|
||||
inline bool operator <=(float a, const Fixed b) { return Fixed(a) <= b; }
|
||||
inline bool operator >=(float a, const Fixed b) { return Fixed(a) >= b; }
|
||||
inline bool operator <(float a, const Fixed b) { return Fixed(a) < b; }
|
||||
inline bool operator >(float a, const Fixed b) { return Fixed(a) > b; }
|
||||
|
||||
inline Fixed operator +(double a, const Fixed b) { return Fixed(a)+b; }
|
||||
inline Fixed operator -(double a, const Fixed b) { return Fixed(a)-b; }
|
||||
inline Fixed operator *(double a, const Fixed b) { return Fixed(a)*b; }
|
||||
inline Fixed operator /(double a, const Fixed b) { return Fixed(a)/b; }
|
||||
|
||||
inline bool operator ==(double a, const Fixed b) { return Fixed(a) == b; }
|
||||
inline bool operator !=(double a, const Fixed b) { return Fixed(a) != b; }
|
||||
inline bool operator <=(double a, const Fixed b) { return Fixed(a) <= b; }
|
||||
inline bool operator >=(double a, const Fixed b) { return Fixed(a) >= b; }
|
||||
inline bool operator <(double a, const Fixed b) { return Fixed(a) < b; }
|
||||
inline bool operator >(double a, const Fixed b) { return Fixed(a) > b; }
|
||||
|
||||
inline bool operator ==(int a, const Fixed b) { return Fixed(a) == b; }
|
||||
inline bool operator !=(int a, const Fixed b) { return Fixed(a) != b; }
|
||||
inline bool operator <=(int a, const Fixed b) { return Fixed(a) <= b; }
|
||||
inline bool operator >=(int a, const Fixed b) { return Fixed(a) >= b; }
|
||||
inline bool operator <(int a, const Fixed b) { return Fixed(a) < b; }
|
||||
inline bool operator >(int a, const Fixed b) { return Fixed(a) > b; }
|
||||
|
||||
inline int& operator +=(int& a, const Fixed b) { a = (Fixed)a + b; return a; }
|
||||
inline int& operator -=(int& a, const Fixed b) { a = (Fixed)a - b; return a; }
|
||||
inline int& operator *=(int& a, const Fixed b) { a = (Fixed)a * b; return a; }
|
||||
inline int& operator /=(int& a, const Fixed b) { a = (Fixed)a / b; return a; }
|
||||
|
||||
inline long& operator +=(long& a, const Fixed b) { a = (Fixed)a + b; return a; }
|
||||
inline long& operator -=(long& a, const Fixed b) { a = (Fixed)a - b; return a; }
|
||||
inline long& operator *=(long& a, const Fixed b) { a = (Fixed)a * b; return a; }
|
||||
inline long& operator /=(long& a, const Fixed b) { a = (Fixed)a / b; return a; }
|
||||
|
||||
inline float& operator +=(float& a, const Fixed b) { a = a + b; return a; }
|
||||
inline float& operator -=(float& a, const Fixed b) { a = a - b; return a; }
|
||||
inline float& operator *=(float& a, const Fixed b) { a = a * b; return a; }
|
||||
inline float& operator /=(float& a, const Fixed b) { a = a / b; return a; }
|
||||
|
||||
inline double& operator +=(double& a, const Fixed b) { a = a + b; return a; }
|
||||
inline double& operator -=(double& a, const Fixed b) { a = a - b; return a; }
|
||||
inline double& operator *=(double& a, const Fixed b) { a = a * b; return a; }
|
||||
inline double& operator /=(double& a, const Fixed b) { a = a / b; return a; }
|
||||
|
||||
inline Fixed Fixed::abs() { return (g>0) ? Fixed(RAW, g) : Fixed(RAW, -g); }
|
||||
inline Fixed abs(Fixed f) { return f.abs(); }
|
||||
|
||||
//inline Fixed atan2(Fixed a, Fixed b) { return atan2f((float) a, (float) b); }
|
||||
inline Fixed atan2(Fixed y, Fixed x)
|
||||
{
|
||||
Fixed abs_y = y.abs() + FIXED_EPSILON; // avoid 0/0
|
||||
Fixed r, angle;
|
||||
|
||||
if(x >= 0.0f) {
|
||||
r = (x - abs_y) / (x + abs_y);
|
||||
angle = 3.1415926/4.0;
|
||||
} else {
|
||||
r = (x + abs_y) / (abs_y - x);
|
||||
angle = 3.0*3.1415926/4.0;
|
||||
}
|
||||
angle += Fixed(0.1963) * (r * r * r) - Fixed(0.9817) * r;
|
||||
return (y < 0) ? -angle : angle;
|
||||
}
|
||||
|
||||
#if TARGET_IS_NDS
|
||||
|
||||
static inline long nds_sqrt64(long long a)
|
||||
{
|
||||
SQRT_CR = SQRT_64;
|
||||
while(SQRT_CR & SQRT_BUSY);
|
||||
SQRT_PARAM64 = a;
|
||||
while(SQRT_CR & SQRT_BUSY);
|
||||
|
||||
return SQRT_RESULT32;
|
||||
}
|
||||
|
||||
static inline int32 div6464(int64 num, int64 den)
|
||||
{
|
||||
DIV_CR = DIV_64_64;
|
||||
while(DIV_CR & DIV_BUSY);
|
||||
DIV_NUMERATOR64 = num;
|
||||
DIV_DENOMINATOR64 = den;
|
||||
while(DIV_CR & DIV_BUSY);
|
||||
|
||||
return (DIV_RESULT32);
|
||||
}
|
||||
|
||||
inline Fixed Fixed::sqrt()
|
||||
{
|
||||
return Fixed(RAW, nds_sqrt64(((long long)(g))<<BP));
|
||||
}
|
||||
#else
|
||||
inline Fixed Fixed::sqrt()
|
||||
{
|
||||
long long m, root = 0, left = (long long)g<<FIXED_BP;
|
||||
for ( m = (long long)1<<( (sizeof(long long)<<3) - 2); m; m >>= 2 )
|
||||
{
|
||||
if ( ( left & -m ) > root )
|
||||
left -= ( root += m ), root += m;
|
||||
root >>= 1;
|
||||
}
|
||||
return Fixed(RAW, root);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline Fixed sqrt(Fixed a) { return a.sqrt(); }
|
||||
inline Fixed sqrtf(Fixed a) { return a.sqrt(); }
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_IS_NDS
|
||||
// Use the libnds lookup tables for trigonometry functions
|
||||
inline Fixed Fixed::cosf() {
|
||||
int idx = (((long long)g*(long long)G_1_DIV_PI)>>24)%512;
|
||||
if(idx < 0)
|
||||
idx += 512;
|
||||
return Fixed(RAW, COS_bin[idx] << 4);
|
||||
}
|
||||
inline Fixed cosf(Fixed x) { return x.cosf(); }
|
||||
inline Fixed Fixed::sinf() {
|
||||
int idx = (((long long)g*(long long)G_1_DIV_PI)>>24)%512;
|
||||
if(idx < 0)
|
||||
idx += 512;
|
||||
return Fixed(RAW, SIN_bin[idx] << 4);
|
||||
}
|
||||
inline Fixed sinf(Fixed x) { return x.sinf(); }
|
||||
inline Fixed Fixed::tanf() {
|
||||
int idx = (((long long)g*(long long)G_1_DIV_PI)>>24)%512;
|
||||
if(idx < 0)
|
||||
idx += 512;
|
||||
return Fixed(RAW, TAN_bin[idx] << 4);
|
||||
}
|
||||
inline Fixed tanf(Fixed x) { return x.tanf(); }
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2BlockAllocator.h"
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <climits>
|
||||
#include <string.h>
|
||||
|
||||
int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] =
|
||||
{
|
||||
16, // 0
|
||||
32, // 1
|
||||
64, // 2
|
||||
96, // 3
|
||||
128, // 4
|
||||
160, // 5
|
||||
192, // 6
|
||||
224, // 7
|
||||
256, // 8
|
||||
320, // 9
|
||||
384, // 10
|
||||
448, // 11
|
||||
512, // 12
|
||||
640, // 13
|
||||
};
|
||||
uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1];
|
||||
bool b2BlockAllocator::s_blockSizeLookupInitialized;
|
||||
|
||||
struct b2Chunk
|
||||
{
|
||||
int32 blockSize;
|
||||
b2Block* blocks;
|
||||
};
|
||||
|
||||
struct b2Block
|
||||
{
|
||||
b2Block* next;
|
||||
};
|
||||
|
||||
b2BlockAllocator::b2BlockAllocator()
|
||||
{
|
||||
b2Assert(b2_blockSizes < UCHAR_MAX);
|
||||
|
||||
m_chunkSpace = b2_chunkArrayIncrement;
|
||||
m_chunkCount = 0;
|
||||
m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
|
||||
|
||||
memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
|
||||
memset(m_freeLists, 0, sizeof(m_freeLists));
|
||||
|
||||
if (s_blockSizeLookupInitialized == false)
|
||||
{
|
||||
int32 j = 0;
|
||||
for (int32 i = 1; i <= b2_maxBlockSize; ++i)
|
||||
{
|
||||
b2Assert(j < b2_blockSizes);
|
||||
if (i <= s_blockSizes[j])
|
||||
{
|
||||
s_blockSizeLookup[i] = (uint8)j;
|
||||
}
|
||||
else
|
||||
{
|
||||
++j;
|
||||
s_blockSizeLookup[i] = (uint8)j;
|
||||
}
|
||||
}
|
||||
|
||||
s_blockSizeLookupInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
b2BlockAllocator::~b2BlockAllocator()
|
||||
{
|
||||
for (int32 i = 0; i < m_chunkCount; ++i)
|
||||
{
|
||||
b2Free(m_chunks[i].blocks);
|
||||
}
|
||||
|
||||
b2Free(m_chunks);
|
||||
}
|
||||
|
||||
void* b2BlockAllocator::Allocate(int32 size)
|
||||
{
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
b2Assert(0 < size && size <= b2_maxBlockSize);
|
||||
|
||||
int32 index = s_blockSizeLookup[size];
|
||||
b2Assert(0 <= index && index < b2_blockSizes);
|
||||
|
||||
if (m_freeLists[index])
|
||||
{
|
||||
b2Block* block = m_freeLists[index];
|
||||
m_freeLists[index] = block->next;
|
||||
return block;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_chunkCount == m_chunkSpace)
|
||||
{
|
||||
b2Chunk* oldChunks = m_chunks;
|
||||
m_chunkSpace += b2_chunkArrayIncrement;
|
||||
m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
|
||||
memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk));
|
||||
memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk));
|
||||
b2Free(oldChunks);
|
||||
}
|
||||
|
||||
b2Chunk* chunk = m_chunks + m_chunkCount;
|
||||
chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize);
|
||||
#if defined(_DEBUG)
|
||||
memset(chunk->blocks, 0xcd, b2_chunkSize);
|
||||
#endif
|
||||
int32 blockSize = s_blockSizes[index];
|
||||
chunk->blockSize = blockSize;
|
||||
int32 blockCount = b2_chunkSize / blockSize;
|
||||
b2Assert(blockCount * blockSize <= b2_chunkSize);
|
||||
for (int32 i = 0; i < blockCount - 1; ++i)
|
||||
{
|
||||
b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i);
|
||||
b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1));
|
||||
block->next = next;
|
||||
}
|
||||
b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1));
|
||||
last->next = NULL;
|
||||
|
||||
m_freeLists[index] = chunk->blocks->next;
|
||||
++m_chunkCount;
|
||||
|
||||
return chunk->blocks;
|
||||
}
|
||||
}
|
||||
|
||||
void b2BlockAllocator::Free(void* p, int32 size)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
b2Assert(0 < size && size <= b2_maxBlockSize);
|
||||
|
||||
int32 index = s_blockSizeLookup[size];
|
||||
b2Assert(0 <= index && index < b2_blockSizes);
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Verify the memory address and size is valid.
|
||||
int32 blockSize = s_blockSizes[index];
|
||||
bool found = false;
|
||||
int32 gap = (int32)((int8*)&m_chunks->blocks - (int8*)m_chunks);
|
||||
for (int32 i = 0; i < m_chunkCount; ++i)
|
||||
{
|
||||
b2Chunk* chunk = m_chunks + i;
|
||||
if (chunk->blockSize != blockSize)
|
||||
{
|
||||
b2Assert( (int8*)p + blockSize <= (int8*)chunk->blocks ||
|
||||
(int8*)chunk->blocks + b2_chunkSize + gap <= (int8*)p);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b2Assert(found);
|
||||
|
||||
memset(p, 0xfd, blockSize);
|
||||
#endif
|
||||
|
||||
b2Block* block = (b2Block*)p;
|
||||
block->next = m_freeLists[index];
|
||||
m_freeLists[index] = block;
|
||||
}
|
||||
|
||||
void b2BlockAllocator::Clear()
|
||||
{
|
||||
for (int32 i = 0; i < m_chunkCount; ++i)
|
||||
{
|
||||
b2Free(m_chunks[i].blocks);
|
||||
}
|
||||
|
||||
m_chunkCount = 0;
|
||||
memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
|
||||
|
||||
memset(m_freeLists, 0, sizeof(m_freeLists));
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_BLOCK_ALLOCATOR_H
|
||||
#define B2_BLOCK_ALLOCATOR_H
|
||||
|
||||
#include "b2Settings.h"
|
||||
|
||||
const int32 b2_chunkSize = 4096;
|
||||
const int32 b2_maxBlockSize = 640;
|
||||
const int32 b2_blockSizes = 14;
|
||||
const int32 b2_chunkArrayIncrement = 128;
|
||||
|
||||
struct b2Block;
|
||||
struct b2Chunk;
|
||||
|
||||
// This is a small object allocator used for allocating small
|
||||
// objects that persist for more than one time step.
|
||||
// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp
|
||||
class b2BlockAllocator
|
||||
{
|
||||
public:
|
||||
b2BlockAllocator();
|
||||
~b2BlockAllocator();
|
||||
|
||||
void* Allocate(int32 size);
|
||||
void Free(void* p, int32 size);
|
||||
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
|
||||
b2Chunk* m_chunks;
|
||||
int32 m_chunkCount;
|
||||
int32 m_chunkSpace;
|
||||
|
||||
b2Block* m_freeLists[b2_blockSizes];
|
||||
|
||||
static int32 s_blockSizes[b2_blockSizes];
|
||||
static uint8 s_blockSizeLookup[b2_maxBlockSize + 1];
|
||||
static bool s_blockSizeLookupInitialized;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2Math.h"
|
||||
|
||||
const b2Vec2 b2Vec2_zero(0.0f, 0.0f);
|
||||
const b2Mat22 b2Mat22_identity(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
const b2XForm b2XForm_identity(b2Vec2_zero, b2Mat22_identity);
|
||||
|
||||
void b2Sweep::GetXForm(b2XForm* xf, float32 t) const
|
||||
{
|
||||
// center = p + R * localCenter
|
||||
if (1.0f - t0 > B2_FLT_EPSILON)
|
||||
{
|
||||
float32 alpha = (t - t0) / (1.0f - t0);
|
||||
xf->position = (1.0f - alpha) * c0 + alpha * c;
|
||||
float32 angle = (1.0f - alpha) * a0 + alpha * a;
|
||||
xf->R.Set(angle);
|
||||
}
|
||||
else
|
||||
{
|
||||
xf->position = c;
|
||||
xf->R.Set(a);
|
||||
}
|
||||
|
||||
// Shift to origin
|
||||
xf->position -= b2Mul(xf->R, localCenter);
|
||||
}
|
||||
|
||||
void b2Sweep::Advance(float32 t)
|
||||
{
|
||||
if (t0 < t && 1.0f - t0 > B2_FLT_EPSILON)
|
||||
{
|
||||
float32 alpha = (t - t0) / (1.0f - t0);
|
||||
c0 = (1.0f - alpha) * c0 + alpha * c;
|
||||
a0 = (1.0f - alpha) * a0 + alpha * a;
|
||||
t0 = t;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,636 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_MATH_H
|
||||
#define B2_MATH_H
|
||||
|
||||
#include "b2Settings.h"
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef TARGET_FLOAT32_IS_FIXED
|
||||
|
||||
inline Fixed b2Min(const Fixed& a, const Fixed& b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
inline Fixed b2Max(const Fixed& a, const Fixed& b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
inline Fixed b2Clamp(Fixed a, Fixed low, Fixed high)
|
||||
{
|
||||
return b2Max(low, b2Min(a, high));
|
||||
}
|
||||
|
||||
inline bool b2IsValid(Fixed x)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#define b2Sqrt(x) sqrt(x)
|
||||
#define b2Atan2(y, x) atan2(y, x)
|
||||
|
||||
#else
|
||||
|
||||
/// This function is used to ensure that a floating point number is
|
||||
/// not a NaN or infinity.
|
||||
inline bool b2IsValid(float32 x)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _finite(x) != 0;
|
||||
#else
|
||||
return finite(x) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// This is a approximate yet fast inverse square-root.
|
||||
inline float32 b2InvSqrt(float32 x)
|
||||
{
|
||||
union
|
||||
{
|
||||
float32 x;
|
||||
int32 i;
|
||||
} convert;
|
||||
|
||||
convert.x = x;
|
||||
float32 xhalf = 0.5f * x;
|
||||
convert.i = 0x5f3759df - (convert.i >> 1);
|
||||
x = convert.x;
|
||||
x = x * (1.5f - xhalf * x * x);
|
||||
return x;
|
||||
}
|
||||
|
||||
#define b2Sqrt(x) sqrtf(x)
|
||||
#define b2Atan2(y, x) atan2f(y, x)
|
||||
|
||||
#endif
|
||||
|
||||
inline float32 b2Abs(float32 a)
|
||||
{
|
||||
return a > 0.0f ? a : -a;
|
||||
}
|
||||
|
||||
/// A 2D column vector.
|
||||
|
||||
struct b2Vec2
|
||||
{
|
||||
/// Default constructor does nothing (for performance).
|
||||
b2Vec2() {}
|
||||
|
||||
/// Construct using coordinates.
|
||||
b2Vec2(float32 x, float32 y) : x(x), y(y) {}
|
||||
|
||||
/// Set this vector to all zeros.
|
||||
void SetZero() { x = 0.0f; y = 0.0f; }
|
||||
|
||||
/// Set this vector to some specified coordinates.
|
||||
void Set(float32 x_, float32 y_) { x = x_; y = y_; }
|
||||
|
||||
/// Negate this vector.
|
||||
b2Vec2 operator -() const { b2Vec2 v; v.Set(-x, -y); return v; }
|
||||
|
||||
/// Add a vector to this vector.
|
||||
void operator += (const b2Vec2& v)
|
||||
{
|
||||
x += v.x; y += v.y;
|
||||
}
|
||||
|
||||
/// Subtract a vector from this vector.
|
||||
void operator -= (const b2Vec2& v)
|
||||
{
|
||||
x -= v.x; y -= v.y;
|
||||
}
|
||||
|
||||
/// Multiply this vector by a scalar.
|
||||
void operator *= (float32 a)
|
||||
{
|
||||
x *= a; y *= a;
|
||||
}
|
||||
|
||||
/// Get the length of this vector (the norm).
|
||||
float32 Length() const
|
||||
{
|
||||
#ifdef TARGET_FLOAT32_IS_FIXED
|
||||
float est = b2Abs(x) + b2Abs(y);
|
||||
if(est == 0.0f) {
|
||||
return 0.0;
|
||||
} else if(est < 0.1) {
|
||||
return (1.0/256.0) * b2Vec2(x<<8, y<<8).Length();
|
||||
} else if(est < 180.0f) {
|
||||
return b2Sqrt(x * x + y * y);
|
||||
} else {
|
||||
return 256.0 * (b2Vec2(x>>8, y>>8).Length());
|
||||
}
|
||||
#else
|
||||
return b2Sqrt(x * x + y * y);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Get the length squared. For performance, use this instead of
|
||||
/// b2Vec2::Length (if possible).
|
||||
float32 LengthSquared() const
|
||||
{
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
/// Convert this vector into a unit vector. Returns the length.
|
||||
#ifdef TARGET_FLOAT32_IS_FIXED
|
||||
float32 Normalize()
|
||||
{
|
||||
float32 length = Length();
|
||||
if (length < B2_FLT_EPSILON)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
#ifdef NORMALIZE_BY_INVERT_MULTIPLY
|
||||
if (length < (1.0/16.0)) {
|
||||
x = x << 4;
|
||||
y = y << 4;
|
||||
return (1.0/16.0)*Normalize();
|
||||
} else if(length > 16.0) {
|
||||
x = x >> 4;
|
||||
y = y >> 4;
|
||||
return 16.0*Normalize();
|
||||
}
|
||||
float32 invLength = 1.0f / length;
|
||||
x *= invLength;
|
||||
y *= invLength;
|
||||
#else
|
||||
x /= length;
|
||||
y /= length;
|
||||
#endif
|
||||
return length;
|
||||
}
|
||||
#else
|
||||
float32 Normalize()
|
||||
{
|
||||
float32 length = Length();
|
||||
if (length < B2_FLT_EPSILON)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
float32 invLength = 1.0f / length;
|
||||
x *= invLength;
|
||||
y *= invLength;
|
||||
|
||||
return length;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Does this vector contain finite coordinates?
|
||||
bool IsValid() const
|
||||
{
|
||||
return b2IsValid(x) && b2IsValid(y);
|
||||
}
|
||||
|
||||
float32 x, y;
|
||||
};
|
||||
|
||||
/// A 2-by-2 matrix. Stored in column-major order.
|
||||
struct b2Mat22
|
||||
{
|
||||
/// The default constructor does nothing (for performance).
|
||||
b2Mat22() {}
|
||||
|
||||
/// Construct this matrix using columns.
|
||||
b2Mat22(const b2Vec2& c1, const b2Vec2& c2)
|
||||
{
|
||||
col1 = c1;
|
||||
col2 = c2;
|
||||
}
|
||||
|
||||
/// Construct this matrix using scalars.
|
||||
b2Mat22(float32 a11, float32 a12, float32 a21, float32 a22)
|
||||
{
|
||||
col1.x = a11; col1.y = a21;
|
||||
col2.x = a12; col2.y = a22;
|
||||
}
|
||||
|
||||
/// Construct this matrix using an angle. This matrix becomes
|
||||
/// an orthonormal rotation matrix.
|
||||
explicit b2Mat22(float32 angle)
|
||||
{
|
||||
float32 c = cosf(angle), s = sinf(angle);
|
||||
col1.x = c; col2.x = -s;
|
||||
col1.y = s; col2.y = c;
|
||||
}
|
||||
|
||||
/// Initialize this matrix using columns.
|
||||
void Set(const b2Vec2& c1, const b2Vec2& c2)
|
||||
{
|
||||
col1 = c1;
|
||||
col2 = c2;
|
||||
}
|
||||
|
||||
/// Initialize this matrix using an angle. This matrix becomes
|
||||
/// an orthonormal rotation matrix.
|
||||
void Set(float32 angle)
|
||||
{
|
||||
float32 c = cosf(angle), s = sinf(angle);
|
||||
col1.x = c; col2.x = -s;
|
||||
col1.y = s; col2.y = c;
|
||||
}
|
||||
|
||||
/// Set this to the identity matrix.
|
||||
void SetIdentity()
|
||||
{
|
||||
col1.x = 1.0f; col2.x = 0.0f;
|
||||
col1.y = 0.0f; col2.y = 1.0f;
|
||||
}
|
||||
|
||||
/// Set this matrix to all zeros.
|
||||
void SetZero()
|
||||
{
|
||||
col1.x = 0.0f; col2.x = 0.0f;
|
||||
col1.y = 0.0f; col2.y = 0.0f;
|
||||
}
|
||||
|
||||
/// Extract the angle from this matrix (assumed to be
|
||||
/// a rotation matrix).
|
||||
float32 GetAngle() const
|
||||
{
|
||||
return b2Atan2(col1.y, col1.x);
|
||||
}
|
||||
|
||||
#ifdef TARGET_FLOAT32_IS_FIXED
|
||||
|
||||
/// Compute the inverse of this matrix, such that inv(A) * A = identity.
|
||||
b2Mat22 Invert() const
|
||||
{
|
||||
float32 a = col1.x, b = col2.x, c = col1.y, d = col2.y;
|
||||
float32 det = a * d - b * c;
|
||||
b2Mat22 B;
|
||||
int n = 0;
|
||||
|
||||
if(b2Abs(det) <= (B2_FLT_EPSILON<<8))
|
||||
{
|
||||
n = 3;
|
||||
a = a<<n; b = b<<n;
|
||||
c = c<<n; d = d<<n;
|
||||
det = a * d - b * c;
|
||||
b2Assert(det != 0.0f);
|
||||
det = float32(1) / det;
|
||||
B.col1.x = ( det * d) << n; B.col2.x = (-det * b) << n;
|
||||
B.col1.y = (-det * c) << n; B.col2.y = ( det * a) << n;
|
||||
}
|
||||
else
|
||||
{
|
||||
n = (b2Abs(det) >= 16.0)? 4 : 0;
|
||||
b2Assert(det != 0.0f);
|
||||
det = float32(1<<n) / det;
|
||||
B.col1.x = ( det * d) >> n; B.col2.x = (-det * b) >> n;
|
||||
B.col1.y = (-det * c) >> n; B.col2.y = ( det * a) >> n;
|
||||
}
|
||||
|
||||
return B;
|
||||
}
|
||||
|
||||
// Solve A * x = b
|
||||
b2Vec2 Solve(const b2Vec2& b) const
|
||||
{
|
||||
float32 a11 = col1.x, a12 = col2.x, a21 = col1.y, a22 = col2.y;
|
||||
float32 det = a11 * a22 - a12 * a21;
|
||||
int n = 0;
|
||||
b2Vec2 x;
|
||||
|
||||
|
||||
if(b2Abs(det) <= (B2_FLT_EPSILON<<8))
|
||||
{
|
||||
n = 3;
|
||||
a11 = col1.x<<n; a12 = col2.x<<n;
|
||||
a21 = col1.y<<n; a22 = col2.y<<n;
|
||||
det = a11 * a22 - a12 * a21;
|
||||
b2Assert(det != 0.0f);
|
||||
det = float32(1) / det;
|
||||
x.x = (det * (a22 * b.x - a12 * b.y)) << n;
|
||||
x.y = (det * (a11 * b.y - a21 * b.x)) << n;
|
||||
}
|
||||
else
|
||||
{
|
||||
n = (b2Abs(det) >= 16.0) ? 4 : 0;
|
||||
b2Assert(det != 0.0f);
|
||||
det = float32(1<<n) / det;
|
||||
x.x = (det * (a22 * b.x - a12 * b.y)) >> n;
|
||||
x.y = (det * (a11 * b.y - a21 * b.x)) >> n;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
#else
|
||||
b2Mat22 Invert() const
|
||||
{
|
||||
float32 a = col1.x, b = col2.x, c = col1.y, d = col2.y;
|
||||
b2Mat22 B;
|
||||
float32 det = a * d - b * c;
|
||||
b2Assert(det != 0.0f);
|
||||
det = float32(1.0f) / det;
|
||||
B.col1.x = det * d; B.col2.x = -det * b;
|
||||
B.col1.y = -det * c; B.col2.y = det * a;
|
||||
return B;
|
||||
}
|
||||
|
||||
/// Solve A * x = b, where b is a column vector. This is more efficient
|
||||
/// than computing the inverse in one-shot cases.
|
||||
b2Vec2 Solve(const b2Vec2& b) const
|
||||
{
|
||||
float32 a11 = col1.x, a12 = col2.x, a21 = col1.y, a22 = col2.y;
|
||||
float32 det = a11 * a22 - a12 * a21;
|
||||
b2Assert(det != 0.0f);
|
||||
det = 1.0f / det;
|
||||
b2Vec2 x;
|
||||
x.x = det * (a22 * b.x - a12 * b.y);
|
||||
x.y = det * (a11 * b.y - a21 * b.x);
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
|
||||
b2Vec2 col1, col2;
|
||||
};
|
||||
|
||||
/// A transform contains translation and rotation. It is used to represent
|
||||
/// the position and orientation of rigid frames.
|
||||
struct b2XForm
|
||||
{
|
||||
/// The default constructor does nothing (for performance).
|
||||
b2XForm() {}
|
||||
|
||||
/// Initialize using a position vector and a rotation matrix.
|
||||
b2XForm(const b2Vec2& position, const b2Mat22& R) : position(position), R(R) {}
|
||||
|
||||
/// Set this to the identity transform.
|
||||
void SetIdentity()
|
||||
{
|
||||
position.SetZero();
|
||||
R.SetIdentity();
|
||||
}
|
||||
|
||||
b2Vec2 position;
|
||||
b2Mat22 R;
|
||||
};
|
||||
|
||||
/// This describes the motion of a body/shape for TOI computation.
|
||||
/// Shapes are defined with respect to the body origin, which may
|
||||
/// no coincide with the center of mass. However, to support dynamics
|
||||
/// we must interpolate the center of mass position.
|
||||
struct b2Sweep
|
||||
{
|
||||
/// Get the interpolated transform at a specific time.
|
||||
/// @param t the normalized time in [0,1].
|
||||
void GetXForm(b2XForm* xf, float32 t) const;
|
||||
|
||||
/// Advance the sweep forward, yielding a new initial state.
|
||||
/// @param t the new initial time.
|
||||
void Advance(float32 t);
|
||||
|
||||
b2Vec2 localCenter; ///< local center of mass position
|
||||
b2Vec2 c0, c; ///< center world positions
|
||||
float32 a0, a; ///< world angles
|
||||
float32 t0; ///< time interval = [t0,1], where t0 is in [0,1]
|
||||
};
|
||||
|
||||
|
||||
extern const b2Vec2 b2Vec2_zero;
|
||||
extern const b2Mat22 b2Mat22_identity;
|
||||
extern const b2XForm b2XForm_identity;
|
||||
|
||||
/// Peform the dot product on two vectors.
|
||||
inline float32 b2Dot(const b2Vec2& a, const b2Vec2& b)
|
||||
{
|
||||
return a.x * b.x + a.y * b.y;
|
||||
}
|
||||
|
||||
/// Perform the cross product on two vectors. In 2D this produces a scalar.
|
||||
inline float32 b2Cross(const b2Vec2& a, const b2Vec2& b)
|
||||
{
|
||||
return a.x * b.y - a.y * b.x;
|
||||
}
|
||||
|
||||
/// Perform the cross product on a vector and a scalar. In 2D this produces
|
||||
/// a vector.
|
||||
inline b2Vec2 b2Cross(const b2Vec2& a, float32 s)
|
||||
{
|
||||
b2Vec2 v; v.Set(s * a.y, -s * a.x);
|
||||
return v;
|
||||
}
|
||||
|
||||
/// Perform the cross product on a scalar and a vector. In 2D this produces
|
||||
/// a vector.
|
||||
inline b2Vec2 b2Cross(float32 s, const b2Vec2& a)
|
||||
{
|
||||
b2Vec2 v; v.Set(-s * a.y, s * a.x);
|
||||
return v;
|
||||
}
|
||||
|
||||
/// Multiply a matrix times a vector. If a rotation matrix is provided,
|
||||
/// then this transforms the vector from one frame to another.
|
||||
inline b2Vec2 b2Mul(const b2Mat22& A, const b2Vec2& v)
|
||||
{
|
||||
b2Vec2 u;
|
||||
u.Set(A.col1.x * v.x + A.col2.x * v.y, A.col1.y * v.x + A.col2.y * v.y);
|
||||
return u;
|
||||
}
|
||||
|
||||
/// Multiply a matrix transpose times a vector. If a rotation matrix is provided,
|
||||
/// then this transforms the vector from one frame to another (inverse transform).
|
||||
inline b2Vec2 b2MulT(const b2Mat22& A, const b2Vec2& v)
|
||||
{
|
||||
b2Vec2 u;
|
||||
u.Set(b2Dot(v, A.col1), b2Dot(v, A.col2));
|
||||
return u;
|
||||
}
|
||||
|
||||
/// Add two vectors component-wise.
|
||||
inline b2Vec2 operator + (const b2Vec2& a, const b2Vec2& b)
|
||||
{
|
||||
b2Vec2 v; v.Set(a.x + b.x, a.y + b.y);
|
||||
return v;
|
||||
}
|
||||
|
||||
/// Subtract two vectors component-wise.
|
||||
inline b2Vec2 operator - (const b2Vec2& a, const b2Vec2& b)
|
||||
{
|
||||
b2Vec2 v; v.Set(a.x - b.x, a.y - b.y);
|
||||
return v;
|
||||
}
|
||||
|
||||
inline b2Vec2 operator * (float32 s, const b2Vec2& a)
|
||||
{
|
||||
b2Vec2 v; v.Set(s * a.x, s * a.y);
|
||||
return v;
|
||||
}
|
||||
|
||||
inline bool operator == (const b2Vec2& a, const b2Vec2& b)
|
||||
{
|
||||
return a.x == b.x && a.y == b.y;
|
||||
}
|
||||
|
||||
inline float32 b2Distance(const b2Vec2& a, const b2Vec2& b)
|
||||
{
|
||||
b2Vec2 c = a - b;
|
||||
return c.Length();
|
||||
}
|
||||
|
||||
inline float32 b2DistanceSquared(const b2Vec2& a, const b2Vec2& b)
|
||||
{
|
||||
b2Vec2 c = a - b;
|
||||
return b2Dot(c, c);
|
||||
}
|
||||
|
||||
inline b2Mat22 operator + (const b2Mat22& A, const b2Mat22& B)
|
||||
{
|
||||
b2Mat22 C;
|
||||
C.Set(A.col1 + B.col1, A.col2 + B.col2);
|
||||
return C;
|
||||
}
|
||||
|
||||
// A * B
|
||||
inline b2Mat22 b2Mul(const b2Mat22& A, const b2Mat22& B)
|
||||
{
|
||||
b2Mat22 C;
|
||||
C.Set(b2Mul(A, B.col1), b2Mul(A, B.col2));
|
||||
return C;
|
||||
}
|
||||
|
||||
// A^T * B
|
||||
inline b2Mat22 b2MulT(const b2Mat22& A, const b2Mat22& B)
|
||||
{
|
||||
b2Vec2 c1; c1.Set(b2Dot(A.col1, B.col1), b2Dot(A.col2, B.col1));
|
||||
b2Vec2 c2; c2.Set(b2Dot(A.col1, B.col2), b2Dot(A.col2, B.col2));
|
||||
b2Mat22 C;
|
||||
C.Set(c1, c2);
|
||||
return C;
|
||||
}
|
||||
|
||||
inline b2Vec2 b2Mul(const b2XForm& T, const b2Vec2& v)
|
||||
{
|
||||
return T.position + b2Mul(T.R, v);
|
||||
}
|
||||
|
||||
inline b2Vec2 b2MulT(const b2XForm& T, const b2Vec2& v)
|
||||
{
|
||||
return b2MulT(T.R, v - T.position);
|
||||
}
|
||||
|
||||
inline b2Vec2 b2Abs(const b2Vec2& a)
|
||||
{
|
||||
b2Vec2 b; b.Set(b2Abs(a.x), b2Abs(a.y));
|
||||
return b;
|
||||
}
|
||||
|
||||
inline b2Mat22 b2Abs(const b2Mat22& A)
|
||||
{
|
||||
b2Mat22 B;
|
||||
B.Set(b2Abs(A.col1), b2Abs(A.col2));
|
||||
return B;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T b2Min(T a, T b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
inline b2Vec2 b2Min(const b2Vec2& a, const b2Vec2& b)
|
||||
{
|
||||
b2Vec2 c;
|
||||
c.x = b2Min(a.x, b.x);
|
||||
c.y = b2Min(a.y, b.y);
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T b2Max(T a, T b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
inline b2Vec2 b2Max(const b2Vec2& a, const b2Vec2& b)
|
||||
{
|
||||
b2Vec2 c;
|
||||
c.x = b2Max(a.x, b.x);
|
||||
c.y = b2Max(a.y, b.y);
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T b2Clamp(T a, T low, T high)
|
||||
{
|
||||
return b2Max(low, b2Min(a, high));
|
||||
}
|
||||
|
||||
inline b2Vec2 b2Clamp(const b2Vec2& a, const b2Vec2& low, const b2Vec2& high)
|
||||
{
|
||||
return b2Max(low, b2Min(a, high));
|
||||
}
|
||||
|
||||
template<typename T> inline void b2Swap(T& a, T& b)
|
||||
{
|
||||
T tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
#define RAND_LIMIT 32767
|
||||
|
||||
// Random number in range [-1,1]
|
||||
inline float32 b2Random()
|
||||
{
|
||||
float32 r = (float32)(rand() & (RAND_LIMIT));
|
||||
r /= RAND_LIMIT;
|
||||
r = 2.0f * r - 1.0f;
|
||||
return r;
|
||||
}
|
||||
|
||||
/// Random floating point number in range [lo, hi]
|
||||
inline float32 b2Random(float32 lo, float32 hi)
|
||||
{
|
||||
float32 r = (float32)(rand() & (RAND_LIMIT));
|
||||
r /= RAND_LIMIT;
|
||||
r = (hi - lo) * r + lo;
|
||||
return r;
|
||||
}
|
||||
|
||||
/// "Next Largest Power of 2
|
||||
/// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm
|
||||
/// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with
|
||||
/// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next
|
||||
/// largest power of 2. For a 32-bit value:"
|
||||
inline uint32 b2NextPowerOfTwo(uint32 x)
|
||||
{
|
||||
x |= (x >> 1);
|
||||
x |= (x >> 2);
|
||||
x |= (x >> 4);
|
||||
x |= (x >> 8);
|
||||
x |= (x >> 16);
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
inline bool b2IsPowerOfTwo(uint32 x)
|
||||
{
|
||||
bool result = x > 0 && (x & (x - 1)) == 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2Settings.h"
|
||||
#include <cstdlib>
|
||||
|
||||
b2Version b2_version = {2, 0, 1};
|
||||
|
||||
int32 b2_byteCount = 0;
|
||||
|
||||
|
||||
|
||||
// Memory allocators. Modify these to use your own allocator.
|
||||
void* b2Alloc(int32 size)
|
||||
{
|
||||
size += 4;
|
||||
b2_byteCount += size;
|
||||
char* bytes = (char*)malloc(size);
|
||||
*(int32*)bytes = size;
|
||||
return bytes + 4;
|
||||
}
|
||||
|
||||
void b2Free(void* mem)
|
||||
{
|
||||
if (mem == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char* bytes = (char*)mem;
|
||||
bytes -= 4;
|
||||
int32 size = *(int32*)bytes;
|
||||
b2Assert(b2_byteCount >= size);
|
||||
b2_byteCount -= size;
|
||||
free(bytes);
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_SETTINGS_H
|
||||
#define B2_SETTINGS_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
|
||||
#define B2_NOT_USED(x) x
|
||||
#define b2Assert(A) assert(A)
|
||||
|
||||
|
||||
// need to include NDS jtypes.h instead of
|
||||
// usual typedefs because NDS jtypes defines
|
||||
// them slightly differently, oh well.
|
||||
#ifdef TARGET_IS_NDS
|
||||
|
||||
#include "jtypes.h"
|
||||
|
||||
#else
|
||||
|
||||
typedef signed char int8;
|
||||
typedef signed short int16;
|
||||
typedef signed int int32;
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_FLOAT32_IS_FIXED
|
||||
|
||||
#include "Fixed.h"
|
||||
|
||||
typedef Fixed float32;
|
||||
#define B2_FLT_MAX FIXED_MAX
|
||||
#define B2_FLT_EPSILON FIXED_EPSILON
|
||||
#define B2FORCE_SCALE(x) ((x)<<7)
|
||||
#define B2FORCE_INV_SCALE(x) ((x)>>7)
|
||||
|
||||
#else
|
||||
|
||||
typedef float float32;
|
||||
#define B2_FLT_MAX FLT_MAX
|
||||
#define B2_FLT_EPSILON FLT_EPSILON
|
||||
#define B2FORCE_SCALE(x) (x)
|
||||
#define B2FORCE_INV_SCALE(x) (x)
|
||||
|
||||
#endif
|
||||
|
||||
const float32 b2_pi = 3.14159265359f;
|
||||
|
||||
/// @file
|
||||
/// Global tuning constants based on meters-kilograms-seconds (MKS) units.
|
||||
///
|
||||
|
||||
// Collision
|
||||
const int32 b2_maxManifoldPoints = 2;
|
||||
const int32 b2_maxPolygonVertices = 8;
|
||||
const int32 b2_maxProxies = 2048; // this must be a power of two
|
||||
const int32 b2_maxPairs = 8 * b2_maxProxies; // this must be a power of two
|
||||
|
||||
// Dynamics
|
||||
|
||||
/// A small length used as a collision and constraint tolerance. Usually it is
|
||||
/// chosen to be numerically significant, but visually insignificant.
|
||||
const float32 b2_linearSlop = 0.005f; // 0.5 cm
|
||||
|
||||
/// A small angle used as a collision and constraint tolerance. Usually it is
|
||||
/// chosen to be numerically significant, but visually insignificant.
|
||||
const float32 b2_angularSlop = 2.0f / 180.0f * b2_pi; // 2 degrees
|
||||
|
||||
/// Continuous collision detection (CCD) works with core, shrunken shapes. This is the
|
||||
/// amount by which shapes are automatically shrunk to work with CCD. This must be
|
||||
/// larger than b2_linearSlop.
|
||||
const float32 b2_toiSlop = 8.0f * b2_linearSlop;
|
||||
|
||||
/// Maximum number of contacts to be handled to solve a TOI island.
|
||||
const int32 b2_maxTOIContactsPerIsland = 32;
|
||||
|
||||
/// A velocity threshold for elastic collisions. Any collision with a relative linear
|
||||
/// velocity below this threshold will be treated as inelastic.
|
||||
const float32 b2_velocityThreshold = 1.0f; // 1 m/s
|
||||
|
||||
/// The maximum linear position correction used when solving constraints. This helps to
|
||||
/// prevent overshoot.
|
||||
const float32 b2_maxLinearCorrection = 0.2f; // 20 cm
|
||||
|
||||
/// The maximum angular position correction used when solving constraints. This helps to
|
||||
/// prevent overshoot.
|
||||
const float32 b2_maxAngularCorrection = 8.0f / 180.0f * b2_pi; // 8 degrees
|
||||
|
||||
/// The maximum linear velocity of a body. This limit is very large and is used
|
||||
/// to prevent numerical problems. You shouldn't need to adjust this.
|
||||
#ifdef TARGET_FLOAT32_IS_FIXED
|
||||
const float32 b2_maxLinearVelocity = 100.0f;
|
||||
#else
|
||||
const float32 b2_maxLinearVelocity = 200.0f;
|
||||
const float32 b2_maxLinearVelocitySquared = b2_maxLinearVelocity * b2_maxLinearVelocity;
|
||||
#endif
|
||||
|
||||
/// The maximum angular velocity of a body. This limit is very large and is used
|
||||
/// to prevent numerical problems. You shouldn't need to adjust this.
|
||||
const float32 b2_maxAngularVelocity = 250.0f;
|
||||
#ifndef TARGET_FLOAT32_IS_FIXED
|
||||
const float32 b2_maxAngularVelocitySquared = b2_maxAngularVelocity * b2_maxAngularVelocity;
|
||||
#endif
|
||||
|
||||
/// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so
|
||||
/// that overlap is removed in one time step. However using values close to 1 often lead
|
||||
/// to overshoot.
|
||||
const float32 b2_contactBaumgarte = 0.2f;
|
||||
|
||||
// Sleep
|
||||
|
||||
/// The time that a body must be still before it will go to sleep.
|
||||
const float32 b2_timeToSleep = 0.5f; // half a second
|
||||
|
||||
/// A body cannot sleep if its linear velocity is above this tolerance.
|
||||
const float32 b2_linearSleepTolerance = 0.01f; // 1 cm/s
|
||||
|
||||
/// A body cannot sleep if its angular velocity is above this tolerance.
|
||||
const float32 b2_angularSleepTolerance = 2.0f / 180.0f; // 2 degrees/s
|
||||
|
||||
// Memory Allocation
|
||||
|
||||
/// The current number of bytes allocated through b2Alloc.
|
||||
extern int32 b2_byteCount;
|
||||
|
||||
/// Implement this function to use your own memory allocator.
|
||||
void* b2Alloc(int32 size);
|
||||
|
||||
/// If you implement b2Alloc, you should also implement this function.
|
||||
void b2Free(void* mem);
|
||||
|
||||
/// Version numbering scheme.
|
||||
/// See http://en.wikipedia.org/wiki/Software_versioning
|
||||
struct b2Version
|
||||
{
|
||||
int32 major; ///< significant changes
|
||||
int32 minor; ///< incremental changes
|
||||
int32 revision; ///< bug fixes
|
||||
};
|
||||
|
||||
/// Current version.
|
||||
extern b2Version b2_version;
|
||||
|
||||
/// Friction mixing law. Feel free to customize this.
|
||||
inline float32 b2MixFriction(float32 friction1, float32 friction2)
|
||||
{
|
||||
return sqrtf(friction1 * friction2);
|
||||
}
|
||||
|
||||
/// Restitution mixing law. Feel free to customize this.
|
||||
inline float32 b2MixRestitution(float32 restitution1, float32 restitution2)
|
||||
{
|
||||
return restitution1 > restitution2 ? restitution1 : restitution2;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2StackAllocator.h"
|
||||
#include "b2Math.h"
|
||||
|
||||
b2StackAllocator::b2StackAllocator()
|
||||
{
|
||||
m_index = 0;
|
||||
m_allocation = 0;
|
||||
m_maxAllocation = 0;
|
||||
m_entryCount = 0;
|
||||
}
|
||||
|
||||
b2StackAllocator::~b2StackAllocator()
|
||||
{
|
||||
b2Assert(m_index == 0);
|
||||
b2Assert(m_entryCount == 0);
|
||||
}
|
||||
|
||||
void* b2StackAllocator::Allocate(int32 size)
|
||||
{
|
||||
b2Assert(m_entryCount < b2_maxStackEntries);
|
||||
|
||||
b2StackEntry* entry = m_entries + m_entryCount;
|
||||
entry->size = size;
|
||||
if (m_index + size > b2_stackSize)
|
||||
{
|
||||
entry->data = (char*)b2Alloc(size);
|
||||
entry->usedMalloc = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->data = m_data + m_index;
|
||||
entry->usedMalloc = false;
|
||||
m_index += size;
|
||||
}
|
||||
|
||||
m_allocation += size;
|
||||
m_maxAllocation = b2Max(m_maxAllocation, m_allocation);
|
||||
++m_entryCount;
|
||||
|
||||
return entry->data;
|
||||
}
|
||||
|
||||
void b2StackAllocator::Free(void* p)
|
||||
{
|
||||
b2Assert(m_entryCount > 0);
|
||||
b2StackEntry* entry = m_entries + m_entryCount - 1;
|
||||
b2Assert(p == entry->data);
|
||||
if (entry->usedMalloc)
|
||||
{
|
||||
b2Free(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_index -= entry->size;
|
||||
}
|
||||
m_allocation -= entry->size;
|
||||
--m_entryCount;
|
||||
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
int32 b2StackAllocator::GetMaxAllocation() const
|
||||
{
|
||||
return m_maxAllocation;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_STACK_ALLOCATOR_H
|
||||
#define B2_STACK_ALLOCATOR_H
|
||||
|
||||
#include "b2Settings.h"
|
||||
|
||||
const int32 b2_stackSize = 100 * 1024; // 100k
|
||||
const int32 b2_maxStackEntries = 32;
|
||||
|
||||
struct b2StackEntry
|
||||
{
|
||||
char* data;
|
||||
int32 size;
|
||||
bool usedMalloc;
|
||||
};
|
||||
|
||||
// This is a stack allocator used for fast per step allocations.
|
||||
// You must nest allocate/free pairs. The code will assert
|
||||
// if you try to interleave multiple allocate/free pairs.
|
||||
class b2StackAllocator
|
||||
{
|
||||
public:
|
||||
b2StackAllocator();
|
||||
~b2StackAllocator();
|
||||
|
||||
void* Allocate(int32 size);
|
||||
void Free(void* p);
|
||||
|
||||
int32 GetMaxAllocation() const;
|
||||
|
||||
private:
|
||||
|
||||
char m_data[b2_stackSize];
|
||||
int32 m_index;
|
||||
|
||||
int32 m_allocation;
|
||||
int32 m_maxAllocation;
|
||||
|
||||
b2StackEntry m_entries[b2_maxStackEntries];
|
||||
int32 m_entryCount;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,139 @@
|
||||
/*---------------------------------------------------------------------------------
|
||||
$Id: jtypes.h,v 1.17 2007/07/18 05:20:45 wntrmute Exp $
|
||||
|
||||
jtypes.h -- Common types (and a few useful macros)
|
||||
|
||||
Copyright (C) 2005
|
||||
Michael Noland (joat)
|
||||
Jason Rogers (dovoto)
|
||||
Dave Murphy (WinterMute)
|
||||
Chris Double (doublec)
|
||||
|
||||
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 NDS_JTYPES_INCLUDE
|
||||
#define NDS_JTYPES_INCLUDE
|
||||
//---------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#define PACKED __attribute__ ((packed))
|
||||
#define packed_struct struct PACKED
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// libgba compatible section macros
|
||||
//---------------------------------------------------------------------------------
|
||||
#define ITCM_CODE __attribute__((section(".itcm"), long_call))
|
||||
|
||||
#define DTCM_DATA __attribute__((section(".dtcm")))
|
||||
#define DTCM_BSS __attribute__((section(".sbss")))
|
||||
#define ALIGN(m) __attribute__((aligned (m)))
|
||||
|
||||
#define PACKED __attribute__ ((packed))
|
||||
#define packed_struct struct PACKED
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// These are linked to the bin2o macro in the Makefile
|
||||
//---------------------------------------------------------------------------------
|
||||
#define GETRAW(name) (name)
|
||||
#define GETRAWSIZE(name) ((int)name##_size)
|
||||
#define GETRAWEND(name) ((int)name##_end)
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define BIT(n) (1 << (n))
|
||||
|
||||
// define libnds types in terms of stdint
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
//typedef float float32;
|
||||
typedef double float64;
|
||||
|
||||
typedef volatile uint8_t vuint8;
|
||||
typedef volatile uint16_t vuint16;
|
||||
typedef volatile uint32_t vuint32;
|
||||
typedef volatile uint64_t vuint64;
|
||||
|
||||
typedef volatile int8_t vint8;
|
||||
typedef volatile int16_t vint16;
|
||||
typedef volatile int32_t vint32;
|
||||
typedef volatile int64_t vint64;
|
||||
|
||||
typedef volatile float vfloat32;
|
||||
typedef volatile float64 vfloat64;
|
||||
|
||||
typedef uint8_t byte;
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
|
||||
typedef volatile u8 vu8;
|
||||
typedef volatile u16 vu16;
|
||||
typedef volatile u32 vu32;
|
||||
typedef volatile u64 vu64;
|
||||
|
||||
typedef volatile s8 vs8;
|
||||
typedef volatile s16 vs16;
|
||||
typedef volatile s32 vs32;
|
||||
typedef volatile s64 vs64;
|
||||
|
||||
typedef struct touchPosition {
|
||||
int16 x;
|
||||
int16 y;
|
||||
int16 px;
|
||||
int16 py;
|
||||
int16 z1;
|
||||
int16 z2;
|
||||
} touchPosition;
|
||||
|
||||
|
||||
#ifndef __cplusplus
|
||||
/** C++ compatible bool for C
|
||||
|
||||
*/
|
||||
typedef enum { false, true } bool;
|
||||
#endif
|
||||
|
||||
// Handy function pointer typedefs
|
||||
typedef void ( * IntFn)(void);
|
||||
typedef void (* VoidFunctionPointer)(void);
|
||||
typedef void (* fp)(void);
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
#endif
|
||||
//---------------------------------------------------------------------------------
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2CircleContact.h"
|
||||
#include "../b2Body.h"
|
||||
#include "../b2WorldCallbacks.h"
|
||||
#include "../../Common/b2BlockAllocator.h"
|
||||
|
||||
#include <new>
|
||||
#include <string.h>
|
||||
|
||||
b2Contact* b2CircleContact::Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator)
|
||||
{
|
||||
void* mem = allocator->Allocate(sizeof(b2CircleContact));
|
||||
return new (mem) b2CircleContact(shape1, shape2);
|
||||
}
|
||||
|
||||
void b2CircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
|
||||
{
|
||||
((b2CircleContact*)contact)->~b2CircleContact();
|
||||
allocator->Free(contact, sizeof(b2CircleContact));
|
||||
}
|
||||
|
||||
b2CircleContact::b2CircleContact(b2Shape* s1, b2Shape* s2)
|
||||
: b2Contact(s1, s2)
|
||||
{
|
||||
b2Assert(m_shape1->GetType() == e_circleShape);
|
||||
b2Assert(m_shape2->GetType() == e_circleShape);
|
||||
m_manifold.pointCount = 0;
|
||||
m_manifold.points[0].normalImpulse = 0.0f;
|
||||
m_manifold.points[0].tangentImpulse = 0.0f;
|
||||
}
|
||||
|
||||
void b2CircleContact::Evaluate(b2ContactListener* listener)
|
||||
{
|
||||
b2Body* b1 = m_shape1->GetBody();
|
||||
b2Body* b2 = m_shape2->GetBody();
|
||||
|
||||
b2Manifold m0;
|
||||
memcpy(&m0, &m_manifold, sizeof(b2Manifold));
|
||||
|
||||
b2CollideCircles(&m_manifold, (b2CircleShape*)m_shape1, b1->GetXForm(), (b2CircleShape*)m_shape2, b2->GetXForm());
|
||||
|
||||
b2ContactPoint cp;
|
||||
cp.shape1 = m_shape1;
|
||||
cp.shape2 = m_shape2;
|
||||
cp.friction = m_friction;
|
||||
cp.restitution = m_restitution;
|
||||
|
||||
if (m_manifold.pointCount > 0)
|
||||
{
|
||||
m_manifoldCount = 1;
|
||||
b2ManifoldPoint* mp = m_manifold.points + 0;
|
||||
|
||||
if (m0.pointCount == 0)
|
||||
{
|
||||
mp->normalImpulse = 0.0f;
|
||||
mp->tangentImpulse = 0.0f;
|
||||
|
||||
if (listener)
|
||||
{
|
||||
cp.position = b1->GetWorldPoint(mp->localPoint1);
|
||||
b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1);
|
||||
b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2);
|
||||
cp.velocity = v2 - v1;
|
||||
cp.normal = m_manifold.normal;
|
||||
cp.separation = mp->separation;
|
||||
cp.id = mp->id;
|
||||
listener->Add(&cp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
b2ManifoldPoint* mp0 = m0.points + 0;
|
||||
mp->normalImpulse = mp0->normalImpulse;
|
||||
mp->tangentImpulse = mp0->tangentImpulse;
|
||||
|
||||
if (listener)
|
||||
{
|
||||
cp.position = b1->GetWorldPoint(mp->localPoint1);
|
||||
b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1);
|
||||
b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2);
|
||||
cp.velocity = v2 - v1;
|
||||
cp.normal = m_manifold.normal;
|
||||
cp.separation = mp->separation;
|
||||
cp.id = mp->id;
|
||||
listener->Persist(&cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_manifoldCount = 0;
|
||||
if (m0.pointCount > 0 && listener)
|
||||
{
|
||||
b2ManifoldPoint* mp0 = m0.points + 0;
|
||||
cp.position = b1->GetWorldPoint(mp0->localPoint1);
|
||||
b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp0->localPoint1);
|
||||
b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp0->localPoint2);
|
||||
cp.velocity = v2 - v1;
|
||||
cp.normal = m0.normal;
|
||||
cp.separation = mp0->separation;
|
||||
cp.id = mp0->id;
|
||||
listener->Remove(&cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef CIRCLE_CONTACT_H
|
||||
#define CIRCLE_CONTACT_H
|
||||
|
||||
#include "../../Common/b2Math.h"
|
||||
#include "../../Collision/b2Collision.h"
|
||||
#include "b2Contact.h"
|
||||
|
||||
class b2BlockAllocator;
|
||||
|
||||
class b2CircleContact : public b2Contact
|
||||
{
|
||||
public:
|
||||
static b2Contact* Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator);
|
||||
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
|
||||
|
||||
b2CircleContact(b2Shape* shape1, b2Shape* shape2);
|
||||
~b2CircleContact() {}
|
||||
|
||||
void Evaluate(b2ContactListener* listener);
|
||||
b2Manifold* GetManifolds()
|
||||
{
|
||||
return &m_manifold;
|
||||
}
|
||||
|
||||
b2Manifold m_manifold;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2Contact.h"
|
||||
#include "b2CircleContact.h"
|
||||
#include "b2PolyAndCircleContact.h"
|
||||
#include "b2PolyContact.h"
|
||||
#include "b2ContactSolver.h"
|
||||
#include "../../Collision/b2Collision.h"
|
||||
#include "../../Collision/Shapes/b2Shape.h"
|
||||
#include "../../Common/b2BlockAllocator.h"
|
||||
#include "../../Dynamics/b2World.h"
|
||||
#include "../../Dynamics/b2Body.h"
|
||||
|
||||
b2ContactRegister b2Contact::s_registers[e_shapeTypeCount][e_shapeTypeCount];
|
||||
bool b2Contact::s_initialized = false;
|
||||
|
||||
void b2Contact::InitializeRegisters()
|
||||
{
|
||||
AddType(b2CircleContact::Create, b2CircleContact::Destroy, e_circleShape, e_circleShape);
|
||||
AddType(b2PolyAndCircleContact::Create, b2PolyAndCircleContact::Destroy, e_polygonShape, e_circleShape);
|
||||
AddType(b2PolygonContact::Create, b2PolygonContact::Destroy, e_polygonShape, e_polygonShape);
|
||||
}
|
||||
|
||||
void b2Contact::AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destoryFcn,
|
||||
b2ShapeType type1, b2ShapeType type2)
|
||||
{
|
||||
b2Assert(e_unknownShape < type1 && type1 < e_shapeTypeCount);
|
||||
b2Assert(e_unknownShape < type2 && type2 < e_shapeTypeCount);
|
||||
|
||||
s_registers[type1][type2].createFcn = createFcn;
|
||||
s_registers[type1][type2].destroyFcn = destoryFcn;
|
||||
s_registers[type1][type2].primary = true;
|
||||
|
||||
if (type1 != type2)
|
||||
{
|
||||
s_registers[type2][type1].createFcn = createFcn;
|
||||
s_registers[type2][type1].destroyFcn = destoryFcn;
|
||||
s_registers[type2][type1].primary = false;
|
||||
}
|
||||
}
|
||||
|
||||
b2Contact* b2Contact::Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator)
|
||||
{
|
||||
if (s_initialized == false)
|
||||
{
|
||||
InitializeRegisters();
|
||||
s_initialized = true;
|
||||
}
|
||||
|
||||
b2ShapeType type1 = shape1->GetType();
|
||||
b2ShapeType type2 = shape2->GetType();
|
||||
|
||||
b2Assert(e_unknownShape < type1 && type1 < e_shapeTypeCount);
|
||||
b2Assert(e_unknownShape < type2 && type2 < e_shapeTypeCount);
|
||||
|
||||
b2ContactCreateFcn* createFcn = s_registers[type1][type2].createFcn;
|
||||
if (createFcn)
|
||||
{
|
||||
if (s_registers[type1][type2].primary)
|
||||
{
|
||||
return createFcn(shape1, shape2, allocator);
|
||||
}
|
||||
else
|
||||
{
|
||||
b2Contact* c = createFcn(shape2, shape1, allocator);
|
||||
for (int32 i = 0; i < c->GetManifoldCount(); ++i)
|
||||
{
|
||||
b2Manifold* m = c->GetManifolds() + i;
|
||||
m->normal = -m->normal;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void b2Contact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
|
||||
{
|
||||
b2Assert(s_initialized == true);
|
||||
|
||||
if (contact->GetManifoldCount() > 0)
|
||||
{
|
||||
contact->GetShape1()->GetBody()->WakeUp();
|
||||
contact->GetShape2()->GetBody()->WakeUp();
|
||||
}
|
||||
|
||||
b2ShapeType type1 = contact->GetShape1()->GetType();
|
||||
b2ShapeType type2 = contact->GetShape2()->GetType();
|
||||
|
||||
b2Assert(e_unknownShape < type1 && type1 < e_shapeTypeCount);
|
||||
b2Assert(e_unknownShape < type2 && type2 < e_shapeTypeCount);
|
||||
|
||||
b2ContactDestroyFcn* destroyFcn = s_registers[type1][type2].destroyFcn;
|
||||
destroyFcn(contact, allocator);
|
||||
}
|
||||
|
||||
b2Contact::b2Contact(b2Shape* s1, b2Shape* s2)
|
||||
{
|
||||
m_flags = 0;
|
||||
|
||||
if (s1->IsSensor() || s2->IsSensor())
|
||||
{
|
||||
m_flags |= e_nonSolidFlag;
|
||||
}
|
||||
|
||||
m_shape1 = s1;
|
||||
m_shape2 = s2;
|
||||
|
||||
m_manifoldCount = 0;
|
||||
|
||||
m_friction = b2MixFriction(m_shape1->GetFriction(), m_shape2->GetFriction());
|
||||
m_restitution = b2MixRestitution(m_shape1->GetRestitution(), m_shape2->GetRestitution());
|
||||
m_prev = NULL;
|
||||
m_next = NULL;
|
||||
|
||||
m_node1.contact = NULL;
|
||||
m_node1.prev = NULL;
|
||||
m_node1.next = NULL;
|
||||
m_node1.other = NULL;
|
||||
|
||||
m_node2.contact = NULL;
|
||||
m_node2.prev = NULL;
|
||||
m_node2.next = NULL;
|
||||
m_node2.other = NULL;
|
||||
}
|
||||
|
||||
void b2Contact::Update(b2ContactListener* listener)
|
||||
{
|
||||
int32 oldCount = GetManifoldCount();
|
||||
|
||||
Evaluate(listener);
|
||||
|
||||
int32 newCount = GetManifoldCount();
|
||||
|
||||
b2Body* body1 = m_shape1->GetBody();
|
||||
b2Body* body2 = m_shape2->GetBody();
|
||||
|
||||
if (newCount == 0 && oldCount > 0)
|
||||
{
|
||||
body1->WakeUp();
|
||||
body2->WakeUp();
|
||||
}
|
||||
|
||||
// Slow contacts don't generate TOI events.
|
||||
if (body1->IsStatic() || body1->IsBullet() || body2->IsStatic() || body2->IsBullet())
|
||||
{
|
||||
m_flags &= ~e_slowFlag;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_flags |= e_slowFlag;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef CONTACT_H
|
||||
#define CONTACT_H
|
||||
|
||||
#include "../../Common/b2Math.h"
|
||||
#include "../../Collision/b2Collision.h"
|
||||
#include "../../Collision/Shapes/b2Shape.h"
|
||||
|
||||
class b2Body;
|
||||
class b2Contact;
|
||||
class b2World;
|
||||
class b2BlockAllocator;
|
||||
class b2StackAllocator;
|
||||
class b2ContactListener;
|
||||
|
||||
typedef b2Contact* b2ContactCreateFcn(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator);
|
||||
typedef void b2ContactDestroyFcn(b2Contact* contact, b2BlockAllocator* allocator);
|
||||
|
||||
struct b2ContactRegister
|
||||
{
|
||||
b2ContactCreateFcn* createFcn;
|
||||
b2ContactDestroyFcn* destroyFcn;
|
||||
bool primary;
|
||||
};
|
||||
|
||||
/// A contact edge is used to connect bodies and contacts together
|
||||
/// in a contact graph where each body is a node and each contact
|
||||
/// is an edge. A contact edge belongs to a doubly linked list
|
||||
/// maintained in each attached body. Each contact has two contact
|
||||
/// nodes, one for each attached body.
|
||||
struct b2ContactEdge
|
||||
{
|
||||
b2Body* other; ///< provides quick access to the other body attached.
|
||||
b2Contact* contact; ///< the contact
|
||||
b2ContactEdge* prev; ///< the previous contact edge in the body's contact list
|
||||
b2ContactEdge* next; ///< the next contact edge in the body's contact list
|
||||
};
|
||||
|
||||
/// This structure is used to report contact points.
|
||||
struct b2ContactPoint
|
||||
{
|
||||
b2Shape* shape1; ///< the first shape
|
||||
b2Shape* shape2; ///< the second shape
|
||||
b2Vec2 position; ///< position in world coordinates
|
||||
b2Vec2 velocity; ///< velocity of point on body2 relative to point on body1 (pre-solver)
|
||||
b2Vec2 normal; ///< points from shape1 to shape2
|
||||
float32 separation; ///< the separation is negative when shapes are touching
|
||||
float32 friction; ///< the combined friction coefficient
|
||||
float32 restitution; ///< the combined restitution coefficient
|
||||
b2ContactID id; ///< the contact id identifies the features in contact
|
||||
};
|
||||
|
||||
/// This structure is used to report contact point results.
|
||||
struct b2ContactResult
|
||||
{
|
||||
b2Shape* shape1; ///< the first shape
|
||||
b2Shape* shape2; ///< the second shape
|
||||
b2Vec2 position; ///< position in world coordinates
|
||||
b2Vec2 normal; ///< points from shape1 to shape2
|
||||
float32 normalImpulse; ///< the normal impulse applied to body2
|
||||
float32 tangentImpulse; ///< the tangent impulse applied to body2
|
||||
b2ContactID id; ///< the contact id identifies the features in contact
|
||||
};
|
||||
|
||||
/// The class manages contact between two shapes. A contact exists for each overlapping
|
||||
/// AABB in the broad-phase (except if filtered). Therefore a contact object may exist
|
||||
/// that has no contact points.
|
||||
class b2Contact
|
||||
{
|
||||
public:
|
||||
|
||||
/// Get the manifold array.
|
||||
virtual b2Manifold* GetManifolds() = 0;
|
||||
|
||||
/// Get the number of manifolds. This is 0 or 1 between convex shapes.
|
||||
/// This may be greater than 1 for convex-vs-concave shapes. Each
|
||||
/// manifold holds up to two contact points with a shared contact normal.
|
||||
int32 GetManifoldCount() const;
|
||||
|
||||
/// Is this contact solid?
|
||||
/// @return true if this contact should generate a response.
|
||||
bool IsSolid() const;
|
||||
|
||||
/// Get the next contact in the world's contact list.
|
||||
b2Contact* GetNext();
|
||||
|
||||
/// Get the first shape in this contact.
|
||||
b2Shape* GetShape1();
|
||||
|
||||
/// Get the second shape in this contact.
|
||||
b2Shape* GetShape2();
|
||||
|
||||
//--------------- Internals Below -------------------
|
||||
public:
|
||||
|
||||
// m_flags
|
||||
enum
|
||||
{
|
||||
e_nonSolidFlag = 0x0001,
|
||||
e_slowFlag = 0x0002,
|
||||
e_islandFlag = 0x0004,
|
||||
e_toiFlag = 0x0008,
|
||||
};
|
||||
|
||||
static void AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destroyFcn,
|
||||
b2ShapeType type1, b2ShapeType type2);
|
||||
static void InitializeRegisters();
|
||||
static b2Contact* Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator);
|
||||
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
|
||||
|
||||
b2Contact() : m_shape1(NULL), m_shape2(NULL) {}
|
||||
b2Contact(b2Shape* shape1, b2Shape* shape2);
|
||||
virtual ~b2Contact() {}
|
||||
|
||||
void Update(b2ContactListener* listener);
|
||||
virtual void Evaluate(b2ContactListener* listener) = 0;
|
||||
static b2ContactRegister s_registers[e_shapeTypeCount][e_shapeTypeCount];
|
||||
static bool s_initialized;
|
||||
|
||||
uint32 m_flags;
|
||||
int32 m_manifoldCount;
|
||||
|
||||
// World pool and list pointers.
|
||||
b2Contact* m_prev;
|
||||
b2Contact* m_next;
|
||||
|
||||
// Nodes for connecting bodies.
|
||||
b2ContactEdge m_node1;
|
||||
b2ContactEdge m_node2;
|
||||
|
||||
b2Shape* m_shape1;
|
||||
b2Shape* m_shape2;
|
||||
|
||||
// Combined friction
|
||||
float32 m_friction;
|
||||
float32 m_restitution;
|
||||
|
||||
float32 m_toi;
|
||||
};
|
||||
|
||||
inline int32 b2Contact::GetManifoldCount() const
|
||||
{
|
||||
return m_manifoldCount;
|
||||
}
|
||||
|
||||
inline bool b2Contact::IsSolid() const
|
||||
{
|
||||
return (m_flags & e_nonSolidFlag) == 0;
|
||||
}
|
||||
|
||||
inline b2Contact* b2Contact::GetNext()
|
||||
{
|
||||
return m_next;
|
||||
}
|
||||
|
||||
inline b2Shape* b2Contact::GetShape1()
|
||||
{
|
||||
return m_shape1;
|
||||
}
|
||||
|
||||
inline b2Shape* b2Contact::GetShape2()
|
||||
{
|
||||
return m_shape2;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2ContactSolver.h"
|
||||
#include "b2Contact.h"
|
||||
#include "../b2Body.h"
|
||||
#include "../b2World.h"
|
||||
#include "../../Common/b2StackAllocator.h"
|
||||
|
||||
b2ContactSolver::b2ContactSolver(const b2TimeStep& step, b2Contact** contacts, int32 contactCount, b2StackAllocator* allocator)
|
||||
{
|
||||
m_step = step;
|
||||
m_allocator = allocator;
|
||||
|
||||
m_constraintCount = 0;
|
||||
for (int32 i = 0; i < contactCount; ++i)
|
||||
{
|
||||
b2Assert(contacts[i]->IsSolid());
|
||||
m_constraintCount += contacts[i]->GetManifoldCount();
|
||||
}
|
||||
|
||||
m_constraints = (b2ContactConstraint*)m_allocator->Allocate(m_constraintCount * sizeof(b2ContactConstraint));
|
||||
|
||||
int32 count = 0;
|
||||
for (int32 i = 0; i < contactCount; ++i)
|
||||
{
|
||||
b2Contact* contact = contacts[i];
|
||||
|
||||
b2Body* b1 = contact->m_shape1->GetBody();
|
||||
b2Body* b2 = contact->m_shape2->GetBody();
|
||||
int32 manifoldCount = contact->GetManifoldCount();
|
||||
b2Manifold* manifolds = contact->GetManifolds();
|
||||
float32 friction = contact->m_friction;
|
||||
float32 restitution = contact->m_restitution;
|
||||
|
||||
b2Vec2 v1 = b1->m_linearVelocity;
|
||||
b2Vec2 v2 = b2->m_linearVelocity;
|
||||
float32 w1 = b1->m_angularVelocity;
|
||||
float32 w2 = b2->m_angularVelocity;
|
||||
|
||||
for (int32 j = 0; j < manifoldCount; ++j)
|
||||
{
|
||||
b2Manifold* manifold = manifolds + j;
|
||||
|
||||
b2Assert(manifold->pointCount > 0);
|
||||
|
||||
const b2Vec2 normal = manifold->normal;
|
||||
|
||||
b2Assert(count < m_constraintCount);
|
||||
b2ContactConstraint* c = m_constraints + count;
|
||||
c->body1 = b1;
|
||||
c->body2 = b2;
|
||||
c->manifold = manifold;
|
||||
c->normal = normal;
|
||||
c->pointCount = manifold->pointCount;
|
||||
c->friction = friction;
|
||||
c->restitution = restitution;
|
||||
|
||||
for (int32 k = 0; k < c->pointCount; ++k)
|
||||
{
|
||||
b2ManifoldPoint* cp = manifold->points + k;
|
||||
b2ContactConstraintPoint* ccp = c->points + k;
|
||||
|
||||
ccp->normalImpulse = cp->normalImpulse;
|
||||
ccp->tangentImpulse = cp->tangentImpulse;
|
||||
ccp->separation = cp->separation;
|
||||
ccp->positionImpulse = 0.0f;
|
||||
|
||||
ccp->localAnchor1 = cp->localPoint1;
|
||||
ccp->localAnchor2 = cp->localPoint2;
|
||||
ccp->r1 = b2Mul(b1->GetXForm().R, cp->localPoint1 - b1->GetLocalCenter());
|
||||
ccp->r2 = b2Mul(b2->GetXForm().R, cp->localPoint2 - b2->GetLocalCenter());
|
||||
|
||||
float32 r1Sqr = b2Dot(ccp->r1, ccp->r1);
|
||||
float32 r2Sqr = b2Dot(ccp->r2, ccp->r2);
|
||||
float32 rn1 = b2Dot(ccp->r1, normal);
|
||||
float32 rn2 = b2Dot(ccp->r2, normal);
|
||||
|
||||
float32 kNormal = b1->m_invMass + b2->m_invMass;
|
||||
kNormal += b1->m_invI * (r1Sqr - rn1 * rn1) + b2->m_invI * (r2Sqr - rn2 * rn2);
|
||||
|
||||
b2Assert(kNormal > B2_FLT_EPSILON);
|
||||
ccp->normalMass = 1.0f / kNormal;
|
||||
|
||||
float32 kEqualized = b1->m_mass * b1->m_invMass + b2->m_mass * b2->m_invMass;
|
||||
kEqualized += b1->m_mass * b1->m_invI * (r1Sqr - rn1 * rn1) + b2->m_mass * b2->m_invI * (r2Sqr - rn2 * rn2);
|
||||
|
||||
b2Assert(kEqualized > B2_FLT_EPSILON);
|
||||
ccp->equalizedMass = 1.0f / kEqualized;
|
||||
|
||||
b2Vec2 tangent = b2Cross(normal, 1.0f);
|
||||
|
||||
float32 rt1 = b2Dot(ccp->r1, tangent);
|
||||
float32 rt2 = b2Dot(ccp->r2, tangent);
|
||||
float32 kTangent = b1->m_invMass + b2->m_invMass;
|
||||
kTangent += b1->m_invI * (r1Sqr - rt1 * rt1) + b2->m_invI * (r2Sqr - rt2 * rt2);
|
||||
|
||||
b2Assert(kTangent > B2_FLT_EPSILON);
|
||||
ccp->tangentMass = 1.0f / kTangent;
|
||||
|
||||
// Setup a velocity bias for restitution.
|
||||
ccp->velocityBias = 0.0f;
|
||||
if (ccp->separation > 0.0f)
|
||||
{
|
||||
ccp->velocityBias = -60.0f * ccp->separation; // TODO_ERIN b2TimeStep
|
||||
}
|
||||
|
||||
float32 vRel = b2Dot(c->normal, v2 + b2Cross(w2, ccp->r2) - v1 - b2Cross(w1, ccp->r1));
|
||||
if (vRel < -b2_velocityThreshold)
|
||||
{
|
||||
ccp->velocityBias += -c->restitution * vRel;
|
||||
}
|
||||
}
|
||||
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
b2Assert(count == m_constraintCount);
|
||||
}
|
||||
|
||||
b2ContactSolver::~b2ContactSolver()
|
||||
{
|
||||
m_allocator->Free(m_constraints);
|
||||
}
|
||||
|
||||
void b2ContactSolver::InitVelocityConstraints(const b2TimeStep& step)
|
||||
{
|
||||
// Warm start.
|
||||
for (int32 i = 0; i < m_constraintCount; ++i)
|
||||
{
|
||||
b2ContactConstraint* c = m_constraints + i;
|
||||
|
||||
b2Body* b1 = c->body1;
|
||||
b2Body* b2 = c->body2;
|
||||
float32 invMass1 = b1->m_invMass;
|
||||
float32 invI1 = b1->m_invI;
|
||||
float32 invMass2 = b2->m_invMass;
|
||||
float32 invI2 = b2->m_invI;
|
||||
b2Vec2 normal = c->normal;
|
||||
b2Vec2 tangent = b2Cross(normal, 1.0f);
|
||||
|
||||
if (step.warmStarting)
|
||||
{
|
||||
for (int32 j = 0; j < c->pointCount; ++j)
|
||||
{
|
||||
b2ContactConstraintPoint* ccp = c->points + j;
|
||||
ccp->normalImpulse *= step.dtRatio;
|
||||
ccp->tangentImpulse *= step.dtRatio;
|
||||
b2Vec2 P = ccp->normalImpulse * normal + ccp->tangentImpulse * tangent;
|
||||
b1->m_angularVelocity -= invI1 * b2Cross(ccp->r1, P);
|
||||
b1->m_linearVelocity -= invMass1 * P;
|
||||
b2->m_angularVelocity += invI2 * b2Cross(ccp->r2, P);
|
||||
b2->m_linearVelocity += invMass2 * P;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int32 j = 0; j < c->pointCount; ++j)
|
||||
{
|
||||
b2ContactConstraintPoint* ccp = c->points + j;
|
||||
ccp->normalImpulse = 0.0f;
|
||||
ccp->tangentImpulse = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void b2ContactSolver::SolveVelocityConstraints()
|
||||
{
|
||||
for (int32 i = 0; i < m_constraintCount; ++i)
|
||||
{
|
||||
b2ContactConstraint* c = m_constraints + i;
|
||||
b2Body* b1 = c->body1;
|
||||
b2Body* b2 = c->body2;
|
||||
float32 w1 = b1->m_angularVelocity;
|
||||
float32 w2 = b2->m_angularVelocity;
|
||||
b2Vec2 v1 = b1->m_linearVelocity;
|
||||
b2Vec2 v2 = b2->m_linearVelocity;
|
||||
float32 invMass1 = b1->m_invMass;
|
||||
float32 invI1 = b1->m_invI;
|
||||
float32 invMass2 = b2->m_invMass;
|
||||
float32 invI2 = b2->m_invI;
|
||||
b2Vec2 normal = c->normal;
|
||||
b2Vec2 tangent = b2Cross(normal, 1.0f);
|
||||
float32 friction = c->friction;
|
||||
//#define DEFERRED_UPDATE
|
||||
#ifdef DEFERRED_UPDATE
|
||||
b2Vec2 b1_linearVelocity = b1->m_linearVelocity;
|
||||
float32 b1_angularVelocity = b1->m_angularVelocity;
|
||||
b2Vec2 b2_linearVelocity = b2->m_linearVelocity;
|
||||
float32 b2_angularVelocity = b2->m_angularVelocity;
|
||||
#endif
|
||||
// Solve normal constraints
|
||||
for (int32 j = 0; j < c->pointCount; ++j)
|
||||
{
|
||||
b2ContactConstraintPoint* ccp = c->points + j;
|
||||
|
||||
// Relative velocity at contact
|
||||
b2Vec2 dv = v2 + b2Cross(w2, ccp->r2) - v1 - b2Cross(w1, ccp->r1);
|
||||
|
||||
// Compute normal impulse
|
||||
float32 vn = b2Dot(dv, normal);
|
||||
float32 lambda = -ccp->normalMass * (vn - ccp->velocityBias);
|
||||
|
||||
// b2Clamp the accumulated impulse
|
||||
float32 newImpulse = b2Max(ccp->normalImpulse + lambda, 0.0f);
|
||||
lambda = newImpulse - ccp->normalImpulse;
|
||||
|
||||
// Apply contact impulse
|
||||
b2Vec2 P = lambda * normal;
|
||||
#ifdef DEFERRED_UPDATE
|
||||
b1_linearVelocity -= invMass1 * P;
|
||||
b1_angularVelocity -= invI1 * b2Cross(r1, P);
|
||||
|
||||
b2_linearVelocity += invMass2 * P;
|
||||
b2_angularVelocity += invI2 * b2Cross(r2, P);
|
||||
#else
|
||||
v1 -= invMass1 * P;
|
||||
w1 -= invI1 * b2Cross(ccp->r1, P);
|
||||
|
||||
v2 += invMass2 * P;
|
||||
w2 += invI2 * b2Cross(ccp->r2, P);
|
||||
#endif
|
||||
ccp->normalImpulse = newImpulse;
|
||||
}
|
||||
|
||||
#ifdef DEFERRED_UPDATE
|
||||
b1->m_linearVelocity = b1_linearVelocity;
|
||||
b1->m_angularVelocity = b1_angularVelocity;
|
||||
b2->m_linearVelocity = b2_linearVelocity;
|
||||
b2->m_angularVelocity = b2_angularVelocity;
|
||||
#endif
|
||||
// Solve tangent constraints
|
||||
for (int32 j = 0; j < c->pointCount; ++j)
|
||||
{
|
||||
b2ContactConstraintPoint* ccp = c->points + j;
|
||||
|
||||
// Relative velocity at contact
|
||||
b2Vec2 dv = v2 + b2Cross(w2, ccp->r2) - v1 - b2Cross(w1, ccp->r1);
|
||||
|
||||
// Compute tangent force
|
||||
float32 vt = b2Dot(dv, tangent);
|
||||
float32 lambda = ccp->tangentMass * (-vt);
|
||||
|
||||
// b2Clamp the accumulated force
|
||||
float32 maxFriction = friction * ccp->normalImpulse;
|
||||
float32 newImpulse = b2Clamp(ccp->tangentImpulse + lambda, -maxFriction, maxFriction);
|
||||
lambda = newImpulse - ccp->tangentImpulse;
|
||||
|
||||
// Apply contact impulse
|
||||
b2Vec2 P = lambda * tangent;
|
||||
|
||||
v1 -= invMass1 * P;
|
||||
w1 -= invI1 * b2Cross(ccp->r1, P);
|
||||
|
||||
v2 += invMass2 * P;
|
||||
w2 += invI2 * b2Cross(ccp->r2, P);
|
||||
|
||||
ccp->tangentImpulse = newImpulse;
|
||||
}
|
||||
|
||||
b1->m_linearVelocity = v1;
|
||||
b1->m_angularVelocity = w1;
|
||||
b2->m_linearVelocity = v2;
|
||||
b2->m_angularVelocity = w2;
|
||||
}
|
||||
}
|
||||
|
||||
void b2ContactSolver::FinalizeVelocityConstraints()
|
||||
{
|
||||
for (int32 i = 0; i < m_constraintCount; ++i)
|
||||
{
|
||||
b2ContactConstraint* c = m_constraints + i;
|
||||
b2Manifold* m = c->manifold;
|
||||
|
||||
for (int32 j = 0; j < c->pointCount; ++j)
|
||||
{
|
||||
m->points[j].normalImpulse = c->points[j].normalImpulse;
|
||||
m->points[j].tangentImpulse = c->points[j].tangentImpulse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool b2ContactSolver::SolvePositionConstraints(float32 baumgarte)
|
||||
{
|
||||
float32 minSeparation = 0.0f;
|
||||
|
||||
for (int32 i = 0; i < m_constraintCount; ++i)
|
||||
{
|
||||
b2ContactConstraint* c = m_constraints + i;
|
||||
b2Body* b1 = c->body1;
|
||||
b2Body* b2 = c->body2;
|
||||
float32 invMass1 = b1->m_mass * b1->m_invMass;
|
||||
float32 invI1 = b1->m_mass * b1->m_invI;
|
||||
float32 invMass2 = b2->m_mass * b2->m_invMass;
|
||||
float32 invI2 = b2->m_mass * b2->m_invI;
|
||||
|
||||
b2Vec2 normal = c->normal;
|
||||
|
||||
// Solver normal constraints
|
||||
for (int32 j = 0; j < c->pointCount; ++j)
|
||||
{
|
||||
b2ContactConstraintPoint* ccp = c->points + j;
|
||||
|
||||
b2Vec2 r1 = b2Mul(b1->GetXForm().R, ccp->localAnchor1 - b1->GetLocalCenter());
|
||||
b2Vec2 r2 = b2Mul(b2->GetXForm().R, ccp->localAnchor2 - b2->GetLocalCenter());
|
||||
|
||||
b2Vec2 p1 = b1->m_sweep.c + r1;
|
||||
b2Vec2 p2 = b2->m_sweep.c + r2;
|
||||
b2Vec2 dp = p2 - p1;
|
||||
|
||||
// Approximate the current separation.
|
||||
float32 separation = b2Dot(dp, normal) + ccp->separation;
|
||||
|
||||
// Track max constraint error.
|
||||
minSeparation = b2Min(minSeparation, separation);
|
||||
|
||||
// Prevent large corrections and allow slop.
|
||||
float32 C = baumgarte * b2Clamp(separation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
|
||||
|
||||
// Compute normal impulse
|
||||
float32 dImpulse = -ccp->equalizedMass * C;
|
||||
|
||||
// b2Clamp the accumulated impulse
|
||||
float32 impulse0 = ccp->positionImpulse;
|
||||
ccp->positionImpulse = b2Max(impulse0 + dImpulse, 0.0f);
|
||||
dImpulse = ccp->positionImpulse - impulse0;
|
||||
|
||||
b2Vec2 impulse = dImpulse * normal;
|
||||
|
||||
b1->m_sweep.c -= invMass1 * impulse;
|
||||
b1->m_sweep.a -= invI1 * b2Cross(r1, impulse);
|
||||
b1->SynchronizeTransform();
|
||||
|
||||
b2->m_sweep.c += invMass2 * impulse;
|
||||
b2->m_sweep.a += invI2 * b2Cross(r2, impulse);
|
||||
b2->SynchronizeTransform();
|
||||
}
|
||||
}
|
||||
|
||||
// We can't expect minSpeparation >= -b2_linearSlop because we don't
|
||||
// push the separation above -b2_linearSlop.
|
||||
return minSeparation >= -1.5f * b2_linearSlop;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef CONTACT_SOLVER_H
|
||||
#define CONTACT_SOLVER_H
|
||||
|
||||
#include "../../Common/b2Math.h"
|
||||
#include "../../Collision/b2Collision.h"
|
||||
#include "../b2World.h"
|
||||
|
||||
class b2Contact;
|
||||
class b2Body;
|
||||
class b2Island;
|
||||
class b2StackAllocator;
|
||||
|
||||
struct b2ContactConstraintPoint
|
||||
{
|
||||
b2Vec2 localAnchor1;
|
||||
b2Vec2 localAnchor2;
|
||||
b2Vec2 r1;
|
||||
b2Vec2 r2;
|
||||
float32 normalImpulse;
|
||||
float32 tangentImpulse;
|
||||
float32 positionImpulse;
|
||||
float32 normalMass;
|
||||
float32 tangentMass;
|
||||
float32 equalizedMass;
|
||||
float32 separation;
|
||||
float32 velocityBias;
|
||||
};
|
||||
|
||||
struct b2ContactConstraint
|
||||
{
|
||||
b2ContactConstraintPoint points[b2_maxManifoldPoints];
|
||||
b2Vec2 normal;
|
||||
b2Manifold* manifold;
|
||||
b2Body* body1;
|
||||
b2Body* body2;
|
||||
float32 friction;
|
||||
float32 restitution;
|
||||
int32 pointCount;
|
||||
};
|
||||
|
||||
class b2ContactSolver
|
||||
{
|
||||
public:
|
||||
b2ContactSolver(const b2TimeStep& step, b2Contact** contacts, int32 contactCount, b2StackAllocator* allocator);
|
||||
~b2ContactSolver();
|
||||
|
||||
void InitVelocityConstraints(const b2TimeStep& step);
|
||||
void SolveVelocityConstraints();
|
||||
void FinalizeVelocityConstraints();
|
||||
|
||||
bool SolvePositionConstraints(float32 baumgarte);
|
||||
|
||||
b2TimeStep m_step;
|
||||
b2StackAllocator* m_allocator;
|
||||
b2ContactConstraint* m_constraints;
|
||||
int m_constraintCount;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_NULL_CONTACT_H
|
||||
#define B2_NULL_CONTACT_H
|
||||
|
||||
#include "../../Common/b2Math.h"
|
||||
#include "b2Contact.h"
|
||||
|
||||
class b2NullContact : public b2Contact
|
||||
{
|
||||
public:
|
||||
b2NullContact() {}
|
||||
void Evaluate(b2ContactListener*) {}
|
||||
b2Manifold* GetManifolds() { return NULL; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2PolyAndCircleContact.h"
|
||||
#include "../b2Body.h"
|
||||
#include "../b2WorldCallbacks.h"
|
||||
#include "../../Common/b2BlockAllocator.h"
|
||||
|
||||
#include <new>
|
||||
#include <string.h>
|
||||
|
||||
b2Contact* b2PolyAndCircleContact::Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator)
|
||||
{
|
||||
void* mem = allocator->Allocate(sizeof(b2PolyAndCircleContact));
|
||||
return new (mem) b2PolyAndCircleContact(shape1, shape2);
|
||||
}
|
||||
|
||||
void b2PolyAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
|
||||
{
|
||||
((b2PolyAndCircleContact*)contact)->~b2PolyAndCircleContact();
|
||||
allocator->Free(contact, sizeof(b2PolyAndCircleContact));
|
||||
}
|
||||
|
||||
b2PolyAndCircleContact::b2PolyAndCircleContact(b2Shape* s1, b2Shape* s2)
|
||||
: b2Contact(s1, s2)
|
||||
{
|
||||
b2Assert(m_shape1->GetType() == e_polygonShape);
|
||||
b2Assert(m_shape2->GetType() == e_circleShape);
|
||||
m_manifold.pointCount = 0;
|
||||
m_manifold.points[0].normalImpulse = 0.0f;
|
||||
m_manifold.points[0].tangentImpulse = 0.0f;
|
||||
}
|
||||
|
||||
void b2PolyAndCircleContact::Evaluate(b2ContactListener* listener)
|
||||
{
|
||||
b2Body* b1 = m_shape1->GetBody();
|
||||
b2Body* b2 = m_shape2->GetBody();
|
||||
|
||||
b2Manifold m0;
|
||||
memcpy(&m0, &m_manifold, sizeof(b2Manifold));
|
||||
|
||||
b2CollidePolygonAndCircle(&m_manifold, (b2PolygonShape*)m_shape1, b1->GetXForm(), (b2CircleShape*)m_shape2, b2->GetXForm());
|
||||
|
||||
bool persisted[b2_maxManifoldPoints] = {false, false};
|
||||
|
||||
b2ContactPoint cp;
|
||||
cp.shape1 = m_shape1;
|
||||
cp.shape2 = m_shape2;
|
||||
cp.friction = m_friction;
|
||||
cp.restitution = m_restitution;
|
||||
|
||||
// Match contact ids to facilitate warm starting.
|
||||
if (m_manifold.pointCount > 0)
|
||||
{
|
||||
// Match old contact ids to new contact ids and copy the
|
||||
// stored impulses to warm start the solver.
|
||||
for (int32 i = 0; i < m_manifold.pointCount; ++i)
|
||||
{
|
||||
b2ManifoldPoint* mp = m_manifold.points + i;
|
||||
mp->normalImpulse = 0.0f;
|
||||
mp->tangentImpulse = 0.0f;
|
||||
bool found = false;
|
||||
b2ContactID id = mp->id;
|
||||
|
||||
for (int32 j = 0; j < m0.pointCount; ++j)
|
||||
{
|
||||
if (persisted[j] == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
b2ManifoldPoint* mp0 = m0.points + j;
|
||||
|
||||
if (mp0->id.key == id.key)
|
||||
{
|
||||
persisted[j] = true;
|
||||
mp->normalImpulse = mp0->normalImpulse;
|
||||
mp->tangentImpulse = mp0->tangentImpulse;
|
||||
|
||||
// A persistent point.
|
||||
found = true;
|
||||
|
||||
// Report persistent point.
|
||||
if (listener != NULL)
|
||||
{
|
||||
cp.position = b1->GetWorldPoint(mp->localPoint1);
|
||||
b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1);
|
||||
b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2);
|
||||
cp.velocity = v2 - v1;
|
||||
cp.normal = m_manifold.normal;
|
||||
cp.separation = mp->separation;
|
||||
cp.id = id;
|
||||
listener->Persist(&cp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Report added point.
|
||||
if (found == false && listener != NULL)
|
||||
{
|
||||
cp.position = b1->GetWorldPoint(mp->localPoint1);
|
||||
b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1);
|
||||
b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2);
|
||||
cp.velocity = v2 - v1;
|
||||
cp.normal = m_manifold.normal;
|
||||
cp.separation = mp->separation;
|
||||
cp.id = id;
|
||||
listener->Add(&cp);
|
||||
}
|
||||
}
|
||||
|
||||
m_manifoldCount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_manifoldCount = 0;
|
||||
}
|
||||
|
||||
if (listener == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Report removed points.
|
||||
for (int32 i = 0; i < m0.pointCount; ++i)
|
||||
{
|
||||
if (persisted[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
b2ManifoldPoint* mp0 = m0.points + i;
|
||||
cp.position = b1->GetWorldPoint(mp0->localPoint1);
|
||||
b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp0->localPoint1);
|
||||
b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp0->localPoint2);
|
||||
cp.velocity = v2 - v1;
|
||||
cp.normal = m0.normal;
|
||||
cp.separation = mp0->separation;
|
||||
cp.id = mp0->id;
|
||||
listener->Remove(&cp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef POLY_AND_CIRCLE_CONTACT_H
|
||||
#define POLY_AND_CIRCLE_CONTACT_H
|
||||
|
||||
#include "b2Contact.h"
|
||||
|
||||
class b2BlockAllocator;
|
||||
|
||||
class b2PolyAndCircleContact : public b2Contact
|
||||
{
|
||||
public:
|
||||
static b2Contact* Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator);
|
||||
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
|
||||
|
||||
b2PolyAndCircleContact(b2Shape* shape1, b2Shape* shape2);
|
||||
~b2PolyAndCircleContact() {}
|
||||
|
||||
void Evaluate(b2ContactListener* listener);
|
||||
b2Manifold* GetManifolds()
|
||||
{
|
||||
return &m_manifold;
|
||||
}
|
||||
|
||||
b2Manifold m_manifold;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2PolyContact.h"
|
||||
#include "../b2Body.h"
|
||||
#include "../b2WorldCallbacks.h"
|
||||
#include "../../Common/b2BlockAllocator.h"
|
||||
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <string.h>
|
||||
|
||||
b2Contact* b2PolygonContact::Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator)
|
||||
{
|
||||
void* mem = allocator->Allocate(sizeof(b2PolygonContact));
|
||||
return new (mem) b2PolygonContact(shape1, shape2);
|
||||
}
|
||||
|
||||
void b2PolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
|
||||
{
|
||||
((b2PolygonContact*)contact)->~b2PolygonContact();
|
||||
allocator->Free(contact, sizeof(b2PolygonContact));
|
||||
}
|
||||
|
||||
b2PolygonContact::b2PolygonContact(b2Shape* s1, b2Shape* s2)
|
||||
: b2Contact(s1, s2)
|
||||
{
|
||||
b2Assert(m_shape1->GetType() == e_polygonShape);
|
||||
b2Assert(m_shape2->GetType() == e_polygonShape);
|
||||
m_manifold.pointCount = 0;
|
||||
}
|
||||
|
||||
void b2PolygonContact::Evaluate(b2ContactListener* listener)
|
||||
{
|
||||
b2Body* b1 = m_shape1->GetBody();
|
||||
b2Body* b2 = m_shape2->GetBody();
|
||||
|
||||
b2Manifold m0;
|
||||
memcpy(&m0, &m_manifold, sizeof(b2Manifold));
|
||||
|
||||
b2CollidePolygons(&m_manifold, (b2PolygonShape*)m_shape1, b1->GetXForm(), (b2PolygonShape*)m_shape2, b2->GetXForm());
|
||||
|
||||
bool persisted[b2_maxManifoldPoints] = {false, false};
|
||||
|
||||
b2ContactPoint cp;
|
||||
cp.shape1 = m_shape1;
|
||||
cp.shape2 = m_shape2;
|
||||
cp.friction = m_friction;
|
||||
cp.restitution = m_restitution;
|
||||
|
||||
// Match contact ids to facilitate warm starting.
|
||||
if (m_manifold.pointCount > 0)
|
||||
{
|
||||
// Match old contact ids to new contact ids and copy the
|
||||
// stored impulses to warm start the solver.
|
||||
for (int32 i = 0; i < m_manifold.pointCount; ++i)
|
||||
{
|
||||
b2ManifoldPoint* mp = m_manifold.points + i;
|
||||
mp->normalImpulse = 0.0f;
|
||||
mp->tangentImpulse = 0.0f;
|
||||
bool found = false;
|
||||
b2ContactID id = mp->id;
|
||||
|
||||
for (int32 j = 0; j < m0.pointCount; ++j)
|
||||
{
|
||||
if (persisted[j] == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
b2ManifoldPoint* mp0 = m0.points + j;
|
||||
|
||||
if (mp0->id.key == id.key)
|
||||
{
|
||||
persisted[j] = true;
|
||||
mp->normalImpulse = mp0->normalImpulse;
|
||||
mp->tangentImpulse = mp0->tangentImpulse;
|
||||
|
||||
// A persistent point.
|
||||
found = true;
|
||||
|
||||
// Report persistent point.
|
||||
if (listener != NULL)
|
||||
{
|
||||
cp.position = b1->GetWorldPoint(mp->localPoint1);
|
||||
b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1);
|
||||
b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2);
|
||||
cp.velocity = v2 - v1;
|
||||
cp.normal = m_manifold.normal;
|
||||
cp.separation = mp->separation;
|
||||
cp.id = id;
|
||||
listener->Persist(&cp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Report added point.
|
||||
if (found == false && listener != NULL)
|
||||
{
|
||||
cp.position = b1->GetWorldPoint(mp->localPoint1);
|
||||
b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1);
|
||||
b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2);
|
||||
cp.velocity = v2 - v1;
|
||||
cp.normal = m_manifold.normal;
|
||||
cp.separation = mp->separation;
|
||||
cp.id = id;
|
||||
listener->Add(&cp);
|
||||
}
|
||||
}
|
||||
|
||||
m_manifoldCount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_manifoldCount = 0;
|
||||
}
|
||||
|
||||
if (listener == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Report removed points.
|
||||
for (int32 i = 0; i < m0.pointCount; ++i)
|
||||
{
|
||||
if (persisted[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
b2ManifoldPoint* mp0 = m0.points + i;
|
||||
cp.position = b1->GetWorldPoint(mp0->localPoint1);
|
||||
b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp0->localPoint1);
|
||||
b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp0->localPoint2);
|
||||
cp.velocity = v2 - v1;
|
||||
cp.normal = m0.normal;
|
||||
cp.separation = mp0->separation;
|
||||
cp.id = mp0->id;
|
||||
listener->Remove(&cp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef POLYCONTACT_H
|
||||
#define POLYCONTACT_H
|
||||
|
||||
#include "b2Contact.h"
|
||||
|
||||
class b2BlockAllocator;
|
||||
|
||||
class b2PolygonContact : public b2Contact
|
||||
{
|
||||
public:
|
||||
static b2Contact* Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator);
|
||||
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
|
||||
|
||||
b2PolygonContact(b2Shape* shape1, b2Shape* shape2);
|
||||
~b2PolygonContact() {}
|
||||
|
||||
void Evaluate(b2ContactListener* listener);
|
||||
b2Manifold* GetManifolds()
|
||||
{
|
||||
return &m_manifold;
|
||||
}
|
||||
|
||||
b2Manifold m_manifold;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2DistanceJoint.h"
|
||||
#include "../b2Body.h"
|
||||
#include "../b2World.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)
|
||||
{
|
||||
body1 = b1;
|
||||
body2 = b2;
|
||||
localAnchor1 = body1->GetLocalPoint(anchor1);
|
||||
localAnchor2 = body2->GetLocalPoint(anchor2);
|
||||
b2Vec2 d = anchor2 - anchor1;
|
||||
length = d.Length();
|
||||
}
|
||||
|
||||
|
||||
b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def)
|
||||
: b2Joint(def)
|
||||
{
|
||||
m_localAnchor1 = def->localAnchor1;
|
||||
m_localAnchor2 = def->localAnchor2;
|
||||
m_length = def->length;
|
||||
m_frequencyHz = def->frequencyHz;
|
||||
m_dampingRatio = def->dampingRatio;
|
||||
m_impulse = 0.0f;
|
||||
m_gamma = 0.0f;
|
||||
m_bias = 0.0f;
|
||||
m_inv_dt = 0.0f;
|
||||
}
|
||||
|
||||
void b2DistanceJoint::InitVelocityConstraints(const b2TimeStep& step)
|
||||
{
|
||||
m_inv_dt = step.inv_dt;
|
||||
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
// Compute the effective mass matrix.
|
||||
b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
|
||||
b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
|
||||
m_u = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;
|
||||
|
||||
// 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 cr1u = b2Cross(r1, m_u);
|
||||
float32 cr2u = b2Cross(r2, m_u);
|
||||
float32 invMass = b1->m_invMass + b1->m_invI * cr1u * cr1u + b2->m_invMass + b2->m_invI * cr2u * cr2u;
|
||||
b2Assert(invMass > B2_FLT_EPSILON);
|
||||
m_mass = 1.0f / invMass;
|
||||
|
||||
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
|
||||
m_gamma = 1.0f / (step.dt * (d + step.dt * k));
|
||||
m_bias = C * step.dt * k * m_gamma;
|
||||
|
||||
m_mass = 1.0f / (invMass + m_gamma);
|
||||
}
|
||||
|
||||
if (step.warmStarting)
|
||||
{
|
||||
m_impulse *= step.dtRatio;
|
||||
b2Vec2 P = m_impulse * m_u;
|
||||
b1->m_linearVelocity -= b1->m_invMass * P;
|
||||
b1->m_angularVelocity -= b1->m_invI * b2Cross(r1, P);
|
||||
b2->m_linearVelocity += b2->m_invMass * P;
|
||||
b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_impulse = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void b2DistanceJoint::SolveVelocityConstraints(const b2TimeStep& step)
|
||||
{
|
||||
B2_NOT_USED(step);
|
||||
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
|
||||
b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
|
||||
|
||||
// Cdot = dot(u, v + cross(w, r))
|
||||
b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1);
|
||||
b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2);
|
||||
float32 Cdot = b2Dot(m_u, v2 - v1);
|
||||
|
||||
float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse);
|
||||
m_impulse += impulse;
|
||||
|
||||
b2Vec2 P = impulse * m_u;
|
||||
b1->m_linearVelocity -= b1->m_invMass * P;
|
||||
b1->m_angularVelocity -= b1->m_invI * b2Cross(r1, P);
|
||||
b2->m_linearVelocity += b2->m_invMass * P;
|
||||
b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P);
|
||||
}
|
||||
|
||||
bool b2DistanceJoint::SolvePositionConstraints()
|
||||
{
|
||||
if (m_frequencyHz > 0.0f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
|
||||
b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
|
||||
|
||||
b2Vec2 d = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;
|
||||
|
||||
float32 length = d.Normalize();
|
||||
float32 C = length - m_length;
|
||||
C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection);
|
||||
|
||||
float32 impulse = -m_mass * C;
|
||||
m_u = d;
|
||||
b2Vec2 P = impulse * m_u;
|
||||
|
||||
b1->m_sweep.c -= b1->m_invMass * P;
|
||||
b1->m_sweep.a -= b1->m_invI * b2Cross(r1, P);
|
||||
b2->m_sweep.c += b2->m_invMass * P;
|
||||
b2->m_sweep.a += b2->m_invI * b2Cross(r2, P);
|
||||
|
||||
b1->SynchronizeTransform();
|
||||
b2->SynchronizeTransform();
|
||||
|
||||
return b2Abs(C) < b2_linearSlop;
|
||||
}
|
||||
|
||||
b2Vec2 b2DistanceJoint::GetAnchor1() const
|
||||
{
|
||||
return m_body1->GetWorldPoint(m_localAnchor1);
|
||||
}
|
||||
|
||||
b2Vec2 b2DistanceJoint::GetAnchor2() const
|
||||
{
|
||||
return m_body2->GetWorldPoint(m_localAnchor2);
|
||||
}
|
||||
|
||||
b2Vec2 b2DistanceJoint::GetReactionForce() const
|
||||
{
|
||||
b2Vec2 F = (m_inv_dt * m_impulse) * m_u;
|
||||
return F;
|
||||
}
|
||||
|
||||
float32 b2DistanceJoint::GetReactionTorque() const
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_DISTANCE_JOINT_H
|
||||
#define B2_DISTANCE_JOINT_H
|
||||
|
||||
#include "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;
|
||||
localAnchor1.Set(0.0f, 0.0f);
|
||||
localAnchor2.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* body1, b2Body* body2,
|
||||
const b2Vec2& anchor1, const b2Vec2& anchor2);
|
||||
|
||||
/// The local anchor point relative to body1's origin.
|
||||
b2Vec2 localAnchor1;
|
||||
|
||||
/// The local anchor point relative to body2's origin.
|
||||
b2Vec2 localAnchor2;
|
||||
|
||||
/// The equilibrium length between the anchor points.
|
||||
float32 length;
|
||||
|
||||
/// The response speed.
|
||||
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 GetAnchor1() const;
|
||||
b2Vec2 GetAnchor2() const;
|
||||
|
||||
b2Vec2 GetReactionForce() const;
|
||||
float32 GetReactionTorque() const;
|
||||
|
||||
//--------------- Internals Below -------------------
|
||||
|
||||
b2DistanceJoint(const b2DistanceJointDef* data);
|
||||
|
||||
void InitVelocityConstraints(const b2TimeStep& step);
|
||||
void SolveVelocityConstraints(const b2TimeStep& step);
|
||||
bool SolvePositionConstraints();
|
||||
|
||||
b2Vec2 m_localAnchor1;
|
||||
b2Vec2 m_localAnchor2;
|
||||
b2Vec2 m_u;
|
||||
float32 m_frequencyHz;
|
||||
float32 m_dampingRatio;
|
||||
float32 m_gamma;
|
||||
float32 m_bias;
|
||||
float32 m_impulse;
|
||||
float32 m_mass; // effective mass for the constraint.
|
||||
float32 m_length;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2GearJoint.h"
|
||||
#include "b2RevoluteJoint.h"
|
||||
#include "b2PrismaticJoint.h"
|
||||
#include "../b2Body.h"
|
||||
#include "../b2World.h"
|
||||
|
||||
// Gear Joint:
|
||||
// C0 = (coordinate1 + ratio * coordinate2)_initial
|
||||
// C = C0 - (cordinate1 + ratio * coordinate2) = 0
|
||||
// Cdot = -(Cdot1 + ratio * Cdot2)
|
||||
// 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)
|
||||
{
|
||||
b2JointType type1 = def->joint1->GetType();
|
||||
b2JointType type2 = def->joint2->GetType();
|
||||
|
||||
b2Assert(type1 == e_revoluteJoint || type1 == e_prismaticJoint);
|
||||
b2Assert(type2 == e_revoluteJoint || type2 == e_prismaticJoint);
|
||||
b2Assert(def->joint1->GetBody1()->IsStatic());
|
||||
b2Assert(def->joint2->GetBody1()->IsStatic());
|
||||
|
||||
m_revolute1 = NULL;
|
||||
m_prismatic1 = NULL;
|
||||
m_revolute2 = NULL;
|
||||
m_prismatic2 = NULL;
|
||||
|
||||
float32 coordinate1, coordinate2;
|
||||
|
||||
m_ground1 = def->joint1->GetBody1();
|
||||
m_body1 = def->joint1->GetBody2();
|
||||
if (type1 == e_revoluteJoint)
|
||||
{
|
||||
m_revolute1 = (b2RevoluteJoint*)def->joint1;
|
||||
m_groundAnchor1 = m_revolute1->m_localAnchor1;
|
||||
m_localAnchor1 = m_revolute1->m_localAnchor2;
|
||||
coordinate1 = m_revolute1->GetJointAngle();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_prismatic1 = (b2PrismaticJoint*)def->joint1;
|
||||
m_groundAnchor1 = m_prismatic1->m_localAnchor1;
|
||||
m_localAnchor1 = m_prismatic1->m_localAnchor2;
|
||||
coordinate1 = m_prismatic1->GetJointTranslation();
|
||||
}
|
||||
|
||||
m_ground2 = def->joint2->GetBody1();
|
||||
m_body2 = def->joint2->GetBody2();
|
||||
if (type2 == e_revoluteJoint)
|
||||
{
|
||||
m_revolute2 = (b2RevoluteJoint*)def->joint2;
|
||||
m_groundAnchor2 = m_revolute2->m_localAnchor1;
|
||||
m_localAnchor2 = m_revolute2->m_localAnchor2;
|
||||
coordinate2 = m_revolute2->GetJointAngle();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_prismatic2 = (b2PrismaticJoint*)def->joint2;
|
||||
m_groundAnchor2 = m_prismatic2->m_localAnchor1;
|
||||
m_localAnchor2 = m_prismatic2->m_localAnchor2;
|
||||
coordinate2 = m_prismatic2->GetJointTranslation();
|
||||
}
|
||||
|
||||
m_ratio = def->ratio;
|
||||
|
||||
m_constant = coordinate1 + m_ratio * coordinate2;
|
||||
|
||||
m_force = 0.0f;
|
||||
}
|
||||
|
||||
void b2GearJoint::InitVelocityConstraints(const b2TimeStep& step)
|
||||
{
|
||||
b2Body* g1 = m_ground1;
|
||||
b2Body* g2 = m_ground2;
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
float32 K = 0.0f;
|
||||
m_J.SetZero();
|
||||
|
||||
if (m_revolute1)
|
||||
{
|
||||
m_J.angular1 = -1.0f;
|
||||
K += b1->m_invI;
|
||||
}
|
||||
else
|
||||
{
|
||||
b2Vec2 ug = b2Mul(g1->GetXForm().R, m_prismatic1->m_localXAxis1);
|
||||
b2Vec2 r = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
|
||||
float32 crug = b2Cross(r, ug);
|
||||
m_J.linear1 = -ug;
|
||||
m_J.angular1 = -crug;
|
||||
K += b1->m_invMass + b1->m_invI * crug * crug;
|
||||
}
|
||||
|
||||
if (m_revolute2)
|
||||
{
|
||||
m_J.angular2 = -m_ratio;
|
||||
K += m_ratio * m_ratio * b2->m_invI;
|
||||
}
|
||||
else
|
||||
{
|
||||
b2Vec2 ug = b2Mul(g2->GetXForm().R, m_prismatic2->m_localXAxis1);
|
||||
b2Vec2 r = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
|
||||
float32 crug = b2Cross(r, ug);
|
||||
m_J.linear2 = -m_ratio * ug;
|
||||
m_J.angular2 = -m_ratio * crug;
|
||||
K += m_ratio * m_ratio * (b2->m_invMass + b2->m_invI * crug * crug);
|
||||
}
|
||||
|
||||
// Compute effective mass.
|
||||
b2Assert(K > 0.0f);
|
||||
m_mass = 1.0f / K;
|
||||
|
||||
if (step.warmStarting)
|
||||
{
|
||||
// Warm starting.
|
||||
float32 P = B2FORCE_SCALE(step.dt) * m_force;
|
||||
b1->m_linearVelocity += b1->m_invMass * P * m_J.linear1;
|
||||
b1->m_angularVelocity += b1->m_invI * P * m_J.angular1;
|
||||
b2->m_linearVelocity += b2->m_invMass * P * m_J.linear2;
|
||||
b2->m_angularVelocity += b2->m_invI * P * m_J.angular2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_force = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void b2GearJoint::SolveVelocityConstraints(const b2TimeStep& step)
|
||||
{
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
float32 Cdot = m_J.Compute( b1->m_linearVelocity, b1->m_angularVelocity,
|
||||
b2->m_linearVelocity, b2->m_angularVelocity);
|
||||
|
||||
float32 force = -B2FORCE_INV_SCALE(step.inv_dt) * m_mass * Cdot;
|
||||
m_force += force;
|
||||
|
||||
float32 P = B2FORCE_SCALE(step.dt) * force;
|
||||
b1->m_linearVelocity += b1->m_invMass * P * m_J.linear1;
|
||||
b1->m_angularVelocity += b1->m_invI * P * m_J.angular1;
|
||||
b2->m_linearVelocity += b2->m_invMass * P * m_J.linear2;
|
||||
b2->m_angularVelocity += b2->m_invI * P * m_J.angular2;
|
||||
}
|
||||
|
||||
bool b2GearJoint::SolvePositionConstraints()
|
||||
{
|
||||
float32 linearError = 0.0f;
|
||||
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
float32 coordinate1, coordinate2;
|
||||
if (m_revolute1)
|
||||
{
|
||||
coordinate1 = m_revolute1->GetJointAngle();
|
||||
}
|
||||
else
|
||||
{
|
||||
coordinate1 = m_prismatic1->GetJointTranslation();
|
||||
}
|
||||
|
||||
if (m_revolute2)
|
||||
{
|
||||
coordinate2 = m_revolute2->GetJointAngle();
|
||||
}
|
||||
else
|
||||
{
|
||||
coordinate2 = m_prismatic2->GetJointTranslation();
|
||||
}
|
||||
|
||||
float32 C = m_constant - (coordinate1 + m_ratio * coordinate2);
|
||||
|
||||
float32 impulse = -m_mass * C;
|
||||
|
||||
b1->m_sweep.c += b1->m_invMass * impulse * m_J.linear1;
|
||||
b1->m_sweep.a += b1->m_invI * impulse * m_J.angular1;
|
||||
b2->m_sweep.c += b2->m_invMass * impulse * m_J.linear2;
|
||||
b2->m_sweep.a += b2->m_invI * impulse * m_J.angular2;
|
||||
|
||||
b1->SynchronizeTransform();
|
||||
b2->SynchronizeTransform();
|
||||
|
||||
return linearError < b2_linearSlop;
|
||||
}
|
||||
|
||||
b2Vec2 b2GearJoint::GetAnchor1() const
|
||||
{
|
||||
return m_body1->GetWorldPoint(m_localAnchor1);
|
||||
}
|
||||
|
||||
b2Vec2 b2GearJoint::GetAnchor2() const
|
||||
{
|
||||
return m_body2->GetWorldPoint(m_localAnchor2);
|
||||
}
|
||||
|
||||
b2Vec2 b2GearJoint::GetReactionForce() const
|
||||
{
|
||||
// TODO_ERIN not tested
|
||||
b2Vec2 F = B2FORCE_SCALE(m_force) * m_J.linear2;
|
||||
return F;
|
||||
}
|
||||
|
||||
float32 b2GearJoint::GetReactionTorque() const
|
||||
{
|
||||
// TODO_ERIN not tested
|
||||
b2Vec2 r = b2Mul(m_body2->GetXForm().R, m_localAnchor2 - m_body2->GetLocalCenter());
|
||||
b2Vec2 F = m_force * m_J.linear2;
|
||||
float32 T = B2FORCE_SCALE(m_force * m_J.angular2 - b2Cross(r, F));
|
||||
return T;
|
||||
}
|
||||
|
||||
float32 b2GearJoint::GetRatio() const
|
||||
{
|
||||
return m_ratio;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_GEAR_JOINT_H
|
||||
#define B2_GEAR_JOINT_H
|
||||
|
||||
#include "b2Joint.h"
|
||||
|
||||
class b2RevoluteJoint;
|
||||
class b2PrismaticJoint;
|
||||
|
||||
/// Gear joint definition. This definition requires two existing
|
||||
/// revolute or prismatic joints (any combination will work).
|
||||
/// The provided joints must attach a dynamic body to a static body.
|
||||
struct b2GearJointDef : public b2JointDef
|
||||
{
|
||||
b2GearJointDef()
|
||||
{
|
||||
type = e_gearJoint;
|
||||
joint1 = NULL;
|
||||
joint2 = NULL;
|
||||
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 The revolute and prismatic joints must be attached to
|
||||
/// fixed bodies (which must be body1 on those joints).
|
||||
class b2GearJoint : public b2Joint
|
||||
{
|
||||
public:
|
||||
b2Vec2 GetAnchor1() const;
|
||||
b2Vec2 GetAnchor2() const;
|
||||
|
||||
b2Vec2 GetReactionForce() const;
|
||||
float32 GetReactionTorque() const;
|
||||
|
||||
/// Get the gear ratio.
|
||||
float32 GetRatio() const;
|
||||
|
||||
//--------------- Internals Below -------------------
|
||||
|
||||
b2GearJoint(const b2GearJointDef* data);
|
||||
|
||||
void InitVelocityConstraints(const b2TimeStep& step);
|
||||
void SolveVelocityConstraints(const b2TimeStep& step);
|
||||
bool SolvePositionConstraints();
|
||||
|
||||
b2Body* m_ground1;
|
||||
b2Body* m_ground2;
|
||||
|
||||
// One of these is NULL.
|
||||
b2RevoluteJoint* m_revolute1;
|
||||
b2PrismaticJoint* m_prismatic1;
|
||||
|
||||
// One of these is NULL.
|
||||
b2RevoluteJoint* m_revolute2;
|
||||
b2PrismaticJoint* m_prismatic2;
|
||||
|
||||
b2Vec2 m_groundAnchor1;
|
||||
b2Vec2 m_groundAnchor2;
|
||||
|
||||
b2Vec2 m_localAnchor1;
|
||||
b2Vec2 m_localAnchor2;
|
||||
|
||||
b2Jacobian m_J;
|
||||
|
||||
float32 m_constant;
|
||||
float32 m_ratio;
|
||||
|
||||
// Effective mass
|
||||
float32 m_mass;
|
||||
|
||||
// Impulse for accumulation/warm starting.
|
||||
float32 m_force;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2Joint.h"
|
||||
#include "b2DistanceJoint.h"
|
||||
#include "b2MouseJoint.h"
|
||||
#include "b2RevoluteJoint.h"
|
||||
#include "b2PrismaticJoint.h"
|
||||
#include "b2PulleyJoint.h"
|
||||
#include "b2GearJoint.h"
|
||||
#include "../b2Body.h"
|
||||
#include "../b2World.h"
|
||||
#include "../../Common/b2BlockAllocator.h"
|
||||
#include "../../Collision/b2BroadPhase.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
b2Joint* b2Joint::Create(const b2JointDef* def, b2BlockAllocator* allocator)
|
||||
{
|
||||
b2Joint* joint = NULL;
|
||||
|
||||
switch (def->type)
|
||||
{
|
||||
case e_distanceJoint:
|
||||
{
|
||||
void* mem = allocator->Allocate(sizeof(b2DistanceJoint));
|
||||
joint = new (mem) b2DistanceJoint((b2DistanceJointDef*)def);
|
||||
}
|
||||
break;
|
||||
|
||||
case e_mouseJoint:
|
||||
{
|
||||
void* mem = allocator->Allocate(sizeof(b2MouseJoint));
|
||||
joint = new (mem) b2MouseJoint((b2MouseJointDef*)def);
|
||||
}
|
||||
break;
|
||||
|
||||
case e_prismaticJoint:
|
||||
{
|
||||
void* mem = allocator->Allocate(sizeof(b2PrismaticJoint));
|
||||
joint = new (mem) b2PrismaticJoint((b2PrismaticJointDef*)def);
|
||||
}
|
||||
break;
|
||||
|
||||
case e_revoluteJoint:
|
||||
{
|
||||
void* mem = allocator->Allocate(sizeof(b2RevoluteJoint));
|
||||
joint = new (mem) b2RevoluteJoint((b2RevoluteJointDef*)def);
|
||||
}
|
||||
break;
|
||||
|
||||
case e_pulleyJoint:
|
||||
{
|
||||
void* mem = allocator->Allocate(sizeof(b2PulleyJoint));
|
||||
joint = new (mem) b2PulleyJoint((b2PulleyJointDef*)def);
|
||||
}
|
||||
break;
|
||||
|
||||
case e_gearJoint:
|
||||
{
|
||||
void* mem = allocator->Allocate(sizeof(b2GearJoint));
|
||||
joint = new (mem) b2GearJoint((b2GearJointDef*)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;
|
||||
|
||||
default:
|
||||
b2Assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
b2Joint::b2Joint(const b2JointDef* def)
|
||||
{
|
||||
m_type = def->type;
|
||||
m_prev = NULL;
|
||||
m_next = NULL;
|
||||
m_body1 = def->body1;
|
||||
m_body2 = def->body2;
|
||||
m_collideConnected = def->collideConnected;
|
||||
m_islandFlag = false;
|
||||
m_userData = def->userData;
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef JOINT_H
|
||||
#define JOINT_H
|
||||
|
||||
#include "../../Common/b2Math.h"
|
||||
|
||||
class b2Body;
|
||||
class b2Joint;
|
||||
struct b2TimeStep;
|
||||
class b2BlockAllocator;
|
||||
|
||||
enum b2JointType
|
||||
{
|
||||
e_unknownJoint,
|
||||
e_revoluteJoint,
|
||||
e_prismaticJoint,
|
||||
e_distanceJoint,
|
||||
e_pulleyJoint,
|
||||
e_mouseJoint,
|
||||
e_gearJoint
|
||||
};
|
||||
|
||||
enum b2LimitState
|
||||
{
|
||||
e_inactiveLimit,
|
||||
e_atLowerLimit,
|
||||
e_atUpperLimit,
|
||||
e_equalLimits
|
||||
};
|
||||
|
||||
struct b2Jacobian
|
||||
{
|
||||
b2Vec2 linear1;
|
||||
float32 angular1;
|
||||
b2Vec2 linear2;
|
||||
float32 angular2;
|
||||
|
||||
void SetZero();
|
||||
void Set(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2);
|
||||
float32 Compute(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2);
|
||||
};
|
||||
|
||||
/// 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 = NULL;
|
||||
body1 = NULL;
|
||||
body2 = NULL;
|
||||
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* body1;
|
||||
|
||||
/// The second attached body.
|
||||
b2Body* body2;
|
||||
|
||||
/// 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* GetBody1();
|
||||
|
||||
/// Get the second body attached to this joint.
|
||||
b2Body* GetBody2();
|
||||
|
||||
/// Get the anchor point on body1 in world coordinates.
|
||||
virtual b2Vec2 GetAnchor1() const = 0;
|
||||
|
||||
/// Get the anchor point on body2 in world coordinates.
|
||||
virtual b2Vec2 GetAnchor2() const = 0;
|
||||
|
||||
/// Get the reaction force on body2 at the joint anchor.
|
||||
virtual b2Vec2 GetReactionForce() const = 0;
|
||||
|
||||
/// Get the reaction torque on body2.
|
||||
virtual float32 GetReactionTorque() const = 0;
|
||||
|
||||
/// Get the next joint the world joint list.
|
||||
b2Joint* GetNext();
|
||||
|
||||
/// Get the user data pointer.
|
||||
void* GetUserData();
|
||||
|
||||
/// Set the user data pointer.
|
||||
void SetUserData(void* data);
|
||||
|
||||
//--------------- Internals Below -------------------
|
||||
protected:
|
||||
friend class b2World;
|
||||
friend class b2Body;
|
||||
friend class b2Island;
|
||||
|
||||
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 b2TimeStep& step) = 0;
|
||||
virtual void SolveVelocityConstraints(const b2TimeStep& step) = 0;
|
||||
|
||||
// This returns true if the position errors are within tolerance.
|
||||
virtual void InitPositionConstraints() {}
|
||||
virtual bool SolvePositionConstraints() = 0;
|
||||
|
||||
b2JointType m_type;
|
||||
b2Joint* m_prev;
|
||||
b2Joint* m_next;
|
||||
b2JointEdge m_node1;
|
||||
b2JointEdge m_node2;
|
||||
b2Body* m_body1;
|
||||
b2Body* m_body2;
|
||||
|
||||
float32 m_inv_dt;
|
||||
|
||||
bool m_islandFlag;
|
||||
|
||||
|
||||
void* m_userData;
|
||||
public:
|
||||
bool m_collideConnected;
|
||||
};
|
||||
|
||||
inline void b2Jacobian::SetZero()
|
||||
{
|
||||
linear1.SetZero(); angular1 = 0.0f;
|
||||
linear2.SetZero(); angular2 = 0.0f;
|
||||
}
|
||||
|
||||
inline void b2Jacobian::Set(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2)
|
||||
{
|
||||
linear1 = x1; angular1 = a1;
|
||||
linear2 = x2; angular2 = a2;
|
||||
}
|
||||
|
||||
inline float32 b2Jacobian::Compute(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2)
|
||||
{
|
||||
return b2Dot(linear1, x1) + angular1 * a1 + b2Dot(linear2, x2) + angular2 * a2;
|
||||
}
|
||||
|
||||
inline b2JointType b2Joint::GetType() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
inline b2Body* b2Joint::GetBody1()
|
||||
{
|
||||
return m_body1;
|
||||
}
|
||||
|
||||
inline b2Body* b2Joint::GetBody2()
|
||||
{
|
||||
return m_body2;
|
||||
}
|
||||
|
||||
inline b2Joint* b2Joint::GetNext()
|
||||
{
|
||||
return m_next;
|
||||
}
|
||||
|
||||
inline void* b2Joint::GetUserData()
|
||||
{
|
||||
return m_userData;
|
||||
}
|
||||
|
||||
inline void b2Joint::SetUserData(void* data)
|
||||
{
|
||||
m_userData = data;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2MouseJoint.h"
|
||||
#include "../b2Body.h"
|
||||
#include "../b2World.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)
|
||||
{
|
||||
m_target = def->target;
|
||||
m_localAnchor = b2MulT(m_body2->GetXForm(), m_target);
|
||||
|
||||
m_maxForce = B2FORCE_INV_SCALE(def->maxForce);
|
||||
m_impulse.SetZero();
|
||||
|
||||
float32 mass = m_body2->m_mass;
|
||||
|
||||
// Frequency
|
||||
float32 omega = 2.0f * b2_pi * def->frequencyHz;
|
||||
|
||||
// Damping coefficient
|
||||
float32 d = 2.0f * mass * def->dampingRatio * omega;
|
||||
|
||||
// Spring stiffness
|
||||
float32 k = (def->timeStep * mass) * (omega * omega);
|
||||
|
||||
// magic formulas
|
||||
b2Assert(d + k > B2_FLT_EPSILON);
|
||||
m_gamma = 1.0f / (d + k);
|
||||
m_beta = k / (d + k);
|
||||
}
|
||||
|
||||
void b2MouseJoint::SetTarget(const b2Vec2& target)
|
||||
{
|
||||
if (m_body2->IsSleeping())
|
||||
{
|
||||
m_body2->WakeUp();
|
||||
}
|
||||
m_target = target;
|
||||
}
|
||||
|
||||
void b2MouseJoint::InitVelocityConstraints(const b2TimeStep& step)
|
||||
{
|
||||
b2Body* b = m_body2;
|
||||
|
||||
// Compute the effective mass matrix.
|
||||
b2Vec2 r = b2Mul(b->GetXForm().R, m_localAnchor - b->GetLocalCenter());
|
||||
|
||||
// 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]
|
||||
float32 invMass = b->m_invMass;
|
||||
float32 invI = b->m_invI;
|
||||
|
||||
b2Mat22 K1;
|
||||
K1.col1.x = invMass; K1.col2.x = 0.0f;
|
||||
K1.col1.y = 0.0f; K1.col2.y = invMass;
|
||||
|
||||
b2Mat22 K2;
|
||||
K2.col1.x = invI * r.y * r.y; K2.col2.x = -invI * r.x * r.y;
|
||||
K2.col1.y = -invI * r.x * r.y; K2.col2.y = invI * r.x * r.x;
|
||||
|
||||
b2Mat22 K = K1 + K2;
|
||||
K.col1.x += m_gamma;
|
||||
K.col2.y += m_gamma;
|
||||
|
||||
m_mass = K.Invert();
|
||||
|
||||
m_C = b->m_sweep.c + r - m_target;
|
||||
|
||||
// Cheat with some damping
|
||||
b->m_angularVelocity *= 0.98f;
|
||||
|
||||
// Warm starting.
|
||||
b2Vec2 P = B2FORCE_SCALE(step.dt) * m_impulse;
|
||||
b->m_linearVelocity += invMass * P;
|
||||
b->m_angularVelocity += invI * b2Cross(r, P);
|
||||
}
|
||||
|
||||
void b2MouseJoint::SolveVelocityConstraints(const b2TimeStep& step)
|
||||
{
|
||||
b2Body* b = m_body2;
|
||||
|
||||
b2Vec2 r = b2Mul(b->GetXForm().R, m_localAnchor - b->GetLocalCenter());
|
||||
|
||||
// Cdot = v + cross(w, r)
|
||||
b2Vec2 Cdot = b->m_linearVelocity + b2Cross(b->m_angularVelocity, r);
|
||||
b2Vec2 force = -B2FORCE_INV_SCALE(step.inv_dt) * b2Mul(m_mass, Cdot + (m_beta * step.inv_dt) * m_C + B2FORCE_SCALE(step.dt) * (m_gamma * m_impulse));
|
||||
|
||||
b2Vec2 oldForce = m_impulse;
|
||||
m_impulse += force;
|
||||
float32 forceMagnitude = m_impulse.Length();
|
||||
if (forceMagnitude > m_maxForce)
|
||||
{
|
||||
m_impulse *= m_maxForce / forceMagnitude;
|
||||
}
|
||||
force = m_impulse - oldForce;
|
||||
|
||||
b2Vec2 P = B2FORCE_SCALE(step.dt) * force;
|
||||
b->m_linearVelocity += b->m_invMass * P;
|
||||
b->m_angularVelocity += b->m_invI * b2Cross(r, P);
|
||||
}
|
||||
|
||||
b2Vec2 b2MouseJoint::GetAnchor1() const
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
|
||||
b2Vec2 b2MouseJoint::GetAnchor2() const
|
||||
{
|
||||
return m_body2->GetWorldPoint(m_localAnchor);
|
||||
}
|
||||
|
||||
b2Vec2 b2MouseJoint::GetReactionForce() const
|
||||
{
|
||||
return B2FORCE_SCALE(float32(1.0))*m_impulse;
|
||||
}
|
||||
|
||||
float32 b2MouseJoint::GetReactionTorque() const
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_MOUSE_JOINT_H
|
||||
#define B2_MOUSE_JOINT_H
|
||||
|
||||
#include "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;
|
||||
timeStep = 1.0f / 60.0f;
|
||||
}
|
||||
|
||||
/// 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;
|
||||
|
||||
/// The time step used in the simulation.
|
||||
float32 timeStep;
|
||||
};
|
||||
|
||||
/// 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.
|
||||
class b2MouseJoint : public b2Joint
|
||||
{
|
||||
public:
|
||||
|
||||
/// Implements b2Joint.
|
||||
b2Vec2 GetAnchor1() const;
|
||||
|
||||
/// Implements b2Joint.
|
||||
b2Vec2 GetAnchor2() const;
|
||||
|
||||
/// Implements b2Joint.
|
||||
b2Vec2 GetReactionForce() const;
|
||||
|
||||
/// Implements b2Joint.
|
||||
float32 GetReactionTorque() const;
|
||||
|
||||
/// Use this to update the target point.
|
||||
void SetTarget(const b2Vec2& target);
|
||||
|
||||
//--------------- Internals Below -------------------
|
||||
|
||||
b2MouseJoint(const b2MouseJointDef* def);
|
||||
|
||||
void InitVelocityConstraints(const b2TimeStep& step);
|
||||
void SolveVelocityConstraints(const b2TimeStep& step);
|
||||
bool SolvePositionConstraints()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
b2Vec2 m_localAnchor;
|
||||
b2Vec2 m_target;
|
||||
b2Vec2 m_impulse;
|
||||
|
||||
b2Mat22 m_mass; // effective mass for point-to-point constraint.
|
||||
b2Vec2 m_C; // position error
|
||||
float32 m_maxForce;
|
||||
float32 m_beta; // bias factor
|
||||
float32 m_gamma; // softness
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2PrismaticJoint.h"
|
||||
#include "../b2Body.h"
|
||||
#include "../b2World.h"
|
||||
|
||||
// Linear constraint (point-to-line)
|
||||
// d = p2 - p1 = x2 + r2 - x1 - r1
|
||||
// C = dot(ay1, d)
|
||||
// Cdot = dot(d, cross(w1, ay1)) + dot(ay1, v2 + cross(w2, r2) - v1 - cross(w1, r1))
|
||||
// = -dot(ay1, v1) - dot(cross(d + r1, ay1), w1) + dot(ay1, v2) + dot(cross(r2, ay1), v2)
|
||||
// J = [-ay1 -cross(d+r1,ay1) ay1 cross(r2,ay1)]
|
||||
//
|
||||
// Angular constraint
|
||||
// C = a2 - a1 + a_initial
|
||||
// Cdot = w2 - w1
|
||||
// J = [0 0 -1 0 0 1]
|
||||
|
||||
// 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)]
|
||||
|
||||
void b2PrismaticJointDef::Initialize(b2Body* b1, b2Body* b2, const b2Vec2& anchor, const b2Vec2& axis)
|
||||
{
|
||||
body1 = b1;
|
||||
body2 = b2;
|
||||
localAnchor1 = body1->GetLocalPoint(anchor);
|
||||
localAnchor2 = body2->GetLocalPoint(anchor);
|
||||
localAxis1 = body1->GetLocalVector(axis);
|
||||
referenceAngle = body2->GetAngle() - body1->GetAngle();
|
||||
}
|
||||
|
||||
b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def)
|
||||
: b2Joint(def)
|
||||
{
|
||||
m_localAnchor1 = def->localAnchor1;
|
||||
m_localAnchor2 = def->localAnchor2;
|
||||
m_localXAxis1 = def->localAxis1;
|
||||
m_localYAxis1 = b2Cross(1.0f, m_localXAxis1);
|
||||
m_refAngle = def->referenceAngle;
|
||||
|
||||
m_linearJacobian.SetZero();
|
||||
m_linearMass = 0.0f;
|
||||
m_force = 0.0f;
|
||||
|
||||
m_angularMass = 0.0f;
|
||||
m_torque = 0.0f;
|
||||
|
||||
m_motorJacobian.SetZero();
|
||||
m_motorMass = 0.0;
|
||||
m_motorForce = 0.0f;
|
||||
m_limitForce = 0.0f;
|
||||
m_limitPositionImpulse = 0.0f;
|
||||
|
||||
m_lowerTranslation = def->lowerTranslation;
|
||||
m_upperTranslation = def->upperTranslation;
|
||||
m_maxMotorForce = B2FORCE_INV_SCALE(def->maxMotorForce);
|
||||
m_motorSpeed = def->motorSpeed;
|
||||
m_enableLimit = def->enableLimit;
|
||||
m_enableMotor = def->enableMotor;
|
||||
}
|
||||
|
||||
void b2PrismaticJoint::InitVelocityConstraints(const b2TimeStep& step)
|
||||
{
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
// Compute the effective masses.
|
||||
b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
|
||||
b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
|
||||
|
||||
float32 invMass1 = b1->m_invMass, invMass2 = b2->m_invMass;
|
||||
float32 invI1 = b1->m_invI, invI2 = b2->m_invI;
|
||||
|
||||
// Compute point to line constraint effective mass.
|
||||
// J = [-ay1 -cross(d+r1,ay1) ay1 cross(r2,ay1)]
|
||||
b2Vec2 ay1 = b2Mul(b1->GetXForm().R, m_localYAxis1);
|
||||
b2Vec2 e = b2->m_sweep.c + r2 - b1->m_sweep.c; // e = d + r1
|
||||
|
||||
m_linearJacobian.Set(-ay1, -b2Cross(e, ay1), ay1, b2Cross(r2, ay1));
|
||||
m_linearMass = invMass1 + invI1 * m_linearJacobian.angular1 * m_linearJacobian.angular1 +
|
||||
invMass2 + invI2 * m_linearJacobian.angular2 * m_linearJacobian.angular2;
|
||||
b2Assert(m_linearMass > B2_FLT_EPSILON);
|
||||
m_linearMass = 1.0f / m_linearMass;
|
||||
|
||||
// Compute angular constraint effective mass.
|
||||
m_angularMass = invI1 + invI2;
|
||||
if (m_angularMass > B2_FLT_EPSILON)
|
||||
{
|
||||
m_angularMass = 1.0f / m_angularMass;
|
||||
}
|
||||
|
||||
// Compute motor and limit terms.
|
||||
if (m_enableLimit || m_enableMotor)
|
||||
{
|
||||
// The motor and limit share a Jacobian and effective mass.
|
||||
b2Vec2 ax1 = b2Mul(b1->GetXForm().R, m_localXAxis1);
|
||||
m_motorJacobian.Set(-ax1, -b2Cross(e, ax1), ax1, b2Cross(r2, ax1));
|
||||
m_motorMass = invMass1 + invI1 * m_motorJacobian.angular1 * m_motorJacobian.angular1 +
|
||||
invMass2 + invI2 * m_motorJacobian.angular2 * m_motorJacobian.angular2;
|
||||
b2Assert(m_motorMass > B2_FLT_EPSILON);
|
||||
m_motorMass = 1.0f / m_motorMass;
|
||||
|
||||
if (m_enableLimit)
|
||||
{
|
||||
b2Vec2 d = e - r1; // p2 - p1
|
||||
float32 jointTranslation = b2Dot(ax1, 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_limitForce = 0.0f;
|
||||
}
|
||||
m_limitState = e_atLowerLimit;
|
||||
}
|
||||
else if (jointTranslation >= m_upperTranslation)
|
||||
{
|
||||
if (m_limitState != e_atUpperLimit)
|
||||
{
|
||||
m_limitForce = 0.0f;
|
||||
}
|
||||
m_limitState = e_atUpperLimit;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_limitState = e_inactiveLimit;
|
||||
m_limitForce = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_enableMotor == false)
|
||||
{
|
||||
m_motorForce = 0.0f;
|
||||
}
|
||||
|
||||
if (m_enableLimit == false)
|
||||
{
|
||||
m_limitForce = 0.0f;
|
||||
}
|
||||
|
||||
if (step.warmStarting)
|
||||
{
|
||||
b2Vec2 P1 = B2FORCE_SCALE(step.dt) * (m_force * m_linearJacobian.linear1 + (m_motorForce + m_limitForce) * m_motorJacobian.linear1);
|
||||
b2Vec2 P2 = B2FORCE_SCALE(step.dt) * (m_force * m_linearJacobian.linear2 + (m_motorForce + m_limitForce) * m_motorJacobian.linear2);
|
||||
float32 L1 = B2FORCE_SCALE(step.dt) * (m_force * m_linearJacobian.angular1 - m_torque + (m_motorForce + m_limitForce) * m_motorJacobian.angular1);
|
||||
float32 L2 = B2FORCE_SCALE(step.dt) * (m_force * m_linearJacobian.angular2 + m_torque + (m_motorForce + m_limitForce) * m_motorJacobian.angular2);
|
||||
|
||||
b1->m_linearVelocity += invMass1 * P1;
|
||||
b1->m_angularVelocity += invI1 * L1;
|
||||
|
||||
b2->m_linearVelocity += invMass2 * P2;
|
||||
b2->m_angularVelocity += invI2 * L2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_force = 0.0f;
|
||||
m_torque = 0.0f;
|
||||
m_limitForce = 0.0f;
|
||||
m_motorForce = 0.0f;
|
||||
}
|
||||
|
||||
m_limitPositionImpulse = 0.0f;
|
||||
}
|
||||
|
||||
void b2PrismaticJoint::SolveVelocityConstraints(const b2TimeStep& step)
|
||||
{
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
float32 invMass1 = b1->m_invMass, invMass2 = b2->m_invMass;
|
||||
float32 invI1 = b1->m_invI, invI2 = b2->m_invI;
|
||||
|
||||
// Solve linear constraint.
|
||||
float32 linearCdot = m_linearJacobian.Compute(b1->m_linearVelocity, b1->m_angularVelocity, b2->m_linearVelocity, b2->m_angularVelocity);
|
||||
float32 force = -B2FORCE_INV_SCALE(step.inv_dt) * m_linearMass * linearCdot;
|
||||
m_force += force;
|
||||
|
||||
float32 P = B2FORCE_SCALE(step.dt) * force;
|
||||
b1->m_linearVelocity += (invMass1 * P) * m_linearJacobian.linear1;
|
||||
b1->m_angularVelocity += invI1 * P * m_linearJacobian.angular1;
|
||||
|
||||
b2->m_linearVelocity += (invMass2 * P) * m_linearJacobian.linear2;
|
||||
b2->m_angularVelocity += invI2 * P * m_linearJacobian.angular2;
|
||||
|
||||
// Solve angular constraint.
|
||||
float32 angularCdot = b2->m_angularVelocity - b1->m_angularVelocity;
|
||||
float32 torque = -B2FORCE_INV_SCALE(step.inv_dt) * m_angularMass * angularCdot;
|
||||
m_torque += torque;
|
||||
|
||||
float32 L = B2FORCE_SCALE(step.dt) * torque;
|
||||
b1->m_angularVelocity -= invI1 * L;
|
||||
b2->m_angularVelocity += invI2 * L;
|
||||
|
||||
// Solve linear motor constraint.
|
||||
if (m_enableMotor && m_limitState != e_equalLimits)
|
||||
{
|
||||
float32 motorCdot = m_motorJacobian.Compute(b1->m_linearVelocity, b1->m_angularVelocity, b2->m_linearVelocity, b2->m_angularVelocity) - m_motorSpeed;
|
||||
float32 motorForce = -B2FORCE_INV_SCALE(step.inv_dt) * m_motorMass * motorCdot;
|
||||
float32 oldMotorForce = m_motorForce;
|
||||
m_motorForce = b2Clamp(m_motorForce + motorForce, -m_maxMotorForce, m_maxMotorForce);
|
||||
motorForce = m_motorForce - oldMotorForce;
|
||||
|
||||
float32 P = B2FORCE_SCALE(step.dt) * motorForce;
|
||||
b1->m_linearVelocity += (invMass1 * P) * m_motorJacobian.linear1;
|
||||
b1->m_angularVelocity += invI1 * P * m_motorJacobian.angular1;
|
||||
|
||||
b2->m_linearVelocity += (invMass2 * P) * m_motorJacobian.linear2;
|
||||
b2->m_angularVelocity += invI2 * P * m_motorJacobian.angular2;
|
||||
}
|
||||
|
||||
// Solve linear limit constraint.
|
||||
if (m_enableLimit && m_limitState != e_inactiveLimit)
|
||||
{
|
||||
float32 limitCdot = m_motorJacobian.Compute(b1->m_linearVelocity, b1->m_angularVelocity, b2->m_linearVelocity, b2->m_angularVelocity);
|
||||
float32 limitForce = -B2FORCE_INV_SCALE(step.inv_dt) * m_motorMass * limitCdot;
|
||||
|
||||
if (m_limitState == e_equalLimits)
|
||||
{
|
||||
m_limitForce += limitForce;
|
||||
}
|
||||
else if (m_limitState == e_atLowerLimit)
|
||||
{
|
||||
float32 oldLimitForce = m_limitForce;
|
||||
m_limitForce = b2Max(m_limitForce + limitForce, 0.0f);
|
||||
limitForce = m_limitForce - oldLimitForce;
|
||||
}
|
||||
else if (m_limitState == e_atUpperLimit)
|
||||
{
|
||||
float32 oldLimitForce = m_limitForce;
|
||||
m_limitForce = b2Min(m_limitForce + limitForce, 0.0f);
|
||||
limitForce = m_limitForce - oldLimitForce;
|
||||
}
|
||||
|
||||
float32 P = B2FORCE_SCALE(step.dt) * limitForce;
|
||||
|
||||
b1->m_linearVelocity += (invMass1 * P) * m_motorJacobian.linear1;
|
||||
b1->m_angularVelocity += invI1 * P * m_motorJacobian.angular1;
|
||||
|
||||
b2->m_linearVelocity += (invMass2 * P) * m_motorJacobian.linear2;
|
||||
b2->m_angularVelocity += invI2 * P * m_motorJacobian.angular2;
|
||||
}
|
||||
}
|
||||
|
||||
bool b2PrismaticJoint::SolvePositionConstraints()
|
||||
{
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
float32 invMass1 = b1->m_invMass, invMass2 = b2->m_invMass;
|
||||
float32 invI1 = b1->m_invI, invI2 = b2->m_invI;
|
||||
|
||||
b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
|
||||
b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
|
||||
b2Vec2 p1 = b1->m_sweep.c + r1;
|
||||
b2Vec2 p2 = b2->m_sweep.c + r2;
|
||||
b2Vec2 d = p2 - p1;
|
||||
b2Vec2 ay1 = b2Mul(b1->GetXForm().R, m_localYAxis1);
|
||||
|
||||
// Solve linear (point-to-line) constraint.
|
||||
float32 linearC = b2Dot(ay1, d);
|
||||
// Prevent overly large corrections.
|
||||
linearC = b2Clamp(linearC, -b2_maxLinearCorrection, b2_maxLinearCorrection);
|
||||
float32 linearImpulse = -m_linearMass * linearC;
|
||||
|
||||
b1->m_sweep.c += (invMass1 * linearImpulse) * m_linearJacobian.linear1;
|
||||
b1->m_sweep.a += invI1 * linearImpulse * m_linearJacobian.angular1;
|
||||
//b1->SynchronizeTransform(); // updated by angular constraint
|
||||
b2->m_sweep.c += (invMass2 * linearImpulse) * m_linearJacobian.linear2;
|
||||
b2->m_sweep.a += invI2 * linearImpulse * m_linearJacobian.angular2;
|
||||
//b2->SynchronizeTransform(); // updated by angular constraint
|
||||
|
||||
float32 positionError = b2Abs(linearC);
|
||||
|
||||
// Solve angular constraint.
|
||||
float32 angularC = b2->m_sweep.a - b1->m_sweep.a - m_refAngle;
|
||||
// Prevent overly large corrections.
|
||||
angularC = b2Clamp(angularC, -b2_maxAngularCorrection, b2_maxAngularCorrection);
|
||||
float32 angularImpulse = -m_angularMass * angularC;
|
||||
|
||||
b1->m_sweep.a -= b1->m_invI * angularImpulse;
|
||||
b2->m_sweep.a += b2->m_invI * angularImpulse;
|
||||
|
||||
b1->SynchronizeTransform();
|
||||
b2->SynchronizeTransform();
|
||||
|
||||
float32 angularError = b2Abs(angularC);
|
||||
|
||||
// Solve linear limit constraint.
|
||||
if (m_enableLimit && m_limitState != e_inactiveLimit)
|
||||
{
|
||||
b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
|
||||
b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
|
||||
b2Vec2 p1 = b1->m_sweep.c + r1;
|
||||
b2Vec2 p2 = b2->m_sweep.c + r2;
|
||||
b2Vec2 d = p2 - p1;
|
||||
b2Vec2 ax1 = b2Mul(b1->GetXForm().R, m_localXAxis1);
|
||||
|
||||
float32 translation = b2Dot(ax1, d);
|
||||
float32 limitImpulse = 0.0f;
|
||||
|
||||
if (m_limitState == e_equalLimits)
|
||||
{
|
||||
// Prevent large angular corrections
|
||||
float32 limitC = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection);
|
||||
limitImpulse = -m_motorMass * limitC;
|
||||
positionError = b2Max(positionError, b2Abs(angularC));
|
||||
}
|
||||
else if (m_limitState == e_atLowerLimit)
|
||||
{
|
||||
float32 limitC = translation - m_lowerTranslation;
|
||||
positionError = b2Max(positionError, -limitC);
|
||||
|
||||
// Prevent large linear corrections and allow some slop.
|
||||
limitC = b2Clamp(limitC + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
|
||||
limitImpulse = -m_motorMass * limitC;
|
||||
float32 oldLimitImpulse = m_limitPositionImpulse;
|
||||
m_limitPositionImpulse = b2Max(m_limitPositionImpulse + limitImpulse, 0.0f);
|
||||
limitImpulse = m_limitPositionImpulse - oldLimitImpulse;
|
||||
}
|
||||
else if (m_limitState == e_atUpperLimit)
|
||||
{
|
||||
float32 limitC = translation - m_upperTranslation;
|
||||
positionError = b2Max(positionError, limitC);
|
||||
|
||||
// Prevent large linear corrections and allow some slop.
|
||||
limitC = b2Clamp(limitC - b2_linearSlop, 0.0f, b2_maxLinearCorrection);
|
||||
limitImpulse = -m_motorMass * limitC;
|
||||
float32 oldLimitImpulse = m_limitPositionImpulse;
|
||||
m_limitPositionImpulse = b2Min(m_limitPositionImpulse + limitImpulse, 0.0f);
|
||||
limitImpulse = m_limitPositionImpulse - oldLimitImpulse;
|
||||
}
|
||||
|
||||
b1->m_sweep.c += (invMass1 * limitImpulse) * m_motorJacobian.linear1;
|
||||
b1->m_sweep.a += invI1 * limitImpulse * m_motorJacobian.angular1;
|
||||
b2->m_sweep.c += (invMass2 * limitImpulse) * m_motorJacobian.linear2;
|
||||
b2->m_sweep.a += invI2 * limitImpulse * m_motorJacobian.angular2;
|
||||
|
||||
b1->SynchronizeTransform();
|
||||
b2->SynchronizeTransform();
|
||||
}
|
||||
|
||||
return positionError <= b2_linearSlop && angularError <= b2_angularSlop;
|
||||
}
|
||||
|
||||
b2Vec2 b2PrismaticJoint::GetAnchor1() const
|
||||
{
|
||||
return m_body1->GetWorldPoint(m_localAnchor1);
|
||||
}
|
||||
|
||||
b2Vec2 b2PrismaticJoint::GetAnchor2() const
|
||||
{
|
||||
return m_body2->GetWorldPoint(m_localAnchor2);
|
||||
}
|
||||
|
||||
b2Vec2 b2PrismaticJoint::GetReactionForce() const
|
||||
{
|
||||
b2Vec2 ax1 = b2Mul(m_body1->GetXForm().R, m_localXAxis1);
|
||||
b2Vec2 ay1 = b2Mul(m_body1->GetXForm().R, m_localYAxis1);
|
||||
|
||||
return B2FORCE_SCALE(float32(1.0))*(m_limitForce * ax1 + m_force * ay1);
|
||||
}
|
||||
|
||||
float32 b2PrismaticJoint::GetReactionTorque() const
|
||||
{
|
||||
return B2FORCE_SCALE(m_torque);
|
||||
}
|
||||
|
||||
float32 b2PrismaticJoint::GetJointTranslation() const
|
||||
{
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
b2Vec2 p1 = b1->GetWorldPoint(m_localAnchor1);
|
||||
b2Vec2 p2 = b2->GetWorldPoint(m_localAnchor2);
|
||||
b2Vec2 d = p2 - p1;
|
||||
b2Vec2 axis = b1->GetWorldVector(m_localXAxis1);
|
||||
|
||||
float32 translation = b2Dot(d, axis);
|
||||
return translation;
|
||||
}
|
||||
|
||||
float32 b2PrismaticJoint::GetJointSpeed() const
|
||||
{
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
|
||||
b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
|
||||
b2Vec2 p1 = b1->m_sweep.c + r1;
|
||||
b2Vec2 p2 = b2->m_sweep.c + r2;
|
||||
b2Vec2 d = p2 - p1;
|
||||
b2Vec2 axis = b1->GetWorldVector(m_localXAxis1);
|
||||
|
||||
b2Vec2 v1 = b1->m_linearVelocity;
|
||||
b2Vec2 v2 = b2->m_linearVelocity;
|
||||
float32 w1 = b1->m_angularVelocity;
|
||||
float32 w2 = b2->m_angularVelocity;
|
||||
|
||||
float32 speed = b2Dot(d, b2Cross(w1, axis)) + b2Dot(axis, v2 + b2Cross(w2, r2) - v1 - b2Cross(w1, r1));
|
||||
return speed;
|
||||
}
|
||||
|
||||
bool b2PrismaticJoint::IsLimitEnabled() const
|
||||
{
|
||||
return m_enableLimit;
|
||||
}
|
||||
|
||||
void b2PrismaticJoint::EnableLimit(bool flag)
|
||||
{
|
||||
m_enableLimit = flag;
|
||||
}
|
||||
|
||||
float32 b2PrismaticJoint::GetLowerLimit() const
|
||||
{
|
||||
return m_lowerTranslation;
|
||||
}
|
||||
|
||||
float32 b2PrismaticJoint::GetUpperLimit() const
|
||||
{
|
||||
return m_upperTranslation;
|
||||
}
|
||||
|
||||
void b2PrismaticJoint::SetLimits(float32 lower, float32 upper)
|
||||
{
|
||||
b2Assert(lower <= upper);
|
||||
m_lowerTranslation = lower;
|
||||
m_upperTranslation = upper;
|
||||
}
|
||||
|
||||
bool b2PrismaticJoint::IsMotorEnabled() const
|
||||
{
|
||||
return m_enableMotor;
|
||||
}
|
||||
|
||||
void b2PrismaticJoint::EnableMotor(bool flag)
|
||||
{
|
||||
m_enableMotor = flag;
|
||||
}
|
||||
|
||||
void b2PrismaticJoint::SetMotorSpeed(float32 speed)
|
||||
{
|
||||
m_motorSpeed = speed;
|
||||
}
|
||||
|
||||
void b2PrismaticJoint::SetMaxMotorForce(float32 force)
|
||||
{
|
||||
m_maxMotorForce = B2FORCE_SCALE(float32(1.0))*force;
|
||||
}
|
||||
|
||||
float32 b2PrismaticJoint::GetMotorForce() const
|
||||
{
|
||||
return m_motorForce;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_PRISMATIC_JOINT_H
|
||||
#define B2_PRISMATIC_JOINT_H
|
||||
|
||||
#include "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;
|
||||
localAnchor1.SetZero();
|
||||
localAnchor2.SetZero();
|
||||
localAxis1.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 world axis.
|
||||
void Initialize(b2Body* body1, b2Body* body2, const b2Vec2& anchor, const b2Vec2& axis);
|
||||
|
||||
/// The local anchor point relative to body1's origin.
|
||||
b2Vec2 localAnchor1;
|
||||
|
||||
/// The local anchor point relative to body2's origin.
|
||||
b2Vec2 localAnchor2;
|
||||
|
||||
/// The local translation axis in body1.
|
||||
b2Vec2 localAxis1;
|
||||
|
||||
/// The constrained angle between the bodies: body2_angle - body1_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 body1. 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 GetAnchor1() const;
|
||||
b2Vec2 GetAnchor2() const;
|
||||
|
||||
b2Vec2 GetReactionForce() const;
|
||||
float32 GetReactionTorque() const;
|
||||
|
||||
/// 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);
|
||||
|
||||
/// Get the current motor force, usually in N.
|
||||
float32 GetMotorForce() const;
|
||||
|
||||
//--------------- Internals Below -------------------
|
||||
|
||||
b2PrismaticJoint(const b2PrismaticJointDef* def);
|
||||
|
||||
void InitVelocityConstraints(const b2TimeStep& step);
|
||||
void SolveVelocityConstraints(const b2TimeStep& step);
|
||||
bool SolvePositionConstraints();
|
||||
|
||||
b2Vec2 m_localAnchor1;
|
||||
b2Vec2 m_localAnchor2;
|
||||
b2Vec2 m_localXAxis1;
|
||||
b2Vec2 m_localYAxis1;
|
||||
float32 m_refAngle;
|
||||
|
||||
b2Jacobian m_linearJacobian;
|
||||
float32 m_linearMass; // effective mass for point-to-line constraint.
|
||||
float32 m_force;
|
||||
|
||||
float32 m_angularMass; // effective mass for angular constraint.
|
||||
float32 m_torque;
|
||||
|
||||
b2Jacobian m_motorJacobian;
|
||||
float32 m_motorMass; // effective mass for motor/limit translational constraint.
|
||||
float32 m_motorForce;
|
||||
float32 m_limitForce;
|
||||
float32 m_limitPositionImpulse;
|
||||
|
||||
float32 m_lowerTranslation;
|
||||
float32 m_upperTranslation;
|
||||
float32 m_maxMotorForce;
|
||||
float32 m_motorSpeed;
|
||||
|
||||
bool m_enableLimit;
|
||||
bool m_enableMotor;
|
||||
b2LimitState m_limitState;
|
||||
};
|
||||
|
||||
inline float32 b2PrismaticJoint::GetMotorSpeed() const
|
||||
{
|
||||
return m_motorSpeed;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,430 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2PulleyJoint.h"
|
||||
#include "../b2Body.h"
|
||||
#include "../b2World.h"
|
||||
|
||||
// Pulley:
|
||||
// length1 = norm(p1 - s1)
|
||||
// length2 = norm(p2 - s2)
|
||||
// C0 = (length1 + ratio * length2)_initial
|
||||
// C = C0 - (length1 + ratio * length2) >= 0
|
||||
// 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)
|
||||
//
|
||||
// Limit:
|
||||
// C = maxLength - length
|
||||
// u = (p - s) / norm(p - s)
|
||||
// Cdot = -dot(u, v + cross(w, r))
|
||||
// K = invMass + invI * cross(r, u)^2
|
||||
// 0 <= impulse
|
||||
|
||||
void b2PulleyJointDef::Initialize(b2Body* b1, b2Body* b2,
|
||||
const b2Vec2& ga1, const b2Vec2& ga2,
|
||||
const b2Vec2& anchor1, const b2Vec2& anchor2,
|
||||
float32 r)
|
||||
{
|
||||
body1 = b1;
|
||||
body2 = b2;
|
||||
groundAnchor1 = ga1;
|
||||
groundAnchor2 = ga2;
|
||||
localAnchor1 = body1->GetLocalPoint(anchor1);
|
||||
localAnchor2 = body2->GetLocalPoint(anchor2);
|
||||
b2Vec2 d1 = anchor1 - ga1;
|
||||
length1 = d1.Length();
|
||||
b2Vec2 d2 = anchor2 - ga2;
|
||||
length2 = d2.Length();
|
||||
ratio = r;
|
||||
b2Assert(ratio > B2_FLT_EPSILON);
|
||||
float32 C = length1 + ratio * length2;
|
||||
maxLength1 = C - ratio * b2_minPulleyLength;
|
||||
maxLength2 = (C - b2_minPulleyLength) / ratio;
|
||||
}
|
||||
|
||||
b2PulleyJoint::b2PulleyJoint(const b2PulleyJointDef* def)
|
||||
: b2Joint(def)
|
||||
{
|
||||
m_ground = m_body1->GetWorld()->GetGroundBody();
|
||||
m_groundAnchor1 = def->groundAnchor1 - m_ground->GetXForm().position;
|
||||
m_groundAnchor2 = def->groundAnchor2 - m_ground->GetXForm().position;
|
||||
m_localAnchor1 = def->localAnchor1;
|
||||
m_localAnchor2 = def->localAnchor2;
|
||||
|
||||
b2Assert(def->ratio != 0.0f);
|
||||
m_ratio = def->ratio;
|
||||
|
||||
m_constant = def->length1 + m_ratio * def->length2;
|
||||
|
||||
m_maxLength1 = b2Min(def->maxLength1, m_constant - m_ratio * b2_minPulleyLength);
|
||||
m_maxLength2 = b2Min(def->maxLength2, (m_constant - b2_minPulleyLength) / m_ratio);
|
||||
|
||||
m_force = 0.0f;
|
||||
m_limitForce1 = 0.0f;
|
||||
m_limitForce2 = 0.0f;
|
||||
}
|
||||
|
||||
void b2PulleyJoint::InitVelocityConstraints(const b2TimeStep& step)
|
||||
{
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
|
||||
b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
|
||||
|
||||
b2Vec2 p1 = b1->m_sweep.c + r1;
|
||||
b2Vec2 p2 = b2->m_sweep.c + r2;
|
||||
|
||||
b2Vec2 s1 = m_ground->GetXForm().position + m_groundAnchor1;
|
||||
b2Vec2 s2 = m_ground->GetXForm().position + m_groundAnchor2;
|
||||
|
||||
// Get the pulley axes.
|
||||
m_u1 = p1 - s1;
|
||||
m_u2 = p2 - s2;
|
||||
|
||||
float32 length1 = m_u1.Length();
|
||||
float32 length2 = m_u2.Length();
|
||||
|
||||
if (length1 > b2_linearSlop)
|
||||
{
|
||||
m_u1 *= 1.0f / length1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_u1.SetZero();
|
||||
}
|
||||
|
||||
if (length2 > b2_linearSlop)
|
||||
{
|
||||
m_u2 *= 1.0f / length2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_u2.SetZero();
|
||||
}
|
||||
|
||||
float32 C = m_constant - length1 - m_ratio * length2;
|
||||
if (C > 0.0f)
|
||||
{
|
||||
m_state = e_inactiveLimit;
|
||||
m_force = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_state = e_atUpperLimit;
|
||||
m_positionImpulse = 0.0f;
|
||||
}
|
||||
|
||||
if (length1 < m_maxLength1)
|
||||
{
|
||||
m_limitState1 = e_inactiveLimit;
|
||||
m_limitForce1 = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_limitState1 = e_atUpperLimit;
|
||||
m_limitPositionImpulse1 = 0.0f;
|
||||
}
|
||||
|
||||
if (length2 < m_maxLength2)
|
||||
{
|
||||
m_limitState2 = e_inactiveLimit;
|
||||
m_limitForce2 = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_limitState2 = e_atUpperLimit;
|
||||
m_limitPositionImpulse2 = 0.0f;
|
||||
}
|
||||
|
||||
// Compute effective mass.
|
||||
float32 cr1u1 = b2Cross(r1, m_u1);
|
||||
float32 cr2u2 = b2Cross(r2, m_u2);
|
||||
|
||||
m_limitMass1 = b1->m_invMass + b1->m_invI * cr1u1 * cr1u1;
|
||||
m_limitMass2 = b2->m_invMass + b2->m_invI * cr2u2 * cr2u2;
|
||||
m_pulleyMass = m_limitMass1 + m_ratio * m_ratio * m_limitMass2;
|
||||
b2Assert(m_limitMass1 > B2_FLT_EPSILON);
|
||||
b2Assert(m_limitMass2 > B2_FLT_EPSILON);
|
||||
b2Assert(m_pulleyMass > B2_FLT_EPSILON);
|
||||
m_limitMass1 = 1.0f / m_limitMass1;
|
||||
m_limitMass2 = 1.0f / m_limitMass2;
|
||||
m_pulleyMass = 1.0f / m_pulleyMass;
|
||||
|
||||
if (step.warmStarting)
|
||||
{
|
||||
// Warm starting.
|
||||
b2Vec2 P1 = B2FORCE_SCALE(step.dt) * (-m_force - m_limitForce1) * m_u1;
|
||||
b2Vec2 P2 = B2FORCE_SCALE(step.dt) * (-m_ratio * m_force - m_limitForce2) * m_u2;
|
||||
b1->m_linearVelocity += b1->m_invMass * P1;
|
||||
b1->m_angularVelocity += b1->m_invI * b2Cross(r1, P1);
|
||||
b2->m_linearVelocity += b2->m_invMass * P2;
|
||||
b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P2);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_force = 0.0f;
|
||||
m_limitForce1 = 0.0f;
|
||||
m_limitForce2 = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void b2PulleyJoint::SolveVelocityConstraints(const b2TimeStep& step)
|
||||
{
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
|
||||
b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
|
||||
|
||||
if (m_state == e_atUpperLimit)
|
||||
{
|
||||
b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1);
|
||||
b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2);
|
||||
|
||||
float32 Cdot = -b2Dot(m_u1, v1) - m_ratio * b2Dot(m_u2, v2);
|
||||
float32 force = -B2FORCE_INV_SCALE(step.inv_dt) * m_pulleyMass * Cdot;
|
||||
float32 oldForce = m_force;
|
||||
m_force = b2Max(0.0f, m_force + force);
|
||||
force = m_force - oldForce;
|
||||
|
||||
b2Vec2 P1 = -B2FORCE_SCALE(step.dt) * force * m_u1;
|
||||
b2Vec2 P2 = -B2FORCE_SCALE(step.dt) * m_ratio * force * m_u2;
|
||||
b1->m_linearVelocity += b1->m_invMass * P1;
|
||||
b1->m_angularVelocity += b1->m_invI * b2Cross(r1, P1);
|
||||
b2->m_linearVelocity += b2->m_invMass * P2;
|
||||
b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P2);
|
||||
}
|
||||
|
||||
if (m_limitState1 == e_atUpperLimit)
|
||||
{
|
||||
b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1);
|
||||
|
||||
float32 Cdot = -b2Dot(m_u1, v1);
|
||||
float32 force = -B2FORCE_INV_SCALE(step.inv_dt) * m_limitMass1 * Cdot;
|
||||
float32 oldForce = m_limitForce1;
|
||||
m_limitForce1 = b2Max(0.0f, m_limitForce1 + force);
|
||||
force = m_limitForce1 - oldForce;
|
||||
|
||||
b2Vec2 P1 = -B2FORCE_SCALE(step.dt) * force * m_u1;
|
||||
b1->m_linearVelocity += b1->m_invMass * P1;
|
||||
b1->m_angularVelocity += b1->m_invI * b2Cross(r1, P1);
|
||||
}
|
||||
|
||||
if (m_limitState2 == e_atUpperLimit)
|
||||
{
|
||||
b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2);
|
||||
|
||||
float32 Cdot = -b2Dot(m_u2, v2);
|
||||
float32 force = -B2FORCE_INV_SCALE(step.inv_dt) * m_limitMass2 * Cdot;
|
||||
float32 oldForce = m_limitForce2;
|
||||
m_limitForce2 = b2Max(0.0f, m_limitForce2 + force);
|
||||
force = m_limitForce2 - oldForce;
|
||||
|
||||
b2Vec2 P2 = -B2FORCE_SCALE(step.dt) * force * m_u2;
|
||||
b2->m_linearVelocity += b2->m_invMass * P2;
|
||||
b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P2);
|
||||
}
|
||||
}
|
||||
|
||||
bool b2PulleyJoint::SolvePositionConstraints()
|
||||
{
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
b2Vec2 s1 = m_ground->GetXForm().position + m_groundAnchor1;
|
||||
b2Vec2 s2 = m_ground->GetXForm().position + m_groundAnchor2;
|
||||
|
||||
float32 linearError = 0.0f;
|
||||
|
||||
if (m_state == e_atUpperLimit)
|
||||
{
|
||||
b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
|
||||
b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
|
||||
|
||||
b2Vec2 p1 = b1->m_sweep.c + r1;
|
||||
b2Vec2 p2 = b2->m_sweep.c + r2;
|
||||
|
||||
// Get the pulley axes.
|
||||
m_u1 = p1 - s1;
|
||||
m_u2 = p2 - s2;
|
||||
|
||||
float32 length1 = m_u1.Length();
|
||||
float32 length2 = m_u2.Length();
|
||||
|
||||
if (length1 > b2_linearSlop)
|
||||
{
|
||||
m_u1 *= 1.0f / length1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_u1.SetZero();
|
||||
}
|
||||
|
||||
if (length2 > b2_linearSlop)
|
||||
{
|
||||
m_u2 *= 1.0f / length2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_u2.SetZero();
|
||||
}
|
||||
|
||||
float32 C = m_constant - length1 - m_ratio * length2;
|
||||
linearError = b2Max(linearError, -C);
|
||||
|
||||
C = b2Clamp(C + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
|
||||
float32 impulse = -m_pulleyMass * C;
|
||||
float32 oldImpulse = m_positionImpulse;
|
||||
m_positionImpulse = b2Max(0.0f, m_positionImpulse + impulse);
|
||||
impulse = m_positionImpulse - oldImpulse;
|
||||
|
||||
b2Vec2 P1 = -impulse * m_u1;
|
||||
b2Vec2 P2 = -m_ratio * impulse * m_u2;
|
||||
|
||||
b1->m_sweep.c += b1->m_invMass * P1;
|
||||
b1->m_sweep.a += b1->m_invI * b2Cross(r1, P1);
|
||||
b2->m_sweep.c += b2->m_invMass * P2;
|
||||
b2->m_sweep.a += b2->m_invI * b2Cross(r2, P2);
|
||||
|
||||
b1->SynchronizeTransform();
|
||||
b2->SynchronizeTransform();
|
||||
}
|
||||
|
||||
if (m_limitState1 == e_atUpperLimit)
|
||||
{
|
||||
b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
|
||||
b2Vec2 p1 = b1->m_sweep.c + r1;
|
||||
|
||||
m_u1 = p1 - s1;
|
||||
float32 length1 = m_u1.Length();
|
||||
|
||||
if (length1 > b2_linearSlop)
|
||||
{
|
||||
m_u1 *= 1.0f / length1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_u1.SetZero();
|
||||
}
|
||||
|
||||
float32 C = m_maxLength1 - length1;
|
||||
linearError = b2Max(linearError, -C);
|
||||
C = b2Clamp(C + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
|
||||
float32 impulse = -m_limitMass1 * C;
|
||||
float32 oldLimitPositionImpulse = m_limitPositionImpulse1;
|
||||
m_limitPositionImpulse1 = b2Max(0.0f, m_limitPositionImpulse1 + impulse);
|
||||
impulse = m_limitPositionImpulse1 - oldLimitPositionImpulse;
|
||||
|
||||
b2Vec2 P1 = -impulse * m_u1;
|
||||
b1->m_sweep.c += b1->m_invMass * P1;
|
||||
b1->m_sweep.a += b1->m_invI * b2Cross(r1, P1);
|
||||
|
||||
b1->SynchronizeTransform();
|
||||
}
|
||||
|
||||
if (m_limitState2 == e_atUpperLimit)
|
||||
{
|
||||
b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
|
||||
b2Vec2 p2 = b2->m_sweep.c + r2;
|
||||
|
||||
m_u2 = p2 - s2;
|
||||
float32 length2 = m_u2.Length();
|
||||
|
||||
if (length2 > b2_linearSlop)
|
||||
{
|
||||
m_u2 *= 1.0f / length2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_u2.SetZero();
|
||||
}
|
||||
|
||||
float32 C = m_maxLength2 - length2;
|
||||
linearError = b2Max(linearError, -C);
|
||||
C = b2Clamp(C + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
|
||||
float32 impulse = -m_limitMass2 * C;
|
||||
float32 oldLimitPositionImpulse = m_limitPositionImpulse2;
|
||||
m_limitPositionImpulse2 = b2Max(0.0f, m_limitPositionImpulse2 + impulse);
|
||||
impulse = m_limitPositionImpulse2 - oldLimitPositionImpulse;
|
||||
|
||||
b2Vec2 P2 = -impulse * m_u2;
|
||||
b2->m_sweep.c += b2->m_invMass * P2;
|
||||
b2->m_sweep.a += b2->m_invI * b2Cross(r2, P2);
|
||||
|
||||
b2->SynchronizeTransform();
|
||||
}
|
||||
|
||||
return linearError < b2_linearSlop;
|
||||
}
|
||||
|
||||
b2Vec2 b2PulleyJoint::GetAnchor1() const
|
||||
{
|
||||
return m_body1->GetWorldPoint(m_localAnchor1);
|
||||
}
|
||||
|
||||
b2Vec2 b2PulleyJoint::GetAnchor2() const
|
||||
{
|
||||
return m_body2->GetWorldPoint(m_localAnchor2);
|
||||
}
|
||||
|
||||
b2Vec2 b2PulleyJoint::GetReactionForce() const
|
||||
{
|
||||
b2Vec2 F = B2FORCE_SCALE(m_force) * m_u2;
|
||||
return F;
|
||||
}
|
||||
|
||||
float32 b2PulleyJoint::GetReactionTorque() const
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
b2Vec2 b2PulleyJoint::GetGroundAnchor1() const
|
||||
{
|
||||
return m_ground->GetXForm().position + m_groundAnchor1;
|
||||
}
|
||||
|
||||
b2Vec2 b2PulleyJoint::GetGroundAnchor2() const
|
||||
{
|
||||
return m_ground->GetXForm().position + m_groundAnchor2;
|
||||
}
|
||||
|
||||
float32 b2PulleyJoint::GetLength1() const
|
||||
{
|
||||
b2Vec2 p = m_body1->GetWorldPoint(m_localAnchor1);
|
||||
b2Vec2 s = m_ground->GetXForm().position + m_groundAnchor1;
|
||||
b2Vec2 d = p - s;
|
||||
return d.Length();
|
||||
}
|
||||
|
||||
float32 b2PulleyJoint::GetLength2() const
|
||||
{
|
||||
b2Vec2 p = m_body2->GetWorldPoint(m_localAnchor2);
|
||||
b2Vec2 s = m_ground->GetXForm().position + m_groundAnchor2;
|
||||
b2Vec2 d = p - s;
|
||||
return d.Length();
|
||||
}
|
||||
|
||||
float32 b2PulleyJoint::GetRatio() const
|
||||
{
|
||||
return m_ratio;
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_PULLEY_JOINT_H
|
||||
#define B2_PULLEY_JOINT_H
|
||||
|
||||
#include "b2Joint.h"
|
||||
|
||||
const float32 b2_minPulleyLength = 2.0f;
|
||||
|
||||
/// Pulley joint definition. This requires two ground anchors,
|
||||
/// two dynamic body anchor points, max lengths for each side,
|
||||
/// and a pulley ratio.
|
||||
struct b2PulleyJointDef : public b2JointDef
|
||||
{
|
||||
b2PulleyJointDef()
|
||||
{
|
||||
type = e_pulleyJoint;
|
||||
groundAnchor1.Set(-1.0f, 1.0f);
|
||||
groundAnchor2.Set(1.0f, 1.0f);
|
||||
localAnchor1.Set(-1.0f, 0.0f);
|
||||
localAnchor2.Set(1.0f, 0.0f);
|
||||
length1 = 0.0f;
|
||||
maxLength1 = 0.0f;
|
||||
length2 = 0.0f;
|
||||
maxLength2 = 0.0f;
|
||||
ratio = 1.0f;
|
||||
collideConnected = true;
|
||||
}
|
||||
|
||||
/// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors.
|
||||
void Initialize(b2Body* body1, b2Body* body2,
|
||||
const b2Vec2& groundAnchor1, const b2Vec2& groundAnchor2,
|
||||
const b2Vec2& anchor1, const b2Vec2& anchor2,
|
||||
float32 ratio);
|
||||
|
||||
/// The first ground anchor in world coordinates. This point never moves.
|
||||
b2Vec2 groundAnchor1;
|
||||
|
||||
/// The second ground anchor in world coordinates. This point never moves.
|
||||
b2Vec2 groundAnchor2;
|
||||
|
||||
/// The local anchor point relative to body1's origin.
|
||||
b2Vec2 localAnchor1;
|
||||
|
||||
/// The local anchor point relative to body2's origin.
|
||||
b2Vec2 localAnchor2;
|
||||
|
||||
/// The a reference length for the segment attached to body1.
|
||||
float32 length1;
|
||||
|
||||
/// The maximum length of the segment attached to body1.
|
||||
float32 maxLength1;
|
||||
|
||||
/// The a reference length for the segment attached to body2.
|
||||
float32 length2;
|
||||
|
||||
/// The maximum length of the segment attached to body2.
|
||||
float32 maxLength2;
|
||||
|
||||
/// 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.
|
||||
/// The pulley also enforces a maximum length limit on both sides. This is
|
||||
/// useful to prevent one side of the pulley hitting the top.
|
||||
class b2PulleyJoint : public b2Joint
|
||||
{
|
||||
public:
|
||||
b2Vec2 GetAnchor1() const;
|
||||
b2Vec2 GetAnchor2() const;
|
||||
|
||||
b2Vec2 GetReactionForce() const;
|
||||
float32 GetReactionTorque() const;
|
||||
|
||||
/// Get the first ground anchor.
|
||||
b2Vec2 GetGroundAnchor1() const;
|
||||
|
||||
/// Get the second ground anchor.
|
||||
b2Vec2 GetGroundAnchor2() const;
|
||||
|
||||
/// Get the current length of the segment attached to body1.
|
||||
float32 GetLength1() const;
|
||||
|
||||
/// Get the current length of the segment attached to body2.
|
||||
float32 GetLength2() const;
|
||||
|
||||
/// Get the pulley ratio.
|
||||
float32 GetRatio() const;
|
||||
|
||||
//--------------- Internals Below -------------------
|
||||
|
||||
b2PulleyJoint(const b2PulleyJointDef* data);
|
||||
|
||||
void InitVelocityConstraints(const b2TimeStep& step);
|
||||
void SolveVelocityConstraints(const b2TimeStep& step);
|
||||
bool SolvePositionConstraints();
|
||||
|
||||
b2Body* m_ground;
|
||||
b2Vec2 m_groundAnchor1;
|
||||
b2Vec2 m_groundAnchor2;
|
||||
b2Vec2 m_localAnchor1;
|
||||
b2Vec2 m_localAnchor2;
|
||||
|
||||
b2Vec2 m_u1;
|
||||
b2Vec2 m_u2;
|
||||
|
||||
float32 m_constant;
|
||||
float32 m_ratio;
|
||||
|
||||
float32 m_maxLength1;
|
||||
float32 m_maxLength2;
|
||||
|
||||
// Effective masses
|
||||
float32 m_pulleyMass;
|
||||
float32 m_limitMass1;
|
||||
float32 m_limitMass2;
|
||||
|
||||
// Impulses for accumulation/warm starting.
|
||||
float32 m_force;
|
||||
float32 m_limitForce1;
|
||||
float32 m_limitForce2;
|
||||
|
||||
// Position impulses for accumulation.
|
||||
float32 m_positionImpulse;
|
||||
float32 m_limitPositionImpulse1;
|
||||
float32 m_limitPositionImpulse2;
|
||||
|
||||
b2LimitState m_state;
|
||||
b2LimitState m_limitState1;
|
||||
b2LimitState m_limitState2;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2RevoluteJoint.h"
|
||||
#include "../b2Body.h"
|
||||
#include "../b2World.h"
|
||||
|
||||
#include "../b2Island.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* b1, b2Body* b2, const b2Vec2& anchor)
|
||||
{
|
||||
body1 = b1;
|
||||
body2 = b2;
|
||||
localAnchor1 = body1->GetLocalPoint(anchor);
|
||||
localAnchor2 = body2->GetLocalPoint(anchor);
|
||||
referenceAngle = body2->GetAngle() - body1->GetAngle();
|
||||
}
|
||||
|
||||
b2RevoluteJoint::b2RevoluteJoint(const b2RevoluteJointDef* def)
|
||||
: b2Joint(def)
|
||||
{
|
||||
m_localAnchor1 = def->localAnchor1;
|
||||
m_localAnchor2 = def->localAnchor2;
|
||||
m_referenceAngle = def->referenceAngle;
|
||||
|
||||
m_pivotForce.Set(0.0f, 0.0f);
|
||||
m_motorForce = 0.0f;
|
||||
m_limitForce = 0.0f;
|
||||
m_limitPositionImpulse = 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;
|
||||
}
|
||||
|
||||
void b2RevoluteJoint::InitVelocityConstraints(const b2TimeStep& step)
|
||||
{
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
// Compute the effective mass matrix.
|
||||
b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
|
||||
b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
|
||||
|
||||
// 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]
|
||||
float32 invMass1 = b1->m_invMass, invMass2 = b2->m_invMass;
|
||||
float32 invI1 = b1->m_invI, invI2 = b2->m_invI;
|
||||
|
||||
b2Mat22 K1;
|
||||
K1.col1.x = invMass1 + invMass2; K1.col2.x = 0.0f;
|
||||
K1.col1.y = 0.0f; K1.col2.y = invMass1 + invMass2;
|
||||
|
||||
b2Mat22 K2;
|
||||
K2.col1.x = invI1 * r1.y * r1.y; K2.col2.x = -invI1 * r1.x * r1.y;
|
||||
K2.col1.y = -invI1 * r1.x * r1.y; K2.col2.y = invI1 * r1.x * r1.x;
|
||||
|
||||
b2Mat22 K3;
|
||||
K3.col1.x = invI2 * r2.y * r2.y; K3.col2.x = -invI2 * r2.x * r2.y;
|
||||
K3.col1.y = -invI2 * r2.x * r2.y; K3.col2.y = invI2 * r2.x * r2.x;
|
||||
|
||||
b2Mat22 K = K1 + K2 + K3;
|
||||
m_pivotMass = K.Invert();
|
||||
|
||||
m_motorMass = 1.0f / (invI1 + invI2);
|
||||
|
||||
if (m_enableMotor == false)
|
||||
{
|
||||
m_motorForce = 0.0f;
|
||||
}
|
||||
|
||||
if (m_enableLimit)
|
||||
{
|
||||
float32 jointAngle = b2->m_sweep.a - b1->m_sweep.a - 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_limitForce = 0.0f;
|
||||
}
|
||||
m_limitState = e_atLowerLimit;
|
||||
}
|
||||
else if (jointAngle >= m_upperAngle)
|
||||
{
|
||||
if (m_limitState != e_atUpperLimit)
|
||||
{
|
||||
m_limitForce = 0.0f;
|
||||
}
|
||||
m_limitState = e_atUpperLimit;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_limitState = e_inactiveLimit;
|
||||
m_limitForce = 0.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_limitForce = 0.0f;
|
||||
}
|
||||
|
||||
if (step.warmStarting)
|
||||
{
|
||||
b1->m_linearVelocity -= B2FORCE_SCALE(step.dt) * invMass1 * m_pivotForce;
|
||||
b1->m_angularVelocity -= B2FORCE_SCALE(step.dt) * invI1 * (b2Cross(r1, m_pivotForce) + B2FORCE_INV_SCALE(m_motorForce + m_limitForce));
|
||||
|
||||
b2->m_linearVelocity += B2FORCE_SCALE(step.dt) * invMass2 * m_pivotForce;
|
||||
b2->m_angularVelocity += B2FORCE_SCALE(step.dt) * invI2 * (b2Cross(r2, m_pivotForce) + B2FORCE_INV_SCALE(m_motorForce + m_limitForce));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pivotForce.SetZero();
|
||||
m_motorForce = 0.0f;
|
||||
m_limitForce = 0.0f;
|
||||
}
|
||||
|
||||
m_limitPositionImpulse = 0.0f;
|
||||
}
|
||||
|
||||
void b2RevoluteJoint::SolveVelocityConstraints(const b2TimeStep& step)
|
||||
{
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
|
||||
b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
|
||||
|
||||
// Solve point-to-point constraint
|
||||
b2Vec2 pivotCdot = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2) - b1->m_linearVelocity - b2Cross(b1->m_angularVelocity, r1);
|
||||
b2Vec2 pivotForce = -B2FORCE_INV_SCALE(step.inv_dt) * b2Mul(m_pivotMass, pivotCdot);
|
||||
m_pivotForce += pivotForce;
|
||||
|
||||
b2Vec2 P = B2FORCE_SCALE(step.dt) * pivotForce;
|
||||
b1->m_linearVelocity -= b1->m_invMass * P;
|
||||
b1->m_angularVelocity -= b1->m_invI * b2Cross(r1, P);
|
||||
|
||||
b2->m_linearVelocity += b2->m_invMass * P;
|
||||
b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P);
|
||||
|
||||
if (m_enableMotor && m_limitState != e_equalLimits)
|
||||
{
|
||||
float32 motorCdot = b2->m_angularVelocity - b1->m_angularVelocity - m_motorSpeed;
|
||||
float32 motorForce = -step.inv_dt * m_motorMass * motorCdot;
|
||||
float32 oldMotorForce = m_motorForce;
|
||||
m_motorForce = b2Clamp(m_motorForce + motorForce, -m_maxMotorTorque, m_maxMotorTorque);
|
||||
motorForce = m_motorForce - oldMotorForce;
|
||||
|
||||
float32 P = step.dt * motorForce;
|
||||
b1->m_angularVelocity -= b1->m_invI * P;
|
||||
b2->m_angularVelocity += b2->m_invI * P;
|
||||
}
|
||||
|
||||
if (m_enableLimit && m_limitState != e_inactiveLimit)
|
||||
{
|
||||
float32 limitCdot = b2->m_angularVelocity - b1->m_angularVelocity;
|
||||
float32 limitForce = -step.inv_dt * m_motorMass * limitCdot;
|
||||
|
||||
if (m_limitState == e_equalLimits)
|
||||
{
|
||||
m_limitForce += limitForce;
|
||||
}
|
||||
else if (m_limitState == e_atLowerLimit)
|
||||
{
|
||||
float32 oldLimitForce = m_limitForce;
|
||||
m_limitForce = b2Max(m_limitForce + limitForce, 0.0f);
|
||||
limitForce = m_limitForce - oldLimitForce;
|
||||
}
|
||||
else if (m_limitState == e_atUpperLimit)
|
||||
{
|
||||
float32 oldLimitForce = m_limitForce;
|
||||
m_limitForce = b2Min(m_limitForce + limitForce, 0.0f);
|
||||
limitForce = m_limitForce - oldLimitForce;
|
||||
}
|
||||
|
||||
float32 P = step.dt * limitForce;
|
||||
b1->m_angularVelocity -= b1->m_invI * P;
|
||||
b2->m_angularVelocity += b2->m_invI * P;
|
||||
}
|
||||
}
|
||||
|
||||
bool b2RevoluteJoint::SolvePositionConstraints()
|
||||
{
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
|
||||
float32 positionError = 0.0f;
|
||||
|
||||
// Solve point-to-point position error.
|
||||
b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
|
||||
b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
|
||||
|
||||
b2Vec2 p1 = b1->m_sweep.c + r1;
|
||||
b2Vec2 p2 = b2->m_sweep.c + r2;
|
||||
b2Vec2 ptpC = p2 - p1;
|
||||
|
||||
positionError = ptpC.Length();
|
||||
|
||||
// Prevent overly large corrections.
|
||||
//b2Vec2 dpMax(b2_maxLinearCorrection, b2_maxLinearCorrection);
|
||||
//ptpC = b2Clamp(ptpC, -dpMax, dpMax);
|
||||
|
||||
float32 invMass1 = b1->m_invMass, invMass2 = b2->m_invMass;
|
||||
float32 invI1 = b1->m_invI, invI2 = b2->m_invI;
|
||||
|
||||
b2Mat22 K1;
|
||||
K1.col1.x = invMass1 + invMass2; K1.col2.x = 0.0f;
|
||||
K1.col1.y = 0.0f; K1.col2.y = invMass1 + invMass2;
|
||||
|
||||
b2Mat22 K2;
|
||||
K2.col1.x = invI1 * r1.y * r1.y; K2.col2.x = -invI1 * r1.x * r1.y;
|
||||
K2.col1.y = -invI1 * r1.x * r1.y; K2.col2.y = invI1 * r1.x * r1.x;
|
||||
|
||||
b2Mat22 K3;
|
||||
K3.col1.x = invI2 * r2.y * r2.y; K3.col2.x = -invI2 * r2.x * r2.y;
|
||||
K3.col1.y = -invI2 * r2.x * r2.y; K3.col2.y = invI2 * r2.x * r2.x;
|
||||
|
||||
b2Mat22 K = K1 + K2 + K3;
|
||||
b2Vec2 impulse = K.Solve(-ptpC);
|
||||
|
||||
b1->m_sweep.c -= b1->m_invMass * impulse;
|
||||
b1->m_sweep.a -= b1->m_invI * b2Cross(r1, impulse);
|
||||
|
||||
b2->m_sweep.c += b2->m_invMass * impulse;
|
||||
b2->m_sweep.a += b2->m_invI * b2Cross(r2, impulse);
|
||||
|
||||
b1->SynchronizeTransform();
|
||||
b2->SynchronizeTransform();
|
||||
|
||||
// Handle limits.
|
||||
float32 angularError = 0.0f;
|
||||
|
||||
if (m_enableLimit && m_limitState != e_inactiveLimit)
|
||||
{
|
||||
float32 angle = b2->m_sweep.a - b1->m_sweep.a - m_referenceAngle;
|
||||
float32 limitImpulse = 0.0f;
|
||||
|
||||
if (m_limitState == e_equalLimits)
|
||||
{
|
||||
// Prevent large angular corrections
|
||||
float32 limitC = b2Clamp(angle, -b2_maxAngularCorrection, b2_maxAngularCorrection);
|
||||
limitImpulse = -m_motorMass * limitC;
|
||||
angularError = b2Abs(limitC);
|
||||
}
|
||||
else if (m_limitState == e_atLowerLimit)
|
||||
{
|
||||
float32 limitC = angle - m_lowerAngle;
|
||||
angularError = b2Max(0.0f, -limitC);
|
||||
|
||||
// Prevent large angular corrections and allow some slop.
|
||||
limitC = b2Clamp(limitC + b2_angularSlop, -b2_maxAngularCorrection, 0.0f);
|
||||
limitImpulse = -m_motorMass * limitC;
|
||||
float32 oldLimitImpulse = m_limitPositionImpulse;
|
||||
m_limitPositionImpulse = b2Max(m_limitPositionImpulse + limitImpulse, 0.0f);
|
||||
limitImpulse = m_limitPositionImpulse - oldLimitImpulse;
|
||||
}
|
||||
else if (m_limitState == e_atUpperLimit)
|
||||
{
|
||||
float32 limitC = angle - m_upperAngle;
|
||||
angularError = b2Max(0.0f, limitC);
|
||||
|
||||
// Prevent large angular corrections and allow some slop.
|
||||
limitC = b2Clamp(limitC - b2_angularSlop, 0.0f, b2_maxAngularCorrection);
|
||||
limitImpulse = -m_motorMass * limitC;
|
||||
float32 oldLimitImpulse = m_limitPositionImpulse;
|
||||
m_limitPositionImpulse = b2Min(m_limitPositionImpulse + limitImpulse, 0.0f);
|
||||
limitImpulse = m_limitPositionImpulse - oldLimitImpulse;
|
||||
}
|
||||
|
||||
b1->m_sweep.a -= b1->m_invI * limitImpulse;
|
||||
b2->m_sweep.a += b2->m_invI * limitImpulse;
|
||||
|
||||
b1->SynchronizeTransform();
|
||||
b2->SynchronizeTransform();
|
||||
}
|
||||
|
||||
return positionError <= b2_linearSlop && angularError <= b2_angularSlop;
|
||||
}
|
||||
|
||||
b2Vec2 b2RevoluteJoint::GetAnchor1() const
|
||||
{
|
||||
return m_body1->GetWorldPoint(m_localAnchor1);
|
||||
}
|
||||
|
||||
b2Vec2 b2RevoluteJoint::GetAnchor2() const
|
||||
{
|
||||
return m_body2->GetWorldPoint(m_localAnchor2);
|
||||
}
|
||||
|
||||
b2Vec2 b2RevoluteJoint::GetReactionForce() const
|
||||
{
|
||||
return B2FORCE_SCALE(float32(1.0))*m_pivotForce;
|
||||
}
|
||||
|
||||
float32 b2RevoluteJoint::GetReactionTorque() const
|
||||
{
|
||||
return m_limitForce;
|
||||
}
|
||||
|
||||
float32 b2RevoluteJoint::GetJointAngle() const
|
||||
{
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
return b2->m_sweep.a - b1->m_sweep.a - m_referenceAngle;
|
||||
}
|
||||
|
||||
float32 b2RevoluteJoint::GetJointSpeed() const
|
||||
{
|
||||
b2Body* b1 = m_body1;
|
||||
b2Body* b2 = m_body2;
|
||||
return b2->m_angularVelocity - b1->m_angularVelocity;
|
||||
}
|
||||
|
||||
bool b2RevoluteJoint::IsMotorEnabled() const
|
||||
{
|
||||
return m_enableMotor;
|
||||
}
|
||||
|
||||
void b2RevoluteJoint::EnableMotor(bool flag)
|
||||
{
|
||||
m_enableMotor = flag;
|
||||
}
|
||||
|
||||
float32 b2RevoluteJoint::GetMotorTorque() const
|
||||
{
|
||||
return m_motorForce;
|
||||
}
|
||||
|
||||
void b2RevoluteJoint::SetMotorSpeed(float32 speed)
|
||||
{
|
||||
m_motorSpeed = speed;
|
||||
}
|
||||
|
||||
void b2RevoluteJoint::SetMaxMotorTorque(float32 torque)
|
||||
{
|
||||
m_maxMotorTorque = torque;
|
||||
}
|
||||
|
||||
bool b2RevoluteJoint::IsLimitEnabled() const
|
||||
{
|
||||
return m_enableLimit;
|
||||
}
|
||||
|
||||
void b2RevoluteJoint::EnableLimit(bool flag)
|
||||
{
|
||||
m_enableLimit = flag;
|
||||
}
|
||||
|
||||
float32 b2RevoluteJoint::GetLowerLimit() const
|
||||
{
|
||||
return m_lowerAngle;
|
||||
}
|
||||
|
||||
float32 b2RevoluteJoint::GetUpperLimit() const
|
||||
{
|
||||
return m_upperAngle;
|
||||
}
|
||||
|
||||
void b2RevoluteJoint::SetLimits(float32 lower, float32 upper)
|
||||
{
|
||||
b2Assert(lower <= upper);
|
||||
m_lowerAngle = lower;
|
||||
m_upperAngle = upper;
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_REVOLUTE_JOINT_H
|
||||
#define B2_REVOLUTE_JOINT_H
|
||||
|
||||
#include "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;
|
||||
localAnchor1.Set(0.0f, 0.0f);
|
||||
localAnchor2.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 the world
|
||||
/// anchor.
|
||||
void Initialize(b2Body* body1, b2Body* body2, const b2Vec2& anchor);
|
||||
|
||||
/// The local anchor point relative to body1's origin.
|
||||
b2Vec2 localAnchor1;
|
||||
|
||||
/// The local anchor point relative to body2's origin.
|
||||
b2Vec2 localAnchor2;
|
||||
|
||||
/// The body2 angle minus body1 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 to 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 GetAnchor1() const;
|
||||
b2Vec2 GetAnchor2() const;
|
||||
|
||||
b2Vec2 GetReactionForce() const;
|
||||
float32 GetReactionTorque() const;
|
||||
|
||||
/// 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);
|
||||
|
||||
/// Get the current motor torque, usually in N-m.
|
||||
float32 GetMotorTorque() const;
|
||||
|
||||
//--------------- Internals Below -------------------
|
||||
b2RevoluteJoint(const b2RevoluteJointDef* def);
|
||||
|
||||
void InitVelocityConstraints(const b2TimeStep& step);
|
||||
void SolveVelocityConstraints(const b2TimeStep& step);
|
||||
|
||||
bool SolvePositionConstraints();
|
||||
|
||||
b2Vec2 m_localAnchor1; // relative
|
||||
b2Vec2 m_localAnchor2;
|
||||
b2Vec2 m_pivotForce;
|
||||
float32 m_motorForce;
|
||||
float32 m_limitForce;
|
||||
float32 m_limitPositionImpulse;
|
||||
|
||||
b2Mat22 m_pivotMass; // effective mass for point-to-point constraint.
|
||||
float32 m_motorMass; // effective mass for motor/limit angular constraint.
|
||||
|
||||
bool m_enableMotor;
|
||||
float32 m_maxMotorTorque;
|
||||
float32 m_motorSpeed;
|
||||
|
||||
bool m_enableLimit;
|
||||
float32 m_referenceAngle;
|
||||
float32 m_lowerAngle;
|
||||
float32 m_upperAngle;
|
||||
b2LimitState m_limitState;
|
||||
};
|
||||
|
||||
inline float32 b2RevoluteJoint::GetMotorSpeed() const
|
||||
{
|
||||
return m_motorSpeed;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2Body.h"
|
||||
#include "b2World.h"
|
||||
#include "Joints/b2Joint.h"
|
||||
#include "../Collision/Shapes/b2Shape.h"
|
||||
|
||||
b2Body::b2Body(const b2BodyDef* bd, b2World* world)
|
||||
{
|
||||
b2Assert(world->m_lock == false);
|
||||
|
||||
m_flags = 0;
|
||||
|
||||
if (bd->isBullet)
|
||||
{
|
||||
m_flags |= e_bulletFlag;
|
||||
}
|
||||
if (bd->fixedRotation)
|
||||
{
|
||||
m_flags |= e_fixedRotationFlag;
|
||||
}
|
||||
if (bd->allowSleep)
|
||||
{
|
||||
m_flags |= e_allowSleepFlag;
|
||||
}
|
||||
if (bd->isSleeping)
|
||||
{
|
||||
m_flags |= e_sleepFlag;
|
||||
}
|
||||
|
||||
m_world = world;
|
||||
|
||||
m_xf.position = bd->position;
|
||||
m_xf.R.Set(bd->angle);
|
||||
|
||||
m_sweep.localCenter = bd->massData.center;
|
||||
m_sweep.t0 = 1.0f;
|
||||
m_sweep.a0 = m_sweep.a = bd->angle;
|
||||
m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
|
||||
|
||||
m_jointList = NULL;
|
||||
m_contactList = NULL;
|
||||
m_prev = NULL;
|
||||
m_next = NULL;
|
||||
|
||||
m_linearDamping = bd->linearDamping;
|
||||
m_angularDamping = bd->angularDamping;
|
||||
|
||||
m_force.Set(0.0f, 0.0f);
|
||||
m_torque = 0.0f;
|
||||
|
||||
m_linearVelocity.SetZero();
|
||||
m_angularVelocity = 0.0f;
|
||||
|
||||
m_sleepTime = 0.0f;
|
||||
|
||||
m_invMass = 0.0f;
|
||||
m_I = 0.0f;
|
||||
m_invI = 0.0f;
|
||||
|
||||
m_mass = bd->massData.mass;
|
||||
|
||||
if (m_mass > 0.0f)
|
||||
{
|
||||
m_invMass = 1.0f / m_mass;
|
||||
}
|
||||
|
||||
if ((m_flags & b2Body::e_fixedRotationFlag) == 0)
|
||||
{
|
||||
m_I = bd->massData.I;
|
||||
}
|
||||
|
||||
if (m_I > 0.0f)
|
||||
{
|
||||
m_invI = 1.0f / m_I;
|
||||
}
|
||||
|
||||
if (m_invMass == 0.0f && m_invI == 0.0f)
|
||||
{
|
||||
m_type = e_staticType;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_type = e_dynamicType;
|
||||
}
|
||||
|
||||
m_userData = bd->userData;
|
||||
|
||||
m_shapeList = NULL;
|
||||
m_shapeCount = 0;
|
||||
}
|
||||
|
||||
b2Body::~b2Body()
|
||||
{
|
||||
b2Assert(m_world->m_lock == false);
|
||||
// shapes and joints are destroyed in b2World::Destroy
|
||||
}
|
||||
|
||||
b2Shape* b2Body::CreateShape(b2ShapeDef* def)
|
||||
{
|
||||
b2Assert(m_world->m_lock == false);
|
||||
if (m_world->m_lock == true)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b2Shape* s = b2Shape::Create(def, &m_world->m_blockAllocator);
|
||||
|
||||
s->m_next = m_shapeList;
|
||||
m_shapeList = s;
|
||||
++m_shapeCount;
|
||||
|
||||
s->m_body = this;
|
||||
|
||||
// Add the shape to the world's broad-phase.
|
||||
s->CreateProxy(m_world->m_broadPhase, m_xf);
|
||||
|
||||
// Compute the sweep radius for CCD.
|
||||
s->UpdateSweepRadius(m_sweep.localCenter);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void b2Body::DestroyShape(b2Shape* s)
|
||||
{
|
||||
b2Assert(m_world->m_lock == false);
|
||||
if (m_world->m_lock == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
b2Assert(s->GetBody() == this);
|
||||
s->DestroyProxy(m_world->m_broadPhase);
|
||||
|
||||
b2Assert(m_shapeCount > 0);
|
||||
b2Shape** node = &m_shapeList;
|
||||
bool found = false;
|
||||
while (*node != NULL)
|
||||
{
|
||||
if (*node == s)
|
||||
{
|
||||
*node = s->m_next;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
node = &(*node)->m_next;
|
||||
}
|
||||
|
||||
// You tried to remove a shape that is not attached to this body.
|
||||
b2Assert(found);
|
||||
|
||||
s->m_body = NULL;
|
||||
s->m_next = NULL;
|
||||
|
||||
--m_shapeCount;
|
||||
|
||||
b2Shape::Destroy(s, &m_world->m_blockAllocator);
|
||||
}
|
||||
|
||||
// TODO_ERIN adjust linear velocity and torque to account for movement of center.
|
||||
void b2Body::SetMass(const b2MassData* massData)
|
||||
{
|
||||
b2Assert(m_world->m_lock == false);
|
||||
if (m_world->m_lock == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_invMass = 0.0f;
|
||||
m_I = 0.0f;
|
||||
m_invI = 0.0f;
|
||||
|
||||
m_mass = massData->mass;
|
||||
|
||||
if (m_mass > 0.0f)
|
||||
{
|
||||
m_invMass = 1.0f / m_mass;
|
||||
}
|
||||
|
||||
if ((m_flags & b2Body::e_fixedRotationFlag) == 0)
|
||||
{
|
||||
m_I = massData->I;
|
||||
}
|
||||
|
||||
if (m_I > 0.0f)
|
||||
{
|
||||
m_invI = 1.0f / m_I;
|
||||
}
|
||||
|
||||
// Move center of mass.
|
||||
m_sweep.localCenter = massData->center;
|
||||
m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
|
||||
|
||||
// Update the sweep radii of all child shapes.
|
||||
for (b2Shape* s = m_shapeList; s; s = s->m_next)
|
||||
{
|
||||
s->UpdateSweepRadius(m_sweep.localCenter);
|
||||
}
|
||||
|
||||
int16 oldType = m_type;
|
||||
if (m_invMass == 0.0f && m_invI == 0.0f)
|
||||
{
|
||||
m_type = e_staticType;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_type = e_dynamicType;
|
||||
}
|
||||
|
||||
// If the body type changed, we need to refilter the broad-phase proxies.
|
||||
if (oldType != m_type)
|
||||
{
|
||||
for (b2Shape* s = m_shapeList; s; s = s->m_next)
|
||||
{
|
||||
s->RefilterProxy(m_world->m_broadPhase, m_xf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO_ERIN adjust linear velocity and torque to account for movement of center.
|
||||
void b2Body::SetMassFromShapes()
|
||||
{
|
||||
b2Assert(m_world->m_lock == false);
|
||||
if (m_world->m_lock == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute mass data from shapes. Each shape has its own density.
|
||||
m_mass = 0.0f;
|
||||
m_invMass = 0.0f;
|
||||
m_I = 0.0f;
|
||||
m_invI = 0.0f;
|
||||
|
||||
b2Vec2 center = b2Vec2_zero;
|
||||
for (b2Shape* s = m_shapeList; s; s = s->m_next)
|
||||
{
|
||||
b2MassData massData;
|
||||
s->ComputeMass(&massData);
|
||||
m_mass += massData.mass;
|
||||
center += massData.mass * massData.center;
|
||||
m_I += massData.I;
|
||||
}
|
||||
|
||||
// Compute center of mass, and shift the origin to the COM.
|
||||
if (m_mass > 0.0f)
|
||||
{
|
||||
m_invMass = 1.0f / m_mass;
|
||||
center *= m_invMass;
|
||||
}
|
||||
|
||||
if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0)
|
||||
{
|
||||
// Center the inertia about the center of mass.
|
||||
m_I -= m_mass * b2Dot(center, center);
|
||||
b2Assert(m_I > 0.0f);
|
||||
m_invI = 1.0f / m_I;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_I = 0.0f;
|
||||
m_invI = 0.0f;
|
||||
}
|
||||
|
||||
// Move center of mass.
|
||||
m_sweep.localCenter = center;
|
||||
m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
|
||||
|
||||
// Update the sweep radii of all child shapes.
|
||||
for (b2Shape* s = m_shapeList; s; s = s->m_next)
|
||||
{
|
||||
s->UpdateSweepRadius(m_sweep.localCenter);
|
||||
}
|
||||
|
||||
int16 oldType = m_type;
|
||||
if (m_invMass == 0.0f && m_invI == 0.0f)
|
||||
{
|
||||
m_type = e_staticType;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_type = e_dynamicType;
|
||||
}
|
||||
|
||||
// If the body type changed, we need to refilter the broad-phase proxies.
|
||||
if (oldType != m_type)
|
||||
{
|
||||
for (b2Shape* s = m_shapeList; s; s = s->m_next)
|
||||
{
|
||||
s->RefilterProxy(m_world->m_broadPhase, m_xf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool b2Body::SetXForm(const b2Vec2& position, float32 angle)
|
||||
{
|
||||
b2Assert(m_world->m_lock == false);
|
||||
if (m_world->m_lock == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsFrozen())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_xf.R.Set(angle);
|
||||
m_xf.position = position;
|
||||
|
||||
m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
|
||||
m_sweep.a0 = m_sweep.a = angle;
|
||||
|
||||
bool freeze = false;
|
||||
for (b2Shape* s = m_shapeList; s; s = s->m_next)
|
||||
{
|
||||
bool inRange = s->Synchronize(m_world->m_broadPhase, m_xf, m_xf);
|
||||
|
||||
if (inRange == false)
|
||||
{
|
||||
freeze = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (freeze == true)
|
||||
{
|
||||
m_flags |= e_frozenFlag;
|
||||
m_linearVelocity.SetZero();
|
||||
m_angularVelocity = 0.0f;
|
||||
for (b2Shape* s = m_shapeList; s; s = s->m_next)
|
||||
{
|
||||
s->DestroyProxy(m_world->m_broadPhase);
|
||||
}
|
||||
|
||||
// Failure
|
||||
return false;
|
||||
}
|
||||
|
||||
// Success
|
||||
m_world->m_broadPhase->Commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool b2Body::SynchronizeShapes()
|
||||
{
|
||||
b2XForm xf1;
|
||||
xf1.R.Set(m_sweep.a0);
|
||||
xf1.position = m_sweep.c0 - b2Mul(xf1.R, m_sweep.localCenter);
|
||||
|
||||
bool inRange = true;
|
||||
for (b2Shape* s = m_shapeList; s; s = s->m_next)
|
||||
{
|
||||
inRange = s->Synchronize(m_world->m_broadPhase, xf1, m_xf);
|
||||
if (inRange == false)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (inRange == false)
|
||||
{
|
||||
m_flags |= e_frozenFlag;
|
||||
m_linearVelocity.SetZero();
|
||||
m_angularVelocity = 0.0f;
|
||||
for (b2Shape* s = m_shapeList; s; s = s->m_next)
|
||||
{
|
||||
s->DestroyProxy(m_world->m_broadPhase);
|
||||
}
|
||||
|
||||
// Failure
|
||||
return false;
|
||||
}
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,587 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_BODY_H
|
||||
#define B2_BODY_H
|
||||
|
||||
#include "../Common/b2Math.h"
|
||||
#include "../Collision/Shapes/b2Shape.h"
|
||||
#include "Joints/b2Joint.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class b2Joint;
|
||||
class b2Contact;
|
||||
class b2World;
|
||||
struct b2JointEdge;
|
||||
struct b2ContactEdge;
|
||||
|
||||
/// A body definition holds all the data needed to construct a rigid body.
|
||||
/// You can safely re-use body definitions.
|
||||
struct b2BodyDef
|
||||
{
|
||||
/// This constructor sets the body definition default values.
|
||||
b2BodyDef()
|
||||
{
|
||||
massData.center.SetZero();
|
||||
massData.mass = 0.0f;
|
||||
massData.I = 0.0f;
|
||||
userData = NULL;
|
||||
position.Set(0.0f, 0.0f);
|
||||
angle = 0.0f;
|
||||
linearDamping = 0.0f;
|
||||
angularDamping = 0.0f;
|
||||
allowSleep = true;
|
||||
isSleeping = false;
|
||||
fixedRotation = false;
|
||||
isBullet = false;
|
||||
}
|
||||
|
||||
/// You can use this to initialized the mass properties of the body.
|
||||
/// If you prefer, you can set the mass properties after the shapes
|
||||
/// have been added using b2Body::SetMassFromShapes.
|
||||
b2MassData massData;
|
||||
|
||||
/// Use this to store application specific body data.
|
||||
void* userData;
|
||||
|
||||
/// The world position of the body. Avoid creating bodies at the origin
|
||||
/// since this can lead to many overlapping shapes.
|
||||
b2Vec2 position;
|
||||
|
||||
/// The world angle of the body in radians.
|
||||
float32 angle;
|
||||
|
||||
/// Linear damping is use to reduce the linear velocity. The damping parameter
|
||||
/// can be larger than 1.0f but the damping effect becomes sensitive to the
|
||||
/// time step when the damping parameter is large.
|
||||
float32 linearDamping;
|
||||
|
||||
/// Angular damping is use to reduce the angular velocity. The damping parameter
|
||||
/// can be larger than 1.0f but the damping effect becomes sensitive to the
|
||||
/// time step when the damping parameter is large.
|
||||
float32 angularDamping;
|
||||
|
||||
/// Set this flag to false if this body should never fall asleep. Note that
|
||||
/// this increases CPU usage.
|
||||
bool allowSleep;
|
||||
|
||||
/// Is this body initially sleeping?
|
||||
bool isSleeping;
|
||||
|
||||
/// Should this body be prevented from rotating? Useful for characters.
|
||||
bool fixedRotation;
|
||||
|
||||
/// Is this a fast moving body that should be prevented from tunneling through
|
||||
/// other moving bodies? Note that all bodies are prevented from tunneling through
|
||||
/// static bodies.
|
||||
/// @warning You should use this flag sparingly since it increases processing time.
|
||||
bool isBullet;
|
||||
};
|
||||
|
||||
/// A rigid body.
|
||||
class b2Body
|
||||
{
|
||||
public:
|
||||
/// Creates a shape and attach it to this body.
|
||||
/// @param shapeDef the shape definition.
|
||||
/// @warning This function is locked during callbacks.
|
||||
b2Shape* CreateShape(b2ShapeDef* shapeDef);
|
||||
|
||||
/// Destroy a shape. This removes the shape from the broad-phase and
|
||||
/// therefore destroys any contacts associated with this shape. All shapes
|
||||
/// attached to a body are implicitly destroyed when the body is destroyed.
|
||||
/// @param shape the shape to be removed.
|
||||
/// @warning This function is locked during callbacks.
|
||||
void DestroyShape(b2Shape* shape);
|
||||
|
||||
/// Set the mass properties. Note that this changes the center of mass position.
|
||||
/// If you are not sure how to compute mass properties, use SetMassFromShapes.
|
||||
/// The inertia tensor is assumed to be relative to the center of mass.
|
||||
/// @param massData the mass properties.
|
||||
void SetMass(const b2MassData* massData);
|
||||
|
||||
/// Compute the mass properties from the attached shapes. You typically call this
|
||||
/// after adding all the shapes. If you add or remove shapes later, you may want
|
||||
/// to call this again. Note that this changes the center of mass position.
|
||||
void SetMassFromShapes();
|
||||
|
||||
/// Set the position of the body's origin and rotation (radians).
|
||||
/// This breaks any contacts and wakes the other bodies.
|
||||
/// @param position the new world position of the body's origin (not necessarily
|
||||
/// the center of mass).
|
||||
/// @param angle the new world rotation angle of the body in radians.
|
||||
/// @return false if the movement put a shape outside the world. In this case the
|
||||
/// body is automatically frozen.
|
||||
bool SetXForm(const b2Vec2& position, float32 angle);
|
||||
|
||||
/// Get the body transform for the body's origin.
|
||||
/// @return the world transform of the body's origin.
|
||||
const b2XForm& GetXForm() const;
|
||||
|
||||
/// Get the world body origin position.
|
||||
/// @return the world position of the body's origin.
|
||||
const b2Vec2& GetPosition() const;
|
||||
|
||||
/// Get the angle in radians.
|
||||
/// @return the current world rotation angle in radians.
|
||||
float32 GetAngle() const;
|
||||
|
||||
/// Get the world position of the center of mass.
|
||||
const b2Vec2& GetWorldCenter() const;
|
||||
|
||||
/// Get the local position of the center of mass.
|
||||
const b2Vec2& GetLocalCenter() const;
|
||||
|
||||
/// Set the linear velocity of the center of mass.
|
||||
/// @param v the new linear velocity of the center of mass.
|
||||
void SetLinearVelocity(const b2Vec2& v);
|
||||
|
||||
/// Get the linear velocity of the center of mass.
|
||||
/// @return the linear velocity of the center of mass.
|
||||
b2Vec2 GetLinearVelocity() const;
|
||||
|
||||
/// Set the angular velocity.
|
||||
/// @param omega the new angular velocity in radians/second.
|
||||
void SetAngularVelocity(float32 omega);
|
||||
|
||||
/// Get the angular velocity.
|
||||
/// @return the angular velocity in radians/second.
|
||||
float32 GetAngularVelocity() const;
|
||||
|
||||
/// Apply a force at a world point. If the force is not
|
||||
/// applied at the center of mass, it will generate a torque and
|
||||
/// affect the angular velocity. This wakes up the body.
|
||||
/// @param force the world force vector, usually in Newtons (N).
|
||||
/// @param point the world position of the point of application.
|
||||
void ApplyForce(const b2Vec2& force, const b2Vec2& point);
|
||||
|
||||
/// Apply a torque. This affects the angular velocity
|
||||
/// without affecting the linear velocity of the center of mass.
|
||||
/// This wakes up the body.
|
||||
/// @param torque about the z-axis (out of the screen), usually in N-m.
|
||||
void ApplyTorque(float32 torque);
|
||||
|
||||
/// Apply an impulse at a point. This immediately modifies the velocity.
|
||||
/// It also modifies the angular velocity if the point of application
|
||||
/// is not at the center of mass. This wakes up the body.
|
||||
/// @param impulse the world impulse vector, usually in N-seconds or kg-m/s.
|
||||
/// @param point the world position of the point of application.
|
||||
void ApplyImpulse(const b2Vec2& impulse, const b2Vec2& point);
|
||||
|
||||
/// Get the total mass of the body.
|
||||
/// @return the mass, usually in kilograms (kg).
|
||||
float32 GetMass() const;
|
||||
|
||||
/// Get the central rotational inertia of the body.
|
||||
/// @return the rotational inertia, usually in kg-m^2.
|
||||
float32 GetInertia() const;
|
||||
|
||||
/// Get the world coordinates of a point given the local coordinates.
|
||||
/// @param localPoint a point on the body measured relative the the body's origin.
|
||||
/// @return the same point expressed in world coordinates.
|
||||
b2Vec2 GetWorldPoint(const b2Vec2& localPoint) const;
|
||||
|
||||
/// Get the world coordinates of a vector given the local coordinates.
|
||||
/// @param localVector a vector fixed in the body.
|
||||
/// @return the same vector expressed in world coordinates.
|
||||
b2Vec2 GetWorldVector(const b2Vec2& localVector) const;
|
||||
|
||||
/// Gets a local point relative to the body's origin given a world point.
|
||||
/// @param a point in world coordinates.
|
||||
/// @return the corresponding local point relative to the body's origin.
|
||||
b2Vec2 GetLocalPoint(const b2Vec2& worldPoint) const;
|
||||
|
||||
/// Gets a local vector given a world vector.
|
||||
/// @param a vector in world coordinates.
|
||||
/// @return the corresponding local vector.
|
||||
b2Vec2 GetLocalVector(const b2Vec2& worldVector) const;
|
||||
|
||||
/// Get the world linear velocity of a world point attached to this body.
|
||||
/// @param a point in world coordinates.
|
||||
/// @return the world velocity of a point.
|
||||
b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const;
|
||||
|
||||
/// Get the world velocity of a local point.
|
||||
/// @param a point in local coordinates.
|
||||
/// @return the world velocity of a point.
|
||||
b2Vec2 GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const;
|
||||
|
||||
/// Is this body treated like a bullet for continuous collision detection?
|
||||
bool IsBullet() const;
|
||||
|
||||
/// Should this body be treated like a bullet for continuous collision detection?
|
||||
void SetBullet(bool flag);
|
||||
|
||||
/// Is this body static (immovable)?
|
||||
bool IsStatic() const;
|
||||
|
||||
/// Is this body dynamic (movable)?
|
||||
bool IsDynamic() const;
|
||||
|
||||
/// Is this body frozen?
|
||||
bool IsFrozen() const;
|
||||
|
||||
/// Is this body sleeping (not simulating).
|
||||
bool IsSleeping() const;
|
||||
|
||||
/// You can disable sleeping on this body.
|
||||
void AllowSleeping(bool flag);
|
||||
|
||||
/// Wake up this body so it will begin simulating.
|
||||
void WakeUp();
|
||||
|
||||
/// Put this body to sleep so it will stop simulating.
|
||||
/// This also sets the velocity to zero.
|
||||
void PutToSleep();
|
||||
|
||||
/// Get the list of all shapes attached to this body.
|
||||
b2Shape* GetShapeList();
|
||||
|
||||
/// Get the list of all joints attached to this body.
|
||||
b2JointEdge* GetJointList();
|
||||
|
||||
/// Get the next body in the world's body list.
|
||||
b2Body* GetNext();
|
||||
|
||||
/// Get the user data pointer that was provided in the body definition.
|
||||
void* GetUserData();
|
||||
|
||||
/// Set the user data. Use this to store your application specific data.
|
||||
void SetUserData(void* data);
|
||||
|
||||
/// Get the parent world of this body.
|
||||
b2World* GetWorld();
|
||||
|
||||
public:
|
||||
|
||||
friend class b2World;
|
||||
friend class b2Island;
|
||||
friend class b2ContactManager;
|
||||
friend class b2ContactSolver;
|
||||
|
||||
friend class b2DistanceJoint;
|
||||
friend class b2GearJoint;
|
||||
friend class b2MouseJoint;
|
||||
friend class b2PrismaticJoint;
|
||||
friend class b2PulleyJoint;
|
||||
friend class b2RevoluteJoint;
|
||||
|
||||
// m_flags
|
||||
enum
|
||||
{
|
||||
e_frozenFlag = 0x0002,
|
||||
e_islandFlag = 0x0004,
|
||||
e_sleepFlag = 0x0008,
|
||||
e_allowSleepFlag = 0x0010,
|
||||
e_bulletFlag = 0x0020,
|
||||
e_fixedRotationFlag = 0x0040,
|
||||
};
|
||||
|
||||
// m_type
|
||||
enum
|
||||
{
|
||||
e_staticType,
|
||||
e_dynamicType,
|
||||
e_maxTypes,
|
||||
};
|
||||
|
||||
b2Body(const b2BodyDef* bd, b2World* world);
|
||||
~b2Body();
|
||||
|
||||
bool SynchronizeShapes();
|
||||
|
||||
void SynchronizeTransform();
|
||||
|
||||
// This is used to prevent connected bodies from colliding.
|
||||
// It may lie, depending on the collideConnected flag.
|
||||
bool IsConnected(const b2Body* other) const;
|
||||
|
||||
void Advance(float32 t);
|
||||
|
||||
uint16 m_flags;
|
||||
int16 m_type;
|
||||
|
||||
b2XForm m_xf; // the body origin transform
|
||||
|
||||
b2Sweep m_sweep; // the swept motion for CCD
|
||||
|
||||
b2Vec2 m_linearVelocity;
|
||||
float32 m_angularVelocity;
|
||||
|
||||
b2Vec2 m_force;
|
||||
float32 m_torque;
|
||||
|
||||
b2World* m_world;
|
||||
b2Body* m_prev;
|
||||
b2Body* m_next;
|
||||
|
||||
b2Shape* m_shapeList;
|
||||
int32 m_shapeCount;
|
||||
|
||||
b2JointEdge* m_jointList;
|
||||
b2ContactEdge* m_contactList;
|
||||
|
||||
float32 m_mass, m_invMass;
|
||||
float32 m_I, m_invI;
|
||||
|
||||
float32 m_linearDamping;
|
||||
float32 m_angularDamping;
|
||||
|
||||
float32 m_sleepTime;
|
||||
|
||||
void* m_userData;
|
||||
};
|
||||
|
||||
inline const b2XForm& b2Body::GetXForm() const
|
||||
{
|
||||
return m_xf;
|
||||
}
|
||||
|
||||
inline const b2Vec2& b2Body::GetPosition() const
|
||||
{
|
||||
return m_xf.position;
|
||||
}
|
||||
|
||||
inline float32 b2Body::GetAngle() const
|
||||
{
|
||||
return m_sweep.a;
|
||||
}
|
||||
|
||||
inline const b2Vec2& b2Body::GetWorldCenter() const
|
||||
{
|
||||
return m_sweep.c;
|
||||
}
|
||||
|
||||
inline const b2Vec2& b2Body::GetLocalCenter() const
|
||||
{
|
||||
return m_sweep.localCenter;
|
||||
}
|
||||
|
||||
inline void b2Body::SetLinearVelocity(const b2Vec2& v)
|
||||
{
|
||||
m_linearVelocity = v;
|
||||
}
|
||||
|
||||
inline b2Vec2 b2Body::GetLinearVelocity() const
|
||||
{
|
||||
return m_linearVelocity;
|
||||
}
|
||||
|
||||
inline void b2Body::SetAngularVelocity(float32 w)
|
||||
{
|
||||
m_angularVelocity = w;
|
||||
}
|
||||
|
||||
inline float32 b2Body::GetAngularVelocity() const
|
||||
{
|
||||
return m_angularVelocity;
|
||||
}
|
||||
|
||||
inline float32 b2Body::GetMass() const
|
||||
{
|
||||
return m_mass;
|
||||
}
|
||||
|
||||
inline float32 b2Body::GetInertia() const
|
||||
{
|
||||
return m_I;
|
||||
}
|
||||
|
||||
inline b2Vec2 b2Body::GetWorldPoint(const b2Vec2& localPoint) const
|
||||
{
|
||||
return b2Mul(m_xf, localPoint);
|
||||
}
|
||||
|
||||
inline b2Vec2 b2Body::GetWorldVector(const b2Vec2& localVector) const
|
||||
{
|
||||
return b2Mul(m_xf.R, localVector);
|
||||
}
|
||||
|
||||
inline b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint) const
|
||||
{
|
||||
return b2MulT(m_xf, worldPoint);
|
||||
}
|
||||
|
||||
inline b2Vec2 b2Body::GetLocalVector(const b2Vec2& worldVector) const
|
||||
{
|
||||
return b2MulT(m_xf.R, worldVector);
|
||||
}
|
||||
|
||||
inline b2Vec2 b2Body::GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const
|
||||
{
|
||||
return m_linearVelocity + b2Cross(m_angularVelocity, worldPoint - m_sweep.c);
|
||||
}
|
||||
|
||||
inline b2Vec2 b2Body::GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const
|
||||
{
|
||||
return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint));
|
||||
}
|
||||
|
||||
inline bool b2Body::IsBullet() const
|
||||
{
|
||||
return (m_flags & e_bulletFlag) == e_bulletFlag;
|
||||
}
|
||||
|
||||
inline void b2Body::SetBullet(bool flag)
|
||||
{
|
||||
if (flag)
|
||||
{
|
||||
m_flags |= e_bulletFlag;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_flags &= ~e_bulletFlag;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool b2Body::IsStatic() const
|
||||
{
|
||||
return m_type == e_staticType;
|
||||
}
|
||||
|
||||
inline bool b2Body::IsDynamic() const
|
||||
{
|
||||
return m_type == e_dynamicType;
|
||||
}
|
||||
|
||||
inline bool b2Body::IsFrozen() const
|
||||
{
|
||||
return (m_flags & e_frozenFlag) == e_frozenFlag;
|
||||
}
|
||||
|
||||
inline bool b2Body::IsSleeping() const
|
||||
{
|
||||
return (m_flags & e_sleepFlag) == e_sleepFlag;
|
||||
}
|
||||
|
||||
inline void b2Body::AllowSleeping(bool flag)
|
||||
{
|
||||
if (flag)
|
||||
{
|
||||
m_flags |= e_allowSleepFlag;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_flags &= ~e_allowSleepFlag;
|
||||
WakeUp();
|
||||
}
|
||||
}
|
||||
|
||||
inline void b2Body::WakeUp()
|
||||
{
|
||||
m_flags &= ~e_sleepFlag;
|
||||
m_sleepTime = 0.0f;
|
||||
}
|
||||
|
||||
inline void b2Body::PutToSleep()
|
||||
{
|
||||
m_flags |= e_sleepFlag;
|
||||
m_sleepTime = 0.0f;
|
||||
m_linearVelocity.SetZero();
|
||||
m_angularVelocity = 0.0f;
|
||||
m_force.SetZero();
|
||||
m_torque = 0.0f;
|
||||
}
|
||||
|
||||
inline b2Shape* b2Body::GetShapeList()
|
||||
{
|
||||
return m_shapeList;
|
||||
}
|
||||
|
||||
inline b2JointEdge* b2Body::GetJointList()
|
||||
{
|
||||
return m_jointList;
|
||||
}
|
||||
|
||||
inline b2Body* b2Body::GetNext()
|
||||
{
|
||||
return m_next;
|
||||
}
|
||||
|
||||
inline void* b2Body::GetUserData()
|
||||
{
|
||||
return m_userData;
|
||||
}
|
||||
|
||||
inline void b2Body::SetUserData(void* data)
|
||||
{
|
||||
m_userData = data;
|
||||
}
|
||||
|
||||
inline bool b2Body::IsConnected(const b2Body* other) const
|
||||
{
|
||||
for (b2JointEdge* jn = m_jointList; jn; jn = jn->next)
|
||||
{
|
||||
if (jn->other == other)
|
||||
return jn->joint->m_collideConnected == false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point)
|
||||
{
|
||||
if (IsSleeping())
|
||||
{
|
||||
WakeUp();
|
||||
}
|
||||
m_force += force;
|
||||
m_torque += b2Cross(point - m_sweep.c, force);
|
||||
}
|
||||
|
||||
inline void b2Body::ApplyTorque(float32 torque)
|
||||
{
|
||||
if (IsSleeping())
|
||||
{
|
||||
WakeUp();
|
||||
}
|
||||
m_torque += torque;
|
||||
}
|
||||
|
||||
inline void b2Body::ApplyImpulse(const b2Vec2& impulse, const b2Vec2& point)
|
||||
{
|
||||
if (IsSleeping())
|
||||
{
|
||||
WakeUp();
|
||||
}
|
||||
m_linearVelocity += m_invMass * impulse;
|
||||
m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse);
|
||||
}
|
||||
|
||||
inline void b2Body::SynchronizeTransform()
|
||||
{
|
||||
m_xf.R.Set(m_sweep.a);
|
||||
m_xf.position = m_sweep.c - b2Mul(m_xf.R, m_sweep.localCenter);
|
||||
}
|
||||
|
||||
inline void b2Body::Advance(float32 t)
|
||||
{
|
||||
// Advance to the new safe time.
|
||||
m_sweep.Advance(t);
|
||||
m_sweep.c = m_sweep.c0;
|
||||
m_sweep.a = m_sweep.a0;
|
||||
SynchronizeTransform();
|
||||
}
|
||||
|
||||
inline b2World* b2Body::GetWorld()
|
||||
{
|
||||
return m_world;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2ContactManager.h"
|
||||
#include "b2World.h"
|
||||
#include "b2Body.h"
|
||||
|
||||
// This is a callback from the broadphase when two AABB proxies begin
|
||||
// to overlap. We create a b2Contact to manage the narrow phase.
|
||||
void* b2ContactManager::PairAdded(void* proxyUserData1, void* proxyUserData2)
|
||||
{
|
||||
b2Shape* shape1 = (b2Shape*)proxyUserData1;
|
||||
b2Shape* shape2 = (b2Shape*)proxyUserData2;
|
||||
|
||||
b2Body* body1 = shape1->GetBody();
|
||||
b2Body* body2 = shape2->GetBody();
|
||||
|
||||
if (body1->IsStatic() && body2->IsStatic())
|
||||
{
|
||||
return &m_nullContact;
|
||||
}
|
||||
|
||||
if (shape1->GetBody() == shape2->GetBody())
|
||||
{
|
||||
return &m_nullContact;
|
||||
}
|
||||
|
||||
if (body2->IsConnected(body1))
|
||||
{
|
||||
return &m_nullContact;
|
||||
}
|
||||
|
||||
if (m_world->m_contactFilter != NULL && m_world->m_contactFilter->ShouldCollide(shape1, shape2) == false)
|
||||
{
|
||||
return &m_nullContact;
|
||||
}
|
||||
|
||||
// Call the factory.
|
||||
b2Contact* c = b2Contact::Create(shape1, shape2, &m_world->m_blockAllocator);
|
||||
|
||||
if (c == NULL)
|
||||
{
|
||||
return &m_nullContact;
|
||||
}
|
||||
|
||||
// Contact creation may swap shapes.
|
||||
shape1 = c->GetShape1();
|
||||
shape2 = c->GetShape2();
|
||||
body1 = shape1->GetBody();
|
||||
body2 = shape2->GetBody();
|
||||
|
||||
// Insert into the world.
|
||||
c->m_prev = NULL;
|
||||
c->m_next = m_world->m_contactList;
|
||||
if (m_world->m_contactList != NULL)
|
||||
{
|
||||
m_world->m_contactList->m_prev = c;
|
||||
}
|
||||
m_world->m_contactList = c;
|
||||
|
||||
// Connect to island graph.
|
||||
|
||||
// Connect to body 1
|
||||
c->m_node1.contact = c;
|
||||
c->m_node1.other = body2;
|
||||
|
||||
c->m_node1.prev = NULL;
|
||||
c->m_node1.next = body1->m_contactList;
|
||||
if (body1->m_contactList != NULL)
|
||||
{
|
||||
body1->m_contactList->prev = &c->m_node1;
|
||||
}
|
||||
body1->m_contactList = &c->m_node1;
|
||||
|
||||
// Connect to body 2
|
||||
c->m_node2.contact = c;
|
||||
c->m_node2.other = body1;
|
||||
|
||||
c->m_node2.prev = NULL;
|
||||
c->m_node2.next = body2->m_contactList;
|
||||
if (body2->m_contactList != NULL)
|
||||
{
|
||||
body2->m_contactList->prev = &c->m_node2;
|
||||
}
|
||||
body2->m_contactList = &c->m_node2;
|
||||
|
||||
++m_world->m_contactCount;
|
||||
return c;
|
||||
}
|
||||
|
||||
// This is a callback from the broadphase when two AABB proxies cease
|
||||
// to overlap. We retire the b2Contact.
|
||||
void b2ContactManager::PairRemoved(void* proxyUserData1, void* proxyUserData2, void* pairUserData)
|
||||
{
|
||||
B2_NOT_USED(proxyUserData1);
|
||||
B2_NOT_USED(proxyUserData2);
|
||||
|
||||
if (pairUserData == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
b2Contact* c = (b2Contact*)pairUserData;
|
||||
if (c == &m_nullContact)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// An attached body is being destroyed, we must destroy this contact
|
||||
// immediately to avoid orphaned shape pointers.
|
||||
Destroy(c);
|
||||
}
|
||||
|
||||
void b2ContactManager::Destroy(b2Contact* c)
|
||||
{
|
||||
b2Shape* shape1 = c->GetShape1();
|
||||
b2Shape* shape2 = c->GetShape2();
|
||||
|
||||
// Inform the user that this contact is ending.
|
||||
int32 manifoldCount = c->GetManifoldCount();
|
||||
if (manifoldCount > 0 && m_world->m_contactListener)
|
||||
{
|
||||
b2Body* b1 = shape1->GetBody();
|
||||
b2Body* b2 = shape2->GetBody();
|
||||
|
||||
b2Manifold* manifolds = c->GetManifolds();
|
||||
b2ContactPoint cp;
|
||||
cp.shape1 = c->GetShape1();
|
||||
cp.shape2 = c->GetShape2();
|
||||
cp.friction = c->m_friction;
|
||||
cp.restitution = c->m_restitution;
|
||||
|
||||
for (int32 i = 0; i < manifoldCount; ++i)
|
||||
{
|
||||
b2Manifold* manifold = manifolds + i;
|
||||
cp.normal = manifold->normal;
|
||||
|
||||
for (int32 j = 0; j < manifold->pointCount; ++j)
|
||||
{
|
||||
b2ManifoldPoint* mp = manifold->points + j;
|
||||
cp.position = b1->GetWorldPoint(mp->localPoint1);
|
||||
b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1);
|
||||
b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2);
|
||||
cp.velocity = v2 - v1;
|
||||
cp.separation = mp->separation;
|
||||
cp.id = mp->id;
|
||||
m_world->m_contactListener->Remove(&cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from the world.
|
||||
if (c->m_prev)
|
||||
{
|
||||
c->m_prev->m_next = c->m_next;
|
||||
}
|
||||
|
||||
if (c->m_next)
|
||||
{
|
||||
c->m_next->m_prev = c->m_prev;
|
||||
}
|
||||
|
||||
if (c == m_world->m_contactList)
|
||||
{
|
||||
m_world->m_contactList = c->m_next;
|
||||
}
|
||||
|
||||
b2Body* body1 = shape1->GetBody();
|
||||
b2Body* body2 = shape2->GetBody();
|
||||
|
||||
// Remove from body 1
|
||||
if (c->m_node1.prev)
|
||||
{
|
||||
c->m_node1.prev->next = c->m_node1.next;
|
||||
}
|
||||
|
||||
if (c->m_node1.next)
|
||||
{
|
||||
c->m_node1.next->prev = c->m_node1.prev;
|
||||
}
|
||||
|
||||
if (&c->m_node1 == body1->m_contactList)
|
||||
{
|
||||
body1->m_contactList = c->m_node1.next;
|
||||
}
|
||||
|
||||
// Remove from body 2
|
||||
if (c->m_node2.prev)
|
||||
{
|
||||
c->m_node2.prev->next = c->m_node2.next;
|
||||
}
|
||||
|
||||
if (c->m_node2.next)
|
||||
{
|
||||
c->m_node2.next->prev = c->m_node2.prev;
|
||||
}
|
||||
|
||||
if (&c->m_node2 == body2->m_contactList)
|
||||
{
|
||||
body2->m_contactList = c->m_node2.next;
|
||||
}
|
||||
|
||||
// Call the factory.
|
||||
b2Contact::Destroy(c, &m_world->m_blockAllocator);
|
||||
--m_world->m_contactCount;
|
||||
}
|
||||
|
||||
// This is the top level collision call for the time step. Here
|
||||
// all the narrow phase collision is processed for the world
|
||||
// contact list.
|
||||
void b2ContactManager::Collide()
|
||||
{
|
||||
// Update awake contacts.
|
||||
for (b2Contact* c = m_world->m_contactList; c; c = c->GetNext())
|
||||
{
|
||||
b2Body* body1 = c->GetShape1()->GetBody();
|
||||
b2Body* body2 = c->GetShape2()->GetBody();
|
||||
if (body1->IsSleeping() && body2->IsSleeping())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
c->Update(m_world->m_contactListener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_CONTACT_MANAGER_H
|
||||
#define B2_CONTACT_MANAGER_H
|
||||
|
||||
#include "../Collision/b2BroadPhase.h"
|
||||
#include "../Dynamics/Contacts/b2NullContact.h"
|
||||
|
||||
class b2World;
|
||||
class b2Contact;
|
||||
struct b2TimeStep;
|
||||
|
||||
// Delegate of b2World.
|
||||
class b2ContactManager : public b2PairCallback
|
||||
{
|
||||
public:
|
||||
b2ContactManager() : m_world(NULL), m_destroyImmediate(false) {}
|
||||
|
||||
// Implements PairCallback
|
||||
void* PairAdded(void* proxyUserData1, void* proxyUserData2);
|
||||
|
||||
// Implements PairCallback
|
||||
void PairRemoved(void* proxyUserData1, void* proxyUserData2, void* pairUserData);
|
||||
|
||||
void Destroy(b2Contact* c);
|
||||
|
||||
void Collide();
|
||||
|
||||
b2World* m_world;
|
||||
|
||||
// This lets us provide broadphase proxy pair user data for
|
||||
// contacts that shouldn't exist.
|
||||
b2NullContact m_nullContact;
|
||||
|
||||
bool m_destroyImmediate;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2Island.h"
|
||||
#include "b2Body.h"
|
||||
#include "b2World.h"
|
||||
#include "Contacts/b2Contact.h"
|
||||
#include "Contacts/b2ContactSolver.h"
|
||||
#include "Joints/b2Joint.h"
|
||||
#include "../Common/b2StackAllocator.h"
|
||||
|
||||
/*
|
||||
Position Correction Notes
|
||||
=========================
|
||||
I tried the several algorithms for position correction of the 2D revolute joint.
|
||||
I looked at these systems:
|
||||
- simple pendulum (1m diameter sphere on massless 5m stick) with initial angular velocity of 100 rad/s.
|
||||
- suspension bridge with 30 1m long planks of length 1m.
|
||||
- multi-link chain with 30 1m long links.
|
||||
|
||||
Here are the algorithms:
|
||||
|
||||
Baumgarte - A fraction of the position error is added to the velocity error. There is no
|
||||
separate position solver.
|
||||
|
||||
Pseudo Velocities - After the velocity solver and position integration,
|
||||
the position error, Jacobian, and effective mass are recomputed. Then
|
||||
the velocity constraints are solved with pseudo velocities and a fraction
|
||||
of the position error is added to the pseudo velocity error. The pseudo
|
||||
velocities are initialized to zero and there is no warm-starting. After
|
||||
the position solver, the pseudo velocities are added to the positions.
|
||||
This is also called the First Order World method or the Position LCP method.
|
||||
|
||||
Modified Nonlinear Gauss-Seidel (NGS) - Like Pseudo Velocities except the
|
||||
position error is re-computed for each constraint and the positions are updated
|
||||
after the constraint is solved. The radius vectors (aka Jacobians) are
|
||||
re-computed too (otherwise the algorithm has horrible instability). The pseudo
|
||||
velocity states are not needed because they are effectively zero at the beginning
|
||||
of each iteration. Since we have the current position error, we allow the
|
||||
iterations to terminate early if the error becomes smaller than b2_linearSlop.
|
||||
|
||||
Full NGS or just NGS - Like Modified NGS except the effective mass are re-computed
|
||||
each time a constraint is solved.
|
||||
|
||||
Here are the results:
|
||||
Baumgarte - this is the cheapest algorithm but it has some stability problems,
|
||||
especially with the bridge. The chain links separate easily close to the root
|
||||
and they jitter as they struggle to pull together. This is one of the most common
|
||||
methods in the field. The big drawback is that the position correction artificially
|
||||
affects the momentum, thus leading to instabilities and false bounce. I used a
|
||||
bias factor of 0.2. A larger bias factor makes the bridge less stable, a smaller
|
||||
factor makes joints and contacts more spongy.
|
||||
|
||||
Pseudo Velocities - the is more stable than the Baumgarte method. The bridge is
|
||||
stable. However, joints still separate with large angular velocities. Drag the
|
||||
simple pendulum in a circle quickly and the joint will separate. The chain separates
|
||||
easily and does not recover. I used a bias factor of 0.2. A larger value lead to
|
||||
the bridge collapsing when a heavy cube drops on it.
|
||||
|
||||
Modified NGS - this algorithm is better in some ways than Baumgarte and Pseudo
|
||||
Velocities, but in other ways it is worse. The bridge and chain are much more
|
||||
stable, but the simple pendulum goes unstable at high angular velocities.
|
||||
|
||||
Full NGS - stable in all tests. The joints display good stiffness. The bridge
|
||||
still sags, but this is better than infinite forces.
|
||||
|
||||
Recommendations
|
||||
Pseudo Velocities are not really worthwhile because the bridge and chain cannot
|
||||
recover from joint separation. In other cases the benefit over Baumgarte is small.
|
||||
|
||||
Modified NGS is not a robust method for the revolute joint due to the violent
|
||||
instability seen in the simple pendulum. Perhaps it is viable with other constraint
|
||||
types, especially scalar constraints where the effective mass is a scalar.
|
||||
|
||||
This leaves Baumgarte and Full NGS. Baumgarte has small, but manageable instabilities
|
||||
and is very fast. I don't think we can escape Baumgarte, especially in highly
|
||||
demanding cases where high constraint fidelity is not needed.
|
||||
|
||||
Full NGS is robust and easy on the eyes. I recommend this as an option for
|
||||
higher fidelity simulation and certainly for suspension bridges and long chains.
|
||||
Full NGS might be a good choice for ragdolls, especially motorized ragdolls where
|
||||
joint separation can be problematic. The number of NGS iterations can be reduced
|
||||
for better performance without harming robustness much.
|
||||
|
||||
Each joint in a can be handled differently in the position solver. So I recommend
|
||||
a system where the user can select the algorithm on a per joint basis. I would
|
||||
probably default to the slower Full NGS and let the user select the faster
|
||||
Baumgarte method in performance critical scenarios.
|
||||
*/
|
||||
|
||||
b2Island::b2Island(
|
||||
int32 bodyCapacity,
|
||||
int32 contactCapacity,
|
||||
int32 jointCapacity,
|
||||
b2StackAllocator* allocator,
|
||||
b2ContactListener* listener)
|
||||
{
|
||||
m_bodyCapacity = bodyCapacity;
|
||||
m_contactCapacity = contactCapacity;
|
||||
m_jointCapacity = jointCapacity;
|
||||
m_bodyCount = 0;
|
||||
m_contactCount = 0;
|
||||
m_jointCount = 0;
|
||||
|
||||
m_allocator = allocator;
|
||||
m_listener = listener;
|
||||
|
||||
m_bodies = (b2Body**)m_allocator->Allocate(bodyCapacity * sizeof(b2Body*));
|
||||
m_contacts = (b2Contact**)m_allocator->Allocate(contactCapacity * sizeof(b2Contact*));
|
||||
m_joints = (b2Joint**)m_allocator->Allocate(jointCapacity * sizeof(b2Joint*));
|
||||
|
||||
m_positionIterationCount = 0;
|
||||
}
|
||||
|
||||
b2Island::~b2Island()
|
||||
{
|
||||
// Warning: the order should reverse the constructor order.
|
||||
m_allocator->Free(m_joints);
|
||||
m_allocator->Free(m_contacts);
|
||||
m_allocator->Free(m_bodies);
|
||||
}
|
||||
|
||||
void b2Island::Solve(const b2TimeStep& step, const b2Vec2& gravity, bool correctPositions, bool allowSleep)
|
||||
{
|
||||
// Integrate velocities and apply damping.
|
||||
for (int32 i = 0; i < m_bodyCount; ++i)
|
||||
{
|
||||
b2Body* b = m_bodies[i];
|
||||
|
||||
if (b->IsStatic())
|
||||
continue;
|
||||
|
||||
// Integrate velocities.
|
||||
b->m_linearVelocity += step.dt * (gravity + b->m_invMass * b->m_force);
|
||||
b->m_angularVelocity += step.dt * b->m_invI * b->m_torque;
|
||||
|
||||
// Reset forces.
|
||||
b->m_force.Set(0.0f, 0.0f);
|
||||
b->m_torque = 0.0f;
|
||||
|
||||
// Apply damping.
|
||||
// ODE: dv/dt + c * v = 0
|
||||
// Solution: v(t) = v0 * exp(-c * t)
|
||||
// Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt)
|
||||
// v2 = exp(-c * dt) * v1
|
||||
// Taylor expansion:
|
||||
// v2 = (1.0f - c * dt) * v1
|
||||
b->m_linearVelocity *= b2Clamp(1.0f - step.dt * b->m_linearDamping, 0.0f, 1.0f);
|
||||
b->m_angularVelocity *= b2Clamp(1.0f - step.dt * b->m_angularDamping, 0.0f, 1.0f);
|
||||
|
||||
// Check for large velocities.
|
||||
#ifdef TARGET_FLOAT32_IS_FIXED
|
||||
// Fixed point code written this way to prevent
|
||||
// overflows, float code is optimized for speed
|
||||
|
||||
float32 vMagnitude = b->m_linearVelocity.Length();
|
||||
if(vMagnitude > b2_maxLinearVelocity) {
|
||||
b->m_linearVelocity *= b2_maxLinearVelocity/vMagnitude;
|
||||
}
|
||||
b->m_angularVelocity = b2Clamp(b->m_angularVelocity,
|
||||
-b2_maxAngularVelocity, b2_maxAngularVelocity);
|
||||
|
||||
#else
|
||||
|
||||
if (b2Dot(b->m_linearVelocity, b->m_linearVelocity) > b2_maxLinearVelocitySquared)
|
||||
{
|
||||
b->m_linearVelocity.Normalize();
|
||||
b->m_linearVelocity *= b2_maxLinearVelocity;
|
||||
}
|
||||
if (b->m_angularVelocity * b->m_angularVelocity > b2_maxAngularVelocitySquared)
|
||||
{
|
||||
if (b->m_angularVelocity < 0.0f)
|
||||
{
|
||||
b->m_angularVelocity = -b2_maxAngularVelocity;
|
||||
}
|
||||
else
|
||||
{
|
||||
b->m_angularVelocity = b2_maxAngularVelocity;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
b2ContactSolver contactSolver(step, m_contacts, m_contactCount, m_allocator);
|
||||
|
||||
// Initialize velocity constraints.
|
||||
contactSolver.InitVelocityConstraints(step);
|
||||
|
||||
for (int32 i = 0; i < m_jointCount; ++i)
|
||||
{
|
||||
m_joints[i]->InitVelocityConstraints(step);
|
||||
}
|
||||
|
||||
// Solve velocity constraints.
|
||||
for (int32 i = 0; i < step.maxIterations; ++i)
|
||||
{
|
||||
contactSolver.SolveVelocityConstraints();
|
||||
|
||||
for (int32 j = 0; j < m_jointCount; ++j)
|
||||
{
|
||||
m_joints[j]->SolveVelocityConstraints(step);
|
||||
}
|
||||
}
|
||||
|
||||
// Post-solve (store impulses for warm starting).
|
||||
contactSolver.FinalizeVelocityConstraints();
|
||||
|
||||
// Integrate positions.
|
||||
for (int32 i = 0; i < m_bodyCount; ++i)
|
||||
{
|
||||
b2Body* b = m_bodies[i];
|
||||
|
||||
if (b->IsStatic())
|
||||
continue;
|
||||
|
||||
// Store positions for continuous collision.
|
||||
b->m_sweep.c0 = b->m_sweep.c;
|
||||
b->m_sweep.a0 = b->m_sweep.a;
|
||||
|
||||
// Integrate
|
||||
b->m_sweep.c += step.dt * b->m_linearVelocity;
|
||||
b->m_sweep.a += step.dt * b->m_angularVelocity;
|
||||
|
||||
// Compute new transform
|
||||
b->SynchronizeTransform();
|
||||
|
||||
// Note: shapes are synchronized later.
|
||||
}
|
||||
|
||||
if (correctPositions)
|
||||
{
|
||||
// Initialize position constraints.
|
||||
// Contacts don't need initialization.
|
||||
for (int32 i = 0; i < m_jointCount; ++i)
|
||||
{
|
||||
m_joints[i]->InitPositionConstraints();
|
||||
}
|
||||
|
||||
// Iterate over constraints.
|
||||
for (m_positionIterationCount = 0; m_positionIterationCount < step.maxIterations; ++m_positionIterationCount)
|
||||
{
|
||||
bool contactsOkay = contactSolver.SolvePositionConstraints(b2_contactBaumgarte);
|
||||
|
||||
bool jointsOkay = true;
|
||||
for (int i = 0; i < m_jointCount; ++i)
|
||||
{
|
||||
bool jointOkay = m_joints[i]->SolvePositionConstraints();
|
||||
jointsOkay = jointsOkay && jointOkay;
|
||||
}
|
||||
|
||||
if (contactsOkay && jointsOkay)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Report(contactSolver.m_constraints);
|
||||
|
||||
if (allowSleep)
|
||||
{
|
||||
float32 minSleepTime = B2_FLT_MAX;
|
||||
|
||||
#ifndef TARGET_FLOAT32_IS_FIXED
|
||||
const float32 linTolSqr = b2_linearSleepTolerance * b2_linearSleepTolerance;
|
||||
const float32 angTolSqr = b2_angularSleepTolerance * b2_angularSleepTolerance;
|
||||
#endif
|
||||
|
||||
for (int32 i = 0; i < m_bodyCount; ++i)
|
||||
{
|
||||
b2Body* b = m_bodies[i];
|
||||
if (b->m_invMass == 0.0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((b->m_flags & b2Body::e_allowSleepFlag) == 0)
|
||||
{
|
||||
b->m_sleepTime = 0.0f;
|
||||
minSleepTime = 0.0f;
|
||||
}
|
||||
|
||||
if ((b->m_flags & b2Body::e_allowSleepFlag) == 0 ||
|
||||
#ifdef TARGET_FLOAT32_IS_FIXED
|
||||
b2Abs(b->m_angularVelocity) > b2_angularSleepTolerance ||
|
||||
b2Abs(b->m_linearVelocity.x) > b2_linearSleepTolerance ||
|
||||
b2Abs(b->m_linearVelocity.y) > b2_linearSleepTolerance)
|
||||
#else
|
||||
b->m_angularVelocity * b->m_angularVelocity > angTolSqr ||
|
||||
b2Dot(b->m_linearVelocity, b->m_linearVelocity) > linTolSqr)
|
||||
#endif
|
||||
{
|
||||
b->m_sleepTime = 0.0f;
|
||||
minSleepTime = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
b->m_sleepTime += step.dt;
|
||||
minSleepTime = b2Min(minSleepTime, b->m_sleepTime);
|
||||
}
|
||||
}
|
||||
|
||||
if (minSleepTime >= b2_timeToSleep)
|
||||
{
|
||||
for (int32 i = 0; i < m_bodyCount; ++i)
|
||||
{
|
||||
b2Body* b = m_bodies[i];
|
||||
b->m_flags |= b2Body::e_sleepFlag;
|
||||
b->m_linearVelocity = b2Vec2_zero;
|
||||
b->m_angularVelocity = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void b2Island::SolveTOI(const b2TimeStep& subStep)
|
||||
{
|
||||
b2ContactSolver contactSolver(subStep, m_contacts, m_contactCount, m_allocator);
|
||||
|
||||
// No warm starting needed for TOI events.
|
||||
|
||||
// Solve velocity constraints.
|
||||
for (int32 i = 0; i < subStep.maxIterations; ++i)
|
||||
{
|
||||
contactSolver.SolveVelocityConstraints();
|
||||
}
|
||||
|
||||
// Don't store the TOI contact forces for warm starting
|
||||
// because they can be quite large.
|
||||
|
||||
// Integrate positions.
|
||||
for (int32 i = 0; i < m_bodyCount; ++i)
|
||||
{
|
||||
b2Body* b = m_bodies[i];
|
||||
|
||||
if (b->IsStatic())
|
||||
continue;
|
||||
|
||||
// Store positions for continuous collision.
|
||||
b->m_sweep.c0 = b->m_sweep.c;
|
||||
b->m_sweep.a0 = b->m_sweep.a;
|
||||
|
||||
// Integrate
|
||||
b->m_sweep.c += subStep.dt * b->m_linearVelocity;
|
||||
b->m_sweep.a += subStep.dt * b->m_angularVelocity;
|
||||
|
||||
// Compute new transform
|
||||
b->SynchronizeTransform();
|
||||
|
||||
// Note: shapes are synchronized later.
|
||||
}
|
||||
|
||||
// Solve position constraints.
|
||||
const float32 k_toiBaumgarte = 0.75f;
|
||||
for (int32 i = 0; i < subStep.maxIterations; ++i)
|
||||
{
|
||||
bool contactsOkay = contactSolver.SolvePositionConstraints(k_toiBaumgarte);
|
||||
if (contactsOkay)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Report(contactSolver.m_constraints);
|
||||
}
|
||||
|
||||
void b2Island::Report(b2ContactConstraint* constraints)
|
||||
{
|
||||
if (m_listener == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < m_contactCount; ++i)
|
||||
{
|
||||
b2Contact* c = m_contacts[i];
|
||||
b2ContactConstraint* cc = constraints + i;
|
||||
b2ContactResult cr;
|
||||
cr.shape1 = c->GetShape1();
|
||||
cr.shape2 = c->GetShape2();
|
||||
b2Body* b1 = cr.shape1->GetBody();
|
||||
int32 manifoldCount = c->GetManifoldCount();
|
||||
b2Manifold* manifolds = c->GetManifolds();
|
||||
for (int32 j = 0; j < manifoldCount; ++j)
|
||||
{
|
||||
b2Manifold* manifold = manifolds + j;
|
||||
cr.normal = manifold->normal;
|
||||
for (int32 k = 0; k < manifold->pointCount; ++k)
|
||||
{
|
||||
b2ManifoldPoint* point = manifold->points + k;
|
||||
b2ContactConstraintPoint* ccp = cc->points + k;
|
||||
cr.position = b1->GetWorldPoint(point->localPoint1);
|
||||
|
||||
// TOI constraint results are not stored, so get
|
||||
// the result from the constraint.
|
||||
cr.normalImpulse = ccp->normalImpulse;
|
||||
cr.tangentImpulse = ccp->tangentImpulse;
|
||||
cr.id = point->id;
|
||||
|
||||
m_listener->Result(&cr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_ISLAND_H
|
||||
#define B2_ISLAND_H
|
||||
|
||||
#include "../Common/b2Math.h"
|
||||
|
||||
class b2Contact;
|
||||
class b2Body;
|
||||
class b2Joint;
|
||||
class b2StackAllocator;
|
||||
class b2ContactListener;
|
||||
struct b2ContactConstraint;
|
||||
struct b2TimeStep;
|
||||
|
||||
class b2Island
|
||||
{
|
||||
public:
|
||||
b2Island(int32 bodyCapacity, int32 contactCapacity, int32 jointCapacity,
|
||||
b2StackAllocator* allocator, b2ContactListener* listener);
|
||||
~b2Island();
|
||||
|
||||
void Clear()
|
||||
{
|
||||
m_bodyCount = 0;
|
||||
m_contactCount = 0;
|
||||
m_jointCount = 0;
|
||||
}
|
||||
|
||||
void Solve(const b2TimeStep& step, const b2Vec2& gravity, bool correctPositions, bool allowSleep);
|
||||
|
||||
void SolveTOI(const b2TimeStep& subStep);
|
||||
|
||||
void Add(b2Body* body)
|
||||
{
|
||||
b2Assert(m_bodyCount < m_bodyCapacity);
|
||||
m_bodies[m_bodyCount++] = body;
|
||||
}
|
||||
|
||||
void Add(b2Contact* contact)
|
||||
{
|
||||
b2Assert(m_contactCount < m_contactCapacity);
|
||||
m_contacts[m_contactCount++] = contact;
|
||||
}
|
||||
|
||||
void Add(b2Joint* joint)
|
||||
{
|
||||
b2Assert(m_jointCount < m_jointCapacity);
|
||||
m_joints[m_jointCount++] = joint;
|
||||
}
|
||||
|
||||
void Report(b2ContactConstraint* constraints);
|
||||
|
||||
b2StackAllocator* m_allocator;
|
||||
b2ContactListener* m_listener;
|
||||
|
||||
b2Body** m_bodies;
|
||||
b2Contact** m_contacts;
|
||||
b2Joint** m_joints;
|
||||
|
||||
int32 m_bodyCount;
|
||||
int32 m_jointCount;
|
||||
int32 m_contactCount;
|
||||
|
||||
int32 m_bodyCapacity;
|
||||
int32 m_contactCapacity;
|
||||
int32 m_jointCapacity;
|
||||
|
||||
int32 m_positionIterationCount;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_WORLD_H
|
||||
#define B2_WORLD_H
|
||||
|
||||
#include "../Common/b2Math.h"
|
||||
#include "../Common/b2BlockAllocator.h"
|
||||
#include "../Common/b2StackAllocator.h"
|
||||
#include "b2ContactManager.h"
|
||||
#include "b2WorldCallbacks.h"
|
||||
|
||||
struct b2AABB;
|
||||
struct b2ShapeDef;
|
||||
struct b2BodyDef;
|
||||
struct b2JointDef;
|
||||
class b2Body;
|
||||
class b2Joint;
|
||||
class b2Shape;
|
||||
class b2Contact;
|
||||
class b2BroadPhase;
|
||||
|
||||
struct b2TimeStep
|
||||
{
|
||||
float32 dt; // time step
|
||||
float32 inv_dt; // inverse time step (0 if dt == 0).
|
||||
float32 dtRatio; // dt * inv_dt0
|
||||
int32 maxIterations;
|
||||
bool warmStarting;
|
||||
bool positionCorrection;
|
||||
};
|
||||
|
||||
/// The world class manages all physics entities, dynamic simulation,
|
||||
/// and asynchronous queries. The world also contains efficient memory
|
||||
/// management facilities.
|
||||
class b2World
|
||||
{
|
||||
public:
|
||||
/// Construct a world object.
|
||||
/// @param worldAABB a bounding box that completely encompasses all your shapes.
|
||||
/// @param gravity the world gravity vector.
|
||||
/// @param doSleep improve performance by not simulating inactive bodies.
|
||||
b2World(const b2AABB& worldAABB, const b2Vec2& gravity, bool doSleep);
|
||||
|
||||
/// Destruct the world. All physics entities are destroyed and all heap memory is released.
|
||||
~b2World();
|
||||
|
||||
/// Register a destruction listener.
|
||||
void SetDestructionListener(b2DestructionListener* listener);
|
||||
|
||||
/// Register a broad-phase boundary listener.
|
||||
void SetBoundaryListener(b2BoundaryListener* listener);
|
||||
|
||||
/// Register a contact filter to provide specific control over collision.
|
||||
/// Otherwise the default filter is used (b2_defaultFilter).
|
||||
void SetContactFilter(b2ContactFilter* filter);
|
||||
|
||||
/// Register a contact event listener
|
||||
void SetContactListener(b2ContactListener* listener);
|
||||
|
||||
/// Register a routine for debug drawing. The debug draw functions are called
|
||||
/// inside the b2World::Step method, so make sure your renderer is ready to
|
||||
/// consume draw commands when you call Step().
|
||||
void SetDebugDraw(b2DebugDraw* debugDraw);
|
||||
|
||||
/// Create a rigid body given a definition. No reference to the definition
|
||||
/// is retained.
|
||||
/// @warning This function is locked during callbacks.
|
||||
b2Body* CreateBody(const b2BodyDef* def);
|
||||
|
||||
/// Destroy a rigid body given a definition. No reference to the definition
|
||||
/// is retained. This function is locked during callbacks.
|
||||
/// @warning This automatically deletes all associated shapes and joints.
|
||||
/// @warning This function is locked during callbacks.
|
||||
void DestroyBody(b2Body* body);
|
||||
|
||||
/// Create a joint to constrain bodies together. No reference to the definition
|
||||
/// is retained. This may cause the connected bodies to cease colliding.
|
||||
/// @warning This function is locked during callbacks.
|
||||
b2Joint* CreateJoint(const b2JointDef* def);
|
||||
|
||||
/// Destroy a joint. This may cause the connected bodies to begin colliding.
|
||||
/// @warning This function is locked during callbacks.
|
||||
void DestroyJoint(b2Joint* joint);
|
||||
|
||||
/// The world provides a single static ground body with no collision shapes.
|
||||
/// You can use this to simplify the creation of joints and static shapes.
|
||||
b2Body* GetGroundBody();
|
||||
|
||||
/// Take a time step. This performs collision detection, integration,
|
||||
/// and constraint solution.
|
||||
/// @param timeStep the amount of time to simulate, this should not vary.
|
||||
/// @param iterations the number of iterations to be used by the constraint solver.
|
||||
void Step(float32 timeStep, int32 iterations);
|
||||
|
||||
/// Query the world for all shapes that potentially overlap the
|
||||
/// provided AABB. You provide a shape pointer buffer of specified
|
||||
/// size. The number of shapes found is returned.
|
||||
/// @param aabb the query box.
|
||||
/// @param shapes a user allocated shape pointer array of size maxCount (or greater).
|
||||
/// @param maxCount the capacity of the shapes array.
|
||||
/// @return the number of shapes found in aabb.
|
||||
int32 Query(const b2AABB& aabb, b2Shape** shapes, int32 maxCount);
|
||||
|
||||
/// Get the world body list. With the returned body, use b2Body::GetNext to get
|
||||
/// the next body in the world list. A NULL body indicates the end of the list.
|
||||
/// @return the head of the world body list.
|
||||
b2Body* GetBodyList();
|
||||
|
||||
/// Get the world joint list. With the returned joint, use b2Joint::GetNext to get
|
||||
/// the next joint in the world list. A NULL joint indicates the end of the list.
|
||||
/// @return the head of the world joint list.
|
||||
b2Joint* GetJointList();
|
||||
|
||||
/// Re-filter a shape. This re-runs contact filtering on a shape.
|
||||
void Refilter(b2Shape* shape);
|
||||
|
||||
/// Enable/disable warm starting. For testing.
|
||||
void SetWarmStarting(bool flag) { m_warmStarting = flag; }
|
||||
|
||||
/// Enable/disable position correction. For testing.
|
||||
void SetPositionCorrection(bool flag) { m_positionCorrection = flag; }
|
||||
|
||||
/// Enable/disable continuous physics. For testing.
|
||||
void SetContinuousPhysics(bool flag) { m_continuousPhysics = flag; }
|
||||
|
||||
/// Perform validation of internal data structures.
|
||||
void Validate();
|
||||
|
||||
/// Get the number of broad-phase proxies.
|
||||
int32 GetProxyCount() const;
|
||||
|
||||
/// Get the number of broad-phase pairs.
|
||||
int32 GetPairCount() const;
|
||||
|
||||
/// Get the number of bodies.
|
||||
int32 GetBodyCount() const;
|
||||
|
||||
/// Get the number joints.
|
||||
int32 GetJointCount() const;
|
||||
|
||||
/// Get the number of contacts (each may have 0 or more contact points).
|
||||
int32 GetContactCount() const;
|
||||
|
||||
/// Change the global gravity vector.
|
||||
void SetGravity(const b2Vec2& gravity);
|
||||
|
||||
public:
|
||||
|
||||
friend class b2Body;
|
||||
friend class b2ContactManager;
|
||||
|
||||
void Solve(const b2TimeStep& step);
|
||||
void SolveTOI(const b2TimeStep& step);
|
||||
|
||||
void DrawJoint(b2Joint* joint);
|
||||
void DrawShape(b2Shape* shape, const b2XForm& xf, const b2Color& color, bool core);
|
||||
void DrawDebugData();
|
||||
|
||||
b2BlockAllocator m_blockAllocator;
|
||||
b2StackAllocator m_stackAllocator;
|
||||
|
||||
bool m_lock;
|
||||
|
||||
b2BroadPhase* m_broadPhase;
|
||||
b2ContactManager m_contactManager;
|
||||
|
||||
b2Body* m_bodyList;
|
||||
b2Joint* m_jointList;
|
||||
|
||||
// Do not access
|
||||
b2Contact* m_contactList;
|
||||
|
||||
int32 m_bodyCount;
|
||||
int32 m_contactCount;
|
||||
int32 m_jointCount;
|
||||
|
||||
b2Vec2 m_gravity;
|
||||
bool m_allowSleep;
|
||||
|
||||
b2Body* m_groundBody;
|
||||
|
||||
b2DestructionListener* m_destructionListener;
|
||||
b2BoundaryListener* m_boundaryListener;
|
||||
b2ContactFilter* m_contactFilter;
|
||||
b2ContactListener* m_contactListener;
|
||||
b2DebugDraw* m_debugDraw;
|
||||
|
||||
float32 m_inv_dt0;
|
||||
|
||||
int32 m_positionIterationCount;
|
||||
|
||||
// This is for debugging the solver.
|
||||
bool m_positionCorrection;
|
||||
|
||||
// This is for debugging the solver.
|
||||
bool m_warmStarting;
|
||||
|
||||
// This is for debugging the solver.
|
||||
bool m_continuousPhysics;
|
||||
};
|
||||
|
||||
inline b2Body* b2World::GetGroundBody()
|
||||
{
|
||||
return m_groundBody;
|
||||
}
|
||||
|
||||
inline b2Body* b2World::GetBodyList()
|
||||
{
|
||||
return m_bodyList;
|
||||
}
|
||||
|
||||
inline b2Joint* b2World::GetJointList()
|
||||
{
|
||||
return m_jointList;
|
||||
}
|
||||
|
||||
inline int32 b2World::GetBodyCount() const
|
||||
{
|
||||
return m_bodyCount;
|
||||
}
|
||||
|
||||
inline int32 b2World::GetJointCount() const
|
||||
{
|
||||
return m_jointCount;
|
||||
}
|
||||
|
||||
inline int32 b2World::GetContactCount() const
|
||||
{
|
||||
return m_contactCount;
|
||||
}
|
||||
|
||||
inline void b2World::SetGravity(const b2Vec2& gravity)
|
||||
{
|
||||
m_gravity = gravity;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "b2WorldCallbacks.h"
|
||||
#include "../Collision/Shapes/b2Shape.h"
|
||||
|
||||
b2ContactFilter b2_defaultFilter;
|
||||
|
||||
// Return true if contact calculations should be performed between these two shapes.
|
||||
// If you implement your own collision filter you may want to build from this implementation.
|
||||
bool b2ContactFilter::ShouldCollide(b2Shape* shape1, b2Shape* shape2)
|
||||
{
|
||||
const b2FilterData& filter1 = shape1->GetFilterData();
|
||||
const b2FilterData& filter2 = shape2->GetFilterData();
|
||||
|
||||
if (filter1.groupIndex == filter2.groupIndex && filter1.groupIndex != 0)
|
||||
{
|
||||
return filter1.groupIndex > 0;
|
||||
}
|
||||
|
||||
bool collide = (filter1.maskBits & filter2.categoryBits) != 0 && (filter1.categoryBits & filter2.maskBits) != 0;
|
||||
return collide;
|
||||
}
|
||||
|
||||
b2DebugDraw::b2DebugDraw()
|
||||
{
|
||||
m_drawFlags = 0;
|
||||
}
|
||||
|
||||
void b2DebugDraw::SetFlags(uint32 flags)
|
||||
{
|
||||
m_drawFlags = flags;
|
||||
}
|
||||
|
||||
uint32 b2DebugDraw::GetFlags() const
|
||||
{
|
||||
return m_drawFlags;
|
||||
}
|
||||
|
||||
void b2DebugDraw::AppendFlags(uint32 flags)
|
||||
{
|
||||
m_drawFlags |= flags;
|
||||
}
|
||||
|
||||
void b2DebugDraw::ClearFlags(uint32 flags)
|
||||
{
|
||||
m_drawFlags &= ~flags;
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B2_WORLD_CALLBACKS_H
|
||||
#define B2_WORLD_CALLBACKS_H
|
||||
|
||||
#include "../Common/b2Settings.h"
|
||||
|
||||
struct b2Vec2;
|
||||
struct b2XForm;
|
||||
class b2Shape;
|
||||
class b2Body;
|
||||
class b2Joint;
|
||||
class b2Contact;
|
||||
struct b2ContactPoint;
|
||||
struct b2ContactResult;
|
||||
|
||||
/// Joints and shapes are destroyed when their associated
|
||||
/// body is destroyed. Implement this listener so that you
|
||||
/// may nullify references to these joints and shapes.
|
||||
class b2DestructionListener
|
||||
{
|
||||
public:
|
||||
virtual ~b2DestructionListener() {}
|
||||
|
||||
/// Called when any joint is about to be destroyed due
|
||||
/// to the destruction of one of its attached bodies.
|
||||
virtual void SayGoodbye(b2Joint* joint) = 0;
|
||||
|
||||
/// Called when any shape is about to be destroyed due
|
||||
/// to the destruction of its parent body.
|
||||
virtual void SayGoodbye(b2Shape* shape) = 0;
|
||||
};
|
||||
|
||||
|
||||
/// This is called when a body's shape passes outside of the world boundary.
|
||||
class b2BoundaryListener
|
||||
{
|
||||
public:
|
||||
virtual ~b2BoundaryListener() {}
|
||||
|
||||
/// This is called for each body that leaves the world boundary.
|
||||
/// @warning you can't modify the world inside this callback.
|
||||
virtual void Violation(b2Body* body) = 0;
|
||||
};
|
||||
|
||||
|
||||
/// Implement this class to provide collision filtering. In other words, you can implement
|
||||
/// this class if you want finer control over contact creation.
|
||||
class b2ContactFilter
|
||||
{
|
||||
public:
|
||||
virtual ~b2ContactFilter() {}
|
||||
|
||||
/// Return true if contact calculations should be performed between these two shapes.
|
||||
/// @warning for performance reasons this is only called when the AABBs begin to overlap.
|
||||
virtual bool ShouldCollide(b2Shape* shape1, b2Shape* shape2);
|
||||
};
|
||||
|
||||
/// The default contact filter.
|
||||
extern b2ContactFilter b2_defaultFilter;
|
||||
|
||||
/// Implement this class to get collision results. You can use these results for
|
||||
/// things like sounds and game logic. You can also get contact results by
|
||||
/// traversing the contact lists after the time step. However, you might miss
|
||||
/// some contacts because continuous physics leads to sub-stepping.
|
||||
/// Additionally you may receive multiple callbacks for the same contact in a
|
||||
/// single time step.
|
||||
/// You should strive to make your callbacks efficient because there may be
|
||||
/// many callbacks per time step.
|
||||
/// @warning The contact separation is the last computed value.
|
||||
/// @warning You cannot create/destroy Box2D entities inside these callbacks.
|
||||
class b2ContactListener
|
||||
{
|
||||
public:
|
||||
virtual ~b2ContactListener() {}
|
||||
|
||||
/// Called when a contact point is added. This includes the geometry
|
||||
/// and the forces.
|
||||
virtual void Add(const b2ContactPoint* point) { }
|
||||
|
||||
/// Called when a contact point persists. This includes the geometry
|
||||
/// and the forces.
|
||||
virtual void Persist(const b2ContactPoint* point) { }
|
||||
|
||||
/// Called when a contact point is removed. This includes the last
|
||||
/// computed geometry and forces.
|
||||
virtual void Remove(const b2ContactPoint* point) { }
|
||||
|
||||
/// Called after a contact point is solved.
|
||||
virtual void Result(const b2ContactResult* point) { }
|
||||
};
|
||||
|
||||
/// Color for debug drawing. Each value has the range [0,1].
|
||||
struct b2Color
|
||||
{
|
||||
b2Color() {}
|
||||
b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {}
|
||||
float32 r, g, b;
|
||||
};
|
||||
|
||||
/// Implement and register this class with a b2World to provide debug drawing of physics
|
||||
/// entities in your game.
|
||||
class b2DebugDraw
|
||||
{
|
||||
public:
|
||||
b2DebugDraw();
|
||||
|
||||
virtual ~b2DebugDraw() {}
|
||||
|
||||
enum
|
||||
{
|
||||
e_shapeBit = 0x0001, ///< draw shapes
|
||||
e_jointBit = 0x0002, ///< draw joint connections
|
||||
e_coreShapeBit = 0x0004, ///< draw core (TOI) shapes
|
||||
e_aabbBit = 0x0008, ///< draw axis aligned bounding boxes
|
||||
e_obbBit = 0x0010, ///< draw oriented bounding boxes
|
||||
e_pairBit = 0x0020, ///< draw broad-phase pairs
|
||||
e_centerOfMassBit = 0x0040, ///< draw center of mass frame
|
||||
};
|
||||
|
||||
/// Set the drawing flags.
|
||||
void SetFlags(uint32 flags);
|
||||
|
||||
/// Get the drawing flags.
|
||||
uint32 GetFlags() const;
|
||||
|
||||
/// Append flags to the current flags.
|
||||
void AppendFlags(uint32 flags);
|
||||
|
||||
/// Clear flags from the current flags.
|
||||
void ClearFlags(uint32 flags);
|
||||
|
||||
/// Draw a closed polygon provided in CCW order.
|
||||
virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
|
||||
|
||||
/// Draw a solid closed polygon provided in CCW order.
|
||||
virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
|
||||
|
||||
/// Draw a circle.
|
||||
virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0;
|
||||
|
||||
/// Draw a solid circle.
|
||||
virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0;
|
||||
|
||||
/// Draw a line segment.
|
||||
virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0;
|
||||
|
||||
/// Draw a transform. Choose your own length scale.
|
||||
/// @param xf a transform.
|
||||
virtual void DrawXForm(const b2XForm& xf) = 0;
|
||||
|
||||
protected:
|
||||
uint32 m_drawFlags;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "World.h"
|
||||
|
||||
#include "Shape.h"
|
||||
#include "Contact.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
|
||||
World::World(b2AABB aabb)
|
||||
: add_ref(0), meter(DEFAULT_METER)
|
||||
{
|
||||
world = new b2World(scaleDown(aabb), b2Vec2(0,0), true);
|
||||
world->SetContactListener(this);
|
||||
add_contacts.reserve(10);
|
||||
}
|
||||
|
||||
World::World(b2AABB aabb, b2Vec2 gravity, bool sleep)
|
||||
: add_ref(0), meter(DEFAULT_METER)
|
||||
{
|
||||
world = new b2World(scaleDown(aabb), scaleDown(gravity), sleep);
|
||||
world->SetContactListener(this);
|
||||
add_contacts.reserve(10);
|
||||
}
|
||||
|
||||
World::~World()
|
||||
{
|
||||
if(add_ref != 0)
|
||||
delete add_ref;
|
||||
|
||||
delete world;
|
||||
}
|
||||
|
||||
void World::update(float dt)
|
||||
{
|
||||
world->Step(dt, 10);
|
||||
|
||||
// Process contacts.
|
||||
if(add_ref != 0)
|
||||
{
|
||||
lua_State * L = add_ref->getL();
|
||||
for(int i = 0;i<(int)add_contacts.size();i++)
|
||||
{
|
||||
// Push the function.
|
||||
add_ref->push();
|
||||
|
||||
// Push first userdata.
|
||||
{
|
||||
shapeudata * d = (shapeudata *)(add_contacts[i]->point.shape1->GetUserData());
|
||||
if(d->ref != 0)
|
||||
d->ref->push();
|
||||
else
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
// Push first userdata.
|
||||
{
|
||||
shapeudata * d = (shapeudata *)(add_contacts[i]->point.shape2->GetUserData());
|
||||
if(d->ref != 0)
|
||||
d->ref->push();
|
||||
else
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
luax_newtype(L, "Contact", (LOVE_PHYSICS_CONTACT_BITS), (void*)add_contacts[i], false);
|
||||
lua_call(L, 3, 0);
|
||||
}
|
||||
|
||||
// Clear contacts.
|
||||
for(int i = 0;i<(int)add_contacts.size();i++)
|
||||
delete add_contacts[i];
|
||||
add_contacts.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void World::Add(const b2ContactPoint* point)
|
||||
{
|
||||
/**
|
||||
* We must copy contacts, since we're not allowed to process
|
||||
* them inside this function. Removing bodies in this function
|
||||
* pretty much guarantees segfault. ^^
|
||||
**/
|
||||
|
||||
if(add_ref != 0)
|
||||
add_contacts.push_back(new Contact(this, point));
|
||||
}
|
||||
|
||||
int World::setCallback(lua_State * L)
|
||||
{
|
||||
luax_assert_argc(L, 1, 1);
|
||||
luax_assert_function(L, -1);
|
||||
|
||||
if(add_ref != 0)
|
||||
{
|
||||
delete add_ref;
|
||||
add_ref = 0;
|
||||
}
|
||||
|
||||
add_ref = new Reference(L);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int World::getCallback(lua_State * L)
|
||||
{
|
||||
if(add_ref != 0)
|
||||
add_ref->push();
|
||||
else
|
||||
lua_pushnil(L);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void World::setGravity(float x, float y)
|
||||
{
|
||||
world->SetGravity(scaleDown(b2Vec2(x, y)));
|
||||
}
|
||||
|
||||
int World::getGravity(lua_State * L)
|
||||
{
|
||||
b2Vec2 v = scaleUp(world->m_gravity);
|
||||
lua_pushnumber(L, v.x);
|
||||
lua_pushnumber(L, v.y);
|
||||
return 2;
|
||||
}
|
||||
|
||||
void World::setAllowSleep(bool allow)
|
||||
{
|
||||
world->m_allowSleep = allow;
|
||||
}
|
||||
|
||||
bool World::isAllowSleep() const
|
||||
{
|
||||
return world->m_allowSleep;
|
||||
}
|
||||
|
||||
int World::getBodyCount()
|
||||
{
|
||||
return world->GetBodyCount();
|
||||
}
|
||||
|
||||
int World::getJointCount()
|
||||
{
|
||||
return world->GetJointCount();
|
||||
}
|
||||
|
||||
void World::setMeter(int meter)
|
||||
{
|
||||
this->meter = meter;
|
||||
}
|
||||
|
||||
int World::getMeter() const
|
||||
{
|
||||
return this->meter;
|
||||
}
|
||||
|
||||
void World::scaleDown(float & x, float & y)
|
||||
{
|
||||
x /= (float)meter;
|
||||
y /= (float)meter;
|
||||
}
|
||||
|
||||
void World::scaleUp(float & x, float & y)
|
||||
{
|
||||
x *= (float)meter;
|
||||
y *= (float)meter;
|
||||
}
|
||||
|
||||
float World::scaleDown(float f)
|
||||
{
|
||||
return f/(float)meter;
|
||||
}
|
||||
|
||||
float World::scaleUp(float f)
|
||||
{
|
||||
return f*(float)meter;
|
||||
}
|
||||
|
||||
b2Vec2 World::scaleDown(const b2Vec2 & v)
|
||||
{
|
||||
b2Vec2 t = v;
|
||||
scaleDown(t.x, t.y);
|
||||
return t;
|
||||
}
|
||||
|
||||
b2Vec2 World::scaleUp(const b2Vec2 & v)
|
||||
{
|
||||
b2Vec2 t = v;
|
||||
scaleUp(t.x, t.y);
|
||||
return t;
|
||||
}
|
||||
|
||||
b2AABB World::scaleDown(const b2AABB & aabb)
|
||||
{
|
||||
b2AABB t;
|
||||
t.lowerBound = scaleDown(aabb.lowerBound);
|
||||
t.upperBound = scaleDown(aabb.upperBound);
|
||||
return t;
|
||||
}
|
||||
|
||||
b2AABB World::scaleUp(const b2AABB & aabb)
|
||||
{
|
||||
b2AABB t;
|
||||
t.lowerBound = scaleUp(aabb.lowerBound);
|
||||
t.upperBound = scaleUp(aabb.upperBound);
|
||||
return t;
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,237 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_WORLD_H
|
||||
#define LOVE_PHYSICS_BOX2D_WORLD_H
|
||||
|
||||
// LOVE
|
||||
#include <common/Object.h>
|
||||
#include <common/runtime.h>
|
||||
#include <common/Reference.h>
|
||||
|
||||
// STD
|
||||
#include <vector>
|
||||
|
||||
// Box2D
|
||||
#include "Include/Box2D.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
|
||||
class Contact;
|
||||
|
||||
/**
|
||||
* The World is the "God" container class,
|
||||
* which contains all Bodies and Joints. Shapes
|
||||
* are contained in their associated Body.
|
||||
*
|
||||
* Bodies in different worlds can obviously not
|
||||
* collide.
|
||||
*
|
||||
* The world also controls global parameters, like
|
||||
* gravity.
|
||||
**/
|
||||
class World : public Object, public b2ContactListener
|
||||
{
|
||||
// Friends.
|
||||
friend class Joint;
|
||||
friend class DistanceJoint;
|
||||
friend class MouseJoint;
|
||||
friend class Body;
|
||||
|
||||
private:
|
||||
|
||||
// Pointer to the Box2D world.
|
||||
b2World * world;
|
||||
|
||||
// Contact callbacks.
|
||||
Reference * add_ref;
|
||||
|
||||
// Contacts buffers.
|
||||
std::vector<Contact *> add_contacts;
|
||||
|
||||
// The length of one meter in pixels.
|
||||
int meter;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* 30 pixels in one meter by default.
|
||||
**/
|
||||
static const int DEFAULT_METER = 30;
|
||||
|
||||
/**
|
||||
* Creates a new world with the given bounding box.
|
||||
* @param aabb The bounding box.
|
||||
**/
|
||||
World(b2AABB aabb);
|
||||
|
||||
/**
|
||||
* Creates a new world with the given bounding box, gravity
|
||||
* and whether or not the bodies should sleep when appropriate.
|
||||
* @param aabb The bounding box.
|
||||
* @param gravity The gravity of the World.
|
||||
* @param sleep True if the bodies should be able to sleep,
|
||||
* false otherwise.
|
||||
**/
|
||||
World(b2AABB aabb, b2Vec2 gravity, bool sleep);
|
||||
|
||||
~World();
|
||||
|
||||
/**
|
||||
* Updates everything in the world one timestep.
|
||||
* This is called update() and not step() to conform
|
||||
* with all other objects in LOVE.
|
||||
* @param dt The timestep.
|
||||
**/
|
||||
void update(float dt);
|
||||
|
||||
// From b2ContactListener
|
||||
void Add(const b2ContactPoint* point);
|
||||
|
||||
/**
|
||||
* Recieves a Lua function as argument, and
|
||||
* stores it for use when a collision occurs.
|
||||
**/
|
||||
int setCallback(lua_State * L);
|
||||
|
||||
/**
|
||||
* Returns the stored Lua function for collision
|
||||
* handling, or nil if there is none.
|
||||
**/
|
||||
int getCallback(lua_State * L);
|
||||
|
||||
/**
|
||||
* Sets the current gravity of the World.
|
||||
* @param x Gravity in the x-direction.
|
||||
* @param y Gravity in the y-direction.
|
||||
**/
|
||||
void setGravity(float x, float y);
|
||||
|
||||
/**
|
||||
* Gets the current gravity.
|
||||
* @returns Gravity in the x-direction.
|
||||
* @returns Gravity in the y-direction.
|
||||
**/
|
||||
int getGravity(lua_State * L);
|
||||
|
||||
/**
|
||||
* Sets whether this World allows sleep.
|
||||
* @param allow True to allow, false to disallow.
|
||||
**/
|
||||
void setAllowSleep(bool allow);
|
||||
|
||||
/**
|
||||
* Returns whether this World allows sleep.
|
||||
* @return True if allowed, false if disallowed.
|
||||
**/
|
||||
bool isAllowSleep() const;
|
||||
|
||||
/**
|
||||
* Get the current body count.
|
||||
* @return The number of bodies.
|
||||
**/
|
||||
int getBodyCount();
|
||||
|
||||
/**
|
||||
* Get the current joint count.
|
||||
* @return The number of joints.
|
||||
**/
|
||||
int getJointCount();
|
||||
|
||||
/**
|
||||
* Sets the number of pixels in one meter.
|
||||
* @param pixels The number of pixels in one meter. (1m ~= 3.3ft).
|
||||
**/
|
||||
void setMeter(int meter);
|
||||
|
||||
/**
|
||||
* Gets the number of pixels in one meter.
|
||||
* @param pixels The number of pixels in one meter. (1m ~= 3.3ft).
|
||||
**/
|
||||
int getMeter() const;
|
||||
|
||||
/**
|
||||
* Scales a value down according to the current meter in pixels.
|
||||
* @param f The unscaled input value.
|
||||
**/
|
||||
float scaleDown(float f);
|
||||
|
||||
/**
|
||||
* Scales a value up according to the current meter in pixels.
|
||||
* @param f The unscaled input value.
|
||||
**/
|
||||
float scaleUp(float f);
|
||||
|
||||
/**
|
||||
* Scales a point down according to the current meter
|
||||
* in pixels, for instance x = x0/meter, y = x0/meter.
|
||||
* @param x The x-coordinate of the point to scale.
|
||||
* @param y The y-coordinate of the point to scale.
|
||||
**/
|
||||
void scaleDown(float & x, float & y);
|
||||
|
||||
/**
|
||||
* Scales a point up according to the current meter
|
||||
* in pixels, for instance x = x0/meter, y = x0/meter.
|
||||
* @param x The x-coordinate of the point to scale.
|
||||
* @param y The y-coordinate of the point to scale.
|
||||
**/
|
||||
void scaleUp(float & x, float & y);
|
||||
|
||||
/**
|
||||
* Scales a b2Vec2 down according to the current meter in pixels.
|
||||
* @param v The unscaled input vector.
|
||||
* @return The scaled vector.
|
||||
**/
|
||||
b2Vec2 scaleDown(const b2Vec2 & v);
|
||||
|
||||
/**
|
||||
* Scales a b2Vec up according to the current meter in pixels.
|
||||
* @param v The unscaled input vector.
|
||||
* @return The scaled vector.
|
||||
**/
|
||||
b2Vec2 scaleUp(const b2Vec2 & v);
|
||||
|
||||
/**
|
||||
* Scales a b2AABB down according to the current meter in pixels.
|
||||
* @param v The unscaled input AABB.
|
||||
* @return The scaled AABB.
|
||||
**/
|
||||
b2AABB scaleDown(const b2AABB & aabb);
|
||||
|
||||
/**
|
||||
* Scales a b2AABB up according to the current meter in pixels.
|
||||
* @param v The unscaled input AABB.
|
||||
* @return The scaled AABB.
|
||||
**/
|
||||
b2AABB scaleUp(const b2AABB & aabb);
|
||||
|
||||
};
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_WORLD_H
|
||||
@@ -0,0 +1,122 @@
|
||||
#include "GrahamScanConvexHull.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
bool GrahamScanConvexHull::operator()(const std::vector < point2d >& pnt, std::vector< point2d >& final_hull)
|
||||
{
|
||||
final_hull.clear();
|
||||
|
||||
if (pnt.size() <= 3)
|
||||
{
|
||||
std::copy(pnt.begin(), pnt.end(), std::back_inserter(final_hull));
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int j = 0;
|
||||
gs_point2d tmp_pnt;
|
||||
|
||||
for(unsigned int i = 0; i < pnt.size(); i++)
|
||||
{
|
||||
point.push_back(gs_point2d(pnt[i].x,pnt[i].y,0.0));
|
||||
|
||||
if (point[i].y < point[j].y)
|
||||
j = i;
|
||||
else if (point[i].y == point[j].y)
|
||||
if (point[i].x < point[j].x)
|
||||
j = i;
|
||||
}
|
||||
|
||||
tmp_pnt = point[0];
|
||||
point[0] = point[j];
|
||||
point[j] = tmp_pnt;
|
||||
|
||||
anchor = point[0];
|
||||
|
||||
for (unsigned int i = 1; i < point.size(); i++)
|
||||
{
|
||||
point[i].angle = cartesian_angle(point[i].x - anchor.x, point[i].y - anchor.y);
|
||||
}
|
||||
|
||||
sort(++point.begin(),point.end(),GSPoint2DCompare(&anchor));
|
||||
|
||||
graham_scan(final_hull);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void GrahamScanConvexHull::graham_scan(std::vector< point2d >& final_hull)
|
||||
{
|
||||
const std::size_t HEAD = 0;
|
||||
const std::size_t PRE_HEAD = 1;
|
||||
|
||||
std::deque<gs_point2d> pnt_queue;
|
||||
|
||||
pnt_queue.push_front(point[0]);
|
||||
pnt_queue.push_front(point[1]);
|
||||
|
||||
unsigned int i = 2;
|
||||
|
||||
while(i < point.size())
|
||||
{
|
||||
if (pnt_queue.size() > 1)
|
||||
{
|
||||
if (orientation(pnt_queue[PRE_HEAD],pnt_queue[HEAD],point[i]) == counter_clock_wise)
|
||||
pnt_queue.push_front(point[i++]);
|
||||
else
|
||||
pnt_queue.pop_front();
|
||||
}
|
||||
else
|
||||
pnt_queue.push_front(point[i++]);
|
||||
}
|
||||
|
||||
for(std::deque<gs_point2d>::iterator it = pnt_queue.begin(); it != pnt_queue.end(); it++)
|
||||
{
|
||||
final_hull.push_back(point2d((*it).x, (*it).y));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline double GrahamScanConvexHull::cartesian_angle(double x, double y)
|
||||
{
|
||||
if ((x > 0.0) && (y > 0.0)) return (atan( y / x) * _180DivPI);
|
||||
else if ((x < 0.0) && (y > 0.0)) return (atan(-x / y) * _180DivPI) + 90.0;
|
||||
else if ((x < 0.0) && (y < 0.0)) return (atan( y / x) * _180DivPI) + 180.0;
|
||||
else if ((x > 0.0) && (y < 0.0)) return (atan(-x / y) * _180DivPI) + 270.0;
|
||||
else if ((x == 0.0) && (y > 0.0)) return 90.0;
|
||||
else if ((x < 0.0) && (y == 0.0)) return 180.0;
|
||||
else if ((x == 0.0) && (y < 0.0)) return 270.0;
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
|
||||
inline int GrahamScanConvexHull::orientation(const gs_point2d& p1, const gs_point2d& p2, const gs_point2d& p3)
|
||||
{
|
||||
return orientation(p1.x,p1.y,p2.x,p2.y,p3.x,p3.y);
|
||||
}
|
||||
|
||||
|
||||
inline int GrahamScanConvexHull::orientation(const double x1, const double y1,
|
||||
const double x2, const double y2,
|
||||
const double px, const double py)
|
||||
{
|
||||
double orin = (x2 - x1) * (py - y1) - (px - x1) * (y2 - y1);
|
||||
|
||||
if (is_equal(orin,0.0))
|
||||
return 0; /* Orientaion is neutral aka collinear */
|
||||
else if (orin < 0.0)
|
||||
return -1; /* Orientaion is to the right-hand side */
|
||||
else
|
||||
return +1; /* Orientaion is to the left-hand side */
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline bool GrahamScanConvexHull::is_equal(const double v1, const double& v2, const double epsilon)
|
||||
{
|
||||
double diff = v1 - v2;
|
||||
return (-epsilon <= diff) && (diff <= epsilon);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
**************************************************************************
|
||||
* Class: Graham Scan Convex Hull *
|
||||
* By Arash Partow - 2001 *
|
||||
* URL: http://www.partow.net *
|
||||
* *
|
||||
* Copyright Notice: *
|
||||
* Free use of this library is permitted under the guidelines and *
|
||||
* in accordance with the most current version of the Common Public *
|
||||
* License. *
|
||||
* http://www.opensource.org/licenses/cpl.php *
|
||||
* *
|
||||
**************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_GRAHAMSCANCONVEXHULL_H
|
||||
#define INCLUDE_GRAHAMSCANCONVEXHULL_H
|
||||
|
||||
#include <iostream>
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
struct point2d
|
||||
{
|
||||
point2d(double _x = 0.0 , double _y = 0.0) : x(_x), y(_y){}
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
class ConvexHull
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~ConvexHull(){};
|
||||
virtual bool operator()(const std::vector<point2d>& pnt, std::vector<point2d>& final_hull) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct gs_point2d
|
||||
{
|
||||
public:
|
||||
gs_point2d(double _x = 0.0, double _y = 0.0, double _angle = 0.0) : x(_x), y(_y), angle(_angle){}
|
||||
double x;
|
||||
double y;
|
||||
double angle;
|
||||
};
|
||||
|
||||
const double _180DivPI = 57.295779513082320876798154814105000;
|
||||
const int counter_clock_wise = +1;
|
||||
const int clock_wise = -1;
|
||||
|
||||
|
||||
class GSPoint2DCompare
|
||||
{
|
||||
public:
|
||||
|
||||
GSPoint2DCompare(gs_point2d* _anchor):anchor(_anchor){};
|
||||
|
||||
bool operator()(const gs_point2d& p1, const gs_point2d& p2)
|
||||
{
|
||||
if (p1.angle < p2.angle) return true;
|
||||
else if (p1.angle > p2.angle) return false;
|
||||
else if (is_equal(p1,p2)) return false;
|
||||
else if (lay_distance(anchor->x, anchor->y, p1.x, p1.y) < lay_distance(anchor->x, anchor->y, p2.x, p2.y))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
inline bool is_equal(const gs_point2d p1, gs_point2d p2)
|
||||
{
|
||||
return is_equal(p1.x,p2.x) && is_equal(p1.y,p2.y);
|
||||
}
|
||||
|
||||
inline bool is_equal(const double v1, const double& v2, const double epsilon = 1.0e-12)
|
||||
{
|
||||
double diff = v1 - v2;
|
||||
return (-epsilon <= diff) && (diff <= epsilon);
|
||||
}
|
||||
|
||||
inline double lay_distance(const double& x1, const double& y1, const double& x2, const double& y2)
|
||||
{
|
||||
double dx = (x1 - x2);
|
||||
double dy = (y1 - y2);
|
||||
return (dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
gs_point2d* anchor;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class GrahamScanConvexHull : public ConvexHull
|
||||
{
|
||||
public:
|
||||
|
||||
GrahamScanConvexHull(){};
|
||||
~GrahamScanConvexHull(){};
|
||||
|
||||
virtual bool operator()(const std::vector < point2d >& pnt, std::vector< point2d >& final_hull);
|
||||
|
||||
private:
|
||||
|
||||
void graham_scan(std::vector< point2d >& final_hull);
|
||||
|
||||
inline double cartesian_angle(double x, double y);
|
||||
|
||||
inline int orientation(const gs_point2d& p1,
|
||||
const gs_point2d& p2,
|
||||
const gs_point2d& p3);
|
||||
|
||||
inline int orientation(const double x1, const double y1,
|
||||
const double x2, const double y2,
|
||||
const double px, const double py);
|
||||
|
||||
inline bool is_equal(const double v1, const double& v2, const double epsilon = 1.0e-12);
|
||||
|
||||
std::vector<gs_point2d> point;
|
||||
gs_point2d anchor;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,374 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "wrap_Body.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
Body * luax_checkbody(lua_State * L, int idx)
|
||||
{
|
||||
return luax_checktype<Body>(L, idx, "Body", LOVE_PHYSICS_BODY_BITS);
|
||||
}
|
||||
|
||||
int _wrap_Body_getX(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
lua_pushnumber(L, t->getX());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_Body_getY(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
lua_pushnumber(L, t->getY());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_Body_getAngle(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
lua_pushnumber(L, t->getAngle());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_Body_getPosition(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
return t->getPosition(L);
|
||||
}
|
||||
|
||||
int _wrap_Body_getVelocity(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
return t->getVelocity(L);
|
||||
}
|
||||
|
||||
int _wrap_Body_getWorldCenter(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
return t->getWorldCenter(L);
|
||||
}
|
||||
|
||||
int _wrap_Body_getLocalCenter(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
return t->getLocalCenter(L);
|
||||
}
|
||||
|
||||
int _wrap_Body_getSpin(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
lua_pushnumber(L, t->getSpin());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_Body_getMass(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
lua_pushnumber(L, t->getMass());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_Body_getInertia(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
lua_pushnumber(L, t->getInertia());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_Body_getAngularDamping(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
lua_pushnumber(L, t->getAngularDamping());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_Body_getDamping(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
lua_pushnumber(L, t->getDamping());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_Body_applyImpulse(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
float jx = (float)luaL_checknumber(L, 2);
|
||||
float jy = (float)luaL_checknumber(L, 3);
|
||||
float rx = (float)luaL_optnumber(L, 4, 0);
|
||||
float ry = (float)luaL_optnumber(L, 5, 0);
|
||||
t->applyImpulse(jx, jy, rx, ry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_Body_applyTorque(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
float arg = (float)luaL_checknumber(L, 2);
|
||||
t->applyTorque(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_Body_applyForce(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
float fx = (float)luaL_checknumber(L, 2);
|
||||
float fy = (float)luaL_checknumber(L, 3);
|
||||
float rx = (float)luaL_optnumber(L, 4, 0);
|
||||
float ry = (float)luaL_optnumber(L, 5, 0);
|
||||
t->applyForce(fx, fy, rx, ry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_Body_setX(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
t->setX(arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_Body_setY(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
t->setY(arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_Body_setVelocity(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
float arg2 = (float)luaL_checknumber(L, 3);
|
||||
t->setVelocity(arg1, arg2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_Body_setAngle(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
t->setAngle(arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_Body_setSpin(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
t->setSpin(arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_Body_setPosition(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
float arg2 = (float)luaL_checknumber(L, 3);
|
||||
t->setPosition(arg1, arg2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_Body_setMassFromShapes(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
t->setMassFromShapes();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_Body_setMass(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
float x = (float)luaL_checknumber(L, 2);
|
||||
float y = (float)luaL_checknumber(L, 3);
|
||||
float m = (float)luaL_checknumber(L, 4);
|
||||
float i = (float)luaL_checknumber(L, 5);
|
||||
t->setMass(x, y, m, i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_Body_setAngularDamping(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
t->setAngularDamping(arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_Body_setDamping(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
t->setDamping(arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_Body_getWorldPoint(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
return t->getWorldPoint(L);
|
||||
}
|
||||
|
||||
int _wrap_Body_getWorldVector(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
return t->getWorldVector(L);
|
||||
}
|
||||
|
||||
int _wrap_Body_getLocalPoint(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
return t->getLocalPoint(L);
|
||||
}
|
||||
|
||||
int _wrap_Body_getLocalVector(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
return t->getLocalVector(L);
|
||||
}
|
||||
|
||||
int _wrap_Body_getVelocityWorldPoint(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
return t->getVelocityWorldPoint(L);
|
||||
}
|
||||
|
||||
int _wrap_Body_getVelocityLocalPoint(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
return t->getVelocityLocalPoint(L);
|
||||
}
|
||||
|
||||
int _wrap_Body_isBullet(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
luax_pushboolean(L, t->isBullet());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_Body_setBullet(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
bool b = luax_toboolean(L, 2);
|
||||
t->setBullet(b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_Body_isStatic(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
luax_pushboolean(L, t->isStatic());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_Body_isDynamic(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
luax_pushboolean(L, t->isDynamic());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_Body_isFrozen(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
luax_pushboolean(L, t->isFrozen());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_Body_isSleeping(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
luax_pushboolean(L, t->isSleeping());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_Body_setAllowSleep(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
bool b = luax_toboolean(L, 2);
|
||||
t->setAllowSleep(b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_Body_setSleep(lua_State * L)
|
||||
{
|
||||
Body * t = luax_checkbody(L, 1);
|
||||
bool b = luax_toboolean(L, 2);
|
||||
t->setSleep(b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const luaL_Reg wrap_Body_functions[] = {
|
||||
{ "getX", _wrap_Body_getX },
|
||||
{ "getY", _wrap_Body_getY },
|
||||
{ "getAngle", _wrap_Body_getAngle },
|
||||
{ "getPosition", _wrap_Body_getPosition },
|
||||
{ "getVelocity", _wrap_Body_getVelocity },
|
||||
{ "getWorldCenter", _wrap_Body_getWorldCenter },
|
||||
{ "getLocalCenter", _wrap_Body_getLocalCenter },
|
||||
{ "getSpin", _wrap_Body_getSpin },
|
||||
{ "getMass", _wrap_Body_getMass },
|
||||
{ "getInertia", _wrap_Body_getInertia },
|
||||
{ "getAngularDamping", _wrap_Body_getAngularDamping },
|
||||
{ "getDamping", _wrap_Body_getDamping },
|
||||
{ "applyImpulse", _wrap_Body_applyImpulse },
|
||||
{ "applyTorque", _wrap_Body_applyTorque },
|
||||
{ "applyForce", _wrap_Body_applyForce },
|
||||
{ "setX", _wrap_Body_setX },
|
||||
{ "setY", _wrap_Body_setY },
|
||||
{ "setVelocity", _wrap_Body_setVelocity },
|
||||
{ "setAngle", _wrap_Body_setAngle },
|
||||
{ "setSpin", _wrap_Body_setSpin },
|
||||
{ "setPosition", _wrap_Body_setPosition },
|
||||
{ "setMassFromShapes", _wrap_Body_setMassFromShapes },
|
||||
{ "setMass", _wrap_Body_setMass },
|
||||
{ "setAngularDamping", _wrap_Body_setAngularDamping },
|
||||
{ "setDamping", _wrap_Body_setDamping },
|
||||
{ "getWorldPoint", _wrap_Body_getWorldPoint },
|
||||
{ "getWorldVector", _wrap_Body_getWorldVector },
|
||||
{ "getLocalPoint", _wrap_Body_getLocalPoint },
|
||||
{ "getLocalVector", _wrap_Body_getLocalVector },
|
||||
{ "getVelocityWorldPoint", _wrap_Body_getVelocityWorldPoint },
|
||||
{ "getVelocityLocalPoint", _wrap_Body_getVelocityLocalPoint },
|
||||
{ "isBullet", _wrap_Body_isBullet },
|
||||
{ "setBullet", _wrap_Body_setBullet },
|
||||
{ "isStatic", _wrap_Body_isStatic },
|
||||
{ "isDynamic", _wrap_Body_isDynamic },
|
||||
{ "isFrozen", _wrap_Body_isFrozen },
|
||||
{ "isSleeping", _wrap_Body_isSleeping },
|
||||
{ "setAllowSleep", _wrap_Body_setAllowSleep },
|
||||
{ "setSleep", _wrap_Body_setSleep },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
int wrap_Body_open(lua_State * L)
|
||||
{
|
||||
luax_register_type(L, "Body", wrap_Body_functions);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_WRAP_BODY_H
|
||||
#define LOVE_PHYSICS_BOX2D_WRAP_BODY_H
|
||||
|
||||
// LOVE
|
||||
#include <common/runtime.h>
|
||||
#include "Body.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
|
||||
Body * luax_checkbody(lua_State * L, int idx);
|
||||
int _wrap_Body_getX(lua_State * L);
|
||||
int _wrap_Body_getY(lua_State * L);
|
||||
int _wrap_Body_getAngle(lua_State * L);
|
||||
int _wrap_Body_getPosition(lua_State * L);
|
||||
int _wrap_Body_getVelocity(lua_State * L);
|
||||
int _wrap_Body_getWorldCenter(lua_State * L);
|
||||
int _wrap_Body_getLocalCenter(lua_State * L);
|
||||
int _wrap_Body_getSpin(lua_State * L);
|
||||
int _wrap_Body_getMass(lua_State * L);
|
||||
int _wrap_Body_getInertia(lua_State * L);
|
||||
int _wrap_Body_getAngularDamping(lua_State * L);
|
||||
int _wrap_Body_getDamping(lua_State * L);
|
||||
int _wrap_Body_applyImpulse(lua_State * L);
|
||||
int _wrap_Body_applyTorque(lua_State * L);
|
||||
int _wrap_Body_applyForce(lua_State * L);
|
||||
int _wrap_Body_setX(lua_State * L);
|
||||
int _wrap_Body_setY(lua_State * L);
|
||||
int _wrap_Body_setVelocity(lua_State * L);
|
||||
int _wrap_Body_setAngle(lua_State * L);
|
||||
int _wrap_Body_setSpin(lua_State * L);
|
||||
int _wrap_Body_setPosition(lua_State * L);
|
||||
int _wrap_Body_setMassFromShapes(lua_State * L);
|
||||
int _wrap_Body_setMass(lua_State * L);
|
||||
int _wrap_Body_setAngularDamping(lua_State * L);
|
||||
int _wrap_Body_setDamping(lua_State * L);
|
||||
int _wrap_Body_getWorldPoint(lua_State * L);
|
||||
int _wrap_Body_getWorldVector(lua_State * L);
|
||||
int _wrap_Body_getLocalPoint(lua_State * L);
|
||||
int _wrap_Body_getLocalVector(lua_State * L);
|
||||
int _wrap_Body_getVelocityWorldPoint(lua_State * L);
|
||||
int _wrap_Body_getVelocityLocalPoint(lua_State * L);
|
||||
int _wrap_Body_isBullet(lua_State * L);
|
||||
int _wrap_Body_setBullet(lua_State * L);
|
||||
int _wrap_Body_isStatic(lua_State * L);
|
||||
int _wrap_Body_isDynamic(lua_State * L);
|
||||
int _wrap_Body_isFrozen(lua_State * L);
|
||||
int _wrap_Body_isSleeping(lua_State * L);
|
||||
int _wrap_Body_setAllowSleep(lua_State * L);
|
||||
int _wrap_Body_setSleep(lua_State * L);
|
||||
int wrap_Body_open(lua_State * L);
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_WRAP_BODY_H
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "wrap_CircleShape.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
CircleShape * luax_checkcircleshape(lua_State * L, int idx)
|
||||
{
|
||||
return luax_checktype<CircleShape>(L, idx, "CircleShape", LOVE_PHYSICS_CIRCLE_SHAPE_BITS);
|
||||
}
|
||||
|
||||
int _wrap_CircleShape_getRadius(lua_State * L)
|
||||
{
|
||||
CircleShape * c = luax_checkcircleshape(L, 1);
|
||||
lua_pushnumber(L, c->getRadius());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg wrap_CircleShape_functions[] = {
|
||||
{ "getRadius", _wrap_CircleShape_getRadius },
|
||||
// From Shape.
|
||||
{ "getType", _wrap_Shape_getType },
|
||||
{ "setFriction", _wrap_Shape_setFriction },
|
||||
{ "setRestitution", _wrap_Shape_setRestitution },
|
||||
{ "setDensity", _wrap_Shape_setDensity },
|
||||
{ "setSensor", _wrap_Shape_setSensor },
|
||||
{ "getFriction", _wrap_Shape_getFriction },
|
||||
{ "getRestituion", _wrap_Shape_getRestituion },
|
||||
{ "getDensity", _wrap_Shape_getDensity },
|
||||
{ "isSensor", _wrap_Shape_isSensor },
|
||||
{ "testPoint", _wrap_Shape_testPoint },
|
||||
{ "testSegment", _wrap_Shape_testSegment },
|
||||
{ "setCategory", _wrap_Shape_setCategory },
|
||||
{ "getCategory", _wrap_Shape_getCategory },
|
||||
{ "setMask", _wrap_Shape_setMask },
|
||||
{ "getMask", _wrap_Shape_getMask },
|
||||
{ "setData", _wrap_Shape_setData },
|
||||
{ "getData", _wrap_Shape_getData },
|
||||
{ "getBoundingBox", _wrap_Shape_getBoundingBox },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
int wrap_CircleShape_open(lua_State * L)
|
||||
{
|
||||
luax_register_type(L, "CircleShape", wrap_CircleShape_functions);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_WRAP_CIRCLE_SHAPE_H
|
||||
#define LOVE_PHYSICS_BOX2D_WRAP_CIRCLE_SHAPE_H
|
||||
|
||||
// LOVE
|
||||
#include <common/runtime.h>
|
||||
#include "wrap_Shape.h"
|
||||
#include "CircleShape.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
CircleShape * luax_checkcircleshape(lua_State * L, int idx);
|
||||
int _wrap_CircleShape_getRadius(lua_State * L);
|
||||
int wrap_CircleShape_open(lua_State * L);
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_WRAP_CIRCLE_SHAPE_H
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "wrap_Contact.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
|
||||
Contact * luax_checkcontact(lua_State * L, int idx)
|
||||
{
|
||||
return luax_checktype<Contact>(L, idx, "Contact", LOVE_PHYSICS_CONTACT_BITS);
|
||||
}
|
||||
|
||||
int _wrap_Contact_getPosition(lua_State * L)
|
||||
{
|
||||
Contact * t = luax_checkcontact(L, 1);
|
||||
return t->getPosition(L);
|
||||
}
|
||||
|
||||
int _wrap_Contact_getVelocity(lua_State * L)
|
||||
{
|
||||
Contact * t = luax_checkcontact(L, 1);
|
||||
return t->getVelocity(L);
|
||||
}
|
||||
|
||||
int _wrap_Contact_getNormal(lua_State * L)
|
||||
{
|
||||
Contact * t = luax_checkcontact(L, 1);
|
||||
return t->getNormal(L);
|
||||
}
|
||||
|
||||
int _wrap_Contact_getSeparation(lua_State * L)
|
||||
{
|
||||
Contact * t = luax_checkcontact(L, 1);
|
||||
lua_pushnumber(L, t->getSeparation());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_Contact_getFriction(lua_State * L)
|
||||
{
|
||||
Contact * t = luax_checkcontact(L, 1);
|
||||
lua_pushnumber(L, t->getFriction());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_Contact_getRestitution(lua_State * L)
|
||||
{
|
||||
Contact * t = luax_checkcontact(L, 1);
|
||||
lua_pushnumber(L, t->getRestitution());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg wrap_Contact_functions[] = {
|
||||
{ "getPosition", _wrap_Contact_getPosition },
|
||||
{ "getVelocity", _wrap_Contact_getVelocity },
|
||||
{ "getNormal", _wrap_Contact_getNormal },
|
||||
{ "getSeparation", _wrap_Contact_getSeparation },
|
||||
{ "getFriction", _wrap_Contact_getFriction },
|
||||
{ "getRestitution", _wrap_Contact_getRestitution },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
int wrap_Contact_open(lua_State * L)
|
||||
{
|
||||
luax_register_type(L, "Contact", wrap_Contact_functions);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_WRAP_CONTACT_H
|
||||
#define LOVE_PHYSICS_BOX2D_WRAP_CONTACT_H
|
||||
|
||||
// LOVE
|
||||
#include <common/runtime.h>
|
||||
#include "Contact.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
Contact * luax_checkcontact(lua_State * L, int idx);
|
||||
int _wrap_Contact_getPosition(lua_State * L);
|
||||
int _wrap_Contact_getVelocity(lua_State * L);
|
||||
int _wrap_Contact_getNormal(lua_State * L);
|
||||
int _wrap_Contact_getSeparation(lua_State * L);
|
||||
int _wrap_Contact_getFriction(lua_State * L);
|
||||
int _wrap_Contact_getRestitution(lua_State * L);
|
||||
int wrap_Contact_open(lua_State * L);
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_WRAP_CONTACT_H
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 "wrap_DistanceJoint.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
DistanceJoint * luax_checkdistancejoint(lua_State * L, int idx)
|
||||
{
|
||||
return luax_checktype<DistanceJoint>(L, idx, "DistanceJoint", LOVE_PHYSICS_DISTANCE_JOINT_BITS);
|
||||
}
|
||||
|
||||
int _wrap_DistanceJoint_setLength(lua_State * L)
|
||||
{
|
||||
DistanceJoint * t = luax_checkdistancejoint(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
t->setLength(arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_DistanceJoint_getLength(lua_State * L)
|
||||
{
|
||||
DistanceJoint * t = luax_checkdistancejoint(L, 1);
|
||||
lua_pushnumber(L, t->getLength());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_DistanceJoint_setFrequency(lua_State * L)
|
||||
{
|
||||
DistanceJoint * t = luax_checkdistancejoint(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
t->setFrequency(arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_DistanceJoint_getFrequency(lua_State * L)
|
||||
{
|
||||
DistanceJoint * t = luax_checkdistancejoint(L, 1);
|
||||
lua_pushnumber(L, t->getFrequency());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _wrap_DistanceJoint_setDamping(lua_State * L)
|
||||
{
|
||||
DistanceJoint * t = luax_checkdistancejoint(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
t->setDamping(arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _wrap_DistanceJoint_getDamping(lua_State * L)
|
||||
{
|
||||
DistanceJoint * t = luax_checkdistancejoint(L, 1);
|
||||
lua_pushnumber(L, t->getDamping());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg wrap_DistanceJoint_functions[] = {
|
||||
{ "setLength", _wrap_DistanceJoint_setLength },
|
||||
{ "getLength", _wrap_DistanceJoint_getLength },
|
||||
{ "setFrequency", _wrap_DistanceJoint_setFrequency },
|
||||
{ "getFrequency", _wrap_DistanceJoint_getFrequency },
|
||||
{ "setDamping", _wrap_DistanceJoint_setDamping },
|
||||
{ "getDamping", _wrap_DistanceJoint_getDamping },
|
||||
// From Joint.
|
||||
{ "getType", _wrap_Joint_getType },
|
||||
{ "getAnchors", _wrap_Joint_getAnchors },
|
||||
{ "getReactionForce", _wrap_Joint_getReactionForce },
|
||||
{ "getReactionTorque", _wrap_Joint_getReactionTorque },
|
||||
{ "setCollideConnected", _wrap_Joint_setCollideConnected },
|
||||
{ "getCollideConnected", _wrap_Joint_getCollideConnected },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
int wrap_DistanceJoint_open(lua_State * L)
|
||||
{
|
||||
luax_register_type(L, "DistanceJoint", wrap_DistanceJoint_functions);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2009 LOVE Development Team
|
||||
*
|
||||
* 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 LOVE_PHYSICS_BOX2D_WRAP_DISTANCE_JOINT_H
|
||||
#define LOVE_PHYSICS_BOX2D_WRAP_DISTANCE_JOINT_H
|
||||
|
||||
// LOVE
|
||||
#include <common/runtime.h>
|
||||
#include "wrap_Joint.h"
|
||||
#include "DistanceJoint.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace physics
|
||||
{
|
||||
namespace box2d
|
||||
{
|
||||
DistanceJoint * luax_checkdistancejoint(lua_State * L, int idx);
|
||||
int _wrap_DistanceJoint_setLength(lua_State * L);
|
||||
int _wrap_DistanceJoint_getLength(lua_State * L);
|
||||
int _wrap_DistanceJoint_setFrequency(lua_State * L);
|
||||
int _wrap_DistanceJoint_getFrequency(lua_State * L);
|
||||
int _wrap_DistanceJoint_setDamping(lua_State * L);
|
||||
int _wrap_DistanceJoint_getDamping(lua_State * L);
|
||||
int wrap_DistanceJoint_open(lua_State * L);
|
||||
|
||||
} // box2d
|
||||
} // physics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_PHYSICS_BOX2D_WRAP_DISTANCE_JOINT_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user