diff --git a/SDK/include/NDK/Components/GraphicsComponent.hpp b/SDK/include/NDK/Components/GraphicsComponent.hpp index c94cec4ab..aed427105 100644 --- a/SDK/include/NDK/Components/GraphicsComponent.hpp +++ b/SDK/include/NDK/Components/GraphicsComponent.hpp @@ -31,6 +31,10 @@ namespace Ndk inline void Attach(Nz::InstancedRenderableRef renderable, int renderOrder = 0); + inline void Clear(); + + inline void Detach(const Nz::InstancedRenderableRef& renderable); + inline void EnsureBoundingVolumeUpdate() const; inline void EnsureTransformMatrixUpdate() const; @@ -63,6 +67,22 @@ namespace Ndk { } + Renderable(Renderable&& renderable) noexcept : + data(std::move(renderable.data)), + renderable(std::move(renderable.renderable)), + dataUpdated(renderable.dataUpdated) + { + } + + Renderable& operator=(Renderable&& r) noexcept + { + data = std::move(r.data); + dataUpdated = r.dataUpdated; + renderable = std::move(r.renderable); + + return *this; + } + NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableInvalidateData, renderableInvalidationSlot); mutable Nz::InstancedRenderable::InstanceData data; diff --git a/SDK/include/NDK/Components/GraphicsComponent.inl b/SDK/include/NDK/Components/GraphicsComponent.inl index c330da5eb..9ca100d0e 100644 --- a/SDK/include/NDK/Components/GraphicsComponent.inl +++ b/SDK/include/NDK/Components/GraphicsComponent.inl @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Prerequesites.hpp #include +#include "GraphicsComponent.hpp" namespace Ndk { @@ -46,6 +47,26 @@ namespace Ndk InvalidateBoundingVolume(); } + inline void GraphicsComponent::Clear() + { + m_renderables.clear(); + + InvalidateBoundingVolume(); + } + + inline void GraphicsComponent::Detach(const Nz::InstancedRenderableRef& renderable) + { + for (auto it = m_renderables.begin(); it != m_renderables.end(); ++it) + { + if (it->renderable == renderable) + { + InvalidateBoundingVolume(); + m_renderables.erase(it); + break; + } + } + } + inline void GraphicsComponent::EnsureBoundingVolumeUpdate() const { if (!m_boundingVolumeUpdated) diff --git a/include/Nazara/Core/ObjectRef.hpp b/include/Nazara/Core/ObjectRef.hpp index 6f3ccab9a..d1cd13ec0 100644 --- a/include/Nazara/Core/ObjectRef.hpp +++ b/include/Nazara/Core/ObjectRef.hpp @@ -44,8 +44,33 @@ namespace Nz T* m_object; }; - template struct PointedType> {typedef T type;}; - template struct PointedType const> {typedef T type;}; + template bool operator==(const ObjectRef& lhs, const ObjectRef& rhs); + template bool operator==(const T& lhs, const ObjectRef& rhs); + template bool operator==(const ObjectRef& lhs, const T& rhs); + + template bool operator!=(const ObjectRef& lhs, const ObjectRef& rhs); + template bool operator!=(const T& lhs, const ObjectRef& rhs); + template bool operator!=(const ObjectRef& lhs, const T& rhs); + + template bool operator<(const ObjectRef& lhs, const ObjectRef& rhs); + template bool operator<(const T& lhs, const ObjectRef& rhs); + template bool operator<(const ObjectRef& lhs, const T& rhs); + + template bool operator<=(const ObjectRef, const ObjectRef& rhs); + template bool operator<=(const T& lhs, const ObjectRef& rhs); + template bool operator<=(const ObjectRef& lhs, const T& rhs); + + template bool operator>(const ObjectRef& lhs, const ObjectRef& rhs); + template bool operator>(const T& lhs, const ObjectRef& rhs); + template bool operator>(const ObjectRef& lhs, const T& rhs); + + template bool operator>=(const ObjectRef& lhs, const ObjectRef& rhs); + template bool operator>=(const T& lhs, const ObjectRef& rhs); + template bool operator>=(const ObjectRef& lhs, const T& rhs); + + + template struct PointedType> { typedef T type; }; + template struct PointedType const> { typedef T type; }; } #include diff --git a/include/Nazara/Core/ObjectRef.inl b/include/Nazara/Core/ObjectRef.inl index ad74b4f2e..8dab06948 100644 --- a/include/Nazara/Core/ObjectRef.inl +++ b/include/Nazara/Core/ObjectRef.inl @@ -245,6 +245,241 @@ namespace Nz return *this; } + + + /*! + * \brief Checks whether the first object handle is equal to the second object handle + * \return true if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator==(const ObjectRef& lhs, const ObjectRef& rhs) + { + return lhs.Get() == rhs.Get(); + } + + /*! + * \brief Checks whether the object is equal to the second object handle + * \return true if it is the case + * + * \param first Object to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator==(const T& lhs, const ObjectRef& rhs) + { + return &lhs == rhs.Get(); + } + + /*! + * \brief Checks whether the object handle is equal to the second object + * \return true if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second Object to compare in right hand side + */ + template + bool operator==(const ObjectRef& lhs, const T& rhs) + { + return lhs.Get() == &rhs; + } + + /*! + * \brief Checks whether the first object handle is equal to the second object handle + * \return false if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator!=(const ObjectRef& lhs, const ObjectRef& rhs) + { + return !(lhs == rhs); + } + + /*! + * \brief Checks whether the object is equal to the second object handle + * \return false if it is the case + * + * \param first Object to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator!=(const T& lhs, const ObjectRef& rhs) + { + return !(lhs == rhs); + } + + /*! + * \brief Checks whether the object handle is equal to the second object + * \return false if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second Object to compare in right hand side + */ + template + bool operator!=(const ObjectRef& lhs, const T& rhs) + { + return !(lhs == rhs); + } + + /*! + * \brief Checks whether the first object handle is less than the second object handle + * \return true if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator<(const ObjectRef& lhs, const ObjectRef& rhs) + { + return lhs.m_object < rhs.m_object; + } + + /*! + * \brief Checks whether the first object handle is less than the second object handle + * \return true if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator<(const T& lhs, const ObjectRef& rhs) + { + return &lhs < rhs.m_object; + } + + /*! + * \brief Checks whether the first object handle is less than the second object handle + * \return true if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator<(const ObjectRef& lhs, const T& rhs) + { + return lhs.m_object < &rhs; + } + + /*! + * \brief Checks whether the first object handle is less or equal than the second object handle + * \return true if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator<=(const ObjectRef& lhs, const ObjectRef& rhs) + { + return !(lhs > rhs); + } + + /*! + * \brief Checks whether the first object handle is less or equal than the second object handle + * \return true if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator<=(const T& lhs, const ObjectRef& rhs) + { + return !(lhs > rhs); + } + + /*! + * \brief Checks whether the first object handle is less or equal than the second object handle + * \return true if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator<=(const ObjectRef& lhs, const T& rhs) + { + return !(lhs > rhs); + } + + /*! + * \brief Checks whether the first object handle is greather than the second object handle + * \return true if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator>(const ObjectRef& lhs, const ObjectRef& rhs) + { + return rhs < lhs; + } + + /*! + * \brief Checks whether the first object handle is greather than the second object handle + * \return true if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator>(const T& lhs, const ObjectRef& rhs) + { + return rhs < lhs; + } + + /*! + * \brief Checks whether the first object handle is greather than the second object handle + * \return true if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator>(const ObjectRef& lhs, const T& rhs) + { + return rhs < lhs; + } + + /*! + * \brief Checks whether the first object handle is greather or equal than the second object handle + * \return true if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator>=(const ObjectRef& lhs, const ObjectRef& rhs) + { + return !(lhs < rhs); + } + + /*! + * \brief Checks whether the first object handle is greather or equal than the second object handle + * \return true if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator>=(const T& lhs, const ObjectRef& rhs) + { + return !(lhs < rhs); + } + + /*! + * \brief Checks whether the first object handle is greather or equal than the second object handle + * \return true if it is the case + * + * \param first ObjectRef to compare in left hand side + * \param second ObjectRef to compare in right hand side + */ + template + bool operator>=(const ObjectRef& lhs, const T& rhs) + { + return !(lhs < rhs); + } } namespace std diff --git a/include/Nazara/Core/StringStream.hpp b/include/Nazara/Core/StringStream.hpp index da68e8b27..f727ed35c 100644 --- a/include/Nazara/Core/StringStream.hpp +++ b/include/Nazara/Core/StringStream.hpp @@ -22,6 +22,10 @@ namespace Nz StringStream(const StringStream&) = default; StringStream(StringStream&&) noexcept = default; + void Clear(); + + std::size_t GetBufferSize() const; + String ToString() const; StringStream& operator=(const StringStream&) = default; diff --git a/include/Nazara/Graphics/InstancedRenderable.hpp b/include/Nazara/Graphics/InstancedRenderable.hpp index 561cc4c97..d1c07bf9b 100644 --- a/include/Nazara/Graphics/InstancedRenderable.hpp +++ b/include/Nazara/Graphics/InstancedRenderable.hpp @@ -55,14 +55,27 @@ namespace Nz struct InstanceData { InstanceData(Matrix4f& referenceMatrix) : - transformMatrix(referenceMatrix), + transformMatrix(&referenceMatrix), flags(0) { } + InstanceData(InstanceData&& instanceData) noexcept = default; + + InstanceData& operator=(InstanceData&& instanceData) noexcept + { + data = std::move(instanceData.data); + flags = instanceData.flags; + renderOrder = instanceData.renderOrder; + transformMatrix = instanceData.transformMatrix; + volume = instanceData.volume; + + return *this; + } + std::vector data; BoundingVolumef volume; - Matrix4f& transformMatrix; + Matrix4f* transformMatrix; UInt32 flags; int renderOrder; }; diff --git a/include/Nazara/Graphics/Material.hpp b/include/Nazara/Graphics/Material.hpp index 85c4d315c..b30c215c1 100644 --- a/include/Nazara/Graphics/Material.hpp +++ b/include/Nazara/Graphics/Material.hpp @@ -120,6 +120,8 @@ namespace Nz void Reset(); + void SaveToParameters(ParameterList* matData); + inline bool SetAlphaMap(const String& textureName); inline void SetAlphaMap(TextureRef alphaMap); inline void SetAlphaThreshold(float alphaThreshold); diff --git a/include/Nazara/Math/Vector4.hpp b/include/Nazara/Math/Vector4.hpp index d1e51433a..b84a4cb17 100644 --- a/include/Nazara/Math/Vector4.hpp +++ b/include/Nazara/Math/Vector4.hpp @@ -28,7 +28,7 @@ namespace Nz explicit Vector4(T scale); Vector4(const T vec[4]); Vector4(const Vector2& vec, T Z = 0.0, T W = 1.0); - Vector4(const Vector3& vec, T W = 0.0); + Vector4(const Vector3& vec, T W = 1.0); template explicit Vector4(const Vector4& vec); Vector4(const Vector4& vec) = default; ~Vector4() = default; diff --git a/include/Nazara/Renderer/RenderWindow.hpp b/include/Nazara/Renderer/RenderWindow.hpp index d9889d803..1cda9d63d 100644 --- a/include/Nazara/Renderer/RenderWindow.hpp +++ b/include/Nazara/Renderer/RenderWindow.hpp @@ -65,12 +65,11 @@ namespace Nz protected: bool Activate() const override; void EnsureTargetUpdated() const override; - - private: bool OnWindowCreated() override; void OnWindowDestroy() override; void OnWindowResized() override; + private: mutable std::vector m_buffer; Clock m_clock; ContextParameters m_parameters; diff --git a/include/Nazara/Utility/Formats/OBJParser.hpp b/include/Nazara/Utility/Formats/OBJParser.hpp index 90e653f93..79aa1824a 100644 --- a/include/Nazara/Utility/Formats/OBJParser.hpp +++ b/include/Nazara/Utility/Formats/OBJParser.hpp @@ -29,51 +29,61 @@ namespace Nz struct Face { - std::vector vertices; + std::size_t firstVertex; + std::size_t vertexCount; }; struct Mesh { std::vector faces; + std::vector vertices; String name; - unsigned int material; + std::size_t material; }; - OBJParser(Stream& stream$); - ~OBJParser(); + OBJParser() = default; + ~OBJParser() = default; - const String* GetMaterials() const; - unsigned int GetMaterialCount() const; - const Mesh* GetMeshes() const; - unsigned int GetMeshCount() const; - const String& GetMtlLib() const; - const Vector3f* GetNormals() const; - unsigned int GetNormalCount() const; - const Vector4f* GetPositions() const; - unsigned int GetPositionCount() const; - const Vector3f* GetTexCoords() const; - unsigned int GetTexCoordCount() const; + inline const String* GetMaterials() const; + inline unsigned int GetMaterialCount() const; + inline const Mesh* GetMeshes() const; + inline unsigned int GetMeshCount() const; + inline const String& GetMtlLib() const; + inline const Vector3f* GetNormals() const; + inline unsigned int GetNormalCount() const; + inline const Vector4f* GetPositions() const; + inline unsigned int GetPositionCount() const; + inline const Vector3f* GetTexCoords() const; + inline unsigned int GetTexCoordCount() const; - bool Parse(std::size_t reservedVertexCount = 100); + bool Parse(Stream& stream, std::size_t reservedVertexCount = 100); + + bool Save(Stream& stream) const; 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::vector m_meshes; std::vector m_materials; std::vector m_normals; std::vector m_positions; std::vector m_texCoords; - Stream& m_stream; + mutable Stream* m_currentStream; String m_currentLine; String m_mtlLib; + mutable StringStream m_outputStream; bool m_keepLastLine; unsigned int m_lineCount; - unsigned int m_streamFlags; }; } +#include + #endif // NAZARA_FORMATS_OBJPARSER_HPP diff --git a/include/Nazara/Utility/Formats/OBJParser.inl b/include/Nazara/Utility/Formats/OBJParser.inl new file mode 100644 index 000000000..7cd0060b4 --- /dev/null +++ b/include/Nazara/Utility/Formats/OBJParser.inl @@ -0,0 +1,113 @@ +// 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 const String* OBJParser::GetMaterials() const + { + return m_materials.data(); + } + + inline unsigned int OBJParser::GetMaterialCount() const + { + return m_materials.size(); + } + + inline const OBJParser::Mesh* OBJParser::GetMeshes() const + { + return m_meshes.data(); + } + + inline unsigned int OBJParser::GetMeshCount() const + { + return m_meshes.size(); + } + + inline const String& OBJParser::GetMtlLib() const + { + return m_mtlLib; + } + + inline const Vector3f* OBJParser::GetNormals() const + { + return m_normals.data(); + } + + inline unsigned int OBJParser::GetNormalCount() const + { + return m_normals.size(); + } + + inline const Vector4f* OBJParser::GetPositions() const + { + return m_positions.data(); + } + + inline unsigned int OBJParser::GetPositionCount() const + { + return m_positions.size(); + } + + inline const Vector3f* OBJParser::GetTexCoords() const + { + return m_texCoords.data(); + } + + inline unsigned int OBJParser::GetTexCoordCount() const + { + return m_texCoords.size(); + } + + template + 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 + 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)); + } + + inline void OBJParser::UnrecognizedLine(bool error) + { + String message = "Unrecognized \"" + m_currentLine + '"'; + + if (error) + Error(message); + else + Warning(message); + } +} + +#include diff --git a/include/Nazara/Utility/MaterialData.hpp b/include/Nazara/Utility/MaterialData.hpp index ea8ffd0f5..66df97689 100644 --- a/include/Nazara/Utility/MaterialData.hpp +++ b/include/Nazara/Utility/MaterialData.hpp @@ -22,6 +22,7 @@ namespace Nz static constexpr const char* BackFaceStencilReference = "MatBackFaceStencilReference"; static constexpr const char* BackFaceStencilZFail = "MatBackFaceStencilZFail"; static constexpr const char* Blending = "MatBlending"; + static constexpr const char* CullingSide = "MatCullingSide"; static constexpr const char* CustomDefined = "MatCustomDefined"; static constexpr const char* ColorWrite = "MatColorWrite"; static constexpr const char* DepthBuffer = "MatDepthBuffer"; diff --git a/src/Nazara/Core/PluginManager.cpp b/src/Nazara/Core/PluginManager.cpp index 24fbafcfb..b71af6677 100644 --- a/src/Nazara/Core/PluginManager.cpp +++ b/src/Nazara/Core/PluginManager.cpp @@ -19,8 +19,7 @@ namespace Nz String s_pluginFiles[] = { - "NazaraAssimp", // Plugin_Assimp - "NazaraFreetype" // Plugin_FreeType + "PluginAssimp", // Plugin_Assimp }; } @@ -80,7 +79,13 @@ namespace Nz bool PluginManager::Mount(Plugin plugin) { - return Mount(s_pluginFiles[plugin]); + Nz::String pluginName = s_pluginFiles[plugin]; + #ifdef NAZARA_DEBUG + if (Mount(pluginName + "-d", true)) + return true; + #endif + + return Mount(pluginName, true); } /*! diff --git a/src/Nazara/Core/String.cpp b/src/Nazara/Core/String.cpp index a57d89861..21831bcdf 100644 --- a/src/Nazara/Core/String.cpp +++ b/src/Nazara/Core/String.cpp @@ -211,7 +211,7 @@ namespace Nz */ String::String(const std::string& string) : - String(string.c_str(), string.size()) + String(string.data(), string.size()) { } diff --git a/src/Nazara/Core/StringStream.cpp b/src/Nazara/Core/StringStream.cpp index ebd509c65..14d35799d 100644 --- a/src/Nazara/Core/StringStream.cpp +++ b/src/Nazara/Core/StringStream.cpp @@ -1,3 +1,4 @@ +#include "..\..\..\include\Nazara\Core\StringStream.hpp" // Copyright (C) 2015 Jérôme Leclercq // This file is part of the "Nazara Engine - Core module" // For conditions of distribution and use, see copyright notice in Config.hpp @@ -16,7 +17,6 @@ namespace Nz /*! * \brief Constructs a StringStream object by default */ - StringStream::StringStream() : m_bufferSize(0) { @@ -27,18 +27,34 @@ namespace Nz * * \param str First value of the stream */ - StringStream::StringStream(const String& str) : m_bufferSize(str.GetSize()) { m_strings.push_back(str); } + /*! + * \brief Resets the state of the stream, erasing every contained text + */ + void StringStream::Clear() + { + m_bufferSize = 0; + m_strings.clear(); + } + + /*! + * \brief Get the current buffer size + * \return The internal accumulation buffer size, this is equivalent to the size of the final string + */ + std::size_t StringStream::GetBufferSize() const + { + return m_bufferSize; + } + /*! * \brief Gives a string representation * \return A string representation of the object where every objects of the stream has been converted with Nz::String */ - String StringStream::ToString() const { String string; @@ -56,7 +72,6 @@ namespace Nz * * \param boolean Boolean value */ - StringStream& StringStream::operator<<(bool boolean) { m_strings.push_back(String::Boolean(boolean)); @@ -71,7 +86,6 @@ namespace Nz * * \param number Short value */ - StringStream& StringStream::operator<<(short number) { m_strings.push_back(String::Number(number)); @@ -86,7 +100,6 @@ namespace Nz * * \param number Short value */ - StringStream& StringStream::operator<<(unsigned short number) { m_strings.push_back(String::Number(number)); @@ -101,7 +114,6 @@ namespace Nz * * \param number Int value */ - StringStream& StringStream::operator<<(int number) { m_strings.push_back(String::Number(number)); @@ -116,7 +128,6 @@ namespace Nz * * \param number Int value */ - StringStream& StringStream::operator<<(unsigned int number) { m_strings.push_back(String::Number(number)); @@ -131,7 +142,6 @@ namespace Nz * * \param number Long value */ - StringStream& StringStream::operator<<(long number) { m_strings.push_back(String::Number(number)); @@ -146,7 +156,6 @@ namespace Nz * * \param number Long value */ - StringStream& StringStream::operator<<(unsigned long number) { m_strings.push_back(String::Number(number)); @@ -161,7 +170,6 @@ namespace Nz * * \param number Long long value */ - StringStream& StringStream::operator<<(long long number) { m_strings.push_back(String::Number(number)); @@ -176,7 +184,6 @@ namespace Nz * * \param number Long long value */ - StringStream& StringStream::operator<<(unsigned long long number) { m_strings.push_back(String::Number(number)); @@ -191,7 +198,6 @@ namespace Nz * * \param number Float value */ - StringStream& StringStream::operator<<(float number) { m_strings.push_back(String::Number(number)); @@ -206,7 +212,6 @@ namespace Nz * * \param number Double value */ - StringStream& StringStream::operator<<(double number) { m_strings.push_back(String::Number(number)); @@ -221,7 +226,6 @@ namespace Nz * * \param number Long double value */ - StringStream& StringStream::operator<<(long double number) { m_strings.push_back(String::Number(number)); @@ -236,7 +240,6 @@ namespace Nz * * \param character Char value */ - StringStream& StringStream::operator<<(char character) { m_strings.push_back(String(character)); @@ -251,7 +254,6 @@ namespace Nz * * \param character Char value */ - StringStream& StringStream::operator<<(unsigned char character) { m_strings.push_back(String(static_cast(character))); @@ -266,7 +268,6 @@ namespace Nz * * \param string String value */ - StringStream& StringStream::operator<<(const char* string) { m_strings.push_back(string); @@ -281,7 +282,6 @@ namespace Nz * * \param string String value */ - StringStream& StringStream::operator<<(const std::string& string) { m_strings.push_back(string); @@ -296,7 +296,6 @@ namespace Nz * * \param string String value */ - StringStream& StringStream::operator<<(const String& string) { m_strings.push_back(string); @@ -311,7 +310,6 @@ namespace Nz * * \param ptr Pointer value */ - StringStream& StringStream::operator<<(const void* ptr) { m_strings.push_back(String::Pointer(ptr)); @@ -324,7 +322,6 @@ namespace Nz * \brief Converts this to Nz::String * \return The string representation of the stream */ - StringStream::operator String() const { return ToString(); diff --git a/src/Nazara/Graphics/Billboard.cpp b/src/Nazara/Graphics/Billboard.cpp index 6f47e9847..e06d3c921 100644 --- a/src/Nazara/Graphics/Billboard.cpp +++ b/src/Nazara/Graphics/Billboard.cpp @@ -30,7 +30,7 @@ namespace Nz if (!m_material) return; - renderQueue->AddBillboard(instanceData.renderOrder, m_material, instanceData.transformMatrix.GetTranslation(), m_size, m_sinCos, m_color); + renderQueue->AddBillboard(instanceData.renderOrder, m_material, instanceData.transformMatrix->GetTranslation(), m_size, m_sinCos, m_color); } /* diff --git a/src/Nazara/Graphics/InstancedRenderable.cpp b/src/Nazara/Graphics/InstancedRenderable.cpp index ef5f62b96..03da17984 100644 --- a/src/Nazara/Graphics/InstancedRenderable.cpp +++ b/src/Nazara/Graphics/InstancedRenderable.cpp @@ -80,7 +80,7 @@ namespace Nz NazaraAssert(instanceData, "Invalid instance data"); NazaraUnused(instanceData); - instanceData->volume.Update(instanceData->transformMatrix); + instanceData->volume.Update(*instanceData->transformMatrix); } /*! diff --git a/src/Nazara/Graphics/Material.cpp b/src/Nazara/Graphics/Material.cpp index bfc6ee88a..651f2581c 100644 --- a/src/Nazara/Graphics/Material.cpp +++ b/src/Nazara/Graphics/Material.cpp @@ -170,6 +170,9 @@ namespace Nz if (matData.GetColorParameter(MaterialData::AmbientColor, &color)) SetAmbientColor(color); + if (matData.GetIntegerParameter(MaterialData::CullingSide, &iValue)) + SetFaceCulling(static_cast(iValue)); + if (matData.GetIntegerParameter(MaterialData::DepthFunc, &iValue)) SetDepthFunc(static_cast(iValue)); @@ -182,9 +185,6 @@ namespace Nz if (matData.GetIntegerParameter(MaterialData::DstBlend, &iValue)) SetDstBlend(static_cast(iValue)); - if (matData.GetIntegerParameter(MaterialData::FaceCulling, &iValue)) - SetFaceCulling(static_cast(iValue)); - if (matData.GetIntegerParameter(MaterialData::FaceFilling, &iValue)) SetFaceFilling(static_cast(iValue)); @@ -310,10 +310,108 @@ namespace Nz SetShader(matParams.shaderName); } + void Material::SaveToParameters(ParameterList* matData) + { + NazaraAssert(matData, "Invalid ParameterList"); + + matData->SetParameter(MaterialData::AlphaTest, IsAlphaTestEnabled()); + matData->SetParameter(MaterialData::AlphaThreshold, GetAlphaThreshold()); + matData->SetParameter(MaterialData::AmbientColor, GetAmbientColor()); + matData->SetParameter(MaterialData::CullingSide, int(GetFaceCulling())); + matData->SetParameter(MaterialData::DepthFunc, int(GetDepthFunc())); + matData->SetParameter(MaterialData::DepthSorting, IsDepthSortingEnabled()); + matData->SetParameter(MaterialData::DiffuseColor, GetDiffuseColor()); + matData->SetParameter(MaterialData::DstBlend, int(GetDstBlend())); + matData->SetParameter(MaterialData::FaceFilling, int(GetFaceFilling())); + matData->SetParameter(MaterialData::Lighting, IsLightingEnabled()); + matData->SetParameter(MaterialData::LineWidth, GetRenderStates().lineWidth); + matData->SetParameter(MaterialData::PointSize, GetRenderStates().pointSize); + matData->SetParameter(MaterialData::Shininess, GetShininess()); + matData->SetParameter(MaterialData::SpecularColor, GetSpecularColor()); + matData->SetParameter(MaterialData::SrcBlend, int(GetSrcBlend())); + matData->SetParameter(MaterialData::Transform, IsTransformEnabled()); + + // RendererParameter + matData->SetParameter(MaterialData::Blending, GetRenderStates().parameters[RendererParameter_Blend]); + matData->SetParameter(MaterialData::ColorWrite, GetRenderStates().parameters[RendererParameter_ColorWrite]); + matData->SetParameter(MaterialData::DepthBuffer, GetRenderStates().parameters[RendererParameter_DepthBuffer]); + matData->SetParameter(MaterialData::DepthWrite, GetRenderStates().parameters[RendererParameter_DepthWrite]); + matData->SetParameter(MaterialData::FaceCulling, GetRenderStates().parameters[RendererParameter_FaceCulling]); + matData->SetParameter(MaterialData::ScissorTest, GetRenderStates().parameters[RendererParameter_ScissorTest]); + matData->SetParameter(MaterialData::StencilTest, GetRenderStates().parameters[RendererParameter_StencilTest]); + + // Samplers + matData->SetParameter(MaterialData::DiffuseAnisotropyLevel, int(GetDiffuseSampler().GetAnisotropicLevel())); + matData->SetParameter(MaterialData::DiffuseFilter, int(GetDiffuseSampler().GetFilterMode())); + matData->SetParameter(MaterialData::DiffuseWrap, int(GetDiffuseSampler().GetWrapMode())); + + matData->SetParameter(MaterialData::SpecularAnisotropyLevel, int(GetSpecularSampler().GetAnisotropicLevel())); + matData->SetParameter(MaterialData::SpecularFilter, int(GetSpecularSampler().GetFilterMode())); + matData->SetParameter(MaterialData::SpecularWrap, int(GetSpecularSampler().GetWrapMode())); + + // Stencil + matData->SetParameter(MaterialData::StencilCompare, int(GetRenderStates().frontFace.stencilCompare)); + matData->SetParameter(MaterialData::StencilFail, int(GetRenderStates().frontFace.stencilFail)); + matData->SetParameter(MaterialData::StencilPass, int(GetRenderStates().frontFace.stencilPass)); + matData->SetParameter(MaterialData::StencilZFail, int(GetRenderStates().frontFace.stencilZFail)); + matData->SetParameter(MaterialData::StencilMask, int(GetRenderStates().frontFace.stencilMask)); + matData->SetParameter(MaterialData::StencilReference, int(GetRenderStates().frontFace.stencilReference)); + + // Stencil (back) + matData->SetParameter(MaterialData::BackFaceStencilCompare, int(GetRenderStates().backFace.stencilCompare)); + matData->SetParameter(MaterialData::BackFaceStencilFail, int(GetRenderStates().backFace.stencilFail)); + matData->SetParameter(MaterialData::BackFaceStencilPass, int(GetRenderStates().backFace.stencilPass)); + matData->SetParameter(MaterialData::BackFaceStencilZFail, int(GetRenderStates().backFace.stencilZFail)); + matData->SetParameter(MaterialData::BackFaceStencilMask, int(GetRenderStates().backFace.stencilMask)); + matData->SetParameter(MaterialData::BackFaceStencilReference, int(GetRenderStates().backFace.stencilReference)); + + // Textures + if (HasAlphaMap()) + { + const String& path = GetAlphaMap()->GetFilePath(); + if (!path.IsEmpty()) + matData->SetParameter(MaterialData::AlphaTexturePath, path); + } + + if (HasDiffuseMap()) + { + const String& path = GetDiffuseMap()->GetFilePath(); + if (!path.IsEmpty()) + matData->SetParameter(MaterialData::DiffuseTexturePath, path); + } + + if (HasEmissiveMap()) + { + const String& path = GetEmissiveMap()->GetFilePath(); + if (!path.IsEmpty()) + matData->SetParameter(MaterialData::EmissiveTexturePath, path); + } + + if (HasHeightMap()) + { + const String& path = GetHeightMap()->GetFilePath(); + if (!path.IsEmpty()) + matData->SetParameter(MaterialData::HeightTexturePath, path); + } + + if (HasNormalMap()) + { + const String& path = GetNormalMap()->GetFilePath(); + if (!path.IsEmpty()) + matData->SetParameter(MaterialData::NormalTexturePath, path); + } + + if (HasSpecularMap()) + { + const String& path = GetSpecularMap()->GetFilePath(); + if (!path.IsEmpty()) + matData->SetParameter(MaterialData::SpecularTexturePath, path); + } + } + /*! * \brief Resets the material, cleans everything */ - void Material::Reset() { OnMaterialReset(this); diff --git a/src/Nazara/Graphics/Model.cpp b/src/Nazara/Graphics/Model.cpp index d382c77d9..2b9e03cc1 100644 --- a/src/Nazara/Graphics/Model.cpp +++ b/src/Nazara/Graphics/Model.cpp @@ -82,7 +82,7 @@ namespace Nz meshData.primitiveMode = mesh->GetPrimitiveMode(); meshData.vertexBuffer = mesh->GetVertexBuffer(); - renderQueue->AddMesh(instanceData.renderOrder, material, meshData, mesh->GetAABB(), instanceData.transformMatrix); + renderQueue->AddMesh(instanceData.renderOrder, material, meshData, mesh->GetAABB(), *instanceData.transformMatrix); } } diff --git a/src/Nazara/Graphics/SkeletalModel.cpp b/src/Nazara/Graphics/SkeletalModel.cpp index b91ac0076..8621d1fce 100644 --- a/src/Nazara/Graphics/SkeletalModel.cpp +++ b/src/Nazara/Graphics/SkeletalModel.cpp @@ -69,7 +69,7 @@ namespace Nz meshData.primitiveMode = mesh->GetPrimitiveMode(); meshData.vertexBuffer = SkinningManager::GetBuffer(mesh, &m_skeleton); - renderQueue->AddMesh(instanceData.renderOrder, material, meshData, m_skeleton.GetAABB(), instanceData.transformMatrix); + renderQueue->AddMesh(instanceData.renderOrder, material, meshData, m_skeleton.GetAABB(), *instanceData.transformMatrix); } } diff --git a/src/Nazara/Graphics/Sprite.cpp b/src/Nazara/Graphics/Sprite.cpp index 76bf5fff2..4bf076183 100644 --- a/src/Nazara/Graphics/Sprite.cpp +++ b/src/Nazara/Graphics/Sprite.cpp @@ -58,19 +58,19 @@ namespace Nz SparsePtr texCoordPtr(&vertices[0].uv, sizeof(VertexStruct_XYZ_Color_UV)); *colorPtr++ = m_color; - *posPtr++ = instanceData->transformMatrix.Transform(Vector3f(0.f)); + *posPtr++ = instanceData->transformMatrix->Transform(Vector3f(0.f)); *texCoordPtr++ = m_textureCoords.GetCorner(RectCorner_LeftTop); *colorPtr++ = m_color; - *posPtr++ = instanceData->transformMatrix.Transform(m_size.x*Vector3f::Right()); + *posPtr++ = instanceData->transformMatrix->Transform(m_size.x*Vector3f::Right()); *texCoordPtr++ = m_textureCoords.GetCorner(RectCorner_RightTop); *colorPtr++ = m_color; - *posPtr++ = instanceData->transformMatrix.Transform(m_size.y*Vector3f::Down()); + *posPtr++ = instanceData->transformMatrix->Transform(m_size.y*Vector3f::Down()); *texCoordPtr++ = m_textureCoords.GetCorner(RectCorner_LeftBottom); *colorPtr++ = m_color; - *posPtr++ = instanceData->transformMatrix.Transform(m_size.x*Vector3f::Right() + m_size.y*Vector3f::Down()); + *posPtr++ = instanceData->transformMatrix->Transform(m_size.x*Vector3f::Right() + m_size.y*Vector3f::Down()); *texCoordPtr++ = m_textureCoords.GetCorner(RectCorner_RightBottom); } diff --git a/src/Nazara/Graphics/TextSprite.cpp b/src/Nazara/Graphics/TextSprite.cpp index 42dba4aaf..2f1d733b4 100644 --- a/src/Nazara/Graphics/TextSprite.cpp +++ b/src/Nazara/Graphics/TextSprite.cpp @@ -310,7 +310,7 @@ namespace Nz Vector3f localPos = localVertex->position.x*Vector3f::Right() + localVertex->position.y*Vector3f::Down(); localPos *= m_scale; - *pos++ = instanceData->transformMatrix.Transform(localPos); + *pos++ = instanceData->transformMatrix->Transform(localPos); *color++ = m_color * localVertex->color; *uv++ = localVertex->uv; diff --git a/src/Nazara/Renderer/Texture.cpp b/src/Nazara/Renderer/Texture.cpp index b8bed61a0..458fb9992 100644 --- a/src/Nazara/Renderer/Texture.cpp +++ b/src/Nazara/Renderer/Texture.cpp @@ -582,6 +582,9 @@ namespace Nz } } + // Keep resource path info + SetFilePath(image.GetFilePath()); + destroyOnExit.Reset(); return true; diff --git a/src/Nazara/Utility/Formats/OBJLoader.cpp b/src/Nazara/Utility/Formats/OBJLoader.cpp index 05b39f81f..720b5ec5d 100644 --- a/src/Nazara/Utility/Formats/OBJLoader.cpp +++ b/src/Nazara/Utility/Formats/OBJLoader.cpp @@ -123,8 +123,8 @@ namespace Nz if (!parameters.custom.GetIntegerParameter("NativeOBJLoader_VertexCount", &reservedVertexCount)) reservedVertexCount = 100; - OBJParser parser(stream); - if (!parser.Parse(reservedVertexCount)) + OBJParser parser; + if (!parser.Parse(stream, reservedVertexCount)) { NazaraError("OBJ parser failed"); return false; @@ -177,23 +177,24 @@ namespace Nz { bool operator()(const OBJParser::FaceVertex& lhs, const OBJParser::FaceVertex& rhs) const { - return lhs.normal == rhs.normal && + return lhs.normal == rhs.normal && lhs.position == rhs.position && lhs.texCoord == rhs.texCoord; } }; std::unordered_map vertices; + vertices.reserve(meshes[i].vertices.size()); unsigned int vertexCount = 0; for (unsigned int j = 0; j < faceCount; ++j) { - unsigned int faceVertexCount = meshes[i].faces[j].vertices.size(); + unsigned int faceVertexCount = meshes[i].faces[j].vertexCount; faceIndices.resize(faceVertexCount); for (unsigned int k = 0; k < faceVertexCount; ++k) { - const OBJParser::FaceVertex& vertex = meshes[i].faces[j].vertices[k]; + const OBJParser::FaceVertex& vertex = meshes[i].vertices[meshes[i].faces[j].firstVertex + k]; auto it = vertices.find(vertex); if (it == vertices.end()) @@ -202,6 +203,7 @@ namespace Nz faceIndices[k] = it->second; } + // Triangulation for (unsigned int k = 1; k < faceVertexCount-1; ++k) { indices.push_back(faceIndices[0]); @@ -233,17 +235,17 @@ namespace Nz MeshVertex& vertex = meshVertices[index]; - const Vector4f& vec = positions[vertexIndices.position]; + const Vector4f& vec = positions[vertexIndices.position-1]; vertex.position = Vector3f(parameters.matrix * vec); - if (vertexIndices.normal >= 0) - vertex.normal = normals[vertexIndices.normal]; + if (vertexIndices.normal > 0) + vertex.normal = normals[vertexIndices.normal-1]; else hasNormals = false; - if (vertexIndices.texCoord >= 0) + if (vertexIndices.texCoord > 0) { - const Vector3f& uvw = texCoords[vertexIndices.texCoord]; + const Vector3f& uvw = texCoords[vertexIndices.texCoord-1]; vertex.uv.Set(uvw.x, (parameters.flipUVs) ? 1.f - uvw.y : uvw.y); // Inversion des UVs si demandé } else diff --git a/src/Nazara/Utility/Formats/OBJParser.cpp b/src/Nazara/Utility/Formats/OBJParser.cpp index c0daf1f84..a05ef6960 100644 --- a/src/Nazara/Utility/Formats/OBJParser.cpp +++ b/src/Nazara/Utility/Formats/OBJParser.cpp @@ -3,7 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include +#include #include #include #include @@ -13,77 +13,22 @@ namespace Nz { - OBJParser::OBJParser(Stream& stream) : - m_stream(stream), - m_streamFlags(stream.GetStreamOptions()) //< Saves stream flags + bool OBJParser::Parse(Nz::Stream& stream, std::size_t reservedVertexCount) { - m_stream.EnableTextMode(true); - } + m_currentStream = &stream; - OBJParser::~OBJParser() - { - // 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 String* OBJParser::GetMaterials() const - { - return m_materials.data(); - } + resetTextMode.Reset([&stream] () + { + stream.EnableTextMode(false); + }); + } - unsigned int OBJParser::GetMaterialCount() const - { - return m_materials.size(); - } - - const OBJParser::Mesh* OBJParser::GetMeshes() const - { - return m_meshes.data(); - } - - unsigned int OBJParser::GetMeshCount() const - { - return m_meshes.size(); - } - - const String& OBJParser::GetMtlLib() const - { - return m_mtlLib; - } - - const Vector3f* OBJParser::GetNormals() const - { - return m_normals.data(); - } - - unsigned int OBJParser::GetNormalCount() const - { - return m_normals.size(); - } - - const Vector4f* OBJParser::GetPositions() const - { - return m_positions.data(); - } - - unsigned int OBJParser::GetPositionCount() const - { - return m_positions.size(); - } - - const Vector3f* OBJParser::GetTexCoords() const - { - return m_texCoords.data(); - } - - unsigned int OBJParser::GetTexCoordCount() const - { - return m_texCoords.size(); - } - - bool OBJParser::Parse(std::size_t reservedVertexCount) - { String matName, meshName; matName = meshName = "default"; m_keepLastLine = false; @@ -100,32 +45,56 @@ namespace Nz m_positions.reserve(reservedVertexCount); m_texCoords.reserve(reservedVertexCount); - // On va regrouper les meshs par nom et par matériau - using FaceVec = std::vector; - using MatPair = std::pair; - std::unordered_map> meshes; + // Sort meshes by material and group + using MatPair = std::pair; + std::unordered_map> meshesByName; - unsigned int matIndex = 0; - auto GetMaterial = [&meshes, &matIndex] (const String& mesh, const String& material) -> FaceVec* + std::size_t faceReserve = 0; + std::size_t vertexReserve = 0; + unsigned int matCount = 0; + auto GetMaterial = [&] (const String& meshName, const String& matName) -> Mesh* { - auto& map = meshes[mesh]; - auto it = map.find(material); + auto& map = meshesByName[meshName]; + auto it = map.find(matName); if (it == map.end()) - it = map.insert(std::make_pair(material, MatPair(FaceVec(), matIndex++))).first; + it = map.insert(std::make_pair(matName, MatPair(Mesh(), matCount++))).first; + + Mesh& mesh = it->second.first; + + mesh.faces.reserve(faceReserve); + mesh.vertices.reserve(vertexReserve); + faceReserve = 0; + vertexReserve = 0; return &(it->second.first); }; // On prépare le mesh par défaut - FaceVec* currentMesh = nullptr; + Mesh* currentMesh = nullptr; while (Advance(false)) { switch (std::tolower(m_currentLine[0])) { - case 'f': // Une face + case '#': //< Comment + // Some softwares write comments to gives the number of vertex/faces an importer can expect + std::size_t data; + if (std::sscanf(m_currentLine.GetConstBuffer(), "# position count: %zu", &data) == 1) + m_positions.reserve(data); + else if (std::sscanf(m_currentLine.GetConstBuffer(), "# normal count: %zu", &data) == 1) + m_normals.reserve(data); + else if (std::sscanf(m_currentLine.GetConstBuffer(), "# texcoords count: %zu", &data) == 1) + m_texCoords.reserve(data); + else if (std::sscanf(m_currentLine.GetConstBuffer(), "# face count: %zu", &data) == 1) + faceReserve = data; + else if (std::sscanf(m_currentLine.GetConstBuffer(), "# vertex count: %zu", &data) == 1) + vertexReserve = data; + + break; + + case 'f': //< Face { - if (m_currentLine.GetSize() < 7) // Le minimum syndical pour définir une face de trois sommets (f 1 2 3) + if (m_currentLine.GetSize() < 7) // Since we only treat triangles, this is the minimum length of a face line (f 1 2 3) { #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING UnrecognizedLine(); @@ -142,17 +111,23 @@ namespace Nz break; } + if (!currentMesh) + currentMesh = GetMaterial(meshName, matName); + Face face; - face.vertices.resize(vertexCount); + face.firstVertex = currentMesh->vertices.size(); + face.vertexCount = vertexCount; + + currentMesh->vertices.resize(face.firstVertex + vertexCount, FaceVertex{0, 0, 0}); bool error = false; unsigned int pos = 2; for (unsigned int i = 0; i < vertexCount; ++i) { int offset; - int& n = face.vertices[i].normal; - int& p = face.vertices[i].position; - int& t = face.vertices[i].texCoord; + int& n = currentMesh->vertices[face.firstVertex + i].normal; + int& p = currentMesh->vertices[face.firstVertex + i].position; + int& t = currentMesh->vertices[face.firstVertex + i].texCoord; if (std::sscanf(&m_currentLine[pos], "%d/%d/%d%n", &p, &t, &n, &offset) != 3) { @@ -168,22 +143,13 @@ namespace Nz error = true; break; } - else - { - n = 0; - t = 0; - } } - else - n = 0; } - else - t = 0; } if (p < 0) { - p += m_positions.size(); + p += m_positions.size() - 1; if (p < 0) { Error("Vertex index out of range (" + String::Number(p) + " < 0"); @@ -191,48 +157,42 @@ namespace Nz break; } } - else - p--; if (n < 0) { - n += m_normals.size(); + n += m_normals.size() - 1; if (n < 0) { - Error("Vertex index out of range (" + String::Number(n) + " < 0"); + Error("Normal index out of range (" + String::Number(n) + " < 0"); error = true; break; } } - else - n--; if (t < 0) { - t += m_texCoords.size(); + t += m_texCoords.size() - 1; if (t < 0) { - Error("Vertex index out of range (" + String::Number(t) + " < 0"); + Error("Texture coordinates index out of range (" + String::Number(t) + " < 0"); error = true; break; } } - else - t--; - if (static_cast(p) >= m_positions.size()) + if (static_cast(p) > m_positions.size()) { Error("Vertex index out of range (" + String::Number(p) + " >= " + String::Number(m_positions.size()) + ')'); error = true; break; } - else if (n >= 0 && static_cast(n) >= m_normals.size()) + else if (n != 0 && static_cast(n) > m_normals.size()) { Error("Normal index out of range (" + String::Number(n) + " >= " + String::Number(m_normals.size()) + ')'); error = true; break; } - else if (t >= 0 && static_cast(t) >= m_texCoords.size()) + else if (t != 0 && static_cast(t) > m_texCoords.size()) { Error("TexCoord index out of range (" + String::Number(t) + " >= " + String::Number(m_texCoords.size()) + ')'); error = true; @@ -243,17 +203,14 @@ namespace Nz } if (!error) - { - if (!currentMesh) - currentMesh = GetMaterial(meshName, matName); - - currentMesh->push_back(std::move(face)); - } + currentMesh->faces.push_back(std::move(face)); + else + currentMesh->vertices.resize(face.firstVertex); //< Remove vertices break; } - case 'm': + case 'm': //< MTLLib #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING if (m_currentLine.GetWord(0).ToLower() != "mtllib") UnrecognizedLine(); @@ -262,8 +219,8 @@ namespace Nz m_mtlLib = m_currentLine.SubString(m_currentLine.GetWordPosition(1)); break; - case 'g': - case 'o': + case 'g': //< Group (inside a mesh) + case 'o': //< Object (defines a mesh) { if (m_currentLine.GetSize() <= 2 || m_currentLine[1] != ' ') { @@ -283,12 +240,12 @@ namespace Nz } meshName = objectName; - currentMesh = GetMaterial(meshName, matName); + currentMesh = nullptr; break; } #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING - case 's': + case 's': //< Smooth if (m_currentLine.GetSize() <= 2 || m_currentLine[1] == ' ') { String param = m_currentLine.SubString(2); @@ -298,15 +255,16 @@ namespace Nz else UnrecognizedLine(); break; - #endif + #endif - case 'u': + case 'u': //< Usemtl #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING if (m_currentLine.GetWord(0) != "usemtl") UnrecognizedLine(); #endif matName = m_currentLine.SubString(m_currentLine.GetWordPosition(1)); + currentMesh = nullptr; if (matName.IsEmpty()) { #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING @@ -314,18 +272,16 @@ namespace Nz #endif break; } - - currentMesh = GetMaterial(meshName, matName); break; - case 'v': + case 'v': //< Position/Normal/Texcoords { String word = m_currentLine.GetWord(0).ToLower(); if (word == 'v') { Vector4f vertex(Vector3f::Zero(), 1.f); unsigned int paramCount = std::sscanf(&m_currentLine[2], "%f %f %f %f", &vertex.x, &vertex.y, &vertex.z, &vertex.w); - if (paramCount >= 3) + if (paramCount >= 1) m_positions.push_back(vertex); #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING else @@ -371,26 +327,24 @@ namespace Nz } std::unordered_map materials; - m_materials.resize(matIndex); + m_materials.resize(matCount); - for (auto& meshIt : meshes) + for (auto& meshPair : meshesByName) { - for (auto& matIt : meshIt.second) + for (auto& matPair : meshPair.second) { - auto& faceVec = matIt.second.first; - unsigned int index = matIt.second.second; - if (!faceVec.empty()) + Mesh& mesh = matPair.second.first; + unsigned int index = matPair.second.second; + if (!mesh.faces.empty()) { - Mesh mesh; - mesh.faces = std::move(faceVec); - mesh.name = meshIt.first; + mesh.name = meshPair.first; - auto it = materials.find(matIt.first); + auto it = materials.find(matPair.first); if (it == materials.end()) { mesh.material = index; - materials[matIt.first] = index; - m_materials[index] = matIt.first; + materials[matPair.first] = index; + m_materials[index] = matPair.first; } else mesh.material = it->second; @@ -409,13 +363,155 @@ 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 /* 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) { do { - if (m_stream.EndOfStream()) + if (m_currentStream->EndOfStream()) { if (required) Error("Incomplete OBJ file"); @@ -425,9 +521,8 @@ namespace Nz m_lineCount++; - m_currentLine = m_stream.ReadLine(); - m_currentLine = m_currentLine.SubStringTo("#"); // On ignore les commentaires - m_currentLine.Simplify(); // Pour un traitement plus simple + m_currentLine = m_currentStream->ReadLine(); + m_currentLine.Simplify(); // Simplify lines (convert multiple blanks into a single space and trims) } while (m_currentLine.IsEmpty()); } @@ -436,24 +531,4 @@ namespace Nz return true; } - - void OBJParser::Error(const String& message) - { - NazaraError(message + " at line #" + String::Number(m_lineCount)); - } - - void OBJParser::Warning(const String& message) - { - NazaraWarning(message + " at line #" + String::Number(m_lineCount)); - } - - void OBJParser::UnrecognizedLine(bool error) - { - String message = "Unrecognized \"" + m_currentLine + '"'; - - if (error) - Error(message); - else - Warning(message); - } }