/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.badlogic.gdx.tests.bullet;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.bullet.collision.Collision;
import com.badlogic.gdx.physics.bullet.collision.btCollisionDispatcher;
import com.badlogic.gdx.physics.bullet.collision.btCollisionObject;
import com.badlogic.gdx.physics.bullet.collision.btCollisionObjectWrapper;
import com.badlogic.gdx.physics.bullet.collision.btCollisionWorld;
import com.badlogic.gdx.physics.bullet.collision.ContactResultCallback;
import com.badlogic.gdx.physics.bullet.collision.btConvexHullShape;
import com.badlogic.gdx.physics.bullet.collision.btDbvtBroadphase;
import com.badlogic.gdx.physics.bullet.collision.btDefaultCollisionConfiguration;
import com.badlogic.gdx.physics.bullet.collision.btManifoldPoint;
import com.badlogic.gdx.physics.bullet.collision.btShapeHull;
import com.badlogic.gdx.physics.bullet.linearmath.btVector3;
/** @author xoppa, didum */
public class ConvexHullDistanceTest extends BaseBulletTest {
private ConvexHullDistance distance;
private ShapeRenderer shapeRenderer;
@Override
public void create () {
super.create();
final Model carModel = objLoader.loadModel(Gdx.files.internal("data/car.obj"));
disposables.add(carModel);
carModel.materials.get(0).clear();
carModel.materials.get(0).set(ColorAttribute.createDiffuse(Color.WHITE), ColorAttribute.createSpecular(Color.WHITE));
world.addConstructor("car", new BulletConstructor(carModel, 5f, createConvexHullShape(carModel, true)));
// Create the entities
world.add("ground", 0f, 0f, 0f).setColor(0.25f + 0.5f * (float)Math.random(), 0.25f + 0.5f * (float)Math.random(),
0.25f + 0.5f * (float)Math.random(), 1f);
for (float y = 10f; y < 50f; y += 5f)
world.add("car", -2f + (float)Math.random() * 4f, y, -2f + (float)Math.random() * 4f).setColor(
0.25f + 0.5f * (float)Math.random(), 0.25f + 0.5f * (float)Math.random(), 0.25f + 0.5f * (float)Math.random(), 1f);
distance = new ConvexHullDistance();
shapeRenderer = new ShapeRenderer();
}
@Override
public boolean tap (float x, float y, int count, int button) {
shoot(x, y);
return true;
}
@Override
public void render () {
super.render();
// Draw the lines of the distances
camera.update();
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeType.Line);
shapeRenderer.setColor(1, 1, 0, 1);
for (int i = 0; i < world.entities.size; i++) {
btCollisionObject collisionObject0 = world.entities.get(i).body;
for (int j = 0; j < world.entities.size; j++) {
if (i != j) {
btCollisionObject collisionObject1 = world.entities.get(j).body;
distance.calculateDistance(collisionObject0, collisionObject1);
shapeRenderer.line(distance.getVector3()[0], distance.getVector3()[1]);
}
}
}
shapeRenderer.end();
}
public static btConvexHullShape createConvexHullShape (final Model model, boolean optimize) {
final Mesh mesh = model.meshes.get(0);
final btConvexHullShape shape = new btConvexHullShape(mesh.getVerticesBuffer(), mesh.getNumVertices(), mesh.getVertexSize());
if (!optimize) return shape;
// now optimize the shape
final btShapeHull hull = new btShapeHull(shape);
hull.buildHull(shape.getMargin());
final btConvexHullShape result = new btConvexHullShape(hull);
// delete the temporary shape
shape.dispose();
hull.dispose();
return result;
}
private class ConvexHullDistance {
private btDefaultCollisionConfiguration collisionConfiguration;
private btCollisionDispatcher dispatcher;
private btDbvtBroadphase pairCache;
private btCollisionWorld collisionWorld;
Vector3[] vectors = new Vector3[]{new Vector3(), new Vector3()};
public ConvexHullDistance () {
collisionConfiguration = new btDefaultCollisionConfiguration();
dispatcher = new btCollisionDispatcher(collisionConfiguration);
pairCache = new btDbvtBroadphase();
collisionWorld = new btCollisionWorld(dispatcher, pairCache, collisionConfiguration);
}
public Vector3[] getVector3 () {
return vectors;
}
public void calculateDistance (btCollisionObject colObjA, btCollisionObject colObjB) {
DistanceInternalResultCallback result = new DistanceInternalResultCallback();
Collision.setGContactBreakingThreshold(100f);
collisionWorld.contactPairTest(colObjA, colObjB, result);
Collision.setGContactBreakingThreshold(0.02f);
}
private class DistanceInternalResultCallback extends ContactResultCallback {
public DistanceInternalResultCallback () {
}
@Override
public float addSingleResult (btManifoldPoint cp, btCollisionObjectWrapper colObj0Wrap, int partId0, int index0,
btCollisionObjectWrapper colObj1Wrap, int partId1, int index1) {
cp.getPositionWorldOnA(vectors[0]);
cp.getPositionWorldOnB(vectors[1]);
return 1.f;
}
}
}
}