//===========================================================================//
// File:	extntbox.cc                                                        //
// Project: MUNGA           Brick: Math Library                              //
// Contents: Implementation details of bounding box class                    //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 01/07/95  JMA  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1994,1995 Virtual World Entertainment, Inc.                 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include <munga.hpp>
#pragma hdrstop

#if !defined(EXTNTBOX_HPP)
#	include <extntbox.hpp>
#endif

#if !defined(CSTR_HPP)
	#include <cstr.hpp>
#endif

#if !defined(VECTOR3D_HPP)
	#include <vector3d.hpp>
#endif

#if !defined(NOTATION_HPP)
	#include <notation.hpp>
#endif

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#if defined(USE_SIGNATURE)
	int
		Is_Signature_Bad(const volatile ExtentBox *)
	{
		return False;
	}
#endif

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ExtentBox::ExtentBox(
	const Vector3D &min,
	const Vector3D &max
)
{
	Check_Pointer(this);
	Check(&min);
	Check(&max);

	if (min.x <= max.x)
	{
		minX = min.x;
		maxX = max.x;
	}
	else
	{
		minX = max.x;
		maxX = min.x;
	}

	if (min.y <= max.y)
	{
		minY = min.y;
		maxY = max.y;
	}
	else
	{
		minY = max.y;
		maxY = min.y;
	}

	if (min.z <= max.z)
	{
		minZ = min.z;
		maxZ = max.z;
	}
	else
	{
		minZ = max.z;
		maxZ = min.z;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ExtentBox::ExtentBox(const ExtentBox &box)
{
	Check_Pointer(this);
	Check(&box);

	minX = box.minX;
	maxX = box.maxX;
	minY = box.minY;
	maxY = box.maxY;
	minZ = box.minZ;
	maxZ = box.maxZ;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ExtentBox&
	ExtentBox::Intersect(
		const ExtentBox &box_1,
		const ExtentBox &box_2
	)
{
	Check_Pointer(this);
	Check(&box_1);
	Check(&box_2);

	Verify(box_1.minX <= box_2.maxX);
	Verify(box_1.maxX >= box_2.minX);
	Verify(box_1.minY <= box_2.maxY);
	Verify(box_1.maxY >= box_2.minY);
	Verify(box_1.minZ <= box_2.maxZ);
	Verify(box_1.maxZ >= box_2.minZ);

	minX = Max(box_1.minX, box_2.minX);
	maxX = Min(box_1.maxX, box_2.maxX);
	minY = Max(box_1.minY, box_2.minY);
	maxY = Min(box_1.maxY, box_2.maxY);
	minZ = Max(box_1.minZ, box_2.minZ);
	maxZ = Min(box_1.maxZ, box_2.maxZ);

   return *this;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Vector3D*
	ExtentBox::Constrain(Vector3D *point) const
{
	Check(this);
	Check(point);

	Clamp(point->x,minX,maxX);
	Clamp(point->y,minY,maxY);
	Clamp(point->z,minZ,maxZ);
	return point;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	ExtentBox::Contains(const Vector3D &point) const
{
	return
		minX <= point.x && maxX >= point.x
		 && minY <= point.y && maxY >= point.y
		 && minZ <= point.z && maxZ >= point.z;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	ExtentBox::Contains(const ExtentBox &box) const
{
	return
		minX <= box.minX && maxX >= box.maxX
		 && minY <= box.minY && maxY >= box.maxY
		 && minZ <= box.minZ && maxZ >= box.maxZ;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	ExtentBox::Intersects(const ExtentBox &box) const
{
	return
		minX <= box.maxX && maxX >= box.minX
		 && minY <= box.maxY && maxY >= box.minY
		 && minZ <= box.maxZ && maxZ >= box.minZ;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	ExtentBox::TestInstance() const
{
	return minX<=maxX && minY<=maxY && minZ<=maxZ;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ostream&
	operator<<(
		ostream& stream,
		const ExtentBox& e
	)
{
	return stream << '[' << e.minX << ".." << e.maxX << "],[" << e.minY << ".."
   	<< e.maxY << "],[" << e.minZ << ".." << e.maxZ << ']';
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~ ExtentBox functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
   Convert_From_Ascii(
      const char *str,
      ExtentBox *extent_box
   )
{
	Check_Pointer(str);
	Check_Signature(extent_box);

   CString parse_string(str);
   Check(&parse_string);

   Check_Pointer(parse_string.GetNthToken(0));
   extent_box->minX = atof(parse_string.GetNthToken(0));

   Check_Pointer(parse_string.GetNthToken(1));
   extent_box->minY = atof(parse_string.GetNthToken(1));

   Check_Pointer(parse_string.GetNthToken(2));
   extent_box->minZ = atof(parse_string.GetNthToken(2));

   Check_Pointer(parse_string.GetNthToken(3));
   extent_box->maxX = atof(parse_string.GetNthToken(3));

   Check_Pointer(parse_string.GetNthToken(4));
   extent_box->maxY = atof(parse_string.GetNthToken(4));

   Check_Pointer(parse_string.GetNthToken(5));
   extent_box->maxZ = atof(parse_string.GetNthToken(5));

   Check(extent_box);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

ExtentBox *
	MakeExistanceBoxStream(
		NotationFile *notation_file,
		int *size
	)
{

	char page_name[50];

	if (!notation_file->GetEntry("COLLISION", "extentcount", size))
	{
			cerr << "No 'COLLISION' entry!!!!!" << endl;
			Exit(AbortExitCodeID);
	}

	ExtentBox *extents = new ExtentBox[*size];

	for (int j=0; j < *size; ++j)
	{
		sprintf(page_name, "extent %d", j);

		int errorvalue = 0;

		errorvalue |= !notation_file->GetEntry(page_name, "extminX", &extents[j].minX);
		errorvalue |= !notation_file->GetEntry(page_name, "extmaxX", &extents[j].maxX);
		errorvalue |= !notation_file->GetEntry(page_name, "extminY", &extents[j].minY);
		errorvalue |= !notation_file->GetEntry(page_name, "extmaxY", &extents[j].maxY);
		errorvalue |= !notation_file->GetEntry(page_name, "extminZ", &extents[j].minZ);
		errorvalue |= !notation_file->GetEntry(page_name, "extmaxZ", &extents[j].maxZ);

		if ( errorvalue )
		{
			Tell("Extent number : " << j << " is does not have valid slice extents " << endl);
			Exit(AbortExitCodeID);
		}

	}

	return extents;

}
