Merge branch 'master' into vulkan

Former-commit-id: e2aa8425da79e895900639e75c19e6155ae1681e [formerly e85202803b75ef6526f537bb1c8baab5a02c63db]
Former-commit-id: 08e921b9afd2e004413b5777e9371593d42815ee
This commit is contained in:
Lynix 2016-07-17 21:14:29 +02:00
commit cccf5ae36b
20 changed files with 605 additions and 135 deletions

2
.gitattributes vendored
View File

@ -1,2 +1,4 @@
# Auto detect text files and perform LF normalization # Auto detect text files and perform LF normalization
* text=auto * text=auto
extlibs/* linguist-vendored
NazaraModuleTemplate/* linguist-vendored

View File

@ -1,6 +1,6 @@
EXAMPLE.Name = "HardwareInfo" EXAMPLE.Name = "HardwareInfo"
EXAMPLE.Console = true EXAMPLE.EnableConsole = true
EXAMPLE.Defines = { EXAMPLE.Defines = {
"NAZARA_RENDERER_OPENGL" "NAZARA_RENDERER_OPENGL"

View File

@ -84,7 +84,7 @@ namespace Nz
} }
else 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"); NazaraError("Failed to save to file: unable to open \"" + filePath + "\" in write mode");
return false; return false;

View File

@ -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 Nazara Engine - Graphics module
@ -47,6 +47,8 @@
#include <Nazara/Graphics/DeferredRenderPass.hpp> #include <Nazara/Graphics/DeferredRenderPass.hpp>
#include <Nazara/Graphics/DeferredRenderQueue.hpp> #include <Nazara/Graphics/DeferredRenderQueue.hpp>
#include <Nazara/Graphics/DeferredRenderTechnique.hpp> #include <Nazara/Graphics/DeferredRenderTechnique.hpp>
#include <Nazara/Graphics/DepthRenderQueue.hpp>
#include <Nazara/Graphics/DepthRenderTechnique.hpp>
#include <Nazara/Graphics/Drawable.hpp> #include <Nazara/Graphics/Drawable.hpp>
#include <Nazara/Graphics/Enums.hpp> #include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Graphics/ForwardRenderQueue.hpp> #include <Nazara/Graphics/ForwardRenderQueue.hpp>

View File

@ -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 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 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 this software and associated documentation files (the "Software"), to deal in
@ -29,25 +29,16 @@
#ifndef NAZARA_GLOBAL_NOISE_HPP #ifndef NAZARA_GLOBAL_NOISE_HPP
#define NAZARA_GLOBAL_NOISE_HPP #define NAZARA_GLOBAL_NOISE_HPP
#include <Nazara/Noise/Abstract2DNoise.hpp>
#include <Nazara/Noise/Abstract3DNoise.hpp>
#include <Nazara/Noise/Abstract4DNoise.hpp>
#include <Nazara/Noise/ComplexNoiseBase.hpp>
#include <Nazara/Noise/Config.hpp> #include <Nazara/Noise/Config.hpp>
#include <Nazara/Noise/FBM2D.hpp> #include <Nazara/Noise/Enums.hpp>
#include <Nazara/Noise/FBM3D.hpp> #include <Nazara/Noise/FBM.hpp>
#include <Nazara/Noise/FBM4D.hpp> #include <Nazara/Noise/HybridMultiFractal.hpp>
#include <Nazara/Noise/HybridMultiFractal2D.hpp> #include <Nazara/Noise/MixerBase.hpp>
#include <Nazara/Noise/HybridMultiFractal3D.hpp>
#include <Nazara/Noise/HybridMultiFractal4D.hpp>
#include <Nazara/Noise/MappedNoiseBase.hpp>
#include <Nazara/Noise/Noise.hpp> #include <Nazara/Noise/Noise.hpp>
#include <Nazara/Noise/NoiseBase.hpp> #include <Nazara/Noise/NoiseBase.hpp>
#include <Nazara/Noise/Perlin2D.hpp> #include <Nazara/Noise/NoiseTools.hpp>
#include <Nazara/Noise/Perlin3D.hpp> #include <Nazara/Noise/Perlin.hpp>
#include <Nazara/Noise/Perlin4D.hpp> #include <Nazara/Noise/Simplex.hpp>
#include <Nazara/Noise/Simplex2D.hpp> #include <Nazara/Noise/Worley.hpp>
#include <Nazara/Noise/Simplex3D.hpp>
#include <Nazara/Noise/Simplex4D.hpp>
#endif // NAZARA_GLOBAL_NOISE_HPP #endif // NAZARA_GLOBAL_NOISE_HPP

View File

@ -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 Nazara Engine - Utility module
@ -54,6 +54,7 @@
#include <Nazara/Utility/Joint.hpp> #include <Nazara/Utility/Joint.hpp>
#include <Nazara/Utility/Joystick.hpp> #include <Nazara/Utility/Joystick.hpp>
#include <Nazara/Utility/Keyboard.hpp> #include <Nazara/Utility/Keyboard.hpp>
#include <Nazara/Utility/MaterialData.hpp>
#include <Nazara/Utility/Mesh.hpp> #include <Nazara/Utility/Mesh.hpp>
#include <Nazara/Utility/MeshData.hpp> #include <Nazara/Utility/MeshData.hpp>
#include <Nazara/Utility/Mouse.hpp> #include <Nazara/Utility/Mouse.hpp>

View File

@ -19,6 +19,22 @@ namespace Nz
class NAZARA_UTILITY_API MTLParser class NAZARA_UTILITY_API MTLParser
{ {
public: 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<String, Material>& GetMaterials() const;
bool Parse(Stream& stream);
bool Save(Stream& stream) const;
struct Material struct Material
{ {
Color ambient = Color::White; Color ambient = Color::White;
@ -39,27 +55,26 @@ namespace Nz
unsigned int illumModel = 0; unsigned int illumModel = 0;
}; };
MTLParser(Stream& stream$);
~MTLParser();
const Material* GetMaterial(const String& materialName) const;
const std::unordered_map<String, Material>& GetMaterials() const;
bool Parse();
private: private:
bool Advance(bool required = true); bool Advance(bool required = true);
void Error(const String& message); template<typename T> void Emit(const T& text) const;
void Warning(const String& message); inline void EmitLine() const;
void UnrecognizedLine(bool error = false); template<typename T> 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<String, Material> m_materials; std::unordered_map<String, Material> m_materials;
Stream& m_stream; mutable Stream* m_currentStream;
String m_currentLine; String m_currentLine;
mutable StringStream m_outputStream;
bool m_keepLastLine; bool m_keepLastLine;
unsigned int m_lineCount; unsigned int m_lineCount;
unsigned int m_streamFlags; unsigned int m_streamFlags;
}; };
} }
#include <Nazara/Utility/Formats/MTLParser.inl>
#endif // NAZARA_FORMATS_MTLPARSER_HPP #endif // NAZARA_FORMATS_MTLPARSER_HPP

View File

@ -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 <Nazara/Utility/Formats/MTLParser.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Utility/Debug.hpp>
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<String, MTLParser::Material>& MTLParser::GetMaterials() const
{
return m_materials;
}
template<typename T>
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<typename T>
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 <Nazara/Utility/DebugOff.hpp>
#include "MTLParser.hpp"

View File

@ -52,6 +52,7 @@ namespace Nz
inline String* SetMaterialCount(std::size_t materialCount); inline String* SetMaterialCount(std::size_t materialCount);
inline Mesh* SetMeshCount(std::size_t meshCount); inline Mesh* SetMeshCount(std::size_t meshCount);
inline void SetMtlLib(const String& mtlLib);
inline Vector3f* SetNormalCount(std::size_t normalCount); inline Vector3f* SetNormalCount(std::size_t normalCount);
inline Vector4f* SetPositionCount(std::size_t positionCount); inline Vector4f* SetPositionCount(std::size_t positionCount);
inline Vector3f* SetTexCoordCount(std::size_t texCoordCount); inline Vector3f* SetTexCoordCount(std::size_t texCoordCount);

View File

@ -109,6 +109,11 @@ namespace Nz
return m_meshes.data(); return m_meshes.data();
} }
inline void OBJParser::SetMtlLib(const String& mtlLib)
{
m_mtlLib = mtlLib;
}
inline Vector3f* OBJParser::SetNormalCount(std::size_t normalCount) inline Vector3f* OBJParser::SetNormalCount(std::size_t normalCount)
{ {
m_normals.resize(normalCount); m_normals.resize(normalCount);

View File

@ -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 <memory>
#include <Nazara/Utility/Debug.hpp>
namespace Nz
{
template<typename... Args>
ImageRef Image::New(Args&&... args)
{
std::unique_ptr<Image> object(new Image(std::forward<Args>(args)...));
object->SetPersistent(false);
return object.release();
}
}
#include <Nazara/Utility/DebugOff.hpp>

View File

@ -71,6 +71,7 @@ namespace Nz
friend MeshLibrary; friend MeshLibrary;
friend MeshLoader; friend MeshLoader;
friend MeshManager; friend MeshManager;
friend MeshSaver;
friend class Utility; friend class Utility;
public: public:
@ -126,6 +127,9 @@ namespace Nz
void RemoveSubMesh(const String& identifier); void RemoveSubMesh(const String& identifier);
void RemoveSubMesh(unsigned int index); 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 SetAnimation(const String& animationPath);
void SetMaterialCount(unsigned int matCount); void SetMaterialCount(unsigned int matCount);
void SetMaterialData(unsigned int matIndex, ParameterList data); void SetMaterialData(unsigned int matIndex, ParameterList data);

View File

@ -102,7 +102,8 @@ namespace Nz
stream.Read(skin, 68*sizeof(char)); stream.Read(skin, 68*sizeof(char));
ParameterList matData; ParameterList matData;
matData.SetParameter(MaterialData::FilePath, baseDir + skin); matData.SetParameter(MaterialData::CustomDefined);
matData.SetParameter(MaterialData::DiffuseTexturePath, baseDir + skin);
mesh->SetMaterialData(i, std::move(matData)); mesh->SetMaterialData(i, std::move(matData));
} }

View File

@ -3,6 +3,7 @@
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Utility/Formats/MTLParser.hpp> #include <Nazara/Utility/Formats/MTLParser.hpp>
#include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Core/Error.hpp> #include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Log.hpp> #include <Nazara/Core/Log.hpp>
#include <Nazara/Utility/Config.hpp> #include <Nazara/Utility/Config.hpp>
@ -12,36 +13,22 @@
namespace Nz namespace Nz
{ {
MTLParser::MTLParser(Stream& stream) : bool MTLParser::Parse(Stream& stream)
m_stream(stream),
m_streamFlags(stream.GetStreamOptions()) //< Saves stream flags
{ {
m_stream.EnableTextMode(true); 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);
});
} }
MTLParser::~MTLParser()
{
// Reset stream flags
if ((m_streamFlags & StreamOption_Text) == 0)
m_stream.EnableTextMode(false);
}
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;
}
const std::unordered_map<String, MTLParser::Material>& MTLParser::GetMaterials() const
{
return m_materials;
}
bool MTLParser::Parse()
{
m_keepLastLine = false; m_keepLastLine = false;
m_lineCount = 0; m_lineCount = 0;
m_materials.clear(); m_materials.clear();
@ -57,7 +44,7 @@ namespace Nz
if (std::sscanf(&m_currentLine[3], "%f %f %f", &r, &g, &b) == 3) if (std::sscanf(&m_currentLine[3], "%f %f %f", &r, &g, &b) == 3)
{ {
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->ambient = Color(static_cast<UInt8>(r*255.f), static_cast<UInt8>(g*255.f), static_cast<UInt8>(b*255.f)); currentMaterial->ambient = Color(static_cast<UInt8>(r*255.f), static_cast<UInt8>(g*255.f), static_cast<UInt8>(b*255.f));
} }
@ -72,7 +59,7 @@ namespace Nz
if (std::sscanf(&m_currentLine[3], "%f %f %f", &r, &g, &b) == 3) if (std::sscanf(&m_currentLine[3], "%f %f %f", &r, &g, &b) == 3)
{ {
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->diffuse = Color(static_cast<UInt8>(r*255.f), static_cast<UInt8>(g*255.f), static_cast<UInt8>(b*255.f)); currentMaterial->diffuse = Color(static_cast<UInt8>(r*255.f), static_cast<UInt8>(g*255.f), static_cast<UInt8>(b*255.f));
} }
@ -87,7 +74,7 @@ namespace Nz
if (std::sscanf(&m_currentLine[3], "%f %f %f", &r, &g, &b) == 3) if (std::sscanf(&m_currentLine[3], "%f %f %f", &r, &g, &b) == 3)
{ {
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->specular = Color(static_cast<UInt8>(r*255.f), static_cast<UInt8>(g*255.f), static_cast<UInt8>(b*255.f)); currentMaterial->specular = Color(static_cast<UInt8>(r*255.f), static_cast<UInt8>(g*255.f), static_cast<UInt8>(b*255.f));
} }
@ -102,7 +89,7 @@ namespace Nz
if (std::sscanf(&m_currentLine[3], "%f", &density) == 1) if (std::sscanf(&m_currentLine[3], "%f", &density) == 1)
{ {
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->refractionIndex = density; currentMaterial->refractionIndex = density;
} }
@ -117,7 +104,7 @@ namespace Nz
if (std::sscanf(&m_currentLine[3], "%f", &coef) == 1) if (std::sscanf(&m_currentLine[3], "%f", &coef) == 1)
{ {
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->shininess = coef; currentMaterial->shininess = coef;
} }
@ -132,7 +119,7 @@ namespace Nz
if (std::sscanf(&m_currentLine[(keyword[0] == 'd') ? 2 : 3], "%f", &alpha) == 1) if (std::sscanf(&m_currentLine[(keyword[0] == 'd') ? 2 : 3], "%f", &alpha) == 1)
{ {
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->alpha = alpha; currentMaterial->alpha = alpha;
} }
@ -147,7 +134,7 @@ namespace Nz
if (std::sscanf(&m_currentLine[(keyword[0] == 'd') ? 2 : 3], "%f", &alpha) == 1) if (std::sscanf(&m_currentLine[(keyword[0] == 'd') ? 2 : 3], "%f", &alpha) == 1)
{ {
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->alpha = 1.f - alpha; // tr vaut pour la "valeur de transparence", 0 = opaque 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 (std::sscanf(&m_currentLine[6], "%u", &model) == 1)
{ {
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->illumModel = model; currentMaterial->illumModel = model;
} }
@ -178,7 +165,7 @@ namespace Nz
{ {
String map = m_currentLine.SubString(mapPos); String map = m_currentLine.SubString(mapPos);
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->ambientMap = map; currentMaterial->ambientMap = map;
} }
@ -190,7 +177,7 @@ namespace Nz
{ {
String map = m_currentLine.SubString(mapPos); String map = m_currentLine.SubString(mapPos);
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->diffuseMap = map; currentMaterial->diffuseMap = map;
} }
@ -202,7 +189,7 @@ namespace Nz
{ {
String map = m_currentLine.SubString(mapPos); String map = m_currentLine.SubString(mapPos);
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->specularMap = map; currentMaterial->specularMap = map;
} }
@ -214,7 +201,7 @@ namespace Nz
{ {
String map = m_currentLine.SubString(mapPos); String map = m_currentLine.SubString(mapPos);
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->bumpMap = map; currentMaterial->bumpMap = map;
} }
@ -226,7 +213,7 @@ namespace Nz
{ {
String map = m_currentLine.SubString(mapPos); String map = m_currentLine.SubString(mapPos);
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->alphaMap = map; currentMaterial->alphaMap = map;
} }
@ -238,7 +225,7 @@ namespace Nz
{ {
String map = m_currentLine.SubString(mapPos); String map = m_currentLine.SubString(mapPos);
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->decalMap = map; currentMaterial->decalMap = map;
} }
@ -250,7 +237,7 @@ namespace Nz
{ {
String map = m_currentLine.SubString(mapPos); String map = m_currentLine.SubString(mapPos);
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->displacementMap = map; currentMaterial->displacementMap = map;
} }
@ -262,7 +249,7 @@ namespace Nz
{ {
String map = m_currentLine.SubString(mapPos); String map = m_currentLine.SubString(mapPos);
if (!currentMaterial) if (!currentMaterial)
currentMaterial = &m_materials["default"]; currentMaterial = AddMaterial("default");
currentMaterial->reflectionMap = map; currentMaterial->reflectionMap = map;
} }
@ -271,7 +258,7 @@ namespace Nz
{ {
String materialName = m_currentLine.SubString(m_currentLine.GetWordPosition(1)); String materialName = m_currentLine.SubString(m_currentLine.GetWordPosition(1));
if (!materialName.IsEmpty()) if (!materialName.IsEmpty())
currentMaterial = &m_materials[materialName]; currentMaterial = AddMaterial(materialName);
#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
else else
UnrecognizedLine(); UnrecognizedLine();
@ -286,13 +273,150 @@ namespace Nz
return true; 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) bool MTLParser::Advance(bool required)
{ {
if (!m_keepLastLine) if (!m_keepLastLine)
{ {
do do
{ {
if (m_stream.EndOfStream()) if (m_currentStream->EndOfStream())
{ {
if (required) if (required)
Error("Incomplete MTL file"); Error("Incomplete MTL file");
@ -302,7 +426,7 @@ namespace Nz
m_lineCount++; m_lineCount++;
m_currentLine = m_stream.ReadLine(); m_currentLine = m_currentStream->ReadLine();
m_currentLine = m_currentLine.SubStringTo("#"); // On ignore les commentaires m_currentLine = m_currentLine.SubStringTo("#"); // On ignore les commentaires
m_currentLine.Simplify(); // Pour un traitement plus simple m_currentLine.Simplify(); // Pour un traitement plus simple
} }
@ -313,24 +437,4 @@ namespace Nz
return true; 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);
}
} }

View File

@ -49,8 +49,8 @@ namespace Nz
return false; return false;
} }
MTLParser materialParser(file); MTLParser materialParser;
if (!materialParser.Parse()) if (!materialParser.Parse(file))
{ {
NazaraError("MTL parser failed"); NazaraError("MTL parser failed");
return false; return false;
@ -90,13 +90,31 @@ namespace Nz
data.SetParameter(MaterialData::SpecularColor, specularColor); data.SetParameter(MaterialData::SpecularColor, specularColor);
if (!mtlMat->alphaMap.IsEmpty()) 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()) 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()) 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 we either have an alpha value or an alpha map, let's configure the material for transparency
if (alphaValue != 255 || !mtlMat->alphaMap.IsEmpty()) if (alphaValue != 255 || !mtlMat->alphaMap.IsEmpty())

View File

@ -386,10 +386,11 @@ namespace Nz
m_outputStream.Clear(); m_outputStream.Clear();
EmitLine("# Exported by Nazara Engine"); EmitLine("# Exported by Nazara Engine");
EmitLine();
if (!m_mtlLib.IsEmpty()) if (!m_mtlLib.IsEmpty())
{ {
Emit("mtlib "); Emit("mtllib ");
EmitLine(m_mtlLib); EmitLine(m_mtlLib);
EmitLine(); EmitLine();
} }
@ -403,8 +404,6 @@ namespace Nz
Emit(position.x); Emit(position.x);
Emit(' '); Emit(' ');
Emit(position.y); Emit(position.y);
if (!NumberEquals(position.z, 0.f) || !NumberEquals(position.w, 1.f))
{
Emit(' '); Emit(' ');
Emit(position.z); Emit(position.z);
@ -413,7 +412,7 @@ namespace Nz
Emit(' '); Emit(' ');
Emit(position.w); Emit(position.w);
} }
}
EmitLine(); EmitLine();
} }
EmitLine(); EmitLine();

View File

@ -0,0 +1,229 @@
// 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.HasParameter(MaterialData::CustomDefined))
{
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();
meshes[i].faces.resize(triangleCount);
meshes[i].material = staticMesh->GetMaterialIndex();
meshes[i].name = "mesh_" + String::Number(i);
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);
}
}
}

View File

@ -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

View File

@ -606,6 +606,16 @@ namespace Nz
InvalidateAABB(); 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) void Mesh::SetAnimation(const String& animationPath)
{ {
NazaraAssert(m_impl, "Mesh should be created first"); NazaraAssert(m_impl, "Mesh should be created first");

View File

@ -26,6 +26,7 @@
#include <Nazara/Utility/Formats/MD5AnimLoader.hpp> #include <Nazara/Utility/Formats/MD5AnimLoader.hpp>
#include <Nazara/Utility/Formats/MD5MeshLoader.hpp> #include <Nazara/Utility/Formats/MD5MeshLoader.hpp>
#include <Nazara/Utility/Formats/OBJLoader.hpp> #include <Nazara/Utility/Formats/OBJLoader.hpp>
#include <Nazara/Utility/Formats/OBJSaver.hpp>
#include <Nazara/Utility/Formats/PCXLoader.hpp> #include <Nazara/Utility/Formats/PCXLoader.hpp>
#include <Nazara/Utility/Formats/STBLoader.hpp> #include <Nazara/Utility/Formats/STBLoader.hpp>
#include <Nazara/Utility/Formats/STBSaver.hpp> #include <Nazara/Utility/Formats/STBSaver.hpp>
@ -125,10 +126,12 @@ namespace Nz
// Mesh (text) // Mesh (text)
Loaders::RegisterOBJLoader(); Loaders::RegisterOBJLoader();
Loaders::RegisterOBJSaver();
// Mesh // Mesh
Loaders::RegisterMD2(); // Loader de fichiers .md2 (v8) Loaders::RegisterMD2(); // Loader de fichiers .md2 (v8)
Loaders::RegisterMD5Mesh(); // Loader de fichiers .md5mesh (v10) Loaders::RegisterMD5Mesh(); // Loader de fichiers .md5mesh (v10)
Loaders::RegisterOBJLoader(); // Loader de fichiers .md5mesh (v10)
// Image // Image
Loaders::RegisterPCX(); // Loader de fichiers .pcx (1, 4, 8, 24 bits) Loaders::RegisterPCX(); // Loader de fichiers .pcx (1, 4, 8, 24 bits)
@ -163,6 +166,7 @@ namespace Nz
Loaders::UnregisterMD5Anim(); Loaders::UnregisterMD5Anim();
Loaders::UnregisterMD5Mesh(); Loaders::UnregisterMD5Mesh();
Loaders::UnregisterOBJLoader(); Loaders::UnregisterOBJLoader();
Loaders::UnregisterOBJSaver();
Loaders::UnregisterPCX(); Loaders::UnregisterPCX();
Loaders::UnregisterSTBLoader(); Loaders::UnregisterSTBLoader();
Loaders::UnregisterSTBSaver(); Loaders::UnregisterSTBSaver();