module gedo.video.meshfile;



private import gedo.video.animation;
private import gedo.video.texture;
private import gedo.video.ggl;
private import gedo.text.parser;
private import gedo.file.path;
private import gedo.math.matrix;



public class MeshFile
{
public:
	this(char[] path)
	{
		auto text = cast(char[]).gedo.file.path.read(path);

		// load mesh
		loadMesh(text, .gedo.file.path.dirname(path));

		// load bone
		loadBone(text);
	}


	GGL_Vertex[] vertices()
	{
		return _vertices;
	}


	GGL_Face[] faces()
	{
		return _faces;
	}


	Texture texture()
	{
		return _texture;
	}


	uint[] cvInBones()
	{
		return _cvInBones;
	}


	Animation[] animations()
	{
		return _animations;
	}


	uint[string] nameToIndex()
	{
		return _nameToIndex;
	}


	uint meshSize()
	{
		return _vertices.length*GGL_Vertex.sizeof + _faces.length*GGL_Face.sizeof + 4*_texture.width*_texture.height;
	}


	uint animationSize()
	{
		uint sum = 0;
		foreach(animation; _animations)
		{
			sum += animation.size;
		}

		return sum;
	}


private:
	uint[string] _nameToIndex;
	GGL_Vertex[] _vertices;
	Animation[]  _animations;
	GGL_Face[]   _faces;
	Texture      _texture;
	uint[]       _cvInBones;


	void loadMesh(char[] text, char[] cwd)
	{
		auto a = new Parser(text, "<mesh>");

		// texture name
		_texture = Texture(.gedo.file.path.join(cwd, a.gets()), true);

		// vertex list
		_vertices.length = a.geti();
		foreach(inout vertex; _vertices)
		{
			foreach(inout x; vertex.position)
			{
				x = a.getf();
			}
			foreach(inout x; vertex.texCoord)
			{
				x = a.getf();
			}
		}

		// face list
		_faces.length = a.geti();
		foreach(inout face; _faces)
		{
			foreach(inout iv; face.vertexIndices)
			{
				iv = a.geti();
			}
		}
	}


	void loadBone(char[] text)
	{
		auto a = new Parser(text, "<bone>");

		if(a.isValid())
		{
			_cvInBones.length = a.geti();

			auto vs = _vertices;
			foreach(inout cvInBone; _cvInBones)
			{
				cvInBone = a.geti();

				Matrix matrixWorldToBone;

				foreach(inout m; matrixWorldToBone)
				{
					m = a.getf();
				}

				foreach(inout v; vs[0..cvInBone])
				{
					.gedo.math.matrix.transform(matrixWorldToBone, cast(Vector)v.position);
				}

				vs = vs[cvInBone .. length];
			}

			a.seek("<animation>");

			_animations.length = a.geti();
			foreach(i, inout animation; _animations)
			{
				animation = new Animation(a, _cvInBones.length);

				_nameToIndex[animation.name] = i;
			}
		}
	}
}
