#include "stdafx.h"
#include "ValveSMD.h"

#include "File.h"
#include "Path.h"
#include "MathHelper.h"
#include "StreamWriter.h"

namespace Assets::Exporters
{
	void ProcessVertex(IO::StreamWriter& Writer, const Vertex& Vertex)
	{
		auto Normal = Vertex.Normal().GetNormalized();

		auto& Position = Vertex.Position();
		auto& UVLayer = Vertex.UVLayers(0);

		Writer.WriteFmt("0 %f %f %f %f %f %f %f %f %d ", Position.X, Position.Y, Position.Z, Normal.X, Normal.Y, Normal.Z, UVLayer.U, (1 - UVLayer.V), Vertex.WeightCount());

		for (uint8_t i = 0; i < Vertex.WeightCount(); i++)
			Writer.WriteFmt("%d %f ", Vertex.Weights(i).Bone, Vertex.Weights(i).Value);

		Writer.Write("\n");
	}

	bool ValveSMD::ExportAnimation(const Animation& Animation, const String& Path)
	{
		return false;
	}

	bool ValveSMD::ExportModel(const Model& Model, const String& Path)
	{
		auto Writer = IO::StreamWriter(IO::File::Create(Path));

		Writer.WriteLine(
			"version 1\n"
			"nodes"
		);

		uint32_t BoneIndex = 0;

		for (auto& Bone : Model.Bones)
		{
			Writer.WriteLineFmt("%d \"%s\" %d", BoneIndex, (char*)Bone.Name(), Bone.Parent());
			BoneIndex++;
		}

		Writer.WriteLine(
			"end\n"
			"skeleton\n"
			"time 0"
		);

		BoneIndex = 0;

		for (auto& Bone : Model.Bones)
		{
			auto Euler = Bone.LocalRotation().ToEulerAngles();

			Writer.WriteLineFmt("%d %f %f %f %f %f %f", BoneIndex, Bone.LocalPosition().X, Bone.LocalPosition().Y, Bone.LocalPosition().Z, MathHelper::DegreesToRadians(Euler.X), MathHelper::DegreesToRadians(Euler.Y), MathHelper::DegreesToRadians(Euler.Z));
			BoneIndex++;
		}

		Writer.WriteLine("end");

		for (auto& Submesh : Model.Meshes)
		{
			Writer.WriteLine("triangles");

			for (auto& Face : Submesh.Faces)
			{
				if (Submesh.MaterialIndices[0] > -1)
					Writer.WriteLine(Model.Materials[Submesh.MaterialIndices[0]].Name);
				else
					Writer.WriteLine("default_material");

				ProcessVertex(Writer, Submesh.Vertices[Face[2]]);
				ProcessVertex(Writer, Submesh.Vertices[Face[1]]);
				ProcessVertex(Writer, Submesh.Vertices[Face[0]]);
			}

			Writer.WriteLine("end");
		}

		return true;
	}

	imstring ValveSMD::ModelExtension()
	{
		return ".smd";
	}

	imstring ValveSMD::AnimationExtension()
	{
		return ".smd";
	}

	ExporterScale ValveSMD::ExportScale()
	{
		// Evaluate whether or not SMDs need a scale constant.
		return ExporterScale::Default;
	}

	bool ValveSMD::SupportsAnimations()
	{
		return true;
	}

	bool ValveSMD::SupportsModels()
	{
		return true;
	}
}