#include "StdAfx.h"
#include "Camera.h"



namespace gl
{

static const float DEFAULT_DST = 5.0f;


void Camera::Reset(void)
{
	m_Manip.m_ViewPos.set(0.0f, 0.0f, 0.0f);
	m_Manip.m_EyePos = lm::vec3f(1.0f, 1.0f, 1.0f).get_normalize() * DEFAULT_DST;
	m_Manip.SetUpAngle( lm::vec3f( 0.0f , 1.0f , 0.0f ) );

	SetClipRangeAuto(DEFAULT_DST);
}

void Camera::ResetViewFront(void)
{
	const lm::vec3f eye_angle(0.0f, 0.0f, 1.0f);
	const lm::vec3f up(0.0f, 1.0f, 0.0f);
	ResetViewOrthoMain(eye_angle, up);
}

void Camera::ResetViewBack(void)
{
	const lm::vec3f eye_angle(0.0f, 0.0f, -1.0f);
	const lm::vec3f up(0.0f, 1.0f, 0.0f);
	ResetViewOrthoMain(eye_angle, up);
}

void Camera::ResetViewLeft(void)
{
	const lm::vec3f eye_angle(1.0f, 0.0f, 0.0f);
	const lm::vec3f up(0.0f, 1.0f, 0.0f);
	ResetViewOrthoMain(eye_angle, up);
}


void Camera::ResetViewRight(void)
{
	const lm::vec3f eye_angle(-1.0f, 0.0f, 0.0f);
	const lm::vec3f up(0.0f, 1.0f, 0.0f);
	ResetViewOrthoMain(eye_angle, up);
}

void Camera::ResetViewTop(void)
{
	const lm::vec3f eye_angle(0.0f, 1.0f, 0.0f);
	const lm::vec3f up(0.0f, 0.0f, -1.0f);
	ResetViewOrthoMain(eye_angle, up);
}

void Camera::ResetViewBottom(void)
{
	const lm::vec3f eye_angle(0.0f, -1.0f, 0.0f);
	const lm::vec3f up(0.0f, 0.0f, -1.0f);
	ResetViewOrthoMain(eye_angle, up);
}

void Camera::ResetViewPerse(void)
{
	const lm::vec3f eye_angle = lm::vec3f(1.0f, 1.0f, 1.0f).get_normalize();
	const lm::vec3f up(0.0f, 1.0f, 0.0f);
	ResetViewOrthoMain(eye_angle, up);
}

void Camera::ResetViewPoint(ViewPoint vp)
{
	switch(vp)
	{
	case ViewPoint::Front  : ResetViewFront  (); break;
	case ViewPoint::Back   : ResetViewBack   (); break;
	case ViewPoint::Left   : ResetViewLeft   (); break;
	case ViewPoint::Right  : ResetViewRight  (); break;
	case ViewPoint::Top    : ResetViewTop    (); break;
	case ViewPoint::Bottom : ResetViewBottom (); break;
	case ViewPoint::Perse  : ResetViewPerse  (); break;

	default:
		assert(false);
		return;
	}
}


void Camera::ResetViewOrthoMain(const lm::vec3f& eye_angle, const lm::vec3f& up)
{
	float d = m_Manip.GetDistanceToLookPos();
	m_Manip.m_EyePos = m_Manip.m_ViewPos + eye_angle * d;
	m_Manip.SetUpAngle( up );
}

void Camera::ResetViewKeepAngle(const lm::range3f& r)
{
	const lm::vec3f eye_angle = m_Manip.GetViewToEye().get_normalize();
	const lm::vec3f up = lm::vec3f(0.0f, 1.0f, 0.0f);
	ResetViewMain(r, eye_angle, up);
}

void Camera::ResetViewMain(const lm::range3f& r, const lm::vec3f& ang, const lm::vec3f& up)
{
	float max_len = r.max_length();
	if(!r.is_valid() || max_len <= 0.0f)
		max_len = DEFAULT_DST;

	m_Manip.m_EyePos = m_Manip.m_ViewPos + ang * max_len * 3.0f;

	SetClipRangeAuto(max_len);

	m_Manip.SetUpAngle( up );
}


//! 現在の視線と注視点の位置関係を維持して, 注視点を原点に移動する.
void Camera::LookOrigin(void)
{
	m_Manip.Translate( -m_Manip.m_ViewPos );
}

void Camera::SetClipRangeAuto(float base_length)
{
	float n = base_length * 0.01f;
	m_Projection.m_Near = n * 0.5f;
	m_Projection.m_Far  = n * 1000.0f;
}


void Camera::SetGLProjection(void)
{
	if(m_ProjMode == PROJ_PERS)
	{
		m_Projection.SetGLProjection();
	}
	else if(m_ProjMode == PROJ_ORTHO)
	{
		m_Projection.SetGLOrtho(m_Manip.GetDistanceToLookPos());
	}
	else
	{
		assert(false);
	}
}

void Camera::SetGLModelview(void)
{
	m_Manip.SetGLModelview();
}

void Camera::SetViewportAndMatrix(void)
{
	GetViewport().SetGLViewport();

	SetGLProjection();
	SetGLModelview();
}

void Camera::SetFrame(int frame)
{
	if (!m_EnableSeqence)
		return;
	if (!m_SeqTrans.HasKey())
		return;

	lm::matrix4f t = m_SeqTrans.GetTransform(frame);

	lm::vec3f d = m_Manip.m_ViewPos - m_Manip.m_EyePos;
	float l = d.length();

	lm::vec3f z = lm::vec3f(0, 0, 0) * t;
	lm::vec3f c = m_SeqPos * t;

	m_Manip.m_EyePos  = c;
	m_Manip.m_Up      = (m_SeqUp * t - z).get_normalize();
	m_Manip.m_ViewPos = (m_SeqLook * t - z).get_normalize() * l + c;

	CoordAdjustFromBlend( m_Manip.m_EyePos  );
	CoordAdjustFromBlend( m_Manip.m_Up      );
	CoordAdjustFromBlend( m_Manip.m_ViewPos );
}

void Camera::CoordAdjustFromBlend(lm::vec3f& v) const
{
	v = lm::vec3f(v.x, v.z, -v.y);
}


}
