package com.blarg.gdx.tilemap3d;

import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.math.collision.BoundingBox;
import com.blarg.gdx.Bitfield;
import com.blarg.gdx.math.SweptSphere;
import com.blarg.gdx.math.SweptSphereCollisionTester;
import com.blarg.gdx.math.SweptSphereWorldCollisionChecker;
import com.blarg.gdx.tilemap3d.tilemesh.TileMesh;

public class TileMapSweptSphereCollisionChecker implements SweptSphereWorldCollisionChecker {
	static final TileCoord min = new TileCoord();
	static final TileCoord max = new TileCoord();
	static final Vector3 tileWorldPosition = new Vector3();
	static final Vector3 a = new Vector3();
	static final Vector3 b = new Vector3();
	static final Vector3 c = new Vector3();

	TileMap tileMap;

	public TileMapSweptSphereCollisionChecker(TileMap tileMap) {
		if (tileMap == null)
			throw new IllegalArgumentException("tileMap can not be null.");

		this.tileMap = tileMap;
	}

	@Override
	public void checkForCollisions(SweptSphere sphere, BoundingBox possibleCollisionArea) {
		min.set(0, 0, 0);
		max.set(0, 0, 0);

		float lastCollisionDistance = Float.MAX_VALUE;

		// TODO: I don't think we even need to check if the area overlaps ... ?
		//       (it probably always will, right?)
		boolean overlapping = tileMap.getOverlappedTiles(possibleCollisionArea, min, max);
		if (overlapping) {
			for (int y = min.y; y <= max.y; ++y) {
				for (int z = min.z; z < max.z; ++z) {
					for (int x = min.x; x < max.x; ++x) {
						Tile tile = tileMap.get(x, y, z);

						// only check solid tiles
						if (Bitfield.isSet(Tile.FLAG_COLLIDEABLE, tile.flags)) {
							// check each triangle in this tile's mesh
							TileMesh mesh = tileMap.tileMeshes.get(tile);
							Vector3[] vertices = mesh.getCollisionVertices();

							// world position of this tile, will be used to move each
							// mesh triangle into world space
							tileWorldPosition.set(x, y, z);

							// also add the global TileMesh offset so the mesh is within
							// 0,0,0 to 1,1,1 and not -0.5,-0.5,-0.5 to 0.5,0.5,0.5
							tileWorldPosition.add(TileMesh.OFFSET);

							Matrix4 transform = Tile.getTransformationFor(tile);

							for (int i = 0; i < vertices.length; i += 3) {
								// get the vertices making up this triangle
								a.set(vertices[i]);
								b.set(vertices[i + 1]);
								c.set(vertices[i + 2]);

								if (transform != null) {
									a.mul(transform);
									b.mul(transform);
									c.mul(transform);
								}

								// move these vertices into world space
								a.add(tileWorldPosition);
								b.add(tileWorldPosition);
								c.add(tileWorldPosition);

								// test against it. we don't actually care about the
								// return value, but just want the CollisionPacket
								// to be updated. at the end of all these tests, it
								// will contain info for the closest intersection
								// found
								boolean collided = SweptSphereCollisionTester.test(sphere, a, b, c);
								if (collided && sphere.nearestCollisionDistance < lastCollisionDistance)
									lastCollisionDistance = sphere.nearestCollisionDistance;
							}
						}
					}
				}
			}
		}
	}
}

@@ -760,16 +760,23 @@
 r3();%0A%0A%09
+public 
 TileMap 
@@ -790,65 +790,103 @@
 ;%0A%0A%09
-public TileMapSweptSphereCollisionChecker(TileMap tileMap
+@Override%0A%09public void checkForCollisions(SweptSphere sphere, BoundingBox possibleCollisionArea
 ) %7B%0A
@@ -925,23 +925,28 @@
 new 
-IllegalArgument
+UnsupportedOperation
 Exce
@@ -956,166 +956,39 @@
 on(%22
-t
+No T
 ileMap 
-can not be null.%22);%0A%0A%09%09this.tileMap = tileMap;%0A%09%7D%0A%0A%09@Override%0A%09public void checkForCollisions(SweptSphere sphere, BoundingBox possibleCollisionArea) %7B
+object is set.%22);%0A%09%09
 %0A%09%09m

allow resetting the TileMap object being checked for collisions