From 1d193ec74adf43427d0234fcbbcdb49800498baa Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 8 Jul 2016 08:34:45 +0200 Subject: [PATCH 01/12] Utility/OBJParser: Prepare for saving Former-commit-id: 245d757401397e329b906a4f48c913b434830475 [formerly da4af71db1570c669e82ab92c0a8a7a6301a5809] Former-commit-id: 5b14b24fe157a1411a9f76d6374c18be82e254de --- src/Nazara/Utility/Formats/OBJParser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Utility/Formats/OBJParser.cpp b/src/Nazara/Utility/Formats/OBJParser.cpp index cec716442..5c941e938 100644 --- a/src/Nazara/Utility/Formats/OBJParser.cpp +++ b/src/Nazara/Utility/Formats/OBJParser.cpp @@ -125,9 +125,9 @@ namespace Nz for (unsigned int i = 0; i < vertexCount; ++i) { int offset; - int n = 0; - int p = 0; - int t = 0; + std::size_t n = 0; + std::size_t p = 0; + std::size_t t = 0; if (std::sscanf(&m_currentLine[pos], "%d/%d/%d%n", &p, &t, &n, &offset) != 3) { From 9bd73098b1fbf6cb57f89f66ca893c3621ea30b0 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 8 Jul 2016 08:38:34 +0200 Subject: [PATCH 02/12] Utility/OBJParser: Fix mistake Former-commit-id: 33818e53f56d87be8138a0380d20aa3a79ddf5ae [formerly f7f5cafdeb378db42fe74bd983d3049b45a9f636] Former-commit-id: 7e02c6e60c944941d2583ad8c96ac7c43ed66e94 --- src/Nazara/Utility/Formats/OBJParser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Utility/Formats/OBJParser.cpp b/src/Nazara/Utility/Formats/OBJParser.cpp index 5c941e938..cec716442 100644 --- a/src/Nazara/Utility/Formats/OBJParser.cpp +++ b/src/Nazara/Utility/Formats/OBJParser.cpp @@ -125,9 +125,9 @@ namespace Nz for (unsigned int i = 0; i < vertexCount; ++i) { int offset; - std::size_t n = 0; - std::size_t p = 0; - std::size_t t = 0; + int n = 0; + int p = 0; + int t = 0; if (std::sscanf(&m_currentLine[pos], "%d/%d/%d%n", &p, &t, &n, &offset) != 3) { From 45c51d2a13398e64ef8d2fd59f020cb6aa4872e3 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 12 Jul 2016 08:09:31 +0200 Subject: [PATCH 03/12] Core/ResourceSaver: Truncate output file Former-commit-id: dc3d2191feeb53daac920670d8054d74bea899c5 [formerly 58e3f50290a8f3dde6f0745438bf5852b12dab29] Former-commit-id: a5b9c5fe16ce738968d2e7b12b922344dc35e52d --- include/Nazara/Core/ResourceSaver.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Nazara/Core/ResourceSaver.inl b/include/Nazara/Core/ResourceSaver.inl index 11d3f2a44..85f95fd3a 100644 --- a/include/Nazara/Core/ResourceSaver.inl +++ b/include/Nazara/Core/ResourceSaver.inl @@ -84,7 +84,7 @@ namespace Nz } else { - if (!file.Open(OpenMode_WriteOnly)) + if (!file.Open(OpenMode_WriteOnly | OpenMode_Truncate)) { NazaraError("Failed to save to file: unable to open \"" + filePath + "\" in write mode"); return false; From 58b014eb95b20bcd46976428c340c71197f16390 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 12 Jul 2016 08:09:42 +0200 Subject: [PATCH 04/12] Build/Examples: Fix HardwareInfo console Former-commit-id: 0e23e60d138e896aa162ddfadda25ef16b2330fe [formerly 87731440d2a891659f6ebcbeaef220ee8a542739] Former-commit-id: 8b7aa329f80c332e5f3c5174942607ebc2b6de27 --- examples/HardwareInfo/build.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/HardwareInfo/build.lua b/examples/HardwareInfo/build.lua index e1b487bd6..afcc7b544 100644 --- a/examples/HardwareInfo/build.lua +++ b/examples/HardwareInfo/build.lua @@ -1,6 +1,6 @@ EXAMPLE.Name = "HardwareInfo" -EXAMPLE.Console = true +EXAMPLE.EnableConsole = true EXAMPLE.Defines = { "NAZARA_RENDERER_OPENGL" From 2d2c34cb4159c02247e1dcd847c9d68c1a43cf87 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 12 Jul 2016 08:10:12 +0200 Subject: [PATCH 05/12] Utility/Formats: Make MD2Loader specify diffuse texture path instead of material filepath Former-commit-id: a2aa5553318958c7bf809bb83ee775062d80dca3 [formerly d290eac77b0ab16b2ccfb394ca5da3d508b66bc7] Former-commit-id: fb2b3a72ddfcd32562a6af726541367516f2adbf --- src/Nazara/Utility/Formats/MD2Loader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Nazara/Utility/Formats/MD2Loader.cpp b/src/Nazara/Utility/Formats/MD2Loader.cpp index 126eeaa35..d1d03cf52 100644 --- a/src/Nazara/Utility/Formats/MD2Loader.cpp +++ b/src/Nazara/Utility/Formats/MD2Loader.cpp @@ -102,7 +102,8 @@ namespace Nz stream.Read(skin, 68*sizeof(char)); ParameterList matData; - matData.SetParameter(MaterialData::FilePath, baseDir + skin); + matData.SetParameter(MaterialData::CustomDefined, true); + matData.SetParameter(MaterialData::DiffuseTexturePath, baseDir + skin); mesh->SetMaterialData(i, std::move(matData)); } From ce8461ca35a9e69faf843c034b3346383a3dd8cc Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 12 Jul 2016 08:11:03 +0200 Subject: [PATCH 06/12] Utility: Add MTL exporting Former-commit-id: b524c2d445f4c5cdadedabc3a9c38307dbfecb9b [formerly d65160f4e3f2fa2c7c9ddd151c73990c6712b4c1] Former-commit-id: 7ccdf043ccf793d3d9a5c9d93c65919ac015b52c --- include/Nazara/Utility/Formats/MTLParser.hpp | 39 +++- include/Nazara/Utility/Formats/MTLParser.inl | 83 +++++++ include/Nazara/Utility/Formats/OBJParser.hpp | 1 + include/Nazara/Utility/Formats/OBJParser.inl | 5 + src/Nazara/Utility/Formats/MTLParser.cpp | 234 +++++++++++++------ src/Nazara/Utility/Formats/OBJLoader.cpp | 28 ++- src/Nazara/Utility/Formats/OBJParser.cpp | 17 +- 7 files changed, 316 insertions(+), 91 deletions(-) create mode 100644 include/Nazara/Utility/Formats/MTLParser.inl diff --git a/include/Nazara/Utility/Formats/MTLParser.hpp b/include/Nazara/Utility/Formats/MTLParser.hpp index d58148ec7..9c5b49828 100644 --- a/include/Nazara/Utility/Formats/MTLParser.hpp +++ b/include/Nazara/Utility/Formats/MTLParser.hpp @@ -19,6 +19,22 @@ namespace Nz class NAZARA_UTILITY_API MTLParser { public: + struct Material; + + MTLParser() = default; + ~MTLParser() = default; + + inline Material* AddMaterial(const String& matName); + + inline void Clear(); + + inline const Material* GetMaterial(const String& materialName) const; + inline const std::unordered_map& GetMaterials() const; + + bool Parse(Stream& stream); + + bool Save(Stream& stream) const; + struct Material { Color ambient = Color::White; @@ -39,27 +55,26 @@ namespace Nz unsigned int illumModel = 0; }; - MTLParser(Stream& stream$); - ~MTLParser(); - - const Material* GetMaterial(const String& materialName) const; - const std::unordered_map& GetMaterials() const; - - bool Parse(); - private: bool Advance(bool required = true); - void Error(const String& message); - void Warning(const String& message); - void UnrecognizedLine(bool error = false); + template void Emit(const T& text) const; + inline void EmitLine() const; + template void EmitLine(const T& line) const; + inline void Error(const String& message); + inline void Flush() const; + inline void Warning(const String& message); + inline void UnrecognizedLine(bool error = false); std::unordered_map m_materials; - Stream& m_stream; + mutable Stream* m_currentStream; String m_currentLine; + mutable StringStream m_outputStream; bool m_keepLastLine; unsigned int m_lineCount; unsigned int m_streamFlags; }; } +#include + #endif // NAZARA_FORMATS_MTLPARSER_HPP diff --git a/include/Nazara/Utility/Formats/MTLParser.inl b/include/Nazara/Utility/Formats/MTLParser.inl new file mode 100644 index 000000000..0f8cd4f66 --- /dev/null +++ b/include/Nazara/Utility/Formats/MTLParser.inl @@ -0,0 +1,83 @@ +// 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 +#include +#include + +namespace Nz +{ + inline MTLParser::Material* MTLParser::AddMaterial(const String& matName) + { + return &m_materials[matName]; + } + + inline void MTLParser::Clear() + { + m_materials.clear(); + } + + inline const MTLParser::Material* MTLParser::GetMaterial(const String& materialName) const + { + auto it = m_materials.find(materialName); + if (it != m_materials.end()) + return &it->second; + else + return nullptr; + } + + inline const std::unordered_map& MTLParser::GetMaterials() const + { + return m_materials; + } + + template + void MTLParser::Emit(const T& text) const + { + m_outputStream << text; + if (m_outputStream.GetBufferSize() > 1024 * 1024) + Flush(); + } + + inline void MTLParser::EmitLine() const + { + Emit('\n'); + } + + template + void MTLParser::EmitLine(const T& line) const + { + Emit(line); + Emit('\n'); + } + + inline void MTLParser::Error(const String& message) + { + NazaraError(message + " at line #" + String::Number(m_lineCount)); + } + + inline void MTLParser::Flush() const + { + m_currentStream->Write(m_outputStream); + m_outputStream.Clear(); + } + + inline void MTLParser::Warning(const String& message) + { + NazaraWarning(message + " at line #" + String::Number(m_lineCount)); + } + + inline void MTLParser::UnrecognizedLine(bool error) + { + String message = "Unrecognized \"" + m_currentLine + '"'; + + if (error) + Error(message); + else + Warning(message); + } +} + +#include +#include "MTLParser.hpp" diff --git a/include/Nazara/Utility/Formats/OBJParser.hpp b/include/Nazara/Utility/Formats/OBJParser.hpp index b9c5e41c3..50fa58900 100644 --- a/include/Nazara/Utility/Formats/OBJParser.hpp +++ b/include/Nazara/Utility/Formats/OBJParser.hpp @@ -52,6 +52,7 @@ namespace Nz inline String* SetMaterialCount(std::size_t materialCount); inline Mesh* SetMeshCount(std::size_t meshCount); + inline void SetMtlLib(const String& mtlLib); inline Vector3f* SetNormalCount(std::size_t normalCount); inline Vector4f* SetPositionCount(std::size_t positionCount); inline Vector3f* SetTexCoordCount(std::size_t texCoordCount); diff --git a/include/Nazara/Utility/Formats/OBJParser.inl b/include/Nazara/Utility/Formats/OBJParser.inl index a4fcffaec..9d961d54f 100644 --- a/include/Nazara/Utility/Formats/OBJParser.inl +++ b/include/Nazara/Utility/Formats/OBJParser.inl @@ -109,6 +109,11 @@ namespace Nz return m_meshes.data(); } + inline void OBJParser::SetMtlLib(const String& mtlLib) + { + m_mtlLib = mtlLib; + } + inline Vector3f* OBJParser::SetNormalCount(std::size_t normalCount) { m_normals.resize(normalCount); diff --git a/src/Nazara/Utility/Formats/MTLParser.cpp b/src/Nazara/Utility/Formats/MTLParser.cpp index 2398ccb3f..6685bcd04 100644 --- a/src/Nazara/Utility/Formats/MTLParser.cpp +++ b/src/Nazara/Utility/Formats/MTLParser.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -12,36 +13,22 @@ namespace Nz { - MTLParser::MTLParser(Stream& stream) : - m_stream(stream), - m_streamFlags(stream.GetStreamOptions()) //< Saves stream flags + bool MTLParser::Parse(Stream& stream) { - m_stream.EnableTextMode(true); - } + m_currentStream = &stream; - MTLParser::~MTLParser() - { - // Reset stream flags - if ((m_streamFlags & StreamOption_Text) == 0) - m_stream.EnableTextMode(false); - } + // Force stream in text mode, reset it at the end + Nz::CallOnExit resetTextMode; + if ((stream.GetStreamOptions() & StreamOption_Text) == 0) + { + stream.EnableTextMode(true); - const MTLParser::Material* MTLParser::GetMaterial(const String& materialName) const - { - auto it = m_materials.find(materialName); - if (it != m_materials.end()) - return &it->second; - else - return nullptr; - } + resetTextMode.Reset([&stream] () + { + stream.EnableTextMode(false); + }); + } - const std::unordered_map& MTLParser::GetMaterials() const - { - return m_materials; - } - - bool MTLParser::Parse() - { m_keepLastLine = false; m_lineCount = 0; m_materials.clear(); @@ -57,7 +44,7 @@ namespace Nz if (std::sscanf(&m_currentLine[3], "%f %f %f", &r, &g, &b) == 3) { if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->ambient = Color(static_cast(r*255.f), static_cast(g*255.f), static_cast(b*255.f)); } @@ -72,7 +59,7 @@ namespace Nz if (std::sscanf(&m_currentLine[3], "%f %f %f", &r, &g, &b) == 3) { if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->diffuse = Color(static_cast(r*255.f), static_cast(g*255.f), static_cast(b*255.f)); } @@ -87,7 +74,7 @@ namespace Nz if (std::sscanf(&m_currentLine[3], "%f %f %f", &r, &g, &b) == 3) { if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->specular = Color(static_cast(r*255.f), static_cast(g*255.f), static_cast(b*255.f)); } @@ -102,7 +89,7 @@ namespace Nz if (std::sscanf(&m_currentLine[3], "%f", &density) == 1) { if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->refractionIndex = density; } @@ -117,7 +104,7 @@ namespace Nz if (std::sscanf(&m_currentLine[3], "%f", &coef) == 1) { if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->shininess = coef; } @@ -132,7 +119,7 @@ namespace Nz if (std::sscanf(&m_currentLine[(keyword[0] == 'd') ? 2 : 3], "%f", &alpha) == 1) { if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->alpha = alpha; } @@ -147,7 +134,7 @@ namespace Nz if (std::sscanf(&m_currentLine[(keyword[0] == 'd') ? 2 : 3], "%f", &alpha) == 1) { if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->alpha = 1.f - alpha; // tr vaut pour la "valeur de transparence", 0 = opaque } @@ -162,7 +149,7 @@ namespace Nz if (std::sscanf(&m_currentLine[6], "%u", &model) == 1) { if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->illumModel = model; } @@ -178,7 +165,7 @@ namespace Nz { String map = m_currentLine.SubString(mapPos); if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->ambientMap = map; } @@ -190,7 +177,7 @@ namespace Nz { String map = m_currentLine.SubString(mapPos); if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->diffuseMap = map; } @@ -202,7 +189,7 @@ namespace Nz { String map = m_currentLine.SubString(mapPos); if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->specularMap = map; } @@ -214,7 +201,7 @@ namespace Nz { String map = m_currentLine.SubString(mapPos); if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->bumpMap = map; } @@ -226,7 +213,7 @@ namespace Nz { String map = m_currentLine.SubString(mapPos); if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->alphaMap = map; } @@ -238,7 +225,7 @@ namespace Nz { String map = m_currentLine.SubString(mapPos); if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->decalMap = map; } @@ -250,7 +237,7 @@ namespace Nz { String map = m_currentLine.SubString(mapPos); if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->displacementMap = map; } @@ -262,7 +249,7 @@ namespace Nz { String map = m_currentLine.SubString(mapPos); if (!currentMaterial) - currentMaterial = &m_materials["default"]; + currentMaterial = AddMaterial("default"); currentMaterial->reflectionMap = map; } @@ -271,7 +258,7 @@ namespace Nz { String materialName = m_currentLine.SubString(m_currentLine.GetWordPosition(1)); if (!materialName.IsEmpty()) - currentMaterial = &m_materials[materialName]; + currentMaterial = AddMaterial(materialName); #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING else UnrecognizedLine(); @@ -286,13 +273,150 @@ namespace Nz return true; } + bool MTLParser::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"); + EmitLine(); + + Emit("# material count: "); + Emit(m_materials.size()); + EmitLine(); + + for (auto& pair : m_materials) + { + const String& matName = pair.first; + const Material& mat = pair.second; + + Emit("newmtl "); + EmitLine(pair.first); + EmitLine(); + + Emit("Ka "); + Emit(mat.ambient.r / 255.f); + Emit(' '); + Emit(mat.ambient.g / 255.f); + Emit(' '); + Emit(mat.ambient.b / 255.f); + EmitLine(); + + Emit("Kd "); + Emit(mat.diffuse.r / 255.f); + Emit(' '); + Emit(mat.diffuse.g / 255.f); + Emit(' '); + Emit(mat.diffuse.b / 255.f); + EmitLine(); + + Emit("Ks "); + Emit(mat.specular.r / 255.f); + Emit(' '); + Emit(mat.specular.g / 255.f); + Emit(' '); + Emit(mat.specular.b / 255.f); + EmitLine(); + + if (mat.alpha != 1.f) + { + Emit("d "); + EmitLine(mat.alpha); + } + + if (mat.refractionIndex != 1.f) + { + Emit("ni "); + EmitLine(mat.refractionIndex); + } + + if (mat.shininess != 1.f) + { + Emit("ns "); + EmitLine(mat.shininess); + } + + if (mat.illumModel != 0) + { + Emit("illum "); + EmitLine(mat.illumModel); + } + + if (!mat.ambientMap.IsEmpty()) + { + Emit("map_Ka "); + EmitLine(mat.ambientMap); + } + + if (!mat.diffuseMap.IsEmpty()) + { + Emit("map_Kd "); + EmitLine(mat.diffuseMap); + } + + if (!mat.specularMap.IsEmpty()) + { + Emit("map_Ks "); + EmitLine(mat.specularMap); + } + + if (!mat.bumpMap.IsEmpty()) + { + Emit("map_bump "); + EmitLine(mat.bumpMap); + } + + if (!mat.alphaMap.IsEmpty()) + { + Emit("map_d "); + EmitLine(mat.alphaMap); + } + + if (!mat.decalMap.IsEmpty()) + { + Emit("map_decal "); + EmitLine(mat.decalMap); + } + + if (!mat.displacementMap.IsEmpty()) + { + Emit("map_disp "); + EmitLine(mat.displacementMap); + } + + if (!mat.reflectionMap.IsEmpty()) + { + Emit("map_refl "); + EmitLine(mat.reflectionMap); + } + EmitLine(); + } + + Flush(); + + return true; + } + bool MTLParser::Advance(bool required) { if (!m_keepLastLine) { do { - if (m_stream.EndOfStream()) + if (m_currentStream->EndOfStream()) { if (required) Error("Incomplete MTL file"); @@ -302,7 +426,7 @@ namespace Nz m_lineCount++; - m_currentLine = m_stream.ReadLine(); + m_currentLine = m_currentStream->ReadLine(); m_currentLine = m_currentLine.SubStringTo("#"); // On ignore les commentaires m_currentLine.Simplify(); // Pour un traitement plus simple } @@ -313,24 +437,4 @@ namespace Nz return true; } - - void MTLParser::Error(const String& message) - { - NazaraError(message + " at line #" + String::Number(m_lineCount)); - } - - void MTLParser::Warning(const String& message) - { - NazaraWarning(message + " at line #" + String::Number(m_lineCount)); - } - - void MTLParser::UnrecognizedLine(bool error) - { - String message = "Unrecognized \"" + m_currentLine + '"'; - - if (error) - Error(message); - else - Warning(message); - } } diff --git a/src/Nazara/Utility/Formats/OBJLoader.cpp b/src/Nazara/Utility/Formats/OBJLoader.cpp index a8d5d68ec..1b1835b2b 100644 --- a/src/Nazara/Utility/Formats/OBJLoader.cpp +++ b/src/Nazara/Utility/Formats/OBJLoader.cpp @@ -49,8 +49,8 @@ namespace Nz return false; } - MTLParser materialParser(file); - if (!materialParser.Parse()) + MTLParser materialParser; + if (!materialParser.Parse(file)) { NazaraError("MTL parser failed"); return false; @@ -90,13 +90,31 @@ namespace Nz data.SetParameter(MaterialData::SpecularColor, specularColor); if (!mtlMat->alphaMap.IsEmpty()) - data.SetParameter(MaterialData::AlphaTexturePath, baseDir + mtlMat->alphaMap); + { + String fullPath = mtlMat->alphaMap; + if (!Nz::File::IsAbsolute(fullPath)) + fullPath.Prepend(baseDir); + + data.SetParameter(MaterialData::AlphaTexturePath, fullPath); + } if (!mtlMat->diffuseMap.IsEmpty()) - data.SetParameter(MaterialData::DiffuseTexturePath, baseDir + mtlMat->diffuseMap); + { + String fullPath = mtlMat->diffuseMap; + if (!Nz::File::IsAbsolute(fullPath)) + fullPath.Prepend(baseDir); + + data.SetParameter(MaterialData::DiffuseTexturePath, fullPath); + } if (!mtlMat->specularMap.IsEmpty()) - data.SetParameter(MaterialData::SpecularTexturePath, baseDir + mtlMat->specularMap); + { + String fullPath = mtlMat->specularMap; + if (!Nz::File::IsAbsolute(fullPath)) + fullPath.Prepend(baseDir); + + data.SetParameter(MaterialData::SpecularTexturePath, fullPath); + } // If we either have an alpha value or an alpha map, let's configure the material for transparency if (alphaValue != 255 || !mtlMat->alphaMap.IsEmpty()) diff --git a/src/Nazara/Utility/Formats/OBJParser.cpp b/src/Nazara/Utility/Formats/OBJParser.cpp index cec716442..bd189305f 100644 --- a/src/Nazara/Utility/Formats/OBJParser.cpp +++ b/src/Nazara/Utility/Formats/OBJParser.cpp @@ -386,10 +386,11 @@ namespace Nz m_outputStream.Clear(); EmitLine("# Exported by Nazara Engine"); + EmitLine(); if (!m_mtlLib.IsEmpty()) { - Emit("mtlib "); + Emit("mtllib "); EmitLine(m_mtlLib); EmitLine(); } @@ -403,17 +404,15 @@ namespace Nz 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.z); - - if (!NumberEquals(position.w, 1.f)) - { - Emit(' '); - Emit(position.w); - } + Emit(position.w); } + EmitLine(); } EmitLine(); From 6084ff1707b66f09a3428a727985200c8bcbe626 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 12 Jul 2016 08:11:25 +0200 Subject: [PATCH 07/12] Utility/Mesh: Add MeshSaver properly Former-commit-id: 08a7fb99853e68e692e1346577c8d616c1f4a6f9 [formerly 626e980416ee0ceea15036bd6355321400a19475] Former-commit-id: d39fd4d74d2d58c14057b0f769ceb7ce120c103a --- include/Nazara/Utility/Mesh.hpp | 4 ++++ src/Nazara/Utility/Mesh.cpp | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/include/Nazara/Utility/Mesh.hpp b/include/Nazara/Utility/Mesh.hpp index 36798e689..62a372384 100644 --- a/include/Nazara/Utility/Mesh.hpp +++ b/include/Nazara/Utility/Mesh.hpp @@ -71,6 +71,7 @@ namespace Nz friend MeshLibrary; friend MeshLoader; friend MeshManager; + friend MeshSaver; friend class Utility; public: @@ -126,6 +127,9 @@ namespace Nz void RemoveSubMesh(const String& identifier); void RemoveSubMesh(unsigned int index); + bool SaveToFile(const String& filePath, const MeshParams& params = MeshParams()); + bool SaveToStream(Stream& stream, const String& format, const MeshParams& params = MeshParams()); + void SetAnimation(const String& animationPath); void SetMaterialCount(unsigned int matCount); void SetMaterialData(unsigned int matIndex, ParameterList data); diff --git a/src/Nazara/Utility/Mesh.cpp b/src/Nazara/Utility/Mesh.cpp index 0401a9a10..84559abda 100644 --- a/src/Nazara/Utility/Mesh.cpp +++ b/src/Nazara/Utility/Mesh.cpp @@ -606,6 +606,16 @@ namespace Nz InvalidateAABB(); } + bool Mesh::SaveToFile(const String& filePath, const MeshParams& params) + { + return MeshSaver::SaveToFile(*this, filePath, params); + } + + bool Mesh::SaveToStream(Stream& stream, const String& format, const MeshParams& params) + { + return MeshSaver::SaveToStream(*this, stream, format, params); + } + void Mesh::SetAnimation(const String& animationPath) { NazaraAssert(m_impl, "Mesh should be created first"); From f814f5054e11520cc8ab5c04a07fced2e78fe140 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 12 Jul 2016 08:11:50 +0200 Subject: [PATCH 08/12] Utility/Formats: Add OBJSaver (WIP) Former-commit-id: 8f5fab2823f86ff5b12348eacfe238c74281c235 [formerly 9c9ad4880ee31052ae1850c53e4781690ce69f49] Former-commit-id: bde101aca68d5c6d205bb3d2252d656a6f7e078f --- src/Nazara/Utility/Formats/OBJSaver.cpp | 228 ++++++++++++++++++++++++ src/Nazara/Utility/Formats/OBJSaver.hpp | 21 +++ src/Nazara/Utility/Utility.cpp | 4 + 3 files changed, 253 insertions(+) create mode 100644 src/Nazara/Utility/Formats/OBJSaver.cpp create mode 100644 src/Nazara/Utility/Formats/OBJSaver.hpp diff --git a/src/Nazara/Utility/Formats/OBJSaver.cpp b/src/Nazara/Utility/Formats/OBJSaver.cpp new file mode 100644 index 000000000..4fe468135 --- /dev/null +++ b/src/Nazara/Utility/Formats/OBJSaver.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + namespace + { + template + 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 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 normalCache(objFormat.GetNormals()); + VertexCache positionCache(objFormat.GetPositions()); + VertexCache texCoordsCache(objFormat.GetTexCoords()); + + // Materials + MTLParser mtlFormat; + std::unordered_set 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(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 normalPtr = vertexMapper.GetComponentPtr(VertexComponent_Normal); + SparsePtr positionPtr = vertexMapper.GetComponentPtr(VertexComponent_Position); + SparsePtr texCoordsPtr = vertexMapper.GetComponentPtr(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); + } + } +} diff --git a/src/Nazara/Utility/Formats/OBJSaver.hpp b/src/Nazara/Utility/Formats/OBJSaver.hpp new file mode 100644 index 000000000..ed909f165 --- /dev/null +++ b/src/Nazara/Utility/Formats/OBJSaver.hpp @@ -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 + +namespace Nz +{ + namespace Loaders + { + void RegisterOBJSaver(); + void UnregisterOBJSaver(); + } +} + +#endif // NAZARA_FORMATS_OBJSAVER_HPP diff --git a/src/Nazara/Utility/Utility.cpp b/src/Nazara/Utility/Utility.cpp index ae5b5066d..6b2f66353 100644 --- a/src/Nazara/Utility/Utility.cpp +++ b/src/Nazara/Utility/Utility.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -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(); From f8c4dda97f470a90ef8b6193b210fcd6db530988 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 12 Jul 2016 17:16:20 +0200 Subject: [PATCH 09/12] Delete Image.inl.save-failed Former-commit-id: 160b8d589c85d05886f46f77f191781e966ded37 [formerly 2bd02c1131275b7f48e71966f935c33a8517fa8e] Former-commit-id: b721cff7e246a88538296e29f9f7234f3773b431 --- include/Nazara/Utility/Image.inl.save-failed | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 include/Nazara/Utility/Image.inl.save-failed diff --git a/include/Nazara/Utility/Image.inl.save-failed b/include/Nazara/Utility/Image.inl.save-failed deleted file mode 100644 index 5cb8ef42f..000000000 --- a/include/Nazara/Utility/Image.inl.save-failed +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (C) 2015 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 -#include - -namespace Nz -{ - template - ImageRef Image::New(Args&&... args) - { - std::unique_ptr object(new Image(std::forward(args)...)); - object->SetPersistent(false); - - return object.release(); - } -} - -#include From e3bb204ddf3843409af8f17ce0b742ecc6b12352 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 13 Jul 2016 12:26:38 +0200 Subject: [PATCH 10/12] Prevent GitHub to count external libraries into the project files Former-commit-id: 6ca53002d7211efbcac22d8062d02b19ce9cf85c [formerly 6b0ae084ee52a9d2f12dc251f73db8a9bc5a0d55] Former-commit-id: 7b9361c5c702b7e53556b7d81a011c599ffeeab0 --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitattributes b/.gitattributes index dfe077042..a788acb7e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,4 @@ # Auto detect text files and perform LF normalization * text=auto +extlibs/* linguist-vendored +NazaraModuleTemplate/* linguist-vendored From c7355ad166ffbf27fce73d9c7bca739bc55995ca Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 13 Jul 2016 12:27:30 +0200 Subject: [PATCH 11/12] Update global headers Former-commit-id: 57e803ee99f077bc0436b5284dc14bab7ab33555 [formerly 1551090a7423e44e74b68452c0f209a121ad8cd8] Former-commit-id: b275b8b680a3ddee30589d0e5f67a49d0448f066 --- include/Nazara/Graphics.hpp | 4 +++- include/Nazara/Noise.hpp | 29 ++++++++++------------------- include/Nazara/Utility.hpp | 3 ++- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/include/Nazara/Graphics.hpp b/include/Nazara/Graphics.hpp index 465aeb999..17b10e9a1 100644 --- a/include/Nazara/Graphics.hpp +++ b/include/Nazara/Graphics.hpp @@ -1,4 +1,4 @@ -// This file was automatically generated on 17 Nov 2015 at 13:20:45 +// This file was automatically generated on 12 Jul 2016 at 17:44:43 /* Nazara Engine - Graphics module @@ -47,6 +47,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/include/Nazara/Noise.hpp b/include/Nazara/Noise.hpp index 45b240378..e1d14460e 100644 --- a/include/Nazara/Noise.hpp +++ b/include/Nazara/Noise.hpp @@ -1,9 +1,9 @@ -// This file was automatically generated on 17 Nov 2015 at 13:20:45 +// This file was automatically generated on 12 Jul 2016 at 17:44:43 /* Nazara Engine - Noise module - Copyright (C) 2015 Rémi "Overdrivr" Bèges (remi.beges@laposte.net) + Copyright (C) 2016 Rémi "Overdrivr" Bèges (remi.beges@laposte.net) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -29,25 +29,16 @@ #ifndef NAZARA_GLOBAL_NOISE_HPP #define NAZARA_GLOBAL_NOISE_HPP -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include #endif // NAZARA_GLOBAL_NOISE_HPP diff --git a/include/Nazara/Utility.hpp b/include/Nazara/Utility.hpp index 156ca6389..d7676277e 100644 --- a/include/Nazara/Utility.hpp +++ b/include/Nazara/Utility.hpp @@ -1,4 +1,4 @@ -// This file was automatically generated on 24 Jun 2015 at 13:55:50 +// This file was automatically generated on 12 Jul 2016 at 17:44:43 /* Nazara Engine - Utility module @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include From ef7759468a5d7ca11ae05d85737a758724b8141d Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 17 Jul 2016 21:10:20 +0200 Subject: [PATCH 12/12] Utility/OBJSaver: Fix multiple materials saving Former-commit-id: 18d8c235a58fc627bcc4ecbbe5cfcd8fcdf00014 [formerly 358b88c21f73a36051baed60a943643c3ae9b03c] Former-commit-id: c1f89cb0f375db6c68048f0bc8e857306b6ca034 --- src/Nazara/Utility/Formats/MD2Loader.cpp | 2 +- src/Nazara/Utility/Formats/OBJSaver.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Utility/Formats/MD2Loader.cpp b/src/Nazara/Utility/Formats/MD2Loader.cpp index d1d03cf52..c61dffd09 100644 --- a/src/Nazara/Utility/Formats/MD2Loader.cpp +++ b/src/Nazara/Utility/Formats/MD2Loader.cpp @@ -102,7 +102,7 @@ namespace Nz stream.Read(skin, 68*sizeof(char)); ParameterList matData; - matData.SetParameter(MaterialData::CustomDefined, true); + matData.SetParameter(MaterialData::CustomDefined); matData.SetParameter(MaterialData::DiffuseTexturePath, baseDir + skin); mesh->SetMaterialData(i, std::move(matData)); diff --git a/src/Nazara/Utility/Formats/OBJSaver.cpp b/src/Nazara/Utility/Formats/OBJSaver.cpp index 4fe468135..9a79638bc 100644 --- a/src/Nazara/Utility/Formats/OBJSaver.cpp +++ b/src/Nazara/Utility/Formats/OBJSaver.cpp @@ -122,7 +122,7 @@ namespace Nz bool bValue; String strVal; - if (matData.GetBooleanParameter(MaterialData::CustomDefined, &bValue) && bValue) + if (matData.HasParameter(MaterialData::CustomDefined)) { Color colorVal; float fValue; @@ -160,9 +160,10 @@ namespace Nz const StaticMesh* staticMesh = static_cast(mesh.GetSubMesh(i)); std::size_t triangleCount = staticMesh->GetTriangleCount(); - std::size_t vertexCount = staticMesh->GetVertexCount(); meshes[i].faces.resize(triangleCount); + meshes[i].material = staticMesh->GetMaterialIndex(); + meshes[i].name = "mesh_" + String::Number(i); meshes[i].vertices.resize(triangleCount * 3); {