#ifndef VPLANE_H
#define VPLANE_H

#ifdef _WIN32
#pragma once
#endif

#include "vector.h"

typedef int SideType;

#define	SIDE_FRONT	0
#define	SIDE_BACK	1
#define	SIDE_ON		2

#define VP_EPSILON	0.01f


class VPlane
{
public:
	VPlane();
	VPlane(const Vector& vNormal, vec_t dist);

	void		Init(const Vector& vNormal, vec_t dist);

	vec_t		DistTo(const Vector& vVec) const;

	VPlane& operator=(const VPlane& thePlane);

	SideType	GetPointSide(const Vector& vPoint, vec_t sideEpsilon = VP_EPSILON) const;

	SideType	GetPointSideExact(const Vector& vPoint) const;

	SideType	BoxOnPlaneSide(const Vector& vMin, const Vector& vMax) const;

#ifndef VECTOR_NO_SLOW_OPERATIONS
	VPlane		Flip();

	Vector		GetPointOnPlane() const;

	Vector		SnapPointToPlane(const Vector& vPoint) const;
#endif

public:
	Vector		m_Normal;
	vec_t		m_Dist;

#ifdef VECTOR_NO_SLOW_OPERATIONS
private:
	VPlane(const VPlane& vOther);
#endif
};


inline VPlane::VPlane()
{
}

inline VPlane::VPlane(const Vector& vNormal, vec_t dist)
{
	m_Normal = vNormal;
	m_Dist = dist;
}

inline void	VPlane::Init(const Vector& vNormal, vec_t dist)
{
	m_Normal = vNormal;
	m_Dist = dist;
}

inline vec_t VPlane::DistTo(const Vector& vVec) const
{
	return vVec.Dot(m_Normal) - m_Dist;
}

inline VPlane& VPlane::operator=(const VPlane& thePlane)
{
	m_Normal = thePlane.m_Normal;
	m_Dist = thePlane.m_Dist;
	return *this;
}

#ifndef VECTOR_NO_SLOW_OPERATIONS

inline VPlane VPlane::Flip()
{
	return VPlane(-m_Normal, -m_Dist);
}

inline Vector VPlane::GetPointOnPlane() const
{
	return m_Normal * m_Dist;
}

inline Vector VPlane::SnapPointToPlane(const Vector& vPoint) const
{
	return vPoint - m_Normal * DistTo(vPoint);
}

#endif

inline SideType VPlane::GetPointSide(const Vector& vPoint, vec_t sideEpsilon) const
{
	vec_t fDist;

	fDist = DistTo(vPoint);
	if (fDist >= sideEpsilon)
		return SIDE_FRONT;
	else if (fDist <= -sideEpsilon)
		return SIDE_BACK;
	else
		return SIDE_ON;
}

inline SideType VPlane::GetPointSideExact(const Vector& vPoint) const
{
	return DistTo(vPoint) > 0.0f ? SIDE_FRONT : SIDE_BACK;
}


inline SideType VPlane::BoxOnPlaneSide(const Vector& vMin, const Vector& vMax) const
{
	int i, firstSide, side;
	TableVector vPoints[8] =
	{
		{ vMin.x, vMin.y, vMin.z },
		{ vMin.x, vMin.y, vMax.z },
		{ vMin.x, vMax.y, vMax.z },
		{ vMin.x, vMax.y, vMin.z },

		{ vMax.x, vMin.y, vMin.z },
		{ vMax.x, vMin.y, vMax.z },
		{ vMax.x, vMax.y, vMax.z },
		{ vMax.x, vMax.y, vMin.z },
	};

	firstSide = GetPointSideExact(vPoints[0]);
	for (i = 1; i < 8; i++)
	{
		side = GetPointSideExact(vPoints[i]);

		if (side != firstSide)
			return SIDE_ON;
	}

	return firstSide;
}




#endif  