/*******************************************************************************
 * 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;

		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) {

				btVector3 startVector = cp.getPositionWorldOnA();
				btVector3 endVector = cp.getPositionWorldOnB();

				vectors = new Vector3[] {new Vector3(startVector.getFloats()), new Vector3(endVector.getFloats())};

				return 1.f;
			}
		}
	}
}

@@ -4726,16 +4726,62 @@
  vectors
+ = new Vector3%5B%5D%7Bnew Vector3(), new Vector3()%7D
 ;%0A%0A%09%09pub
@@ -5809,213 +5809,82 @@
 %09%09%09%09
-btVector3 startVector = cp.getPositionWorldOnA();%0A%09%09%09%09btVector3 endVector = cp.getPositionWorldOnB();%0A%0A%09%09%09%09vectors = new Vector3%5B%5D %7Bnew Vector3(startVector.getFloats()), new Vector3(endVector.getFloats())%7D
+cp.getPositionWorldOnA(vectors%5B0%5D);%0A%09%09%09%09cp.getPositionWorldOnB(vectors%5B1%5D)
 ;%0A%0A%09

Update bullet test