#include "stdafx.h"

#include "BaseMeshGen.h"


namespace lib_geo
{



void BaseMeshGen::GenSphere( lib_geo::BaseMesh& mesh , float radius , size_t slice_x , size_t slice_y )
{
	mesh.Clear();

	mesh.m_Faces   .resize( slice_x * slice_y );
	mesh.m_Verts   .resize( slice_x * (slice_y-1) + 2 );
	mesh.m_Normals .resize( slice_x * (slice_y-1) + 2 );
	mesh.m_UVs     .resize( (slice_x+1) * (slice_y+1) );

	mesh.m_Verts.front().set( 0.0f , radius , 0.0f );
	mesh.m_Verts.back().set( 0.0f , -radius , 0.0f );

	for( size_t x = 0 ; x < slice_x ; ++x )
	{
		for( size_t y = 0 ; y < slice_y-1 ; ++y )
		{
			float nx = (float)x / (float)( slice_x );
			float ny = (float)(y+1) / (float)( slice_y );

			lm::vec3f& v = mesh.m_Verts[ 1 + slice_x * y + x ];
			float rx = (float)M_PI * 2.0f * nx;
			float ry = (float)M_PI * ny;
			v.y = radius * cos( ry );
			v.x = radius * sin( ry ) * cos( rx );
			v.z = radius * sin( ry ) * sin( rx );
		}
	}

	for( size_t x = 0 ; x < slice_x+1 ; ++x )
	{
		for( size_t y = 0 ; y < slice_y+1 ; ++y )
		{
			size_t idx = (slice_x+1) * y + x;
			mesh.m_UVs[idx].x = (float)x / (float)( slice_x );
			mesh.m_UVs[idx].y = (float)y / (float)( slice_y );
		}
	}

	for( size_t x = 0 ; x < slice_x ; ++x )
	{
		size_t xi0 = x;
		size_t xi1 = (x+1) % slice_x;

		for( size_t y = 1 ; y < slice_y - 1 ; ++y )
		{
			lib_geo::BaseFace& f = mesh.m_Faces[ slice_x * y + x ];

			f.m_VertIds.resize(4);
			f.m_VertIds[0] = (int)( ( 1 + slice_x * (y-1) + xi0 ) );
			f.m_VertIds[1] = (int)( ( 1 + slice_x * (y-1) + xi1 ) );
			f.m_VertIds[2] = (int)( ( 1 + slice_x * (y  ) + xi1 ) );
			f.m_VertIds[3] = (int)( ( 1 + slice_x * (y  ) + xi0 ) );

			f.m_UVIds.resize(4);
			f.m_UVIds[0] = (int)( ( (slice_x+1) * (y  ) + x   ) );
			f.m_UVIds[1] = (int)( ( (slice_x+1) * (y  ) + x+1 ) );
			f.m_UVIds[2] = (int)( ( (slice_x+1) * (y+1) + x+1 ) );
			f.m_UVIds[3] = (int)( ( (slice_x+1) * (y+1) + x   ) );
		}

		lib_geo::BaseFace& ftop = mesh.m_Faces[ slice_x * 0           + x ];
		lib_geo::BaseFace& fbot = mesh.m_Faces[ slice_x * (slice_y-1) + x ];

		ftop.m_VertIds.resize(3);
		ftop.m_VertIds[0] = 0;
		ftop.m_VertIds[1] = (int)( ( 1 + slice_x * 0 + xi1 ) );
		ftop.m_VertIds[2] = (int)( ( 1 + slice_x * 0 + xi0 ) );

		ftop.m_UVIds.resize(3);
		ftop.m_UVIds[0] = (int)( (slice_x+1) * 0 + (x+0) );
		ftop.m_UVIds[1] = (int)( (slice_x+1) * 1 + (x+1) );
		ftop.m_UVIds[2] = (int)( (slice_x+1) * 1 + (x+0) );

		fbot.m_VertIds.resize(3);
		fbot.m_VertIds[0] = (int)( ( 1 + slice_x * (slice_y-2) + xi0 ) );
		fbot.m_VertIds[1] = (int)( ( 1 + slice_x * (slice_y-2) + xi1 ) );
		fbot.m_VertIds[2] = (int)mesh.m_Verts.size() - 1;

		fbot.m_UVIds.resize(3);
		fbot.m_UVIds[0] = (int)( (slice_x+1) * (slice_y-1) + (x+0) );
		fbot.m_UVIds[1] = (int)( (slice_x+1) * (slice_y-1) + (x+1) );
		fbot.m_UVIds[2] = (int)( (slice_x+1) * (slice_y)   + (x+1) );
	}

	for( size_t i = 0 ; i < mesh.m_Faces.size() ; ++i )
	{
		BaseFace& f = mesh.m_Faces[i];
		f.m_NormIds = f.m_VertIds;
	}

	mesh.UpdateNormal();
}


void BaseMeshGen::GenCrynder( BaseMesh& mesh , float radius , float height , size_t slice_x )
{
	// NOTE : UVは生成されない

	mesh.Clear();

	const float half_height = height * 0.5f;

	mesh.m_Faces   .resize( slice_x * 3 );
	mesh.m_Verts   .resize( slice_x * 2 + 2 );
	mesh.m_Normals .resize( slice_x * 2 + 2 );

	mesh.m_Verts.front().set( 0.0f , half_height , 0.0f );
	mesh.m_Verts.back().set( 0.0f , -half_height , 0.0f );

	for( size_t x = 0 ; x < slice_x ; ++x )
	{
		float nrm_pos = (float)x / (float)( slice_x );
		float rx = (float)M_PI * 2.0f * nrm_pos;

		float px = radius * cos( rx );
		float pz = radius * sin( rx );

		mesh.m_Verts[ 1 + x           ].set( px ,  half_height , pz );
		mesh.m_Verts[ 1 + x + slice_x ].set( px , -half_height , pz );

		int xi0 = (int)x;
		int xi1 = (int)( (x+1) % slice_x );

		lib_geo::BaseFace& ftop = mesh.m_Faces[ slice_x * 0 + x ];
		lib_geo::BaseFace& fmid = mesh.m_Faces[ slice_x * 1 + x ];
		lib_geo::BaseFace& fbot = mesh.m_Faces[ slice_x * 2 + x ];

		ftop.m_VertIds.resize(3);
		ftop.m_NormIds.resize(3);
		ftop.m_VertIds[0] = 0;
		ftop.m_VertIds[1] = ( 1 + xi1 );
		ftop.m_VertIds[2] = ( 1 + xi0 );
		ftop.m_NormIds[0] = 0;
		ftop.m_NormIds[1] = 0;
		ftop.m_NormIds[2] = 0;

		fmid.m_VertIds.resize(4);
		fmid.m_NormIds.resize(4);
		fmid.m_VertIds[0] = ( 1 + xi0 );
		fmid.m_VertIds[1] = ( 1 + xi1 );
		fmid.m_VertIds[2] = ( 1 + xi1 + (int)slice_x );
		fmid.m_VertIds[3] = ( 1 + xi0 + (int)slice_x );
		fmid.m_NormIds = fmid.m_VertIds;

		fbot.m_VertIds.resize(3);
		fbot.m_NormIds.resize(3);
		fbot.m_VertIds[0] = ( 1 + xi0 + (int)slice_x );
		fbot.m_VertIds[1] = ( 1 + xi1 + (int)slice_x );
		fbot.m_VertIds[2] = (int)mesh.m_Verts.size() - 1;
		fbot.m_NormIds[0] = (int)mesh.m_Verts.size() - 1;
		fbot.m_NormIds[1] = (int)mesh.m_Verts.size() - 1;
		fbot.m_NormIds[2] = (int)mesh.m_Verts.size() - 1;
	}

	mesh.UpdateNormal();
}

void BaseMeshGen::GenPipe( BaseMesh& mesh , float radius , float height , size_t slice_x )
{
	mesh.Clear();

	const float half_height = height * 0.5f;

	mesh.m_Faces   .resize( slice_x );
	mesh.m_Verts   .resize( slice_x * 2 );
	mesh.m_Normals .resize( slice_x * 2 );
	mesh.m_UVs     .resize( (slice_x+1) * 2 );

	for( size_t x = 0 ; x < slice_x ; ++x )
	{
		float nrm_pos = (float)x / (float)( slice_x );
		float rx = (float)M_PI * 2.0f * nrm_pos;

		float px =  radius * cos( rx );
		float pz = -radius * sin( rx );

		mesh.m_Verts[ x * 2 + 0 ].set( px ,  half_height , pz );
		mesh.m_Verts[ x * 2 + 1 ].set( px , -half_height , pz );

		mesh.m_UVs[ x * 2 + 0 ].set( nrm_pos , 1.0f );
		mesh.m_UVs[ x * 2 + 1 ].set( nrm_pos , 0.0f );
		if( x+1 == slice_x )
		{
			mesh.m_UVs[ x * 2 + 2 ].set( 1.0f , 1.0f );
			mesh.m_UVs[ x * 2 + 3 ].set( 1.0f , 0.0f );
		}

		int xi0 = (int)x;
		int xi1 = (int)( (x+1) % slice_x );

		lib_geo::BaseFace& f = mesh.m_Faces[ x ];
		f.m_UVIds.resize(4);
		f.m_UVIds[0] = (int)x * 2 + 0;
		f.m_UVIds[1] = (int)x * 2 + 1;
		f.m_UVIds[2] = (int)x * 2 + 3;
		f.m_UVIds[3] = (int)x * 2 + 2;

		f.m_VertIds = f.m_UVIds;
		f.m_VertIds[2] = f.m_VertIds[2] % ( (int)slice_x * 2 );
		f.m_VertIds[3] = f.m_VertIds[3] % ( (int)slice_x * 2 );

		f.m_NormIds = f.m_VertIds;
	}

	mesh.UpdateNormal();
}


void BaseMeshGen::GenBox( BaseMesh& mesh , float width_x , float width_y , float width_z )
{
	mesh.Clear();

	float hx = width_x * 0.5f;
	float hy = width_y * 0.5f;
	float hz = width_z * 0.5f;
	
	mesh.m_Verts.resize( 8 );
	for( size_t x = 0 ; x < 2 ; ++x )
	{
		for( size_t y = 0 ; y < 2 ; ++y )
		{
			for( size_t z = 0 ; z < 2 ; ++z )
			{
				lm::vec3f& v = mesh.m_Verts[ 2 * ( 2 * z + y ) + x ];
				v.x = ( ( x == 0 ) ? 1 : -1 ) * hx;
				v.y = ( ( y == 0 ) ? 1 : -1 ) * hy;
				v.z = ( ( z == 0 ) ? 1 : -1 ) * hz;
			}
		}
	}

	mesh.m_Normals.resize( 6 );

	mesh.m_Faces.resize( 6 );
	for( size_t i = 0 ; i < mesh.m_Faces.size() ; ++i )
	{
		mesh.m_Faces[i].m_VertIds.resize(4);
		mesh.m_Faces[i].m_NormIds.resize(4);
	}

	// xy positive
	mesh.m_Faces[0].m_VertIds[0] = ( 2 * ( 2 * 0 + 0 ) + 0 );
	mesh.m_Faces[0].m_VertIds[1] = ( 2 * ( 2 * 0 + 0 ) + 1 );
	mesh.m_Faces[0].m_VertIds[2] = ( 2 * ( 2 * 0 + 1 ) + 1 );
	mesh.m_Faces[0].m_VertIds[3] = ( 2 * ( 2 * 0 + 1 ) + 0 );

	// yz positive
	mesh.m_Faces[1].m_VertIds[0] = ( 2 * ( 2 * 0 + 0 ) + 0 );
	mesh.m_Faces[1].m_VertIds[1] = ( 2 * ( 2 * 0 + 1 ) + 0 );
	mesh.m_Faces[1].m_VertIds[2] = ( 2 * ( 2 * 1 + 1 ) + 0 );
	mesh.m_Faces[1].m_VertIds[3] = ( 2 * ( 2 * 1 + 0 ) + 0 );

	// zx positive
	mesh.m_Faces[2].m_VertIds[0] = ( 2 * ( 2 * 0 + 0 ) + 0 );
	mesh.m_Faces[2].m_VertIds[1] = ( 2 * ( 2 * 1 + 0 ) + 0 );
	mesh.m_Faces[2].m_VertIds[2] = ( 2 * ( 2 * 1 + 0 ) + 1 );
	mesh.m_Faces[2].m_VertIds[3] = ( 2 * ( 2 * 0 + 0 ) + 1 );

	// xy negative
	mesh.m_Faces[3].m_VertIds[0] = ( 2 * ( 2 * 1 + 1 ) + 1 );
	mesh.m_Faces[3].m_VertIds[1] = ( 2 * ( 2 * 1 + 0 ) + 1 );
	mesh.m_Faces[3].m_VertIds[2] = ( 2 * ( 2 * 1 + 0 ) + 0 );
	mesh.m_Faces[3].m_VertIds[3] = ( 2 * ( 2 * 1 + 1 ) + 0 );

	// yz negative
	mesh.m_Faces[4].m_VertIds[0] = ( 2 * ( 2 * 1 + 1 ) + 1 );
	mesh.m_Faces[4].m_VertIds[1] = ( 2 * ( 2 * 0 + 1 ) + 1 );
	mesh.m_Faces[4].m_VertIds[2] = ( 2 * ( 2 * 0 + 0 ) + 1 );
	mesh.m_Faces[4].m_VertIds[3] = ( 2 * ( 2 * 1 + 0 ) + 1 );

	// zx negative
	mesh.m_Faces[5].m_VertIds[0] = ( 2 * ( 2 * 1 + 1 ) + 1 );
	mesh.m_Faces[5].m_VertIds[1] = ( 2 * ( 2 * 1 + 1 ) + 0 );
	mesh.m_Faces[5].m_VertIds[2] = ( 2 * ( 2 * 0 + 1 ) + 0 );
	mesh.m_Faces[5].m_VertIds[3] = ( 2 * ( 2 * 0 + 1 ) + 1 );

	for( size_t i = 0 ; i < 6 ; ++i )
	{
		for( size_t j = 0 ; j < 4 ; ++j )
			mesh.m_Faces[i].m_NormIds[j] = (int)i;
	}

	mesh.UpdateNormal();
}


void BaseMeshGen::GenPlaneXY( BaseMesh& mesh , float width_x , float width_y , size_t slice_x , size_t slice_y )
{
	mesh.Clear();

	mesh.m_Verts.resize( (slice_x+1) * (slice_y+1) );
	mesh.m_UVs.resize( (slice_x+1) * (slice_y+1) );
	for( size_t i = 0 ; i < slice_x+1 ; ++i )
	{
		for( size_t j = 0 ; j < slice_y+1 ; ++j )
		{
			float nx = (float)i / (float)slice_x;
			float ny = (float)j / (float)slice_y;

			mesh.m_UVs[ i + (slice_x+1) * j ].set( nx , ny );

			nx -= 0.5f;
			ny -= 0.5f;
			mesh.m_Verts[ i + (slice_x+1) * j ].set( nx * width_x , ny * width_y , 0.0f );
		}
	}

	mesh.m_Normals.resize( (slice_x+1) * (slice_y+1) , lm::vec3f( 0.0f , 0.0f , 1.0f ) );

	mesh.m_Faces.reserve( slice_x * slice_y );
	for( size_t i = 0 ; i < slice_x ; ++i )
	{
		for( size_t j = 0 ; j < slice_y ; ++j )
		{
			BaseFace f;
			f.m_VertIds.resize(4);
			f.m_VertIds[0] = (int)( (i+1) + (slice_x + 1) * (j  ) );
			f.m_VertIds[1] = (int)( (i+1) + (slice_x + 1) * (j+1) );
			f.m_VertIds[2] = (int)( (i  ) + (slice_x + 1) * (j+1) );
			f.m_VertIds[3] = (int)( (i  ) + (slice_x + 1) * (j  ) );

			f.m_NormIds = f.m_VertIds;
			f.m_UVIds   = f.m_VertIds;

			mesh.m_Faces.push_back(f);
		}
	}
}

void BaseMeshGen::GenPlaneYZ( BaseMesh& mesh , float width_y , float width_z , size_t slice_y , size_t slice_z )
{
	// 効率低. 要改善.

	GenPlaneXY( mesh , width_y , width_z , slice_y , slice_z );

	for( size_t i = 0 ; i < mesh.m_Verts.size() ; ++i )
	{
		lm::vec3f v = mesh.m_Verts[i];
		mesh.m_Verts[i].set( v.z , v.x , v.y );
	}

	mesh.m_Normals.assign( mesh.m_Normals.size() , lm::vec3f( 1.0f , 0.0f , 0.0f ) );
}

void BaseMeshGen::GenPlaneZX( BaseMesh& mesh , float width_z , float width_x , size_t slice_z , size_t slice_x )
{
	// 効率低. 要改善.
	GenPlaneXY( mesh , width_z , width_x , slice_z , slice_x );

	for( size_t i = 0 ; i < mesh.m_Verts.size() ; ++i )
	{
		lm::vec3f v = mesh.m_Verts[i];
		mesh.m_Verts[i].set( v.y , v.z , v.x );
	}

	mesh.m_Normals.assign( mesh.m_Normals.size() , lm::vec3f( 0.0f , 1.0f , 0.0f ) );
}


}
