// CSG Intersection object. By John Haggerty (Slime).
// http://www.slimeland.com/
// Created January 21, 2003

// requires objects.js.

function CSGIntersection(objects)
{
	this.objects = objects;
	this.setupdefaultmodifiers();
}
CSGIntersection.prototype = new Obj();
CSGIntersection.prototype.copy = function()
{
	var objectscopy = new Array();
	for (var a=0; a < this.objects.length; a++)
		objectscopy[a] = this.objects[a].copy();
	return this.copymodifiers(new CSGIntersection(objectscopy));
}
CSGIntersection.prototype.initialize = function()
{
	for (a=0; a < this.objects.length; a++)
	{
		this.objects[a].transform = Transformation.multipletrans([this.objects[a].transform,this.transform]);
		this.objects[a].texture.transform = Transformation.multipletrans([this.objects[a].texture.transform,this.transform])
		this.objects[a].initialize();
	}
	this.transform = Transformation.IdentityTrans.copy();

	// find the intersection of the bounding boxes of all sub-objects with their volume contained by their bounding boxes
	var v1,v2, nv1,nv2, bounds, foundcontainedobject = false, anyboundsinfinite = false;
	for (var a=0; a < this.objects.length; a++)
	{
		if (!this.objects[a].infinitebounds && !this.objects[a].volumeoutsideofbounds)
		{
			if (!foundcontainedobject) {
				v1 = this.objects[a].boundedby.v1.copy();
				v2 = this.objects[a].boundedby.v2.copy();
			}
			else
			{
				nv1 = this.objects[a].boundedby.v1;
				nv2 = this.objects[a].boundedby.v2;
				if (nv1.x > v1.x) v1.x = nv1.x;
				if (nv1.y > v1.y) v1.y = nv1.y;
				if (nv1.z > v1.z) v1.z = nv1.z;
				if (nv2.x < v2.x) v2.x = nv2.x;
				if (nv2.y < v2.y) v2.y = nv2.y;
				if (nv2.z < v2.z) v2.z = nv2.z;
			}
			foundcontainedobject = true;
		}
		else if (this.objects[a].infinitebounds) anyboundsinfinite = true;
	}
	this.volumeoutsideofbounds = false;
	if (foundcontainedobject) {// at least one object had its volume contained by its bounding box.
		this.boundedby = new Box(v1,v2);
	}
	else if (anyboundsinfinite) {// no objects had volume contained by their bounding boxes, and at least one had infinite bounds.
		this.infinitebounds = true;
	}
	else {
		// all of the objects have volume outside of their bounding boxes.
		// so we take the smallest box enclosing all of them.
		v1 = this.objects[0].boundedby.v1.copy();
		v2 = this.objects[0].boundedby.v2.copy();
		for (var a=1; a < this.objects.length; a++)
		{
			nv1 = this.objects[a].boundedby.v1;
			nv2 = this.objects[a].boundedby.v2;
			if (nv1.x < v1.x) v1.x = nv1.x;
			if (nv1.y < v1.y) v1.y = nv1.y;
			if (nv1.z < v1.z) v1.z = nv1.z;
			if (nv2.x > v2.x) v2.x = nv2.x;
			if (nv2.y > v2.y) v2.y = nv2.y;
			if (nv2.z > v2.z) v2.z = nv2.z;
		}
		this.volumeoutsideofbounds = true;
	}
	if (this.inversed && !this.infinitebounds) {
		this.volumeoutsideofbounds = true;
		// it might be false (for instance, if this is the intersection of two inversed spheres, inversed), 
		// but we don't know for sure and it's safer to assume that it's true.
		// i think the case where it's false is rare enough that it won't really matter.
	}
}
CSGIntersection.prototype.findIntersectionsUntransformed = function(ray)
{
	var toreturn = new Array();
	// take all the intersections of every object that occured within every other object.
	for (var a=0; a < this.objects.length; a++)
	{
		var thisobjectsintersections = this.objects[a].findIntersections(ray);
		for (var b=0; b < thisobjectsintersections.length; b++)
		{
			for (var c=0; c < this.objects.length; c++)
			{
				if (c != a && !this.objects[c].isPointInside(thisobjectsintersections[b].getpos()))
					break;
			}
			if (c == this.objects.length) {
				thisobjectsintersections[b].addobject(this);
				toreturn[toreturn.length] = thisobjectsintersections[b];
			}
		}
	}
	toreturn.sort(Intersection.closerintersection);
	return toreturn;
}
CSGIntersection.prototype.isPointInsideUntransformed = function(pos) {
	for (var a=0; a < this.objects.length; a++)
		if (!this.objects[a].isPointInside(pos)) return false;
	return true;
}