Files
FlaxEngine/Source/Engine/ContentExporters/ExportModel.cpp
2020-12-07 23:40:54 +01:00

232 lines
7.5 KiB
C++

// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#include "AssetExporters.h"
#if COMPILE_WITH_ASSETS_EXPORTER
#include "Engine/Core/Log.h"
#include "Engine/Content/Assets/Model.h"
#include "Engine/Content/Assets/SkinnedModel.h"
#include "Engine/Serialization/FileWriteStream.h"
#include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/Core/DeleteMe.h"
ExportAssetResult AssetExporters::ExportModel(ExportAssetContext& context)
{
// Prepare
auto asset = (Model*)context.Asset.Get();
auto lock = asset->Storage->LockSafe();
auto path = GET_OUTPUT_PATH(context, "obj");
const int32 lodIndex = 0;
// Fetch chunk with data
const auto chunkIndex = MODEL_LOD_TO_CHUNK_INDEX(lodIndex);
if (asset->LoadChunk(chunkIndex))
return ExportAssetResult::CannotLoadData;
const auto chunk = asset->GetChunk(chunkIndex);
if (!chunk)
return ExportAssetResult::CannotLoadData;
MemoryReadStream stream(chunk->Get(), chunk->Size());
FileWriteStream* output = FileWriteStream::Open(path);
if (output == nullptr)
return ExportAssetResult::Error;
DeleteMe<FileWriteStream> outputDeleteMe(output);
const auto name = StringUtils::GetFileNameWithoutExtension(asset->GetPath()).ToStringAnsi();
output->WriteTextFormatted("# Exported model {0}\n", name.Get());
// Extract all meshes
const auto& lod = asset->LODs[lodIndex];
int32 vertexStart = 1; // OBJ counts vertices from 1 not from 0
for (int32 meshIndex = 0; meshIndex < lod.Meshes.Count(); meshIndex++)
{
auto& mesh = lod.Meshes[meshIndex];
// #MODEL_DATA_FORMAT_USAGE
uint32 vertices;
stream.ReadUint32(&vertices);
uint32 triangles;
stream.ReadUint32(&triangles);
uint32 indicesCount = triangles * 3;
bool use16BitIndexBuffer = indicesCount <= MAX_uint16;
uint32 ibStride = use16BitIndexBuffer ? sizeof(uint16) : sizeof(uint32);
if (vertices == 0 || triangles == 0)
return ExportAssetResult::Error;
auto vb0 = stream.Read<VB0ElementType>(vertices);
auto vb1 = stream.Read<VB1ElementType>(vertices);
bool hasColors = stream.ReadBool();
VB2ElementType18* vb2 = nullptr;
if (hasColors)
{
vb2 = stream.Read<VB2ElementType18>(vertices);
}
auto ib = stream.Read<byte>(indicesCount * ibStride);
output->WriteTextFormatted("# Mesh {0}\n", meshIndex);
for (uint32 i = 0; i < vertices; i++)
{
auto v = vb0[i].Position;
output->WriteTextFormatted("v {0} {1} {2}\n", v.X, v.Y, v.Z);
}
output->WriteChar('\n');
for (uint32 i = 0; i < vertices; i++)
{
auto v = vb1[i].TexCoord;
output->WriteTextFormatted("vt {0} {1}\n", ConvertHalfToFloat(v.X), ConvertHalfToFloat(v.Y));
}
output->WriteChar('\n');
for (uint32 i = 0; i < vertices; i++)
{
auto v = vb1[i].Normal.ToVector3() * 2.0f - 1.0f;
output->WriteTextFormatted("vn {0} {1} {2}\n", v.X, v.Y, v.Z);
}
output->WriteChar('\n');
if (use16BitIndexBuffer)
{
auto t = (uint16*)ib;
for (uint32 i = 0; i < triangles; i++)
{
auto i0 = vertexStart + *t++;
auto i1 = vertexStart + *t++;
auto i2 = vertexStart + *t++;
output->WriteTextFormatted("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", i0, i1, i2);
}
}
else
{
auto t = (uint32*)ib;
for (uint32 i = 0; i < triangles; i++)
{
auto i0 = vertexStart + *t++;
auto i1 = vertexStart + *t++;
auto i2 = vertexStart + *t++;
output->WriteTextFormatted("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", i0, i1, i2);
}
}
output->WriteChar('\n');
vertexStart += vertices;
}
if (output->HasError())
return ExportAssetResult::Error;
return ExportAssetResult::Ok;
}
ExportAssetResult AssetExporters::ExportSkinnedModel(ExportAssetContext& context)
{
// Prepare
auto asset = (SkinnedModel*)context.Asset.Get();
auto lock = asset->Storage->LockSafe();
auto path = GET_OUTPUT_PATH(context, "obj");
const int32 lodIndex = 0;
// Fetch chunk with data
const auto chunkIndex = 1;
if (asset->LoadChunk(chunkIndex))
return ExportAssetResult::CannotLoadData;
const auto chunk = asset->GetChunk(chunkIndex);
if (!chunk)
return ExportAssetResult::CannotLoadData;
MemoryReadStream stream(chunk->Get(), chunk->Size());
FileWriteStream* output = FileWriteStream::Open(path);
if (output == nullptr)
return ExportAssetResult::Error;
DeleteMe<FileWriteStream> outputDeleteMe(output);
const auto name = StringUtils::GetFileNameWithoutExtension(asset->GetPath()).ToStringAnsi();
output->WriteTextFormatted("# Exported model {0}\n", name.Get());
// Extract all meshes
const auto& lod = asset->LODs[lodIndex];
int32 vertexStart = 1; // OBJ counts vertices from 1 not from 0
for (int32 meshIndex = 0; meshIndex < lod.Meshes.Count(); meshIndex++)
{
auto& mesh = lod.Meshes[meshIndex];
// #MODEL_DATA_FORMAT_USAGE
uint32 vertices;
stream.ReadUint32(&vertices);
uint32 triangles;
stream.ReadUint32(&triangles);
uint32 indicesCount = triangles * 3;
bool use16BitIndexBuffer = indicesCount <= MAX_uint16;
uint32 ibStride = use16BitIndexBuffer ? sizeof(uint16) : sizeof(uint32);
if (vertices == 0 || triangles == 0)
return ExportAssetResult::Error;
auto vb0 = stream.Read<VB0SkinnedElementType>(vertices);
auto ib = stream.Read<byte>(indicesCount * ibStride);
output->WriteTextFormatted("# Mesh {0}\n", meshIndex);
for (uint32 i = 0; i < vertices; i++)
{
auto v = vb0[i].Position;
output->WriteTextFormatted("v {0} {1} {2}\n", v.X, v.Y, v.Z);
}
output->WriteChar('\n');
for (uint32 i = 0; i < vertices; i++)
{
auto v = vb0[i].TexCoord;
output->WriteTextFormatted("vt {0} {1}\n", ConvertHalfToFloat(v.X), ConvertHalfToFloat(v.Y));
}
output->WriteChar('\n');
for (uint32 i = 0; i < vertices; i++)
{
auto v = vb0[i].Normal.ToVector3() * 2.0f - 1.0f;
output->WriteTextFormatted("vn {0} {1} {2}\n", v.X, v.Y, v.Z);
}
output->WriteChar('\n');
if (use16BitIndexBuffer)
{
auto t = (uint16*)ib;
for (uint32 i = 0; i < triangles; i++)
{
auto i0 = vertexStart + *t++;
auto i1 = vertexStart + *t++;
auto i2 = vertexStart + *t++;
output->WriteTextFormatted("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", i0, i1, i2);
}
}
else
{
auto t = (uint32*)ib;
for (uint32 i = 0; i < triangles; i++)
{
auto i0 = vertexStart + *t++;
auto i1 = vertexStart + *t++;
auto i2 = vertexStart + *t++;
output->WriteTextFormatted("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", i0, i1, i2);
}
}
output->WriteChar('\n');
vertexStart += vertices;
}
if (output->HasError())
return ExportAssetResult::Error;
return ExportAssetResult::Ok;
}
#endif