Skip to content

Commit

Permalink
First addition of the JBox2D physics engine alongside Bullet (3D).
Browse files Browse the repository at this point in the history
Not tested very thoroughly -- and not testable yet from GAML.The same
interfaces now allow to choose between JBullet (java), JBox2D (java),
Bullet (native). The goal, ultimately, is to have two choices : 2D or
3D, which would lead, by default, to either Box2D or Bullet (both
natives). But, in case the natives wouldn't work (or be loaded), to be
able to rely on the two corresponding java libraries.

More integration needs to be made with other plugins too. For the
moment, the two skills in physics only listen to "location" (i.e. to
detect a change of location coming from elsewhere), but it is
technically possigle to listen to any variable (change of shape, change
of speed, change of heading,...).
  • Loading branch information
AlexisDrogoul committed Jun 25, 2021
1 parent 9dd1dde commit ca40712
Show file tree
Hide file tree
Showing 161 changed files with 29,989 additions and 213 deletions.
2 changes: 1 addition & 1 deletion simtools.gaml.extensions.physics/.classpath
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry exported="true" kind="lib" path="lib/jbullet-1.0.1.jar"/>
<classpathentry exported="true" kind="lib" path="lib/jbullet-1.0.1.jar" sourcepath="lib/jbullet-1.0.1-sources.jar"/>
<classpathentry exported="true" kind="lib" path="lib/Libbulletjme-10.4.0.jar" sourcepath="lib/Libbulletjme-10.4.0-sources.jar">
<attributes>
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="simtools.gaml.extensions.physics/lib/native"/>
Expand Down
@@ -0,0 +1,182 @@
package gama.extensions.physics.box2d_version;

import static msi.gaml.types.GamaGeometryType.buildRectangle;

import org.jbox2d.collision.AABB;
import org.jbox2d.collision.shapes.MassData;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.BodyType;
import org.jbox2d.dynamics.FixtureDef;
import org.jbox2d.dynamics.World;

import gama.extensions.physics.common.AbstractBodyWrapper;
import gama.extensions.physics.common.IBody;
import msi.gama.metamodel.agent.IAgent;
import msi.gama.metamodel.shape.GamaPoint;
import msi.gama.metamodel.shape.IShape;

public class Box2DBodyWrapper extends AbstractBodyWrapper<World, Body, Shape, Vec2> implements IBox2DPhysicalEntity {

final BodyDef def = new BodyDef();
final FixtureDef fixtureDef = new FixtureDef();
MassData ms = new MassData();

public Box2DBodyWrapper(final IAgent agent, final Box2DPhysicalWorld world) {
super(agent, world);
}

@Override
public Body createAndInitializeBody(final Shape shape, final World world) {
IBody previous = (IBody) agent.getAttribute(BODY);
if (previous != null) {
GamaPoint pointTransfer = new GamaPoint();
def.type = isStatic ? BodyType.STATIC : BodyType.DYNAMIC;
def.angularDamping = previous.getAngularDamping();
def.angularVelocity = (float) previous.getAngularVelocity(pointTransfer).norm();
def.linearDamping = previous.getLinearDamping();
toVector(previous.getLinearVelocity(pointTransfer), def.linearVelocity);
def.allowSleep = false;
def.userData = this;
}
Body body = world.createBody(def);
if (previous != null) {
fixtureDef.density = 1f;
fixtureDef.friction = previous.getFriction();
fixtureDef.restitution = previous.getRestitution();
fixtureDef.shape = shape;
}
body.createFixture(fixtureDef);
if (previous != null) { ms.mass = previous.getMass(); }
body.setMassData(ms);
return body;
}

@Override
public float getMass() {
return body.m_mass;
}

@Override
public float getFriction() {
return body.getFixtureList().getFriction();
}

@Override
public float getRestitution() {
return body.getFixtureList().getRestitution();
}

@Override
public float getLinearDamping() {
return body.m_linearDamping;
}

@Override
public float getAngularDamping() {
return body.m_angularDamping;
}

@Override
public float getContactDamping() {
// Doesnt exist
return 0;
}

@Override
public GamaPoint getAngularVelocity(final GamaPoint v) {
// TODO Auto-generated method stub
return null;
}

@Override
public GamaPoint getLinearVelocity(final GamaPoint v) {
return toGamaPoint(body.getLinearVelocity(), v);
}

@Override
public IShape getAABB() {
AABB aabb = body.getFixtureList().getAABB(0);
Vec2 v = aabb.getExtents();
return buildRectangle(v.x * 2, v.y * 2, new GamaPoint(v.x, v.y));
}

@Override
public void setMass(final Double mass) {
ms.mass = mass.floatValue();
body.setMassData(ms);

}

@Override
public void setCCD(final boolean v) {
// Verify this
body.setBullet(v);
}

@Override
public void setFriction(final Double friction) {
body.getFixtureList().setFriction(friction.floatValue());

}

@Override
public void setRestitution(final Double restitution) {
body.getFixtureList().setRestitution(restitution.floatValue());
}

@Override
public void setDamping(final Double damping) {
body.setLinearDamping(damping.floatValue());
}

@Override
public void setAngularDamping(final Double damping) {
body.setAngularDamping(damping.floatValue());
}

@Override
public void setContactDamping(final Double damping) {
// Not available
}

@Override
public void setAngularVelocity(final GamaPoint angularVelocity) {
body.setAngularVelocity((float) angularVelocity.norm());
}

@Override
public void setLinearVelocity(final GamaPoint linearVelocity) {
body.setLinearVelocity(toVector(linearVelocity));
}

@Override
public void setLocation(final GamaPoint loc) {
body.setTransform(toVector(loc), body.getAngle());
}

@Override
public void clearForces() {
body.setLinearVelocity(new Vec2(0, 0));
body.setAngularVelocity(0);
}

@Override
public void applyImpulse(final GamaPoint impulse) {
body.applyLinearImpulse(toVector(impulse), body.getLocalCenter(), true);
}

@Override
public void applyTorque(final GamaPoint torque) {
body.applyTorque((float) torque.norm());
}

@Override
public void applyForce(final GamaPoint force) {
body.applyForceToCenter(toVector(force));

}

}
@@ -0,0 +1,77 @@
package gama.extensions.physics.box2d_version;

import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.World;

import gama.extensions.physics.common.AbstractPhysicalWorld;
import gama.extensions.physics.common.IShapeConverter;
import gama.extensions.physics.gaml.PhysicalSimulationAgent;
import msi.gama.metamodel.agent.IAgent;
import msi.gama.metamodel.shape.GamaPoint;

public class Box2DPhysicalWorld extends AbstractPhysicalWorld<World, Shape, Vec2> implements IBox2DPhysicalEntity {

protected Box2DPhysicalWorld(final PhysicalSimulationAgent physicalSimulationAgent) {
super(physicalSimulationAgent);
}

@Override
public void registerAgent(final IAgent agent) {
Box2DBodyWrapper body = new Box2DBodyWrapper(agent, this);
}

@Override
public void unregisterAgent(final IAgent agent) {
// TODO Auto-generated method stub

}

@Override
public void setCCD(final boolean ccd) {

}

@Override
public void setGravity(final GamaPoint gravity) {
if (world != null) { world.setGravity(toVector(gravity)); }
}

@Override
public void dispose() {
// TODO Auto-generated method stub

}

@Override
public void updatePositionsAndRotations() {
// TODO Auto-generated method stub

}

@Override
protected World createWorld() {
GamaPoint p = simulation.getGravity(simulation.getScope());
World result = new World(toVector(p));
result.setAutoClearForces(true);
result.setContactListener(contactListener);
return result;
}

@Override
protected IShapeConverter<Shape, Vec2> createShapeConverter() {
return new Box2DShapeConverter();
}

@Override
protected void updateAgentsShape() {
// TODO Auto-generated method stub

}

@Override
protected void updateEngine(final Double timeStep, final int maxSubSteps) {
getWorld().step(timeStep.floatValue(), maxSubSteps, maxSubSteps);
}

}
@@ -0,0 +1,86 @@
package gama.extensions.physics.box2d_version;

import org.jbox2d.collision.shapes.CircleShape;
import org.jbox2d.collision.shapes.EdgeShape;
import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.common.Vec2;
import org.locationtech.jts.geom.LineString;

import gama.extensions.physics.common.IShapeConverter;
import msi.gama.common.geometry.GeometryUtils;
import msi.gama.metamodel.agent.IAgent;
import msi.gama.metamodel.shape.GamaPoint;
import msi.gama.metamodel.shape.IShape;
import msi.gama.metamodel.shape.IShape.Type;
import msi.gama.runtime.IScope;
import msi.gama.util.matrix.GamaFloatMatrix;

public class Box2DShapeConverter implements IShapeConverter<Shape, Vec2>, IBox2DPhysicalEntity {

@Override
public void computeTranslation(final IAgent agent, final Type type, final float depth, final Vec2 aabbTranslation,
final Vec2 visualTranslation) {
// Normally not applicable.
}

@Override
public Shape convertShape(final IShape shape, final Type type, final float depth) {

switch (type) {
case BOX:
case PLAN:
case SQUARE:
case CUBE:
case CONE:
case PYRAMID:
PolygonShape p = new PolygonShape();
p.setAsBox(shape.getWidth().floatValue() / 2, shape.getHeight().floatValue() / 2);
return p;
case LINECYLINDER:
// oriented on the Y or on the X (default) axis
LineString line = (LineString) shape.getInnerGeometry();
EdgeShape e = new EdgeShape();
e.set(toVector((GamaPoint) line.getCoordinateN(0)), toVector((GamaPoint) line.getCoordinateN(1)));
return e;
case SPHERE:
case CIRCLE:
case POINT:
case CYLINDER:
CircleShape cc = new CircleShape();
cc.setRadius(shape.getWidth().floatValue() / 2);
return cc;
default:
GamaPoint[] points = GeometryUtils.getPointsOf(shape);
switch (points.length) {
case 0:
return null;
case 1:
return convertShape(shape, IShape.Type.POINT, depth);
case 2:
EdgeShape l = new EdgeShape();
l.set(toVector(points[0]), toVector(points[1]));
return l;
default:
PolygonShape ps = new PolygonShape();
Vec2[] vertices = new Vec2[points.length];
for (int i = 0; i < points.length; i++) {
vertices[i] = toVector(points[i]);
}
ps.set(vertices, vertices.length);
return ps;
}

}
}

@Override
public Shape convertTerrain(final IScope scope, final GamaFloatMatrix field, final Double width,
final Double height, final float depth) {
// No way to support "depth" here to build the shape :)
PolygonShape rectangle = new PolygonShape();
rectangle.setAsBox(width.floatValue(), height.floatValue());
return rectangle;
}

}
@@ -0,0 +1,29 @@
package gama.extensions.physics.box2d_version;

import org.jbox2d.common.Vec2;

import gama.extensions.physics.common.IPhysicalEntity;
import gama.extensions.physics.common.VectorUtils;
import msi.gama.metamodel.shape.GamaPoint;

public interface IBox2DPhysicalEntity extends IPhysicalEntity<Vec2> {
@Override
default Vec2 toVector(final GamaPoint v) {
return VectorUtils.toBox2DVector(v);
}

default Vec2 toVector(final GamaPoint v, final Vec2 to) {
return VectorUtils.toBox2DVector(v, to);
}

@Override
default GamaPoint toGamaPoint(final Vec2 v) {
return VectorUtils.toGamaPoint(v);

}

default GamaPoint toGamaPoint(final Vec2 v, final GamaPoint result) {
return VectorUtils.toGamaPoint(v, result);
}

}

0 comments on commit ca40712

Please sign in to comment.