#include "stdafx.h"
#include "Transform.h"


namespace geom
{


SceneTransform::SceneTransform(void)
{
	m_Translate.set(0.0f, 0.0f, 0.0f);
	m_Scale = 1.0f;

	m_CoordType = COORD_RUF;
	m_Rotate.identity();
}

void SceneTransform::Reset(void)
{
	m_Translate.set(0.0f, 0.0f, 0.0f);
	m_Scale = 1.0f;

	ResetOnlyRotate();
}

void SceneTransform::ResetOnlyRotate(void)
{
	m_CoordType = COORD_RUF;
	m_Rotate.identity();
}


lm::vec3f SceneTransform::TransformVec(const lm::vec3f& v) const
{
	lm::vec3f dst = v;

	dst += m_Translate;
	dst *= m_Scale;

	m_Rotate.vec_rotate(dst);

	if (!IsRightHandCoord())
		dst.z = -dst.z;

	return dst;
}

lm::vec3f SceneTransform::InverseTransformVec(const lm::vec3f& v) const
{
	lm::vec3f dst = v;

	if (!IsRightHandCoord())
		dst.z = -dst.z;

	m_Rotate.get_conjugate().vec_rotate(dst);

	dst /= m_Scale;
	dst -= m_Translate;

	return dst;
}


void SceneTransform::SetGLWorldConfig(void)
{
	SetGLTransform();
	SetGLForeFaceAngle();
}

void SceneTransform::SetGLTransform(void)
{
	SetGLTransformOnlyRotate();

	glScalef(m_Scale, m_Scale, m_Scale);

	glTranslatef(m_Translate.x, m_Translate.y, m_Translate.z);
}

void SceneTransform::SetGLTransformOnlyRotate(void)
{
	lm::vec3f ex, ey, ez;
	m_Rotate.get_bases(ex, ey, ez);

	if(!IsRightHandCoord())
		glScalef(1.0, 1.0, -1.0);

	float m[16] =
	{
		ex.x, ex.y, ex.z, 0.0f,
		ey.x, ey.y, ey.z, 0.0f,
		ez.x, ez.y, ez.z, 0.0f,
		0.0f, 0.0f, 0.0f, 1.0f
	};

	glMultMatrixf(m);
}

void SceneTransform::GetRotateMatrix(lm::matrix4f& mat)
{
	lm::vec3f ex, ey, ez;
	m_Rotate.get_bases(ex, ey, ez);

	mat.at(0, 0) = ex.x; mat.at(0, 1) = ex.y; mat.at(0, 2) = ex.z; mat.at(0, 3) = 0.0f;
	mat.at(1, 0) = ey.x; mat.at(1, 1) = ey.y; mat.at(1, 2) = ey.z; mat.at(1, 3) = 0.0f;
	mat.at(2, 0) = ez.x; mat.at(2, 1) = ez.y; mat.at(2, 2) = ez.z; mat.at(2, 3) = 0.0f;
	mat.at(3, 0) = 0.0f; mat.at(3, 1) = 0.0f; mat.at(3, 2) = 0.0f; mat.at(3, 3) = 1.0f;

	if (!IsRightHandCoord())
		mat = mat * lm::matrix4f::get_scale(1.0f, 1.0f, -1.0f);
}


SceneTransform::CoordType SceneTransform::GetCoordType(void) const
{
	return m_CoordType;
}

void SceneTransform::SetCoordType(SceneTransform::CoordType type)
{
	m_CoordType = type;

	UpdateQuatRotate();
}

void SceneTransform::UpdateQuatRotate(void)
{
	lm::vec3f ex(0.0f, 0.0f, 0.0f);
	lm::vec3f ey(0.0f, 0.0f, 0.0f);
	lm::vec3f ez(0.0f, 0.0f, 0.0f);

	switch (m_CoordType)
	{
	case COORD_RUF: ex.x = 1.0f; ey.y = 1.0f; ez.z = 1.0f; break;
	case COORD_RUB: ex.x = 1.0f; ey.y = 1.0f; ez.z = 1.0f; break;
	case COORD_UFR: ex.y = 1.0f; ey.z = 1.0f; ez.x = 1.0f; break;
	case COORD_UBR: ex.y = 1.0f; ey.z = 1.0f; ez.x = 1.0f; break;
	case COORD_FRU: ex.z = 1.0f; ey.x = 1.0f; ez.y = 1.0f; break;
	case COORD_BRU: ex.z = 1.0f; ey.x = 1.0f; ez.y = 1.0f; break;

	default:
		assert(false);
		return;
	}

	m_Rotate.identity();
	m_Rotate.set_rotate_from_coord(ex, ey, ez);
	m_Rotate.normalize();
}


//! RightHand = OpenGL standard coordinate
bool SceneTransform::IsRightHandCoord(void) const
{
	switch (m_CoordType)
	{
	case COORD_RUF:
	case COORD_UFR:
	case COORD_FRU:
		return true;

	default:
		return false;
	}
}

void SceneTransform::SetGLForeFaceAngle(void)
{
	if (IsRightHandCoord())
		glFrontFace(GL_CCW);
	else
		glFrontFace(GL_CW);
}


TextureTransform::TextureTransform(void)
{
	m_FlipY = true;
	m_TexScale = 1.0f;
}

void TextureTransform::SetGLTransform(void)
{
	glPushAttrib(GL_TRANSFORM_BIT);

	glMatrixMode(GL_TEXTURE);
	glLoadIdentity();
	if (m_FlipY)
	{
		glTranslated(0, 1, 0);
		glScaled(1, -1, 1);

		float s = m_TexScale;
		glScalef(s, s, s);
	}

	glPopAttrib();
}


}
