package com.nilunder.bdx.utils;
import java.nio.*;
import javax.vecmath.*;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.math.*;
import com.badlogic.gdx.math.collision.*;
import com.badlogic.gdx.utils.*;
import com.badlogic.gdx.graphics.glutils.*;
import com.bulletphysics.collision.dispatch.*;
import com.bulletphysics.collision.shapes.*;
import com.bulletphysics.dynamics.*;
import com.bulletphysics.linearmath.*;
import com.bulletphysics.util.*;
import com.nilunder.bdx.*;
public class Bullet {
public static class DebugDrawer extends IDebugDraw{
private static ShapeRenderer shapeRenderer;
private static Vector3 from;
private static Vector3 to;
private boolean canDraw;
private boolean debug;
public DebugDrawer(boolean debug){
if (shapeRenderer == null){
shapeRenderer = new ShapeRenderer();
from = new Vector3();
to = new Vector3();
}
this.debug = debug;
}
public void drawLine(Vector3f from, Vector3f to, Vector3f color){
// It appears that this method will be called outside world.debugDrawWorld(),
// to draw things that don't appear to be overly relevant.
// So, instead of buffering vectors to draw at the right time (between shaperRenderer.begin() and end()),
// I simply bail:
if (canDraw){
shapeRenderer.setColor(color.x, color.y, color.z, 1f);
this.from.x = from.x; this.to.x = to.x;
this.from.y = from.y; this.to.y = to.y;
this.from.z = from.z; this.to.z = to.z;
shapeRenderer.line(this.from, this.to);
}
}
public int getDebugMode(){
if (debug)
return DebugDrawModes.DRAW_AABB | DebugDrawModes.DRAW_WIREFRAME;
else
return DebugDrawModes.NO_DEBUG;
}
public void setDebugMode(int mode){}
public void draw3dText(Vector3f v, String s){}
public void reportErrorWarning(String s){}
public void drawContactPoint(Vector3f a, Vector3f b, float f, int i, Vector3f c){}
public void drawWorld(DynamicsWorld world, Camera camera){
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
canDraw = true;
world.debugDrawWorld();
shapeRenderer.end();
canDraw = false;
}
}
public static IndexedMesh makeMesh(Mesh mesh){
ByteBuffer indices = ByteBuffer.allocate(mesh.getIndicesBuffer().capacity() * (Short.SIZE/8));
indices.asShortBuffer().put(mesh.getIndicesBuffer());
mesh.getIndicesBuffer().rewind();
ByteBuffer verts = ByteBuffer.allocate(mesh.getVerticesBuffer().capacity() * (Float.SIZE/8));
verts.asFloatBuffer().put(mesh.getVerticesBuffer());
mesh.getVerticesBuffer().rewind();
IndexedMesh m = new IndexedMesh();
m.numTriangles = mesh.getNumIndices()/3;
m.triangleIndexBase = indices;
m.triangleIndexStride = (Short.SIZE/8) * 3;
m.numVertices = mesh.getNumVertices();
m.vertexBase = verts;
m.vertexStride = (Float.SIZE/8) * Bdx.VERT_STRIDE;
return m;
}
public static CollisionShape makeShape(Mesh mesh, GameObject.BoundsType bounds, float margin, boolean compound){
CollisionShape shape;
if (bounds == GameObject.BoundsType.TRIANGLE_MESH){
TriangleIndexVertexArray mi = new TriangleIndexVertexArray();
mi.addIndexedMesh(Bullet.makeMesh(mesh), ScalarType.SHORT);
shape = new BvhTriangleMeshShape(mi, false);
}else if (bounds == GameObject.BoundsType.CONVEX_HULL){
float[] verts = new float[mesh.getNumVertices() * mesh.getVertexSize()];
mesh.getVertices(verts);
ObjectArrayList<Vector3f> vertList = new ObjectArrayList<Vector3f>();
for (int i = 0; i < mesh.getNumVertices() * Bdx.VERT_STRIDE; i += Bdx.VERT_STRIDE) {
vertList.add(new Vector3f(verts[i], verts[i + 1], verts[i + 2]));
}
shape = new ConvexHullShape(vertList);
margin *= 0.5f;
}else{
Vector3 d = mesh.calculateBoundingBox().getDimensions(new Vector3()).scl(0.5f);
if (bounds == GameObject.BoundsType.SPHERE){
float radius = Math.max(Math.max(d.x, d.y), d.z);
shape = new SphereShape(radius);
}else if (bounds == GameObject.BoundsType.BOX){
shape = new BoxShape(new Vector3f(d.x, d.y, d.z));
}else if (bounds == GameObject.BoundsType.CYLINDER){
shape = new CylinderShapeZ(new Vector3f(d.x, d.y, d.z));
}else if (bounds == GameObject.BoundsType.CAPSULE){
float radius = Math.max(d.x, d.y);
float height = (d.z - radius) * 2;
shape = new CapsuleShapeZ(radius, height);
}else{ //"CONE"
float radius = Math.max(d.x, d.y);
float height = d.z * 2;
shape = new ConeShapeZ(radius, height);
margin *= 0.5f;
}
}
shape.setMargin(margin);
if (compound) {
CompoundShape compShape = new CompoundShape();
compShape.setMargin(0);
Transform trans = new Transform();
trans.setIdentity();
compShape.addChildShape(trans, shape);
return compShape;
}
return shape;
}
public static RigidBody makeBody(Mesh mesh, float[] glTransform, Vector3f origin, GameObject.BodyType bodyType, GameObject.BoundsType boundsType, JsonValue physics){
CollisionShape shape = makeShape(mesh, boundsType, physics.get("margin").asFloat(), physics.get("compound").asBoolean());
float mass = physics.get("mass").asFloat();
Vector3f inertia = new Vector3f();
shape.calculateLocalInertia(mass, inertia);
Transform startTransform = new Transform();
startTransform.setFromOpenGLMatrix(glTransform);
MotionState motionState;
if (boundsType == GameObject.BoundsType.CONVEX_HULL){
Transform centerOfMassOffset = new Transform();
Matrix4f originMatrix = new Matrix4f();
originMatrix.set(origin);
centerOfMassOffset.set(originMatrix);
startTransform.mul(centerOfMassOffset);
motionState = new DefaultMotionState(startTransform, centerOfMassOffset);
}else{
motionState = new DefaultMotionState(startTransform);
}
RigidBodyConstructionInfo ci = new RigidBodyConstructionInfo(mass, motionState, shape, inertia);
RigidBody body = new RigidBody(ci);
int flags = 0;
if (bodyType == GameObject.BodyType.SENSOR){
flags = CollisionFlags.KINEMATIC_OBJECT | CollisionFlags.NO_CONTACT_RESPONSE;
}else{
if (bodyType == GameObject.BodyType.STATIC){
flags = CollisionFlags.KINEMATIC_OBJECT;
//body.setActivationState(CollisionObject.DISABLE_DEACTIVATION);
}else if (bodyType == GameObject.BodyType.DYNAMIC){
body.setAngularFactor(0);
}
if (physics.get("ghost").asBoolean())
flags |= CollisionFlags.NO_CONTACT_RESPONSE;
}
body.setCollisionFlags(flags);
body.setRestitution(physics.get("restitution").asFloat());
body.setFriction(physics.get("friction").asFloat());
return body;
}
public static RigidBody cloneBody(RigidBody body){
GameObject gobj = (GameObject)body.getUserPointer();
JsonValue physics = gobj.json.get("physics");
float mass = gobj.mass();
Vector3f inertia = new Vector3f();
body.getCollisionShape().calculateLocalInertia(mass, inertia);
CollisionShape shape;
if (gobj.modelInstance != null){
shape = makeShape(gobj.modelInstance.model.meshes.first(), GameObject.BoundsType.valueOf(physics.get("bounds_type").asString()), physics.get("margin").asFloat(), physics.get("compound").asBoolean());
}else{
shape = new BoxShape(new Vector3f(0.25f, 0.25f, 0.25f));
}
RigidBody b = new RigidBody(mass, new DefaultMotionState(new Transform(gobj.transform())),
shape,
inertia);
b.setCollisionFlags(gobj.body.getCollisionFlags());
b.setAngularFactor(gobj.body.getAngularFactor());
b.setRestitution(gobj.body.getRestitution());
b.setFriction(gobj.body.getFriction());
return b;
}
}