#pragma once

#include <C2/lm/matrix4.h>


namespace lib_gl
{


// 平面に影を投影するための変換行列を生成する機能
class FlatShadowMatrix
{
public:
	// 指定した面にオブジェクトを投影する変換行列を生成する
	//i_PlaneNormal    : 投影面の法線
	//i_PlanePassPoint : 投影面の通過点
	//i_LightPosition  : 影を発生させる光源の位置
	template<typename T>
	static lm::matrix4<T> create(const lm::vector3<T>& i_PlaneNormal, const lm::vector3<T> &i_PlanePassPoint, const lm::vector3<T>& i_LightPosition);
	template<typename T>
	static void create(const lm::vector3<T>&i_PlaneNormal, const lm::vector3<T> &i_PlanePassPoint, const lm::vector3<T>& i_LightPosition , lm::matrix4<T>& o_mat );

	// 光源位置を同次座標で指定
	template<typename T>
	static lm::matrix4<T> create(const lm::vector3<T>&i_PlaneNormal, const lm::vector3<T> &i_PlanePassPoint, const lm::vector4<T>& i_LightPosition);
	template<typename T>
	static void create(const lm::vector3<T>&i_PlaneNormal, const lm::vector3<T> &i_PlanePassPoint, const lm::vector4<T>& i_LightPosition , lm::matrix4<T>& o_mat );
};



template<typename T> inline
lm::matrix4<T> FlatShadowMatrix::create(const lm::vector3<T>& i_PlaneNormal, const lm::vector3<T> &i_PlanePassPoint, const lm::vector3<T>& i_LightPosition)
{
	lm::matrix4<T> shadow_mat;
	create( i_PlaneNormal , i_PlanePassPoint , i_LightPosition , shadow_mat );
	return shadow_mat;
}

template<typename T> inline
void FlatShadowMatrix::create(const lm::vector3<T>&i_PlaneNormal, const lm::vector3<T> &i_PlanePassPoint, const lm::vector3<T>& i_LightPosition , lm::matrix4<T>& o_mat )
{
	lm::vec4f light_pos4( i_LightPosition.x , i_LightPosition.y , i_LightPosition.z , 1.0f );
	create( i_PlaneNormal , i_PlanePassPoint , light_pos4 , o_mat );
}

template<typename T> inline
lm::matrix4<T> FlatShadowMatrix::create(const lm::vector3<T>&i_PlaneNormal, const lm::vector3<T>& i_PlanePassPoint, const lm::vector4<T> &i_LightPosition)
{
	lm::matrix4<T> shadow_mat;
	create( i_PlaneNormal , i_PlanePassPoint , i_LightPosition , shadow_mat );
	return shadow_mat;
}

template<typename T> inline
void FlatShadowMatrix::create(const lm::vector3<T>&i_PlaneNormal, const lm::vector3<T>& i_PlanePassPoint, const lm::vector4<T>& i_LightPosition , lm::matrix4<T>& o_mat )
{
	lm::vector4<T> plane; // 平面方程式
	plane[0]	=	i_PlaneNormal.x;
	plane[1]	=	i_PlaneNormal.y;
	plane[2]	=	i_PlaneNormal.z;
	plane[3]	=	-dot( i_PlaneNormal , i_PlanePassPoint );

	T dot = lm::dot( plane , i_LightPosition );

	o_mat(0,0) = dot - plane[0] * i_LightPosition[0];
	o_mat(0,1) =     - plane[0] * i_LightPosition[1];
	o_mat(0,2) =     - plane[0] * i_LightPosition[2];
	o_mat(0,3) =     - plane[0] * i_LightPosition[3];

	o_mat(1,0) =     - plane[1] * i_LightPosition[0];
	o_mat(1,1) = dot - plane[1] * i_LightPosition[1];
	o_mat(1,2) =     - plane[1] * i_LightPosition[2];
	o_mat(1,3) =     - plane[1] * i_LightPosition[3];

	o_mat(2,0) =     - plane[2] * i_LightPosition[0];
	o_mat(2,1) =     - plane[2] * i_LightPosition[1];
	o_mat(2,2) = dot - plane[2] * i_LightPosition[2];
	o_mat(2,3) =     - plane[2] * i_LightPosition[3];

	o_mat(3,0) =     - plane[3] * i_LightPosition[0];
	o_mat(3,1) =     - plane[3] * i_LightPosition[1];
	o_mat(3,2) =     - plane[3] * i_LightPosition[2];
	o_mat(3,3) = dot - plane[3] * i_LightPosition[3];
}


}
