Utility/OBJParser: Add saving

Former-commit-id: f991f0a66a82a68659f14a7ba887b49a2690f5a7 [formerly e4c96019484ad436048d001bd307ac549dfc615a]
Former-commit-id: 946f9e5f99ff46c26741f1877391506b23602517
This commit is contained in:
Lynix 2016-07-07 09:00:50 +02:00
parent a92a3a2901
commit bbb218f9a0
3 changed files with 169 additions and 0 deletions

View File

@ -58,6 +58,8 @@ namespace Nz
bool Parse(Stream& stream, std::size_t reservedVertexCount = 100);
bool Save(Stream& stream) const;
private:
bool Advance(bool required = true);
template<typename T> void Emit(const T& text) const;

View File

@ -63,12 +63,37 @@ namespace Nz
return m_texCoords.size();
}
template<typename T>
void OBJParser::Emit(const T& text) const
{
m_outputStream << text;
if (m_outputStream.GetBufferSize() > 1024 * 1024)
Flush();
}
inline void OBJParser::EmitLine() const
{
Emit('\n');
}
template<typename T>
void OBJParser::EmitLine(const T& line) const
{
Emit(line);
Emit('\n');
}
inline void OBJParser::Error(const String& message)
{
NazaraError(message + " at line #" + String::Number(m_lineCount));
}
inline void OBJParser::Flush() const
{
m_currentStream->Write(m_outputStream);
m_outputStream.Clear();
}
inline void OBJParser::Warning(const String& message)
{
NazaraWarning(message + " at line #" + String::Number(m_lineCount));

View File

@ -363,6 +363,148 @@ namespace Nz
return true;
}
bool OBJParser::Save(Stream& stream) const
{
m_currentStream = &stream;
// Force stream in text mode, reset it at the end
Nz::CallOnExit resetTextMode;
if ((stream.GetStreamOptions() & StreamOption_Text) == 0)
{
stream.EnableTextMode(true);
resetTextMode.Reset([&stream] ()
{
stream.EnableTextMode(false);
});
}
m_outputStream.Clear();
EmitLine("# Exported by Nazara Engine");
if (!m_mtlLib.IsEmpty())
{
Emit("mtlib ");
EmitLine(m_mtlLib);
EmitLine();
}
Emit("# position count: ");
EmitLine(m_positions.size());
for (const Nz::Vector4f& position : m_positions)
{
Emit("v ");
Emit(position.x);
Emit(' ');
Emit(position.y);
if (!NumberEquals(position.z, 0.f) || !NumberEquals(position.w, 1.f))
{
Emit(' ');
Emit(position.z);
if (!NumberEquals(position.w, 1.f))
{
Emit(' ');
Emit(position.w);
}
}
EmitLine();
}
EmitLine();
Emit("# normal count: ");
EmitLine(m_normals.size());
for (const Nz::Vector3f& normal : m_normals)
{
Emit("vn ");
Emit(normal.x);
Emit(' ');
Emit(normal.y);
Emit(' ');
Emit(normal.y);
EmitLine();
}
EmitLine();
Emit("# texcoords count: ");
EmitLine(m_texCoords.size());
for (const Nz::Vector3f& uvw : m_texCoords)
{
Emit("vt ");
Emit(uvw.x);
Emit(' ');
Emit(uvw.y);
if (NumberEquals(uvw.z, 0.f))
{
Emit(' ');
Emit(uvw.z);
}
EmitLine();
}
EmitLine();
std::unordered_map<std::size_t /* mesh */, std::vector<std::size_t> /* meshes*/> meshesByMaterials;
std::size_t meshIndex = 0;
for (const Mesh& mesh : m_meshes)
meshesByMaterials[mesh.material].push_back(meshIndex++);
for (auto& pair : meshesByMaterials)
{
Emit("usemtl ");
EmitLine(m_materials[pair.first]);
Emit("# groups count: ");
EmitLine(pair.second.size());
EmitLine();
for (std::size_t meshIndex : pair.second)
{
const Mesh& mesh = m_meshes[meshIndex];
Emit("g ");
EmitLine(mesh.name);
EmitLine();
Emit("# face count: ");
EmitLine(mesh.faces.size());
Emit("# vertex count: ");
EmitLine(mesh.vertices.size());
for (const Face& face : mesh.faces)
{
Emit('f');
for (std::size_t i = 0; i < face.vertexCount; ++i)
{
Emit(' ');
const FaceVertex& faceVertex = mesh.vertices[face.firstVertex + i];
Emit(faceVertex.position);
if (faceVertex.texCoord != 0 || faceVertex.normal != 0)
{
Emit('/');
if (faceVertex.texCoord != 0)
Emit(faceVertex.texCoord);
if (faceVertex.normal != 0)
{
Emit('/');
Emit(faceVertex.normal);
}
}
}
EmitLine();
}
}
EmitLine();
}
Flush();
return true;
}
bool OBJParser::Advance(bool required)
{
if (!m_keepLastLine)