Utility/Formats: Add OBJSaver (WIP)
Former-commit-id: 8f5fab2823f86ff5b12348eacfe238c74281c235 [formerly 9c9ad4880ee31052ae1850c53e4781690ce69f49] Former-commit-id: bde101aca68d5c6d205bb3d2252d656a6f7e078f
This commit is contained in:
parent
6084ff1707
commit
f814f5054e
|
|
@ -0,0 +1,228 @@
|
|||
// Copyright (C) 2016 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Formats/OBJLoader.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Utility/BufferMapper.hpp>
|
||||
#include <Nazara/Utility/IndexMapper.hpp>
|
||||
#include <Nazara/Utility/MaterialData.hpp>
|
||||
#include <Nazara/Utility/Mesh.hpp>
|
||||
#include <Nazara/Utility/StaticMesh.hpp>
|
||||
#include <Nazara/Utility/TriangleIterator.hpp>
|
||||
#include <Nazara/Utility/VertexMapper.hpp>
|
||||
#include <Nazara/Utility/Formats/MTLParser.hpp>
|
||||
#include <Nazara/Utility/Formats/OBJParser.hpp>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template<typename T>
|
||||
class VertexCache
|
||||
{
|
||||
public:
|
||||
VertexCache(T* ptr) :
|
||||
m_count(0),
|
||||
m_buffer(ptr)
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t GetCount() const
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
std::size_t Insert(const T& data)
|
||||
{
|
||||
auto it = m_cache.find(data);
|
||||
if (it == m_cache.end())
|
||||
{
|
||||
it = m_cache.insert(std::make_pair(data, m_count)).first;
|
||||
m_buffer[m_count] = data;
|
||||
m_count++;
|
||||
}
|
||||
|
||||
return it->second + 1;
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t m_count;
|
||||
std::map<T, std::size_t> m_cache;
|
||||
T* m_buffer;
|
||||
};
|
||||
|
||||
bool IsSupported(const String& extension)
|
||||
{
|
||||
return (extension == "obj");
|
||||
}
|
||||
|
||||
bool SaveToStream(const Mesh& mesh, const String& format, Stream& stream, const MeshParams& parameters)
|
||||
{
|
||||
if (!mesh.IsValid())
|
||||
{
|
||||
NazaraError("Invalid mesh");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mesh.IsAnimable())
|
||||
{
|
||||
NazaraError("An animated mesh cannot be saved to " + format + " format");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::size_t worstCacheVertexCount = mesh.GetVertexCount();
|
||||
OBJParser objFormat;
|
||||
objFormat.SetNormalCount(worstCacheVertexCount);
|
||||
objFormat.SetPositionCount(worstCacheVertexCount);
|
||||
objFormat.SetTexCoordCount(worstCacheVertexCount);
|
||||
|
||||
String mtlPath = stream.GetPath();
|
||||
if (!mtlPath.IsEmpty())
|
||||
{
|
||||
mtlPath.Replace(".obj", ".mtl");
|
||||
String fileName = mtlPath.SubStringFrom(NAZARA_DIRECTORY_SEPARATOR, -1, true);
|
||||
if (!fileName.IsEmpty())
|
||||
objFormat.SetMtlLib(fileName);
|
||||
}
|
||||
|
||||
VertexCache<Vector3f> normalCache(objFormat.GetNormals());
|
||||
VertexCache<Vector4f> positionCache(objFormat.GetPositions());
|
||||
VertexCache<Vector3f> texCoordsCache(objFormat.GetTexCoords());
|
||||
|
||||
// Materials
|
||||
MTLParser mtlFormat;
|
||||
std::unordered_set<String> registredMaterials;
|
||||
|
||||
std::size_t matCount = mesh.GetMaterialCount();
|
||||
String* materialNames = objFormat.SetMaterialCount(matCount);
|
||||
for (std::size_t i = 0; i < matCount; ++i)
|
||||
{
|
||||
const ParameterList& matData = mesh.GetMaterialData(i);
|
||||
|
||||
String name;
|
||||
if (!matData.GetStringParameter(MaterialData::Name, &name))
|
||||
name = "material_" + String::Number(i);
|
||||
|
||||
// Makes sure we only have one material of that name
|
||||
while (registredMaterials.find(name) != registredMaterials.end())
|
||||
name += '_';
|
||||
|
||||
registredMaterials.insert(name);
|
||||
materialNames[i] = name;
|
||||
|
||||
MTLParser::Material* material = mtlFormat.AddMaterial(name);
|
||||
|
||||
bool bValue;
|
||||
String strVal;
|
||||
if (matData.GetBooleanParameter(MaterialData::CustomDefined, &bValue) && bValue)
|
||||
{
|
||||
Color colorVal;
|
||||
float fValue;
|
||||
|
||||
if (matData.GetColorParameter(MaterialData::AmbientColor, &colorVal))
|
||||
material->ambient = colorVal;
|
||||
|
||||
if (matData.GetColorParameter(MaterialData::DiffuseColor, &colorVal))
|
||||
material->diffuse = colorVal;
|
||||
|
||||
if (matData.GetColorParameter(MaterialData::SpecularColor, &colorVal))
|
||||
material->specular = colorVal;
|
||||
|
||||
if (matData.GetFloatParameter(MaterialData::Shininess, &fValue))
|
||||
material->shininess = fValue;
|
||||
|
||||
if (matData.GetStringParameter(MaterialData::AlphaTexturePath, &strVal))
|
||||
material->alphaMap = strVal;
|
||||
|
||||
if (matData.GetStringParameter(MaterialData::DiffuseTexturePath, &strVal))
|
||||
material->diffuseMap = strVal;
|
||||
|
||||
if (matData.GetStringParameter(MaterialData::SpecularTexturePath, &strVal))
|
||||
material->specularMap = strVal;
|
||||
}
|
||||
else if (matData.GetStringParameter(MaterialData::FilePath, &strVal))
|
||||
material->diffuseMap = strVal;
|
||||
}
|
||||
|
||||
// Meshes
|
||||
std::size_t meshCount = mesh.GetSubMeshCount();
|
||||
OBJParser::Mesh* meshes = objFormat.SetMeshCount(meshCount);
|
||||
for (std::size_t i = 0; i < meshCount; ++i)
|
||||
{
|
||||
const StaticMesh* staticMesh = static_cast<const StaticMesh*>(mesh.GetSubMesh(i));
|
||||
|
||||
std::size_t triangleCount = staticMesh->GetTriangleCount();
|
||||
std::size_t vertexCount = staticMesh->GetVertexCount();
|
||||
|
||||
meshes[i].faces.resize(triangleCount);
|
||||
meshes[i].vertices.resize(triangleCount * 3);
|
||||
|
||||
{
|
||||
VertexMapper vertexMapper(staticMesh);
|
||||
|
||||
SparsePtr<Vector3f> normalPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Normal);
|
||||
SparsePtr<Vector3f> positionPtr = vertexMapper.GetComponentPtr<Vector3f>(VertexComponent_Position);
|
||||
SparsePtr<Vector2f> texCoordsPtr = vertexMapper.GetComponentPtr<Vector2f>(VertexComponent_TexCoord);
|
||||
|
||||
std::size_t faceIndex = 0;
|
||||
TriangleIterator triangle(staticMesh);
|
||||
do
|
||||
{
|
||||
OBJParser::Face& face = meshes[i].faces[faceIndex];
|
||||
face.firstVertex = faceIndex * 3;
|
||||
face.vertexCount = 3;
|
||||
|
||||
for (std::size_t j = 0; j < 3; ++j)
|
||||
{
|
||||
OBJParser::FaceVertex& vertexIndices = meshes[i].vertices[face.firstVertex + j];
|
||||
|
||||
std::size_t index = triangle[j];
|
||||
vertexIndices.normal = normalCache.Insert(normalPtr[index]);
|
||||
vertexIndices.position = positionCache.Insert(positionPtr[index]);
|
||||
vertexIndices.texCoord = texCoordsCache.Insert(texCoordsPtr[index]);
|
||||
}
|
||||
|
||||
faceIndex++;
|
||||
}
|
||||
while (triangle.Advance());
|
||||
}
|
||||
}
|
||||
|
||||
objFormat.SetNormalCount(normalCache.GetCount());
|
||||
objFormat.SetPositionCount(positionCache.GetCount());
|
||||
objFormat.SetTexCoordCount(texCoordsCache.GetCount());
|
||||
|
||||
objFormat.Save(stream);
|
||||
|
||||
if (!mtlPath.IsEmpty())
|
||||
{
|
||||
File mtlFile(mtlPath, OpenMode_WriteOnly | OpenMode_Truncate);
|
||||
if (mtlFile.IsOpen())
|
||||
mtlFormat.Save(mtlFile);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Loaders
|
||||
{
|
||||
void RegisterOBJSaver()
|
||||
{
|
||||
MeshSaver::RegisterSaver(IsSupported, SaveToStream);
|
||||
}
|
||||
|
||||
void UnregisterOBJSaver()
|
||||
{
|
||||
MeshSaver::UnregisterSaver(IsSupported, SaveToStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_FORMATS_OBJSAVER_HPP
|
||||
#define NAZARA_FORMATS_OBJSAVER_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace Loaders
|
||||
{
|
||||
void RegisterOBJSaver();
|
||||
void UnregisterOBJSaver();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // NAZARA_FORMATS_OBJSAVER_HPP
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
#include <Nazara/Utility/Formats/MD5AnimLoader.hpp>
|
||||
#include <Nazara/Utility/Formats/MD5MeshLoader.hpp>
|
||||
#include <Nazara/Utility/Formats/OBJLoader.hpp>
|
||||
#include <Nazara/Utility/Formats/OBJSaver.hpp>
|
||||
#include <Nazara/Utility/Formats/PCXLoader.hpp>
|
||||
#include <Nazara/Utility/Formats/STBLoader.hpp>
|
||||
#include <Nazara/Utility/Formats/STBSaver.hpp>
|
||||
|
|
@ -125,10 +126,12 @@ namespace Nz
|
|||
|
||||
// Mesh (text)
|
||||
Loaders::RegisterOBJLoader();
|
||||
Loaders::RegisterOBJSaver();
|
||||
|
||||
// Mesh
|
||||
Loaders::RegisterMD2(); // Loader de fichiers .md2 (v8)
|
||||
Loaders::RegisterMD5Mesh(); // Loader de fichiers .md5mesh (v10)
|
||||
Loaders::RegisterOBJLoader(); // Loader de fichiers .md5mesh (v10)
|
||||
|
||||
// Image
|
||||
Loaders::RegisterPCX(); // Loader de fichiers .pcx (1, 4, 8, 24 bits)
|
||||
|
|
@ -163,6 +166,7 @@ namespace Nz
|
|||
Loaders::UnregisterMD5Anim();
|
||||
Loaders::UnregisterMD5Mesh();
|
||||
Loaders::UnregisterOBJLoader();
|
||||
Loaders::UnregisterOBJSaver();
|
||||
Loaders::UnregisterPCX();
|
||||
Loaders::UnregisterSTBLoader();
|
||||
Loaders::UnregisterSTBSaver();
|
||||
|
|
|
|||
Loading…
Reference in New Issue