package com.nilunder.bdx;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.vecmath.Matrix3f;
import javax.vecmath.Matrix4f;
import javax.vecmath.Vector3f;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.model.Node;
import com.badlogic.gdx.graphics.g3d.model.NodePart;
import com.badlogic.gdx.graphics.g3d.model.MeshPart;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder;
import com.badlogic.gdx.math.collision.BoundingBox;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.JsonValue;
import com.bulletphysics.collision.narrowphase.PersistentManifold;
import com.bulletphysics.collision.narrowphase.ManifoldPoint;
import com.bulletphysics.collision.dispatch.CollisionFlags;
import com.bulletphysics.collision.shapes.CollisionShape;
import com.bulletphysics.collision.shapes.CompoundShape;
import com.bulletphysics.dynamics.RigidBody;
import com.bulletphysics.linearmath.MatrixUtil;
import com.bulletphysics.linearmath.Transform;
import com.nilunder.bdx.gl.Material;
import com.nilunder.bdx.gl.Mesh;
import com.nilunder.bdx.utils.*;
public class GameObject implements Named{
public JsonValue json;
public String name;
public ArrayListGameObject touchingObjects;
public ArrayListGameObject touchingObjectsLast;
public ArrayList<PersistentManifold> contactManifolds;
public ModelInstance modelInstance;
public RigidBody body;
public BodyType currBodyType;
public BoundsType currBoundsType;
public Vector3f origin;
public Vector3f dimensionsNoScale;
public HashMap<String, JsonValue> props;
public boolean frustumCulling;
public ArrayListGameObject children;
public ArrayListNamed<Component> components;
public Scene scene;
private GameObject parent;
private Matrix4f localTransform;
private Vector3f localScale;
private boolean visible;
private boolean valid;
public boolean initialized;
public float logicFrequency;
public float logicCounter;
private Vector3f scale;
private Mesh mesh;
public enum BodyType {
NO_COLLISION,
STATIC,
SENSOR,
DYNAMIC,
RIGID_BODY
}
public enum BoundsType {
TRIANGLE_MESH,
CONVEX_HULL,
SPHERE,
BOX,
CYLINDER,
CAPSULE,
CONE
}
public class ArrayListGameObject extends ArrayListNamed<GameObject> {
public GameObject getByProperty(String propName){
for (GameObject t : this) {
if (t.props.containsKey(propName)) {
return t;
}
}
return null;
}
public GameObject getByComponent(String compName){
for (GameObject t : this) {
if (t.components.get(compName) != null) {
return t;
}
}
return null;
}
}
public GameObject() {
touchingObjects = new ArrayListGameObject();
touchingObjectsLast = new ArrayListGameObject();
contactManifolds = new ArrayList<PersistentManifold>();
components = new ArrayListNamed<Component>();
children = new ArrayListGameObject();
valid = true;
scale = new Vector3f();
logicFrequency = Bdx.TICK_RATE;
logicCounter = 1 + Random.random();
frustumCulling = true;
}
public String name(){
return name;
}
public void init(){}
public void main(){}
public void onEnd(){}
public GameObject parent(){
return parent;
}
public void parent(GameObject p){
parent(p, true);
}
public void parent(GameObject p, boolean compound){
CompoundShape compShapeOld = null;
if (parent != null){
parent.children.remove(this);
if (compound){
compShapeOld = parent.compoundShape();
if (compShapeOld != null){
scene.world.removeRigidBody(parent.body);
compShapeOld.removeChildShape(body.getCollisionShape());
scene.world.addRigidBody(parent.body);
}
}
}else if (p == null){
return;
}
parent = p;
if (parent != null){
parent.children.add(this);
updateLocalTransform();
updateLocalScale();
if (compound){
CompoundShape compShape = parent.compoundShape();
if (compShape != null){
scene.world.removeRigidBody(body);
compShape.addChildShape(new Transform(localTransform), body.getCollisionShape());
}
}else{
dynamics(false);
}
}else if (currBodyType == BodyType.STATIC || currBodyType == BodyType.SENSOR){
if (compound && compShapeOld != null)
scene.world.addRigidBody(body);
}else{
dynamics(true);
}
}
public ArrayListGameObject childrenRecursive(){
ArrayListGameObject childList = new ArrayListGameObject();
for (GameObject child : children) {
childList.add(child);
childList.addAll(child.childrenRecursive());
}
return childList;
}
private CompoundShape compoundShape(){
if (body.getCollisionShape() instanceof CompoundShape)
return (CompoundShape) body.getCollisionShape();
return null;
}
public Vector3f position(){
Transform t = new Transform();
body.getWorldTransform(t);
return new Vector3f(t.origin);
}
public void position(Vector3f vec){
activate();
Matrix4f t = transform();
t.setTranslation(vec);
transform(t);
}
public void position(float x, float y, float z){
position(new Vector3f(x, y, z));
}
public void move(Vector3f delta){
position(position().plus(delta));
}
public void move(float x, float y, float z){
move(new Vector3f(x, y, z));
}
public void moveLocal(Vector3f delta){
move(orientation().mult(delta));
}
public void moveLocal(float x, float y, float z){
moveLocal(new Vector3f(x, y, z));
}
public Matrix3f orientation(){
Matrix4f t = transform();
Matrix3f ori = new Matrix3f();
t.getRotationScale(ori);
return ori;
}
public void orientation(Matrix3f ori){
Matrix4f t = transform();
t.setRotation(ori);
transform(t);
}
public void rotate(float x, float y, float z){
Matrix3f ori = orientation();
Matrix3f rot = new Matrix3f();
MatrixUtil.setEulerZYX(rot, x, y, z);
rot.mul(ori);
orientation(rot);
}
public void rotate(Vector3f rot){
rotate(rot.x, rot.y, rot.z);
}
public void rotateLocal(float x, float y, float z){
Matrix3f ori = orientation();
Matrix3f rot = new Matrix3f();
MatrixUtil.setEulerZYX(rot, x, y, z);
ori.mul(rot);
orientation(ori);
}
public Matrix4f transform(){
Transform t = new Transform();
body.getWorldTransform(t);
Vector3f v = new Vector3f();
for (int i = 0; i < 3; ++i){
t.basis.getColumn(i, v);
v.normalize();
t.basis.setColumn(i, v);
}
Matrix4f m = new Matrix4f();
t.getMatrix(m);
return m;
}
public void transform(Matrix4f mat){
transform(mat, true);
}
public void updateChildTransforms(){
Matrix4f pt = transform();
Matrix4f ct = new Matrix4f();
Matrix4f ms = new Matrix4f(); ms.setIdentity();
Vector3f ps = scale();
ms.m00 = ps.x; ms.m11 = ps.y; ms.m22 = ps.z;
pt.mul(ms);
for (GameObject c : children){
ct.mul(pt, c.localTransform);
c.transform(ct, false);
}
}
public void transform(Matrix4f mat, boolean updateLocal){
activate();
Transform t = new Transform();
t.set(mat);
Vector3f v = new Vector3f();
for (int i = 0; i < 3; ++i){
t.basis.getColumn(i, v);
v.normalize();
t.basis.setColumn(i, v);
}
body.setWorldTransform(t);
// required for static objects:
body.getMotionState().setWorldTransform(t);
if (body.isInWorld() && body.isStaticOrKinematicObject()){
scene.world.updateSingleAabb(body);
for (GameObject g : touchingObjects)
g.activate();
}
//
updateChildTransforms();
if (parent != null && updateLocal){
updateLocalTransform();
}
}
private void updateLocalTransform(){
localTransform = parent.transform();
Matrix4f ms = new Matrix4f(); ms.setIdentity();
Vector3f ps = parent.scale();
ms.m00 = ps.x; ms.m11 = ps.y; ms.m22 = ps.z;
localTransform.mul(ms);
localTransform.invert();
localTransform.mul(transform());
}
public void applyForce(Vector3f vec){
activate();
body.applyCentralForce(vec.mul(1f / Bdx.physicsSpeed));
}
public void applyForce(Vector3f force, Vector3f relPos) {
activate();
body.applyForce(force.mul(1f / Bdx.physicsSpeed), relPos);
}
public void applyForce(float x, float y, float z){
Vector3f v = new Vector3f(x, y, z);
applyForce(v);
}
public void applyForceLocal(Vector3f vec){
applyForce(orientation().mult(vec));
}
public void applyForceLocal(float x, float y, float z){
Vector3f v = new Vector3f(x, y, z);
applyForceLocal(v);
}
public void applyForceLocal(Vector3f force, Vector3f relPos) {
applyForce(orientation().mult(force), relPos);
}
public void applyTorque(Vector3f vec){
activate();
body.applyTorque(vec.mul(1f / Bdx.physicsSpeed));
}
public void applyTorque(float x, float y, float z){
Vector3f v = new Vector3f(x, y, z);
applyTorque(v);
}
public void applyTorqueLocal(Vector3f vec){
applyTorque(orientation().mult(vec));
}
public void applyTorqueLocal(float x, float y, float z){
Vector3f v = new Vector3f(x, y, z);
applyTorqueLocal(v);
}
public void velocity(Vector3f vec){
activate();
body.setLinearVelocity(vec);
}
public void velocity(float x, float y, float z){
Vector3f v = new Vector3f(x, y, z);
velocity(v);
}
public Vector3f velocity(){
Vector3f v = new Vector3f();
body.getLinearVelocity(v);
return v;
}
public void velocityLocal(Vector3f vec){
velocity(orientation().mult(vec));
}
public void velocityLocal(float x, float y, float z){
Vector3f v = new Vector3f(x, y, z);
velocityLocal(v);
}
public Vector3f velocityLocal(){
Vector3f v = new Vector3f();
body.getLinearVelocity(v);
Matrix3f invOri = orientation();
invOri.invert();
return invOri.mult(v);
}
public void angularVelocity(Vector3f vec){
activate();
body.setAngularVelocity(vec);
}
public void angularVelocity(float x, float y, float z){
Vector3f v = new Vector3f(x, y, z);
angularVelocity(v);
}
public Vector3f angularVelocity(){
Vector3f v = new Vector3f();
body.getAngularVelocity(v);
return v;
}
public boolean touching(){
return !touchingObjects.isEmpty();
}
public boolean touching(String name){
return touchingObjects.get(name) != null;
}
public boolean touchingProperty(String propName){
return touchingObjects.getByProperty(propName) != null;
}
public boolean touchingComponent(String compName){
return touchingObjects.getByComponent(compName) != null;
}
public boolean hit(){
return hitObjects().size() > 0;
}
public boolean hit(String name){
if (hitObjects().get(name) != null)
return true;
return false;
}
public boolean hitProperty(String propName){
if (hitObjects().getByProperty(propName) != null)
return true;
return false;
}
public boolean hitComponent(String compName){
if (hitObjects().getByComponent(compName) != null)
return true;
return false;
}
public ArrayListGameObject hitObjects(){
ArrayListGameObject g = new ArrayListGameObject();
g.addAll(touchingObjects);
g.removeAll(touchingObjectsLast);
return g;
}
public float reactionForce(){
float force = 0;
int totalContacts = 0;
for (PersistentManifold m : contactManifolds){
int numContacts = m.getNumContacts();
totalContacts += numContacts;
for (int i = 0; i < numContacts; ++i){
ManifoldPoint p = m.getContactPoint(i);
force += p.appliedImpulse;
}
}
return totalContacts != 0 ? force / totalContacts : 0;
}
public void collisionGroup(short group) {
short mask = body.getBroadphaseProxy().collisionFilterMask;
scene.world.removeRigidBody(body);
scene.world.addRigidBody(body, group, mask);
}
public short collisionGroup()
{
return body.getBroadphaseProxy().collisionFilterGroup;
}
public void collisionMask(short mask) {
short group = body.getBroadphaseProxy().collisionFilterGroup;
scene.world.removeRigidBody(body);
scene.world.addRigidBody(body, group, mask);
}
public short collisionMask()
{
return body.getBroadphaseProxy().collisionFilterMask;
}
public boolean visible(){
return visible;
}
public void visible(boolean visible){
for (GameObject g : children){
g.visible(visible);
}
visibleNoChildren(visible);
}
public void visibleNoChildren(boolean visible){
this.visible = visible;
}
public boolean ghost(){
int noContact = body.getCollisionFlags() & CollisionFlags.NO_CONTACT_RESPONSE;
return noContact != 0 ? true : false;
}
public void ghost(boolean ghost){
for (GameObject g : children){
g.ghost(ghost);
}
ghostNoChildren(ghost);
}
public void ghostNoChildren(boolean ghost){
int flags = body.getCollisionFlags();
int noContact = CollisionFlags.NO_CONTACT_RESPONSE;
if (ghost)
flags |= noContact;
else
flags &= ~noContact;
body.setCollisionFlags(flags);
}
public void end(){
endNoChildren();
for (GameObject g : new ArrayList<GameObject>(children)){
g.end();
}
}
public void endNoChildren(){
if (!valid)
return;
onEnd();
valid = false;
for (Component c : components)
c.onGameObjectEnd();
scene.remove(this);
for (GameObject g : touchingObjects)
g.activate();
if (modelInstance != null)
mesh.instances.remove(modelInstance);
}
public boolean valid(){
return valid;
}
public void scale(float x, float y, float z, boolean updateLocal){
activate();
// Set unit scale
Matrix4 t = modelInstance.transform;
Matrix4 mat_scale = new Matrix4();
Vector3 s = new Vector3();
t.getScale(s);
mat_scale.scl(1/s.x, 1/s.y, 1/s.z);
t.mul(mat_scale);
scale.set(x, y, z);
// Set target scale
mat_scale.idt(); mat_scale.scl(x, y, z);
t.mul(mat_scale);
// Relevant bullet body update
CollisionShape cs = body.getCollisionShape();
cs.setLocalScaling(new Vector3f(x, y, z));
if (body.isInWorld() && body.isStaticOrKinematicObject())
scene.world.updateSingleAabb(body);
// Child propagation
Vector3f ps = scale();
Matrix4f pt = transform();
Matrix4f ct = new Matrix4f();
Matrix4f ms = new Matrix4f(); ms.setIdentity();
ms.m00 = ps.x; ms.m11 = ps.y; ms.m22 = ps.z;
pt.mul(ms);
for (GameObject c : children){
c.scale(scale().mul(c.localScale), false);
ct.mul(pt, c.localTransform);
c.transform(ct, false);
}
if (parent != null && updateLocal){
updateLocalScale();
}
}
private void updateLocalScale(){
localScale = scale().div(parent.scale());
}
public void scale(Vector3f s, boolean updateLocal){
scale(s.x, s.y, s.z, updateLocal);
}
public void scale(float x, float y, float z){
scale(x, y, z, true);
}
public void scale(Vector3f s){
scale(s.x, s.y, s.z);
}
public void scale(float s){
scale(s, s, s);
}
public Vector3f scale(){
return new Vector3f(scale);
}
public Vector3f dimensions(){
return dimensionsNoScale.mul(scale());
}
public Vector3f axis(String axisName){
int axis = "XYZ".indexOf(axisName.charAt(axisName.length() - 1));
Vector3f v = new Vector3f();
orientation().getColumn(axis, v);
if (axisName.charAt(0) == '-')
v.negate();
return v;
}
public Vector3f axis(int axis){
return axis(String.valueOf("XYZ".charAt(axis)));
}
public void alignAxisToVec(String axisName, Vector3f vec){
Vector3f alignAxis = axis(axisName);
Vector3f rotAxis = new Vector3f();
rotAxis.cross(alignAxis, vec);
if (rotAxis.length() == 0)
rotAxis = axis(("XYZ".indexOf(axisName) + 1) % 3);
Matrix3f rotMatrix = Matrix3f.rotation(rotAxis, alignAxis.angle(vec));
Matrix3f ori = orientation();
rotMatrix.mul(ori);
orientation(rotMatrix);
}
public void alignAxisToVec(int axis, Vector3f vec){
alignAxisToVec(String.valueOf("XYZ".charAt(axis)), vec);
}
public Mesh mesh(){
return mesh;
}
public void mesh(String meshName){
Mesh m = null;
ArrayList<Scene> sceneList = new ArrayList<Scene>(Bdx.scenes);
if (sceneList.indexOf(scene) >= 0)
Collections.swap(sceneList, sceneList.indexOf(scene), 0);
else
sceneList.add(0, scene);
for (Scene sce : sceneList){
m = sce.meshes.get(meshName);
if (m != null)
break;
}
if (m == null)
throw new RuntimeException("No model found with name '" + meshName + "' in an active scene.");
mesh(m);
}
public void mesh(Mesh mesh) {
String meshName = mesh.name();
if (mesh == this.mesh) // You're already set to the current mesh
return;
JsonValue mOrigin = null;
JsonValue mDimNoScale = null;
ArrayList<Scene> sceneList = new ArrayList<Scene>(Bdx.scenes);
if (sceneList.indexOf(scene) >= 0)
Collections.swap(sceneList, sceneList.indexOf(scene), 0);
else
sceneList.add(0, scene);
for (Scene sce : sceneList) {
if (sce.meshes.containsKey(meshName)){
mOrigin = sce.json.get("origins").get(meshName);
mDimNoScale = sce.json.get("dimensions").get(meshName);
break;
}
}
origin = mOrigin == null ? new Vector3f() : new Vector3f(mOrigin.asFloatArray());
dimensionsNoScale = mDimNoScale == null ? new Vector3f(1, 1, 1) : new Vector3f(mDimNoScale.asFloatArray());
Matrix4 trans;
if (modelInstance != null) {
trans = modelInstance.transform;
this.mesh.instances.remove(this);
}
else
trans = new Matrix4();
this.mesh = mesh;
modelInstance = mesh.getInstance();
modelInstance.transform.set(trans);
}
public void updateBody(Mesh mesh){
GameObject compParent = parent != null && parent.body.getCollisionShape().isCompound() ? parent : null;
boolean isCompChild = compParent != null && !(currBodyType == BodyType.NO_COLLISION || currBodyType == BodyType.SENSOR);
if (isCompChild){
parent(null);
}
Matrix4f transform = transform();
Vector3f scale = scale();
CollisionShape shape = body.getCollisionShape();
body.setCollisionShape(Bullet.makeShape(mesh.model.meshes.first(), currBoundsType, shape.getMargin(), shape.isCompound()));
Transform startTransform = new Transform();
body.getMotionState().getWorldTransform(startTransform);
Matrix4f originMatrix = new Matrix4f();
originMatrix.set(origin);
Transform centerOfMassTransform = new Transform();
centerOfMassTransform.set(originMatrix);
centerOfMassTransform.mul(startTransform);
body.setCenterOfMassTransform(centerOfMassTransform);
transform(transform);
scale(scale);
if (body.isInWorld()){
scene.world.updateSingleAabb(body);
}else{ // update Aabb hack for when not in world
scene.world.addRigidBody(body);
scene.world.updateSingleAabb(body);
scene.world.removeRigidBody(body);
}
if (isCompChild){
parent(compParent);
}
}
public void updateBody(String mesh) {
ArrayList<Scene> sceneList = new ArrayList<Scene>(Bdx.scenes);
if (sceneList.indexOf(scene) >= 0)
Collections.swap(sceneList, sceneList.indexOf(scene), 0);
else
sceneList.add(0, scene);
for (Scene s : sceneList) {
Mesh m = s.meshes.get(mesh);
if (m != null) {
updateBody(m);
return;
}
}
}
public void updateBody(){
updateBody(mesh);
}
public void join(ArrayList<GameObject> objects, boolean endObjects){
// collect scaled transforms per mesh
HashMap<Mesh, ArrayList<Matrix4f>> map = new HashMap<Mesh, ArrayList<Matrix4f>>();
Mesh m;
for (GameObject g : objects){
m = g.mesh();
ArrayList<Matrix4f> l;
if (map.containsKey(m)){
l = map.get(m);
}else{
l = new ArrayList<Matrix4f>();
map.put(m, l);
}
Matrix4f t = g.transform();
Vector3f s = g.scale();
t.setRow(3, s.x, s.y, s.z, 0);
l.add(t);
if (endObjects){
g.end();
}
}
// join
join(map);
}
public void join(ArrayList<GameObject> objects){
join(objects, true);
}
public void join(HashMap<Mesh, ArrayList<Matrix4f>> map){
// Collect transformed vertex arrays for each material & calculate number of indices
int VERT_STRIDE = Bdx.VERT_STRIDE;
HashMap<Material, ArrayList<float[]>> tvaMap = new HashMap<Material, ArrayList<float[]>>();
HashMap<Material, Integer> lenMap = new HashMap<Material, Integer>();
Mesh m;
Node node;
Material mat;
MeshPart meshPart;
float[] va, tva;
int numIndices, numVertices, offset, j, len;
Vector3f p = new Vector3f();
Vector3f s = new Vector3f();
Matrix3f o = new Matrix3f();
Vector3f vP = new Vector3f();
Vector3f nP = new Vector3f();
Vector3f vPT = new Vector3f();
Vector3f nPT = new Vector3f();
Vector3f pos = position();
Vector3f sca = scale();
Matrix3f oriInv = orientation().inverted();
for (Map.Entry<Mesh, ArrayList<Matrix4f>> e : map.entrySet()){
m = e.getKey();
node = m.model.nodes.get(0);
for (Matrix4f t : e.getValue()){
t.get(p);
p.sub(pos);
p = oriInv.mult(p.div(sca));
t.getRotationScale(o);
o = oriInv.mult(o);
s.set(t.m30, t.m31, t.m32);
if (s.length() == 0){
s.set(1, 1, 1);
}
s = s.div(sca);
for (NodePart nodePart : node.parts){
meshPart = nodePart.meshPart;
numIndices = meshPart.size;
numVertices = numIndices * VERT_STRIDE;
offset = meshPart.offset * VERT_STRIDE;
va = meshPart.mesh.getVertices(offset, numVertices, new float[numVertices]);
tva = new float[numVertices];
j = 0;
for (int i = 0; i < numIndices; i++){
vP.set(va[j], va[j+1], va[j+2]);
nP.set(va[j+3], va[j+4], va[j+5]);
vPT.set(o.mult(vP.mul(s)));
vPT.add(p);
nPT.set(o.mult(vP.plus(nP)));
nPT.sub(o.mult(vP));
tva[j] = vPT.x;
tva[j+1] = vPT.y;
tva[j+2] = vPT.z;
tva[j+3] = nPT.x;
tva[j+4] = nPT.y;
tva[j+5] = nPT.z;
tva[j+6] = va[j+6];
tva[j+7] = va[j+7];
j += VERT_STRIDE;
}
mat = m.materials.get(nodePart.material.id);
ArrayList<float[]> l;
if (tvaMap.containsKey(mat)){
l = tvaMap.get(mat);
len = lenMap.get(mat);
}else{
l = new ArrayList<float[]>();
tvaMap.put(mat, l);
len = 0;
}
l.add(tva);
lenMap.put(mat, len + tva.length);
}
}
}
// Build a unique model out of meshparts for each material
ModelBuilder builder = new ModelBuilder();
builder.begin();
short idx = 0;
MeshPartBuilder mpb;
for (Map.Entry<Material, ArrayList<float[]>> e : tvaMap.entrySet()){
mat = e.getKey();
len = lenMap.get(mat);
tva = new float[len];
j = 0;
for (float[] verts : e.getValue()){
numVertices = verts.length;
for (int i = 0; i < numVertices; i++){
tva[i + j] = verts[i];
}
j += numVertices;
}
mpb = builder.part(mat.name(), GL20.GL_TRIANGLES, Usage.Position | Usage.Normal | Usage.TextureCoordinates, mat);
mpb.vertex(tva);
try{
for (short i = 0; i < len / VERT_STRIDE; i++){
mpb.index(idx);
idx += 1;
}
}catch (Error error){
throw new RuntimeException("MODEL ERROR: Models with more than 32767 vertices are not supported. Decrease the number of objects to join.");
}
}
Model finishedModel = builder.end();
// Update mesh
mesh(new Mesh(finishedModel, scene));
// Update dimensionsNoScale and origin
com.badlogic.gdx.graphics.Mesh mesh = finishedModel.meshes.first();
BoundingBox bbox = mesh.calculateBoundingBox();
Vector3 dimensions = bbox.getDimensions(new Vector3());
Vector3 center = bbox.getCenter(new Vector3());
dimensionsNoScale = new Vector3f(dimensions.x, dimensions.y, dimensions.z);
origin = new Vector3f(center.x, center.y, center.z);
// Update body
updateBody();
// Set visbility to initial value if empty
if (json.get("mesh_name").asString() == null){
visible = json.get("visible").asBoolean();
}
}
public String toString(){
return name + " <" + getClass().getName() + "> @" + Integer.toHexString(hashCode());
}
public void dynamics(boolean restore){
if (currBodyType == BodyType.DYNAMIC || currBodyType == BodyType.RIGID_BODY){
if (restore){
bodyType(currBodyType);
}else{ // suspend
body.setCollisionFlags(body.getCollisionFlags() | CollisionFlags.KINEMATIC_OBJECT);
}
}
}
public boolean dynamics(){
return body.isInWorld() && !body.isKinematicObject();
}
public float mass(){
return 1 / body.getInvMass();
}
public void mass(float mass){
if (mass == 0){
throw new RuntimeException("no zero value allowed: use 'dynamics(false)' instead");
}
Vector3f inertia = new Vector3f();
body.getCollisionShape().calculateLocalInertia(mass, inertia);
body.setMassProps(mass, inertia);
}
public BodyType bodyType(){
return currBodyType;
}
public void bodyType(BodyType bodyType){
int flags = body.getCollisionFlags();
if (body.isInWorld())
scene.world.removeRigidBody(body);
if (bodyType == BodyType.NO_COLLISION){
for (GameObject g : touchingObjects)
g.activate();
flags &= ~CollisionFlags.KINEMATIC_OBJECT;
}else{
if (bodyType == BodyType.STATIC){
flags |= CollisionFlags.KINEMATIC_OBJECT;
}else if (bodyType == BodyType.SENSOR){
flags |= CollisionFlags.KINEMATIC_OBJECT;
flags |= CollisionFlags.NO_CONTACT_RESPONSE;
}else{
// NO_COLLISION -> DYNAMIC or RIGID_BODY hack
if (currBodyType == BodyType.NO_COLLISION){
body.clearForces();
body.setLinearVelocity(new Vector3f());
}
// kinematic initialization hack
if (mass() == Float.POSITIVE_INFINITY){
mass(1); // Blender default
flags &= ~CollisionFlags.KINEMATIC_OBJECT;
body.setCollisionFlags(flags);
}
flags &= ~CollisionFlags.KINEMATIC_OBJECT;
if (bodyType == BodyType.DYNAMIC){
body.setAngularVelocity(new Vector3f());
body.setAngularFactor(0);
}else if (bodyType == BodyType.RIGID_BODY){
body.setAngularFactor(1);
}
}
scene.world.addRigidBody(body);
activate();
}
body.setCollisionFlags(flags);
currBodyType = bodyType;
}
public BoundsType boundsType(){
return currBoundsType;
}
public void boundsType(BoundsType boundsType){
com.badlogic.gdx.graphics.Mesh mesh = modelInstance.model.meshes.first();
CollisionShape shape = body.getCollisionShape();
shape = Bullet.makeShape(mesh, boundsType, shape.getMargin(), shape.isCompound());
body.setCollisionShape(shape);
currBoundsType = boundsType;
}
public float collisionMargin(){
return body.getCollisionShape().getMargin();
}
public void collisionMargin(float m){
body.getCollisionShape().setMargin(m);
}
public void activate(){
if (dynamics())
body.activate();
}
public void deactivate(){
body.forceActivationState(2);
}
public boolean insideFrustum(Vector3f customHalfDim){
Vector3f min = new Vector3f();
Vector3f max = new Vector3f();
body.getAabb(min, max);
Vector3f dimHalved = max.minus(min).mul(0.5f);
Vector3f center;
if (origin.length() == 0 || currBoundsType == BoundsType.CONVEX_HULL || currBoundsType == BoundsType.TRIANGLE_MESH)
center = min.plus(dimHalved);
else
center = min.plus(dimHalved).plus(orientation().mult(origin).mul(scale()));
if (customHalfDim == null)
customHalfDim = dimHalved;
return scene.camera.data.frustum.boundsInFrustum(center.x, center.y, center.z, customHalfDim.x, customHalfDim.y, customHalfDim.z);
}
public boolean insideFrustum(){
return insideFrustum(null);
}
public Vector3f vecTo(Vector3f vector){
return vector.minus(position());
}
public Vector3f vecTo(GameObject other){
return vecTo(other.position());
}
public PersistentManifold getManifoldForCollision(GameObject other){
for (PersistentManifold contact : contactManifolds) {
RigidBody rb = (RigidBody) contact.getBody0();
if (rb.getUserPointer() == this)
rb = (RigidBody) contact.getBody1();
if (rb.getUserPointer() == other)
return contact;
}
return null;
}
}