mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
cppkore uses string/wstring as StringBase while we use std::string/std::wstring as string/wstring. Changed all types in cppkore to String/WString instead.
252 lines
7.0 KiB
C++
252 lines
7.0 KiB
C++
#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;
|
|
}
|
|
}
|