/*******************************************************
* class Obj3D
* 概要: 基底オブジェクト。CompositeパターンのComponent
* にあたる。
* Obj3D <-> Group3d
*        -> Boid など
*******************************************************/

#ifndef ATS_COMPONENT_H
#define ATS_COMPONENT_H

// ats_compositeにのみ呼ばれる。

#include "ats_point.h"
#include "ats_exception.h"
#include <math.h>
#include <list>

namespace ats
{
	template<class TFLOAT>
	class Obj3D
	{
	private:

	protected:
		virtual void normalize(TFLOAT* v);
		virtual void normalize(Point<TFLOAT>& v);
		virtual void normal(const TFLOAT const* v1, const TFLOAT const* c, const TFLOAT const* v2, TFLOAT* out);
		virtual void normal(Point<TFLOAT>& v1, Point<TFLOAT>& c, Point<TFLOAT>& v2, Point<TFLOAT>* out);
		virtual void smooth_normal(TFLOAT* cen, TFLOAT* v0, TFLOAT* v1, TFLOAT* v2, TFLOAT* v3, TFLOAT* out);

	public:
		//virtual void translate(Point<TFLOAT>& a) { throw ats::bad_operation("Obj3D::translate throw bad_operation"); }
		//virtual void rotate(Point<TFLOAT>& vec, TFLOAT a) { throw ats::bad_operation("Obj3D::rotate throw bad_operation"); }
		//virtual void scale(Point<TFLOAT>& a) { throw ats::bad_operation("Obj3D::scale throw bad_operation"); }

		virtual void Add(Obj3D<TFLOAT>* a) = 0;
		virtual void Remove(std::list<Obj3D<TFLOAT>*>::iterator a) = 0;
		virtual std::list<Obj3D<TFLOAT>*>::iterator Begin() = 0;
		virtual std::list<Obj3D<TFLOAT>*>::iterator End() = 0;

		// operation
		virtual void Draw() = 0;
		virtual void UpdateTime(double) = 0;
	};

	typedef Obj3D<double> Obj3DD;

	// 平均化した法線ベクトル計算 ---------------------------------------------
	template<class TFLOAT>
	void Obj3D<TFLOAT>::smooth_normal(TFLOAT* cen, TFLOAT* v0, TFLOAT* v1, TFLOAT* v2, TFLOAT* v3, TFLOAT* out)
	{
		/*TFLOAT tmp0[3], tmp1[3], tmp2[3], tmp3[3];
		normal(cen, v0, tmp0);
		normal(cen, v1, tmp1);
		normal(cen, v2, tmp2);
		normal(cen, v3, tmp3);
		out[0] = (tmp0[0] + tmp1[0] + tmp2[0] + tmp3[0]) / 4;
		out[1] = (tmp0[1] + tmp1[1] + tmp2[1] + tmp3[1]) / 4;
		out[2] = (tmp0[2] + tmp1[2] + tmp2[2] + tmp3[2]) / 4;
		normalize(out);*/
	}

	// 平面の法線ベクトル ----------------------------------------------------
	template<class TFLOAT>
	void Obj3D<TFLOAT>::normal(Point<TFLOAT>& v1, Point<TFLOAT>& c, Point<TFLOAT>& v2, Point<TFLOAT>* out)
	{
		*out = (v2 - c) * (v1 - c);
	}

	// 正規化した頂点を返す ------------------------------------------------
	template<class TFLOAT>
	void Obj3D<TFLOAT>::normal(const TFLOAT const* v1, const TFLOAT const* c, const TFLOAT const* v2, TFLOAT* out)
	{
		Point<TFLOAT> cen ( c[0],  c[1],  c[2]);
		Point<TFLOAT> vec1(v1[0], v1[1], v1[2]);
		Point<TFLOAT> vec2(v2[0], v2[1], v2[2]);
		Point<TFLOAT> tmp((vec2 - cen) * (vec1 - cen));
		out[0] = tmp.X();
		out[1] = tmp.Y();
		out[2] = tmp.Z();
	}

	// 正規化関数(ポイント)------------------------------------------------
	template<class TFLOAT>
	void Obj3D<TFLOAT>::normalize(Point<TFLOAT>& v)
	{
		v.Normalize();
	}

	// 正規化関数(頂点配列) ------------------------------------------------
	template<class TFLOAT>
	void Obj3D<TFLOAT>::normalize(TFLOAT* v)
	{
		TFLOAT d = ::sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
		if(!d){ d = 0.0000000000000000001; }
		v[0] /= d; v[1] /= d; v[2] /= d;
	}
}

#endif // #ifndef ATS_COMPONENT_H
