#include "stdafx.h" #include "CoDXAssetExport.h" #include "File.h" #include "Path.h" #include "Matrix.h" #include "StreamWriter.h" namespace Assets::Exporters { bool CoDXAssetExport::ExportAnimation(const Animation& Animation, const String& Path) { return false; } bool CoDXAssetExport::ExportModel(const Model& Model, const String& Path) { auto Writer = IO::StreamWriter(IO::File::Create(Path)); Writer.WriteLine( "MODEL\nVERSION 6\n" ); Writer.WriteLineFmt("NUMBONES %d", Model.Bones.Count()); uint32_t BoneIndex = 0; for (auto& Bone : Model.Bones) { Writer.WriteLineFmt("BONE %d %d \"%s\"", BoneIndex, Bone.Parent(), (char*)Bone.Name()); BoneIndex++; } Writer.Write("\n"); BoneIndex = 0; for (auto& Bone : Model.Bones) { auto Rotation = ::Math::Matrix::CreateFromQuaternion(Bone.GlobalRotation()); auto& Position = Bone.GlobalPosition(); auto& Scale = Bone.Scale(); Writer.WriteLineFmt( "BONE %d\n" "OFFSET %f, %f, %f\n" "SCALE %f, %f, %f\n" "X %f, %f, %f\n" "Y %f, %f, %f\n" "Z %f, %f, %f\n", BoneIndex, Position.X, Position.Y, Position.Z, Scale.X, Scale.Y, Scale.Z, MathHelper::Clamp(Rotation.Mat(0, 0), -1.f, 1.f), MathHelper::Clamp(Rotation.Mat(0, 1), -1.f, 1.f), MathHelper::Clamp(Rotation.Mat(0, 2), -1.f, 1.f), MathHelper::Clamp(Rotation.Mat(1, 0), -1.f, 1.f), MathHelper::Clamp(Rotation.Mat(1, 1), -1.f, 1.f), MathHelper::Clamp(Rotation.Mat(1, 2), -1.f, 1.f), MathHelper::Clamp(Rotation.Mat(2, 0), -1.f, 1.f), MathHelper::Clamp(Rotation.Mat(2, 1), -1.f, 1.f), MathHelper::Clamp(Rotation.Mat(2, 2), -1.f, 1.f) ); BoneIndex++; } auto TotalVertexCount = Model.VertexCount(); auto TotalFaceCount = Model.FaceCount(); if (TotalVertexCount > UINT16_MAX) Writer.WriteLineFmt("NUMVERTS32 %d", TotalVertexCount); else Writer.WriteLineFmt("NUMVERTS %d", TotalVertexCount); uint32_t VertexIndex = 0; for (auto& Submesh : Model.Meshes) { for (auto& Vertex : Submesh.Vertices) { auto& Position = Vertex.Position(); if (TotalVertexCount > UINT16_MAX) Writer.WriteLineFmt( "VERT32 %d\n" "OFFSET %f, %f, %f", VertexIndex, Position.X, Position.Y, Position.Z ); else Writer.WriteLineFmt( "VERT %d\n" "OFFSET %f, %f, %f", VertexIndex, Position.X, Position.Y, Position.Z ); if (Vertex.WeightCount() == 1) Writer.WriteLineFmt( "BONES 1\n" "BONE %d 1.0\n", Vertex.Weights(0).Bone ); else { Writer.WriteLineFmt("BONES %d", Vertex.WeightCount()); for (uint8_t i = 0; i < Vertex.WeightCount(); i++) Writer.WriteLineFmt("BONE %d %f", Vertex.Weights(i).Bone, Vertex.Weights(i).Value); Writer.Write("\n"); } VertexIndex++; } } Writer.WriteLineFmt("NUMFACES %d", TotalFaceCount); uint32_t SubmeshIndex = 0; VertexIndex = 0; for (auto& Submesh : Model.Meshes) { for (auto& Face : Submesh.Faces) { if (SubmeshIndex > UINT8_MAX || Submesh.MaterialIndices[0] > UINT8_MAX) Writer.WriteLineFmt("TRI16 %d %d 0 0", SubmeshIndex, Submesh.MaterialIndices[0]); else Writer.WriteLineFmt("TRI %d %d 0 0", SubmeshIndex, Submesh.MaterialIndices[0]); // // Face vertex [2] // Writer.WriteLineFmt((TotalVertexCount > UINT16_MAX) ? "VERT32 %d" : "VERT %d", (Face[2] + VertexIndex)); auto& Face1Normal = Submesh.Vertices[Face[2]].Normal(); auto& Face1Color = Submesh.Vertices[Face[2]].Color(); Writer.WriteFmt( "NORMAL %f %f %f\n" "COLOR %f %f %f %f\n" "UV %d", Face1Normal.X, Face1Normal.Y, Face1Normal.Z, Face1Color[0], Face1Color[1], Face1Color[2], Face1Color[3], Submesh.Vertices.UVLayerCount() ); for (uint8_t i = 0; i < Submesh.Vertices.UVLayerCount(); i++) Writer.WriteFmt(" %f %f", Submesh.Vertices[Face[2]].UVLayers(i).U, Submesh.Vertices[Face[2]].UVLayers(i).V); Writer.Write("\n"); // // Face vertex [0] // Writer.WriteLineFmt((TotalVertexCount > UINT16_MAX) ? "VERT32 %d" : "VERT %d", (Face[0] + VertexIndex)); auto& Face2Normal = Submesh.Vertices[Face[0]].Normal(); auto& Face2Color = Submesh.Vertices[Face[0]].Color(); Writer.WriteFmt( "NORMAL %f %f %f\n" "COLOR %f %f %f %f\n" "UV %d", Face2Normal.X, Face2Normal.Y, Face2Normal.Z, Face2Color[0], Face2Color[1], Face2Color[2], Face2Color[3], Submesh.Vertices.UVLayerCount() ); for (uint8_t i = 0; i < Submesh.Vertices.UVLayerCount(); i++) Writer.WriteFmt(" %f %f", Submesh.Vertices[Face[0]].UVLayers(i).U, Submesh.Vertices[Face[0]].UVLayers(i).V); Writer.Write("\n"); // // Face vertex [1] // Writer.WriteLineFmt((TotalVertexCount > UINT16_MAX) ? "VERT32 %d" : "VERT %d", (Face[1] + VertexIndex)); auto& Face3Normal = Submesh.Vertices[Face[1]].Normal(); auto& Face3Color = Submesh.Vertices[Face[1]].Color(); Writer.WriteFmt( "NORMAL %f %f %f\n" "COLOR %f %f %f %f\n" "UV %d", Face3Normal.X, Face3Normal.Y, Face3Normal.Z, Face3Color[0], Face3Color[1], Face3Color[2], Face3Color[3], Submesh.Vertices.UVLayerCount() ); for (uint8_t i = 0; i < Submesh.Vertices.UVLayerCount(); i++) Writer.WriteFmt(" %f %f", Submesh.Vertices[Face[1]].UVLayers(i).U, Submesh.Vertices[Face[1]].UVLayers(i).V); Writer.Write("\n"); } VertexIndex += Submesh.Vertices.Count(); SubmeshIndex++; } Writer.WriteLineFmt("\nNUMOBJECTS %d", Model.Meshes.Count()); SubmeshIndex = 0; for (auto& Submesh : Model.Meshes) Writer.WriteLineFmt("OBJECT %d \"KoreMesh_%d\"", SubmeshIndex, SubmeshIndex++); Writer.Write("\n"); Writer.WriteLineFmt("NUMMATERIALS %d", Model.Materials.Count()); uint32_t MaterialIndex = 0; for (auto& Material : Model.Materials) { Writer.WriteFmt("MATERIAL %d \"%s\" \"Phong\" \"", MaterialIndex, (char*)Material.Name); if (Material.Slots.ContainsKey(MaterialSlotType::Albedo)) Writer.WriteFmt("color:%s", (char*)Material.Slots[MaterialSlotType::Albedo].first); else if (Material.Slots.ContainsKey(MaterialSlotType::Diffuse)) Writer.WriteFmt("color:%s", (char*)Material.Slots[MaterialSlotType::Diffuse].first); Writer.WriteLine("\"\nCOLOR 0.000000 0.000000 0.000000 1.000000\nTRANSPARENCY 0.000000 0.000000 0.000000 1.000000\nAMBIENTCOLOR 1.000000 1.000000 1.000000 1.000000\nINCANDESCENCE 0.000000 0.000000 0.000000 1.000000\nCOEFFS 0.800000 0.000000\nGLOW 0.000000 0\nREFRACTIVE 6 1.000000\nSPECULARCOLOR 0.500000 0.500000 0.500000 1.000000\nREFLECTIVECOLOR 0.000000 0.000000 0.000000 1.000000\nREFLECTIVE 1 0.500000\nBLINN -1.000000 -1.000000\nPHONG 20.000000"); MaterialIndex++; } return true; } imstring CoDXAssetExport::ModelExtension() { return ".xmodel_export"; } imstring CoDXAssetExport::AnimationExtension() { return ".xanim_export"; } ExporterScale CoDXAssetExport::ExportScale() { // Call of Duty uses inches as the primary scale constant. return ExporterScale::Inch; } bool CoDXAssetExport::SupportsAnimations() { return true; } bool CoDXAssetExport::SupportsModels() { return true; } }