Code review and more work on WaveFront OBJ export

This commit is contained in:
Chuck Walbourn 2020-02-13 16:38:41 -08:00
parent c3cf5b6c00
commit 2bbef8687c
5 changed files with 84 additions and 40 deletions

View File

@ -290,7 +290,6 @@ HRESULT CIsochartEngine::ParameterizeChartsInHeapParallelized(
parent.emplace_back(m_currentChartHeap.cutTopData());
HRESULT hrOut = S_OK;
int runs = 0;
while (!parent.empty() && !FAILED(hrOut))
{
std::vector<CIsochartMesh*> children;

View File

@ -28,8 +28,6 @@
#include <DirectXCollision.h>
#include <UVAtlas.h>
#include <fstream>
using namespace DirectX;
namespace

View File

@ -42,7 +42,6 @@ public:
void Clear();
void SetMTLFileName(const std::wstring& name) { mtlFileName = name; }
void SetFirstMaterialName(const std::wstring& name) { firstMaterialName = name; }
HRESULT SetIndexData(_In_ size_t nFaces, _In_reads_(nFaces * 3) const uint16_t* indices, _In_reads_opt_(nFaces) uint32_t* attributes = nullptr);
HRESULT SetIndexData(_In_ size_t nFaces, _In_reads_(nFaces * 3) const uint32_t* indices, _In_reads_opt_(nFaces) uint32_t* attributes = nullptr);
@ -146,7 +145,7 @@ public:
}
};
HRESULT ExportToOBJ(const wchar_t* szFileName) const;
HRESULT ExportToOBJ(const wchar_t* szFileName, _In_ size_t nMaterials, _In_reads_opt_(nMaterials) const Material* materials) const;
HRESULT ExportToVBO(_In_z_ const wchar_t* szFileName) const;
HRESULT ExportToCMO(_In_z_ const wchar_t* szFileName, _In_ size_t nMaterials, _In_reads_opt_(nMaterials) const Material* materials) const;
HRESULT ExportToSDKMESH(_In_z_ const wchar_t* szFileName, _In_ size_t nMaterials, _In_reads_opt_(nMaterials) const Material* materials, bool force32bit = false, bool version2 = false) const;
@ -170,8 +169,6 @@ private:
std::unique_ptr<DirectX::XMFLOAT4[]> mBlendWeights;
std::wstring mtlFileName;
std::wstring firstMaterialName;
HRESULT ExportToOBJ(std::string filePath) const;
void ExportToOBJ(std::wostream& os) const;
void ExportToOBJ(std::wostream& os, _In_ size_t nMaterials, _In_reads_opt_(nMaterials) const Material* materials) const;
};

View File

@ -49,6 +49,7 @@ namespace
}
}
//--------------------------------------------------------------------------------------
HRESULT LoadFromOBJ(
const wchar_t* szFilename,
std::unique_ptr<Mesh>& inMesh,
@ -149,62 +150,96 @@ HRESULT LoadFromOBJ(
if (wfReader.materials.size() > 1)
{
inMesh->SetMTLFileName(wfReader.name);
inMesh->SetFirstMaterialName(wfReader.materials[1].strName);
}
return S_OK;
}
//--------------------------------------------------------------------------------------
HRESULT Mesh::ExportToOBJ(std::string filePath) const
{
return ExportToOBJ(std::wstring(filePath.begin(), filePath.end()).c_str());
}
/// Write to file
HRESULT Mesh::ExportToOBJ(const wchar_t* szFileName) const
_Use_decl_annotations_
HRESULT Mesh::ExportToOBJ(const wchar_t* szFileName, size_t nMaterials, const Material* materials) const
{
if (!szFileName)
return E_INVALIDARG;
if (nMaterials > 0 && !materials)
return E_INVALIDARG;
std::wofstream os;
os.open(szFileName);
ExportToOBJ(os);
if (!os)
return E_FAIL;
os << L"# " << szFileName << std::endl << L"#" << std::endl << std::endl;
ExportToOBJ(os, nMaterials, materials);
os.close();
return (os.bad()) ? E_FAIL : S_OK;
}
/// Writing to cout or to a file stream
void Mesh::ExportToOBJ(std::wostream& os) const
_Use_decl_annotations_
void Mesh::ExportToOBJ(std::wostream& os, size_t nMaterials, const Material* materials) const
{
if (!mtlFileName.empty())
os << "mtllib ./" << mtlFileName << ".mtl" << std::endl; // https://stackoverflow.com/questions/4804298/how-to-convert-wstring-into-string converting wstring to string this way works for almost everything except chinese characters
os << L"mtllib ./" << mtlFileName << L".mtl" << std::endl;
for (size_t vert = 0; vert < mnVerts; ++vert)
os << "v " << mPositions[vert].x << " " << mPositions[vert].y << " " << mPositions[vert].z << std::endl;
{
os << L"v " << mPositions[vert].x << L" " << mPositions[vert].y << L" " << mPositions[vert].z << std::endl;
}
os << std::endl;
if (mTexCoords)
for (size_t vert = 0; vert < mnVerts; ++vert) // in this Mesh format the number of texture vertices is always the same as mnVerts
os << "vt " << mTexCoords[vert].x << " " << mTexCoords[vert].y << std::endl;
{
for (size_t vert = 0; vert < mnVerts; ++vert)
{
os << L"vt " << mTexCoords[vert].x << L" " << mTexCoords[vert].y << std::endl;
}
os << std::endl;
}
if (mNormals)
for (size_t vert = 0; vert < mnVerts; ++vert) // in this Mesh format the number of texture vertices is always the same as mnVerts
os << "vn " << mNormals[vert].x << " " << mNormals[vert].y << " " << mNormals[vert].z << std::endl;
{
for (size_t vert = 0; vert < mnVerts; ++vert)
{
os << L"vn " << mNormals[vert].x << L" " << mNormals[vert].y << L" " << mNormals[vert].z << std::endl;
}
os << std::endl;
}
// Using the first material entry as they are all the same for our use cases
if (!firstMaterialName.empty())
os << "usemtl " << firstMaterialName << std::endl; // https://stackoverflow.com/questions/4804298/how-to-convert-wstring-into-string converting wstring to string this way works for almost everything except chinese characters
if (!materials || !mAttributes)
{
os << L"usemtl default" << std::endl;
}
/// Now the faces, a face is the first 3 indexes in indexes on the faces vertex
uint32_t lastAttribute = uint32_t(-1);
for (size_t face = 0; face < mnFaces; ++face)
{
os << "f ";
if (mAttributes && mAttributes[face] != lastAttribute)
{
lastAttribute = mAttributes[face];
if (lastAttribute < nMaterials)
{
os << L"usemtl " << materials[lastAttribute].name << std::endl;
}
}
os << L"f ";
for (size_t point = 0; point < 3; ++point)
{
auto i = mIndices[face * 3 + point] + 1;
uint32_t i = mIndices[face * 3 + point] + 1;
os << i << "/";
os << i << L"/";
if (mTexCoords)
os << i;
os << "/";
os << L"/";
if (mNormals)
os << i;
os << " ";
os << L" ";
}
os << std::endl;
}

View File

@ -70,6 +70,7 @@ enum OPTIONS
OPT_SDKMESH_V2,
OPT_CMO,
OPT_VBO,
OPT_WAVEFRONT_OBJ,
OPT_OUTPUTFILE,
OPT_CLOCKWISE,
OPT_FORCE_32BIT_IB,
@ -146,6 +147,7 @@ const SValue g_pOptions [] =
{ L"sdkmesh2", OPT_SDKMESH_V2 },
{ L"cmo", OPT_CMO },
{ L"vbo", OPT_VBO },
{ L"wf", OPT_WAVEFRONT_OBJ },
{ L"cw", OPT_CLOCKWISE },
{ L"ib32", OPT_FORCE_32BIT_IB },
{ L"y", OPT_OVERWRITE },
@ -281,12 +283,13 @@ namespace
wprintf(L"Usage: uvatlas <options> <files>\n");
wprintf(L"\n");
wprintf(L" Input file type must be Wavefront OBJ\n\n");
wprintf(L" Input file type must be Wavefront Object (.obj)\n\n");
wprintf(L" Output file type:\n");
wprintf(L" -sdkmesh DirectX SDK .sdkmesh format (default)\n");
wprintf(L" -sdkmesh2 .sdkmesh format version 2 (PBR materials)\n");
wprintf(L" -cmo Visual Studio Content Pipeline .cmo format\n");
wprintf(L" -vbo Vertex Buffer Object (.vbo) format\n\n");
wprintf(L" -wf WaveFront Object (.obj) format\n\n");
wprintf(L" -r wildcard filename search is recursive\n");
wprintf(L" -q <level> sets quality level to DEFAULT, FAST or QUALITY\n");
wprintf(L" -n <number> maximum number of charts to generate (def: 0)\n");
@ -575,9 +578,9 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
case OPT_SDKMESH:
case OPT_SDKMESH_V2:
if (dwOptions & ((DWORD64(1) << OPT_VBO) | (DWORD64(1) << OPT_CMO)))
if (dwOptions & ((DWORD64(1) << OPT_VBO) | (DWORD64(1) << OPT_CMO) | (DWORD64(1) << OPT_WAVEFRONT_OBJ)))
{
wprintf(L"Can only use one of sdkmesh, cmo, or vbo\n");
wprintf(L"Can only use one of sdkmesh, cmo, vbo, or wf\n");
return 1;
}
if (dwOption == OPT_SDKMESH_V2)
@ -587,17 +590,25 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
break;
case OPT_CMO:
if (dwOptions & ((DWORD64(1) << OPT_VBO) | (DWORD64(1) << OPT_SDKMESH)))
if (dwOptions & ((DWORD64(1) << OPT_VBO) | (DWORD64(1) << OPT_SDKMESH) | (DWORD64(1) << OPT_WAVEFRONT_OBJ)))
{
wprintf(L"Can only use one of sdkmesh, cmo, or vbo\n");
wprintf(L"Can only use one of sdkmesh, cmo, vbo, or wf\n");
return 1;
}
break;
case OPT_VBO:
if (dwOptions & ((DWORD64(1) << OPT_SDKMESH) | (DWORD64(1) << OPT_CMO)))
if (dwOptions & ((DWORD64(1) << OPT_SDKMESH) | (DWORD64(1) << OPT_CMO) | (DWORD64(1) << OPT_WAVEFRONT_OBJ)))
{
wprintf(L"Can only use one of sdkmesh, cmo, or vbo\n");
wprintf(L"Can only use one of sdkmesh, cmo, vbo, or wf\n");
return 1;
}
break;
case OPT_WAVEFRONT_OBJ:
if (dwOptions & ((DWORD64(1) << OPT_VBO) | (DWORD64(1) << OPT_SDKMESH) | (DWORD64(1) << OPT_CMO)))
{
wprintf(L"Can only use one of sdkmesh, cmo, vbo, or wf\n");
return 1;
}
break;
@ -1190,6 +1201,10 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
{
wcscpy_s(outputExt, L".cmo");
}
else if (dwOptions & (DWORD64(1) << OPT_WAVEFRONT_OBJ))
{
wcscpy_s(outputExt, L".obj");
}
else
{
wcscpy_s(outputExt, L".sdkmesh");
@ -1250,9 +1265,9 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
hr = inMesh->ExportToCMO(outputPath, inMaterial.size(), inMaterial.empty() ? nullptr : inMaterial.data());
}
else if (!_wcsicmp(outputExt, L".obj"))
else if (!_wcsicmp(outputExt, L".obj") || !_wcsicmp(outputExt, L"._obj"))
{
hr = inMesh->ExportToOBJ(outputPath);
hr = inMesh->ExportToOBJ(outputPath, inMaterial.size(), inMaterial.empty() ? nullptr : inMaterial.data());
}
else if (!_wcsicmp(outputExt, L".x"))
{