#include "SDL_opengl.h"

#include "mymath.h"

#include <string>
#include "frustum.h"


	Frustum::Frustum() {
		changed_=true;
	}

	void Frustum::calculate() {
		Matrix4_tpl <float> clip,gl;


		clip.glget(GL_MODELVIEW_MATRIX);
		gl.glget(GL_PROJECTION_MATRIX);

		clip.concatenate(gl);
	
		for (unsigned int i=0;i<C::SLAST;i++) {
			planes[i]=clip.extract_plane((C::side) i);
		}
	}
	/*bool Frustum::test(Box3_tpl <float> b) {
		if (test_point(b.min)) return true;
		if (test_point(b.max)) return true;
		C3f p;

		p=C3f(b.min.x,b.min.y,b.max.z);
		if (test_point(p)) return true;

		p=C3f(b.min.x,b.max.y,b.min.z);
		if (test_point(p)) return true;

		p=C3f(b.max.x,b.min.y,b.min.z);
		if (test_point(p)) return true;

		p=C3f(b.max.x,b.min.y,b.max.z);
		if (test_point(p)) return true;

		p=C3f(b.max.x,b.max.y,b.min.z);
		if (test_point(p)) return true;

		p=C3f(b.min.x,b.max.y,b.max.z);
		if (test_point(p)) return true;

		return false;
	}*/

	void Frustum::changed() {
		changed_=true;
	}


	void Frustum::calculate_if() {
		if (!changed_) {
			return;
		}
		calculate();
		changed_=false;
	}

	bool Frustum::test_corners(C3f pos,float s,float radius) {

		C3f corner;
      corner=pos+C3f(s,s,s);
      if (Frustum::instance()->test_point(corner,radius)) { return true; }

      corner=pos+C3f(-s,s,s);
      if (Frustum::instance()->test_point(corner,radius)) { return true; }

      corner=pos+C3f(s,s,-s);
      if (Frustum::instance()->test_point(corner,radius)) { return true; }

      corner=pos+C3f(-s,s,-s);
      if (Frustum::instance()->test_point(corner,radius)) { return true; }


      corner=pos+C3f(s,-s,s);
      if (Frustum::instance()->test_point(corner,radius)) { return true; }

      corner=pos+C3f(-s,-s,s);
      if (Frustum::instance()->test_point(corner,radius)) { return true; }

      corner=pos+C3f(s,-s,-s);
      if (Frustum::instance()->test_point(corner,radius)) { return true; }

      corner=pos+C3f(-s,-s,-s);
      if (Frustum::instance()->test_point(corner,radius)) { return true; }

		return false;
	}

	bool Frustum::test_point(C3_tpl <float> p,float radius) {
		unsigned int i;
		for (i=0; i<6; i++) {
			if (planes[i].distance_from_plane(p)<-radius) return false;
		}
		return true;
	}

	std::string Frustum::tostring() {
		std::ostringstream os;
		os.precision(4);

		for (unsigned int side=0;side<6;side++) {
			os << planes[side] << std::endl;
		}
		return os.str();
	}

	void Frustum::stat_reset() { drawn_=0; notdrawn_=0; }
	void Frustum::stat_print() { std::cout << "frustum: drawn: " << drawn_ << "  notdrawn: " << notdrawn_ <<std::endl; }
	void Frustum::drawn() { drawn_++; }
	void Frustum::notdrawn() { notdrawn_++; }

	static Frustum * frustum_=NULL;
	Frustum * Frustum::instance() {
		if (frustum_!=NULL) return frustum_;
		frustum_=new Frustum();
		return frustum_;
	}
