// --------------------------
//
// Oriented Bounding Box Class
//
// --------------------------

//
// Check if a point is in this bounding box
//
bool CBBox::IsPointInBox(const CVec3 &InP)
{
	// Rotate the point into the box's coordinates
	CVec3 P = m_M.InvertSimple() * InP;
	
	// Now just use an axis-aligned check
	if ( fabs(P.x) < m_Extent.x && fabs(P.y) < m_Extent.y && fabs(P.z) < m_Extent.z ) 
		return true;
		
	return false;
}

//
// Check if a sphere overlaps any part of this bounding box
//
bool CBBox::IsSphereInBox( const CVec3 &InP, float fRadius)
{
	float fDist;
	float fDistSq = 0;
	CVec3 P = m_M.InvertSimple() * InP;
	
	// Add distance squared from sphere centerpoint to box for each axis
	for ( int i = 0; i < 3; i++ )
	{
		if ( fabs(P[i]) > m_Extent[i] )
		{
			fDist = fabs(P[i]) - m_Extent[i];
			fDistSq += fDist*fDist;
		}
	}
	return ( fDistSq <= fRadius*fRadius );
}

//
// Check if the bounding box is completely behind a plane( defined by a normal and a point )
//
bool CBBox::BoxOutsidePlane( const CVec3 &InNorm, const CVec3 &InP )
{
	// Plane Normal in Box Space
	CVec3 Norm = InNorm.RotByMatrix( m_M.InvertSimple().mf ); // RotByMatrix only uses rotation portion of matrix
	Norm = CVec3( fabs( Norm.x ), fabs( Norm.y ), fabs( Norm.z ) );
	
	float Extent = Norm.Dot( m_Extent ); // Box Extent along the plane normal
	float Distance = InNorm.Dot( GetCenterPoint() - InP ); // Distance from Box Center to the Plane

	// If Box Centerpoint is behind the plane further than its extent, the Box is outside the plane
	if ( Distance < -Extent ) return true;
	return false;
}

//
// Does the Line (L1, L2) intersect the Box?
//
bool CBBox::IsLineInBox( const CVec3& L1, const CVec3& L2 )
{	
	// Put line in box space
	CMatrix MInv = m_M.InvertSimple();
	CVec3 LB1 = MInv * L1;
	CVec3 LB2 = MInv * L2;

	// Get line midpoint and extent
	CVec3 LMid = (LB1 + LB2) * 0.5f; 
	CVec3 L = (LB1 - LMid);
	CVec3 LExt = CVec3( fabs(L.x), fabs(L.y), fabs(L.z) );

	// Use Separating Axis Test
	// Separation vector from box center to line center is LMid, since the line is in box space
	if ( fabs( LMid.x ) > m_Extent.x + LExt.x ) return false;
	if ( fabs( LMid.y ) > m_Extent.y + LExt.y ) return false;
	if ( fabs( LMid.z ) > m_Extent.z + LExt.z ) return false;
	// Crossproducts of line and each axis
	if ( fabs( LMid.y * L.z - LMid.z * L.y)  >  (m_Extent.y * LExt.z + m_Extent.z * LExt.y) ) return false;
	if ( fabs( LMid.x * L.z - LMid.z * L.x)  >  (m_Extent.x * LExt.z + m_Extent.z * LExt.x) ) return false;
	if ( fabs( LMid.x * L.y - LMid.y * L.x)  >  (m_Extent.x * LExt.y + m_Extent.y * LExt.x) ) return false;
	// No separating axis, the line intersects
	return true;
}

//
// Returns a 3x3 rotation matrix as vectors
//
inline void CBBox::GetInvRot( CVec3 *pvRot )
{
	pvRot[0] = CVec3( m_M.mf[0], m_M.mf[1], m_M.mf[2] );
	pvRot[1] = CVec3( m_M.mf[4], m_M.mf[5], m_M.mf[6] );
	pvRot[2] = CVec3( m_M.mf[8], m_M.mf[9], m_M.mf[10] );
}

//
// Check if any part of a box is inside any part of another box
// Uses the separating axis test.
//
bool CBBox::IsBoxInBox( CBBox &BBox )
{
	CVec3 SizeA = m_Extent;
	CVec3 SizeB = BBox.m_Extent;
	CVec3 RotA[3], RotB[3];	
	GetInvRot( RotA );
	BBox.GetInvRot( RotB );

    float R[3][3];  // Rotation from B to A
    float AR[3][3]; // absolute values of R matrix, to use with box extents
    float ExtentA, ExtentB, Separation;
    int i, k;

    // Calculate B to A rotation matrix
    for( i = 0; i < 3; i++ )
        for( k = 0; k < 3; k++ )
			{
            R[i][k] = RotA[i].Dot(RotB[k]); 
            AR[i][k] = fabs(R[i][k]);
            }
            
    // Vector separating the centers of Box B and of Box A	
    CVec3 vSepWS = BBox.GetCenterPoint() - GetCenterPoint();
    // Rotated into Box A's coordinates
    CVec3 vSepA( vSepWS.Dot(RotA[0]), vSepWS.Dot(RotA[1]), vSepWS.Dot(RotA[2]) );            

     // Test if any of A's basis vectors separate the box
	for( i = 0; i < 3; i++ )
	{
		ExtentA = SizeA[i];
		ExtentB = SizeB.Dot( CVec3( AR[i][0], AR[i][1], AR[i][2] ) );
		Separation = fabs( vSepA[i] );

		if( Separation > ExtentA + ExtentB ) return false;
	}

	// Test if any of B's basis vectors separate the box
	for( k = 0; k < 3; k++ )
	{
		ExtentA = SizeA.Dot( CVec3( AR[0][k], AR[1][k], AR[2][k] ) );
		ExtentB = SizeB[k];
		Separation = fabs( vSepA.Dot( CVec3(R[0][k],R[1][k],R[2][k]) ) );

		if( Separation > ExtentA + ExtentB ) return false;
	}

	// Now test Cross Products of each basis vector combination ( A[i], B[k] )
	for( i=0 ; i<3 ; i++ )
		for( k=0 ; k<3 ; k++ )
		{
		int i1 = (i+1)%3, i2 = (i+2)%3;
		int k1 = (k+1)%3, k2 = (k+2)%3;
		ExtentA = SizeA[i1] * AR[i2][k]  +  SizeA[i2] * AR[i1][k];
		ExtentB = SizeB[k1] * AR[i][k2]  +  SizeB[k2] * AR[i][k1];
		Separation = fabs( vSepA[i2] * R[i1][k]  -  vSepA[i1] * R[i2][k] );
		if( Separation > ExtentA + ExtentB ) return false;
		}

	// No separating axis found, the boxes overlap	
	return true;
	}