// computes a frustum with given far and near planes
Frustum BaseCamera::CalculateFrustum( float fNear, float fFar )
{
	noVec3 vZ = Normalize(m_to - m_from);
	noVec3 vX = Normalize(Cross(m_up, vZ));
	noVec3 vY = Normalize(Cross(vZ, vX));

	float fAspect = GetApp()->GetAspectRatio();

	float fNearPlaneHalfHeight = tanf(m_fov * 0.5f) * fNear;
	float fNearPlaneHalfWidth = fNearPlaneHalfHeight * fAspect;

	float fFarPlaneHalfHeight = tanf(m_fov * 0.5f) * fFar;
	float fFarPlaneHalfWidth = fFarPlaneHalfHeight * fAspect;

	noVec3 vNearPlaneCenter = m_from + vZ * fNear;
	noVec3 vFarPlaneCenter = m_from + vZ * fFar;

	Frustum frustum;
	frustum.m_pPoints[0] = noVec3(vNearPlaneCenter - vX*fNearPlaneHalfWidth - vY*fNearPlaneHalfHeight);
	frustum.m_pPoints[1] = noVec3(vNearPlaneCenter - vX*fNearPlaneHalfWidth + vY*fNearPlaneHalfHeight);
	frustum.m_pPoints[2] = noVec3(vNearPlaneCenter + vX*fNearPlaneHalfWidth + vY*fNearPlaneHalfHeight);
	frustum.m_pPoints[3] = noVec3(vNearPlaneCenter + vX*fNearPlaneHalfWidth - vY*fNearPlaneHalfHeight);

	frustum.m_pPoints[4] = noVec3(vFarPlaneCenter - vX*fFarPlaneHalfWidth - vY*fFarPlaneHalfHeight);
	frustum.m_pPoints[5] = noVec3(vFarPlaneCenter - vX*fFarPlaneHalfWidth + vY*fFarPlaneHalfHeight);
	frustum.m_pPoints[6] = noVec3(vFarPlaneCenter + vX*fFarPlaneHalfWidth + vY*fFarPlaneHalfHeight);
	frustum.m_pPoints[7] = noVec3(vFarPlaneCenter + vX*fFarPlaneHalfWidth - vY*fFarPlaneHalfHeight);

	// update frustum AABB
	frustum.CalculateAABB();

	return frustum;
}
// finds scene objects inside the camera frustum
std::vector<SceneObject *> ShadowCamera::FindReceivers(void)
{
  Frustum cameraFrustum = CalculateFrustum(m_fNearMin, m_fFarMax);
  cameraFrustum.CalculateAABB();

  std::vector<SceneObject *> receivers;
  receivers.reserve(g_SceneObjects.size());
  for(unsigned int i=0; i<g_SceneObjects.size(); i++)
  {
    SceneObject *pObject = g_SceneObjects[i];

    // intersection test
    if(g_iVisibilityTest == VISTEST_ACCURATE) {
      // test accurately
      if(!IntersectionTest(pObject->m_AABB, cameraFrustum)) continue;
    } else if(g_iVisibilityTest == VISTEST_CHEAP) {
      // test only with AABB of frustum
      if(!IntersectionTest(pObject->m_AABB, cameraFrustum.m_AABB)) continue;
    }
    
    receivers.push_back(pObject);
  }
  return receivers;
}