diff --git a/include/Nazara/Audio/Algorithm.inl b/include/Nazara/Audio/Algorithm.inl index ec89cdca9..1075a8b57 100644 --- a/include/Nazara/Audio/Algorithm.inl +++ b/include/Nazara/Audio/Algorithm.inl @@ -7,11 +7,21 @@ namespace Nz { + /*! + * \ingroup audio + * \brief Mixes channels in mono + * + * \param input Input buffer with multiples channels + * \param output Output butter for mono + * \param channelCount Number of channels + * \param frameCount Number of frames + * + * \remark The input buffer may be the same as the output one + */ template void MixToMono(T* input, T* output, unsigned int channelCount, unsigned int frameCount) { - ///DOC: Le buffer d'entrée peut être le même que le buffer de sortie - // Pour éviter l'overflow, on utilise comme accumulateur un type assez grand, (u)int 64 bits pour les entiers, double pour les flottants + // To avoid overflow, we use, as an accumulator, a type which is large enough: (u)int 64 bits for integers, double for floatings typedef typename std::conditional::value, UInt64, Int64>::type BiggestInt; typedef typename std::conditional::value, BiggestInt, double>::type Biggest; @@ -19,7 +29,7 @@ namespace Nz { Biggest acc = Biggest(0); for (unsigned int j = 0; j < channelCount; ++j) - acc += input[i*channelCount + j]; + acc += input[i * channelCount + j]; output[i] = static_cast(acc / channelCount); } diff --git a/include/Nazara/Audio/Config.hpp b/include/Nazara/Audio/Config.hpp index e11bda468..8e2068069 100644 --- a/include/Nazara/Audio/Config.hpp +++ b/include/Nazara/Audio/Config.hpp @@ -27,18 +27,23 @@ #ifndef NAZARA_CONFIG_AUDIO_HPP #define NAZARA_CONFIG_AUDIO_HPP -/// Modifier la configuration d'un module nécessite une recompilation quasi-intégrale de celui-ci et de ceux en héritant +/*! +* \defgroup audio (NazaraAudio) Audio module +* Audio/System module including classes to handle music, sound, etc... +*/ -// Utilise un manager de mémoire pour gérer les allocations dynamiques (détecte les leaks au prix d'allocations/libérations dynamiques plus lentes) +/// Each modification of a parameter needs a recompilation of the module + +// Use the MemoryManager to manage dynamic allocations (can detect memory leak but allocations/frees are slower) #define NAZARA_AUDIO_MANAGE_MEMORY 0 -// Active les tests de sécurité supplémentaires (Teste notamment les arguments des fonctions, conseillé pour le développement) +// Activate the security tests based on the code (Advised for development) #define NAZARA_AUDIO_SAFE 1 -// Le nombre de buffers utilisés lors du streaming d'objets audio (Au moins deux) +// The number of buffers used for audio streaming (At least two) #define NAZARA_AUDIO_STREAMED_BUFFER_COUNT 2 -/// Vérification des valeurs et types de certaines constantes +/// Checking the values and types of certain constants #include #if !defined(NAZARA_STATIC) diff --git a/include/Nazara/Audio/ConfigCheck.hpp b/include/Nazara/Audio/ConfigCheck.hpp index 9ed35c1a4..70d0c6fe5 100644 --- a/include/Nazara/Audio/ConfigCheck.hpp +++ b/include/Nazara/Audio/ConfigCheck.hpp @@ -7,12 +7,12 @@ #ifndef NAZARA_CONFIG_CHECK_AUDIO_HPP #define NAZARA_CONFIG_CHECK_AUDIO_HPP -/// Ce fichier sert à vérifier la valeur des constantes du fichier Config.hpp +/// This file is used to check the constant values defined in Config.hpp #include #define NazaraCheckTypeAndVal(name, type, op, val, err) static_assert(std::is_ ##type ::value && name op val, #type err) -// On force la valeur de MANAGE_MEMORY en mode debug +// We force the value of MANAGE_MEMORY in debug #if defined(NAZARA_DEBUG) && !NAZARA_AUDIO_MANAGE_MEMORY #undef NAZARA_AUDIO_MANAGE_MEMORY #define NAZARA_AUDIO_MANAGE_MEMORY 0 diff --git a/include/Nazara/Audio/DebugOff.hpp b/include/Nazara/Audio/DebugOff.hpp index 254d7701d..e5149d5b5 100644 --- a/include/Nazara/Audio/DebugOff.hpp +++ b/include/Nazara/Audio/DebugOff.hpp @@ -2,7 +2,7 @@ // This file is part of the "Nazara Engine - Audio module" // For conditions of distribution and use, see copyright notice in Config.hpp -// On suppose que Debug.hpp a déjà été inclus, tout comme Config.hpp +// We assume that Debug.hpp has already been included, same thing for Config.hpp #if NAZARA_AUDIO_MANAGE_MEMORY #undef delete #undef new diff --git a/include/Nazara/Audio/Enums.hpp b/include/Nazara/Audio/Enums.hpp index b8d3e3ec6..20866e5e9 100644 --- a/include/Nazara/Audio/Enums.hpp +++ b/include/Nazara/Audio/Enums.hpp @@ -13,7 +13,7 @@ namespace Nz { AudioFormat_Unknown = -1, - // La valeur entière est le nombre de canaux possédés par ce format + // The integer value is the number of channels used by the format AudioFormat_Mono = 1, AudioFormat_Stereo = 2, AudioFormat_Quad = 4, diff --git a/include/Nazara/Audio/OpenAL.hpp b/include/Nazara/Audio/OpenAL.hpp index eab95e6d0..aa80f406e 100644 --- a/include/Nazara/Audio/OpenAL.hpp +++ b/include/Nazara/Audio/OpenAL.hpp @@ -15,18 +15,18 @@ #include #include -// Inclusion des headers OpenAL +// Inclusion of OpenAL headers -// Étant donné que les headers OpenAL ne nous permettent pas de n'avoir que les signatures sans les pointeurs de fonctions -// Et que je ne souhaite pas les modifier, je suis contraint de les placer dans un espace de nom différent pour ensuite -// remettre dans l'espace global les choses intéressantes (les typedef notamment) +// OpenAL headers does not allow us to only get the signatures without the pointers to the functions +// And I do no want to modify them, I'm obliged to put them in a different namespace +// to put only interesting things back in the global namespace (specially typedef) namespace OpenALDetail { #include #include } -// Si quelqu'un a une meilleure idée ... +// If someone has a better idea ... using OpenALDetail::ALboolean; using OpenALDetail::ALbyte; using OpenALDetail::ALchar; diff --git a/include/Nazara/Audio/SoundBuffer.inl b/include/Nazara/Audio/SoundBuffer.inl index 9c5d1198b..a4c42be69 100644 --- a/include/Nazara/Audio/SoundBuffer.inl +++ b/include/Nazara/Audio/SoundBuffer.inl @@ -7,6 +7,13 @@ namespace Nz { + /*! + * \brief Creates a new sound buffer from the arguments + * \return A reference to the newly created sound buffer + * + * \param args Arguments for the sound buffer + */ + template SoundBufferRef SoundBuffer::New(Args&&... args) { diff --git a/include/Nazara/Audio/SoundEmitter.hpp b/include/Nazara/Audio/SoundEmitter.hpp index d56cd1bca..9a68d88cc 100644 --- a/include/Nazara/Audio/SoundEmitter.hpp +++ b/include/Nazara/Audio/SoundEmitter.hpp @@ -12,7 +12,7 @@ #include #include -///TODO: Faire hériter SoundEmitter de Node +///TODO: Inherit SoundEmitter from Node namespace Nz { diff --git a/include/Nazara/Core/Algorithm.inl b/include/Nazara/Core/Algorithm.inl index 048fae8e9..6997f8d1e 100644 --- a/include/Nazara/Core/Algorithm.inl +++ b/include/Nazara/Core/Algorithm.inl @@ -78,7 +78,7 @@ namespace Nz * \param v Object to hash * * \remark a HashAppend specialization for type T is required - * + * * \see ComputeHash */ template diff --git a/include/Nazara/Core/ConfigCheck.hpp b/include/Nazara/Core/ConfigCheck.hpp index 8329f4ff0..aa1ac5cfa 100644 --- a/include/Nazara/Core/ConfigCheck.hpp +++ b/include/Nazara/Core/ConfigCheck.hpp @@ -12,7 +12,7 @@ #include #define NazaraCheckTypeAndVal(name, type, op, val, err) static_assert(std::is_ ##type ::value && name op val, #type err) -// We fore the value of MANAGE_MEMORY in debug +// We force the value of MANAGE_MEMORY in debug #if defined(NAZARA_DEBUG) && !NAZARA_CORE_MANAGE_MEMORY #undef NAZARA_CORE_MANAGE_MEMORY #define NAZARA_CORE_MANAGE_MEMORY 0 diff --git a/include/Nazara/Core/HandledObject.inl b/include/Nazara/Core/HandledObject.inl index da435302e..6b4d64c45 100644 --- a/include/Nazara/Core/HandledObject.inl +++ b/include/Nazara/Core/HandledObject.inl @@ -10,6 +10,17 @@ namespace Nz { + /*! + * \ingroup core + * \class Nz::HandledObject + * \brief Core class that represents a handled object + */ + + /*! + * \brief Constructs a HandledObject object by assignation + * + * \param object HandledObject to assign into this + */ template HandledObject::HandledObject(const HandledObject& object) { @@ -17,6 +28,11 @@ namespace Nz // Don't copy anything, we're a copy of the object, we have no handle right now } + /*! + * \brief Constructs a HandledObject object by move semantic + * + * \param object HandledObject to move into this + */ template HandledObject::HandledObject(HandledObject&& object) : m_handles(std::move(object.m_handles)) @@ -25,25 +41,46 @@ namespace Nz handle->OnObjectMoved(static_cast(this)); } + /*! + * \brief Destructs the object and calls UnregisterAllHandles + * + * \see UnregisterAllHandles + */ template HandledObject::~HandledObject() { UnregisterAllHandles(); } + /*! + * \brief Creates a ObjectHandle for this + * \return ObjectHandle to this + */ template ObjectHandle HandledObject::CreateHandle() { return ObjectHandle(static_cast(this)); } + /*! + * \brief Sets the reference of the HandledObject with the handle from another + * \return A reference to this + * + * \param object The other HandledObject + */ template HandledObject& HandledObject::operator=(const HandledObject& object) { // Nothing to do - return *this; + return *this; } + /*! + * \brief Moves the HandledObject into this + * \return A reference to this + * + * \param object HandledObject to move in this + */ template HandledObject& HandledObject::operator=(HandledObject&& object) { @@ -54,13 +91,22 @@ namespace Nz return *this; } + /*! + * \brief Registers a handle + * + * \param handle Handle to register + * + * \remark One handle can only be registered once, errors can occur if it's more than once + */ template void HandledObject::RegisterHandle(ObjectHandle* handle) { - ///DOC: Un handle ne doit être enregistré qu'une fois, des erreurs se produisent s'il l'est plus d'une fois m_handles.push_back(handle); } + /*! + * \brief Unregisters all handles + */ template void HandledObject::UnregisterAllHandles() { @@ -71,10 +117,17 @@ namespace Nz m_handles.clear(); } + /*! + * \brief Unregisters a handle + * + * \param handle Handle to unregister + * + * \remark One handle can only be unregistered once, crash can occur if it's more than once + * \remark Produces a NazaraAssert if handle not registered + */ template void HandledObject::UnregisterHandle(ObjectHandle* handle) noexcept { - ///DOC: Un handle ne doit être libéré qu'une fois, et doit faire partie de la liste, sous peine de crash auto it = std::find(m_handles.begin(), m_handles.end(), handle); NazaraAssert(it != m_handles.end(), "Handle not registered"); @@ -83,6 +136,14 @@ namespace Nz m_handles.pop_back(); } + /*! + * \brief Updates one handle with another + * + * \param oldHandle Old handle to replace + * \param newHandle New handle to take place + * + * \remark Produces a NazaraAssert if handle not registered + */ template void HandledObject::UpdateHandle(ObjectHandle* oldHandle, ObjectHandle* newHandle) noexcept { diff --git a/include/Nazara/Core/ObjectHandle.inl b/include/Nazara/Core/ObjectHandle.inl index cfcd6bc0d..ee6e26268 100644 --- a/include/Nazara/Core/ObjectHandle.inl +++ b/include/Nazara/Core/ObjectHandle.inl @@ -9,12 +9,26 @@ namespace Nz { + /*! + * \ingroup core + * \class Nz::ObjectHandle + * \brief Core class that represents a object handle + */ + + /*! + * \brief Constructs a ObjectHandle object by default + */ template ObjectHandle::ObjectHandle() : m_object(nullptr) { } + /*! + * \brief Constructs a ObjectHandle object with a pointer to an object + * + * \param object Pointer to handle like an object (can be nullptr) + */ template ObjectHandle::ObjectHandle(T* object) : ObjectHandle() @@ -22,59 +36,97 @@ namespace Nz Reset(object); } + /*! + * \brief Constructs a ObjectHandle object by assignation + * + * \param handle ObjectHandle to assign into this + */ template - ObjectHandle::ObjectHandle(const ObjectHandle& handle) : + ObjectHandle::ObjectHandle(const ObjectHandle& handle) : ObjectHandle() { Reset(handle); } + /*! + * \brief Constructs a ObjectHandle object by move semantic + * + * \param handle ObjectHandle to move into this + */ template - ObjectHandle::ObjectHandle(ObjectHandle&& handle) noexcept : + ObjectHandle::ObjectHandle(ObjectHandle&& handle) noexcept : ObjectHandle() { Reset(std::move(handle)); } + /*! + * \brief Destructs the object and calls reset with nullptr + * + * \see Reset + */ template ObjectHandle::~ObjectHandle() { Reset(nullptr); } + /*! + * \brief Gets the underlying object + * \return Underlying object + */ template T* ObjectHandle::GetObject() const { return m_object; } + /*! + * \brief Checks whether the object is valid + * \return true if object is not nullptr + */ template bool ObjectHandle::IsValid() const { return m_object != nullptr; } + /*! + * \brief Resets the content of the ObjectHandle with another object + * + * \param object Object to handle + */ template void ObjectHandle::Reset(T* object) { - // Si nous avions déjà une entité, nous devons l'informer que nous ne pointons plus sur elle + // If we already have an entity, we must alert it that we are not pointing to it anymore if (m_object) m_object->UnregisterHandle(this); m_object = object; if (m_object) - // On informe la nouvelle entité que nous pointons sur elle + // We alert the new entity that we are pointing to it m_object->RegisterHandle(this); } + /*! + * \brief Resets the content of this with another object + * + * \param handle New object to handle + */ template - void ObjectHandle::Reset(const ObjectHandle& handle) + void ObjectHandle::Reset(const ObjectHandle& handle) { Reset(handle.GetObject()); } + /*! + * \brief Resets the content of this with another object by move semantic + * + * \param handle New object to handle to move into this + */ template - void ObjectHandle::Reset(ObjectHandle&& handle) noexcept + void ObjectHandle::Reset(ObjectHandle&& handle) noexcept { if (m_object) m_object->UnregisterHandle(this); @@ -87,12 +139,18 @@ namespace Nz } } + /*! + * \brief Swaps the content of the two ObjectHandle + * \return A reference to this + * + * \param handle ObjectHandle to swap + */ template - ObjectHandle& ObjectHandle::Swap(ObjectHandle& handle) + ObjectHandle& ObjectHandle::Swap(ObjectHandle& handle) { - // Comme nous inversons les handles, nous devons prévenir les entités - // La version par défaut de swap (à base de move) aurait fonctionné, - // mais en enregistrant les handles une fois de plus que nécessaire (à cause de la copie temporaire). + // As we swap the two handles, we must alert the entities + // The default version with swap (move) would be working, + // but will register handles one more time (due to temporary copy). if (m_object) { m_object->UnregisterHandle(this); @@ -105,11 +163,15 @@ namespace Nz handle.m_object->RegisterHandle(this); } - // On effectue l'échange + // We do the swap std::swap(m_object, handle.m_object); return *this; } + /*! + * \brief Gives a string representation + * \return A string representation of the object "ObjectHandle(object representation) or Null" + */ template Nz::String ObjectHandle::ToString() const { @@ -125,24 +187,44 @@ namespace Nz return ss; } + /*! + * \brief Converts the ObjectHandle to bool + * \return true if reference is not nullptr + * + * \see IsValid + */ template ObjectHandle::operator bool() const { return IsValid(); } + /*! + * \brief Dereferences the ObjectHandle + * \return Underlying pointer + */ template ObjectHandle::operator T*() const { return m_object; } + /*! + * \brief Dereferences the ObjectHandle + * \return Underlying pointer + */ template T* ObjectHandle::operator->() const { return m_object; } + /*! + * \brief Assigns the entity into this + * \return A reference to this + * + * \param entity Pointer to handle like an object (can be nullptr) + */ template ObjectHandle& ObjectHandle::operator=(T* entity) { @@ -151,22 +233,37 @@ namespace Nz return *this; } + /*! + * \brief Sets the handle of the ObjectHandle with the handle from another + * \return A reference to this + * + * \param handle The other ObjectHandle + */ template - ObjectHandle& ObjectHandle::operator=(const ObjectHandle& handle) + ObjectHandle& ObjectHandle::operator=(const ObjectHandle& handle) { Reset(handle); return *this; } + /*! + * \brief Moves the ObjectHandle into this + * \return A reference to this + * + * \param handle ObjectHandle to move in this + */ template - ObjectHandle& ObjectHandle::operator=(ObjectHandle&& handle) noexcept + ObjectHandle& ObjectHandle::operator=(ObjectHandle&& handle) noexcept { Reset(std::move(handle)); return *this; } + /*! + * \brief Action to do on object destruction + */ template void ObjectHandle::OnObjectDestroyed() { @@ -174,6 +271,9 @@ namespace Nz m_object = nullptr; } + /*! + * \brief Action to do on object move + */ template void ObjectHandle::OnObjectMoved(T* newObject) { @@ -181,114 +281,247 @@ namespace Nz m_object = newObject; } + /*! + * \brief Output operator + * \return The stream + * + * \param out The stream + * \param handle The ObjectHandle to output + */ template std::ostream& operator<<(std::ostream& out, const ObjectHandle& handle) { return handle.ToString(); } + /*! + * \brief Checks whether the first object handle is equal to the second object handle + * \return true if it is the case + * + * \param first ObjectHandle to compare in left hand side + * \param second ObjectHandle to compare in right hand side + */ template bool operator==(const ObjectHandle& lhs, const ObjectHandle& rhs) { return lhs.GetObject() == rhs.GetObject(); } + /*! + * \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 ObjectHandle to compare in right hand side + */ template bool operator==(const T& lhs, const ObjectHandle& rhs) { return &lhs == rhs.GetObject(); } + /*! + * \brief Checks whether the object handle is equal to the second object + * \return true if it is the case + * + * \param first ObjectHandle to compare in left hand side + * \param second Object to compare in right hand side + */ template bool operator==(const ObjectHandle& lhs, const T& rhs) { return lhs.GetObject() == &rhs; } + /*! + * \brief Checks whether the first object handle is equal to the second object handle + * \return false if it is the case + * + * \param first ObjectHandle to compare in left hand side + * \param second ObjectHandle to compare in right hand side + */ template bool operator!=(const ObjectHandle& lhs, const ObjectHandle& 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 ObjectHandle to compare in right hand side + */ template bool operator!=(const T& lhs, const ObjectHandle& 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 ObjectHandle to compare in left hand side + * \param second Object to compare in right hand side + */ template bool operator!=(const ObjectHandle& 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 ObjectHandle to compare in left hand side + * \param second ObjectHandle to compare in right hand side + */ template bool operator<(const ObjectHandle& lhs, const ObjectHandle& 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 ObjectHandle to compare in left hand side + * \param second ObjectHandle to compare in right hand side + */ template bool operator<(const T& lhs, const ObjectHandle& 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 ObjectHandle to compare in left hand side + * \param second ObjectHandle to compare in right hand side + */ template bool operator<(const ObjectHandle& 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 ObjectHandle to compare in left hand side + * \param second ObjectHandle to compare in right hand side + */ template bool operator<=(const ObjectHandle& lhs, const ObjectHandle& 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 ObjectHandle to compare in left hand side + * \param second ObjectHandle to compare in right hand side + */ template bool operator<=(const T& lhs, const ObjectHandle& 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 ObjectHandle to compare in left hand side + * \param second ObjectHandle to compare in right hand side + */ template bool operator<=(const ObjectHandle& 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 ObjectHandle to compare in left hand side + * \param second ObjectHandle to compare in right hand side + */ template bool operator>(const ObjectHandle& lhs, const ObjectHandle& 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 ObjectHandle to compare in left hand side + * \param second ObjectHandle to compare in right hand side + */ template bool operator>(const T& lhs, const ObjectHandle& 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 ObjectHandle to compare in left hand side + * \param second ObjectHandle to compare in right hand side + */ template bool operator>(const ObjectHandle& 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 ObjectHandle to compare in left hand side + * \param second ObjectHandle to compare in right hand side + */ template bool operator>=(const ObjectHandle& lhs, const ObjectHandle& 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 ObjectHandle to compare in left hand side + * \param second ObjectHandle to compare in right hand side + */ template bool operator>=(const T& lhs, const ObjectHandle& 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 ObjectHandle to compare in left hand side + * \param second ObjectHandle to compare in right hand side + */ template bool operator>=(const ObjectHandle& lhs, const T& rhs) { @@ -301,6 +534,12 @@ namespace Nz namespace std { + /*! + * \brief Swaps two ObjectHandle, specialisation of std + * + * \param lhs First object handle + * \param rhs Second object handle + */ template void swap(Nz::ObjectHandle& lhs, Nz::ObjectHandle& rhs) { diff --git a/include/Nazara/Core/ParameterList.hpp b/include/Nazara/Core/ParameterList.hpp index 119d05cca..751746aea 100644 --- a/include/Nazara/Core/ParameterList.hpp +++ b/include/Nazara/Core/ParameterList.hpp @@ -50,6 +50,8 @@ namespace Nz void SetParameter(const String& name, void* value); void SetParameter(const String& name, void* value, Destructor destructor); + String ToString() const; + ParameterList& operator=(const ParameterList& list); ParameterList& operator=(ParameterList&&) = default; @@ -73,7 +75,7 @@ namespace Nz ParameterType type; union Value { - // On définit un constructeur/destructeur vide, permettant de mettre des classes dans l'union + // We define an empty constructor/destructor, to be able to put classes in the union Value() {} Value(const Value&) {} // Placeholder ~Value() {} @@ -98,4 +100,6 @@ namespace Nz }; } +std::ostream& operator<<(std::ostream& out, const Nz::ParameterList& parameterList); + #endif // NAZARA_PARAMETERLIST_HPP diff --git a/include/Nazara/Core/ResourceLoader.inl b/include/Nazara/Core/ResourceLoader.inl index af0a8a7f0..74e59067d 100644 --- a/include/Nazara/Core/ResourceLoader.inl +++ b/include/Nazara/Core/ResourceLoader.inl @@ -66,7 +66,7 @@ namespace Nz return false; } - File file(path); // Ouvert seulement en cas de besoin + File file(path); // Open only if needed bool found = false; for (Loader& loader : Type::s_loaders) diff --git a/include/Nazara/Graphics/Billboard.inl b/include/Nazara/Graphics/Billboard.inl index c9760d0d1..6c4a1e0a9 100644 --- a/include/Nazara/Graphics/Billboard.inl +++ b/include/Nazara/Graphics/Billboard.inl @@ -7,6 +7,10 @@ namespace Nz { + /*! + * \brief Constructs a Billboard object by default + */ + inline Billboard::Billboard() { SetColor(Color::White); @@ -15,6 +19,12 @@ namespace Nz SetSize(64.f, 64.f); } + /*! + * \brief Constructs a Billboard object with a reference to a material + * + * \param material Reference to a material + */ + inline Billboard::Billboard(MaterialRef material) { SetColor(Color::White); @@ -23,6 +33,12 @@ namespace Nz SetSize(64.f, 64.f); } + /*! + * \brief Constructs a Billboard object with a pointer to a texture + * + * \param texture Pointer to a texture + */ + inline Billboard::Billboard(Texture* texture) { SetColor(Color::White); @@ -31,6 +47,12 @@ namespace Nz SetTexture(texture, true); } + /*! + * \brief Constructs a Billboard object by assignation + * + * \param billboard Billboard to copy into this + */ + inline Billboard::Billboard(const Billboard& billboard) : InstancedRenderable(billboard), m_color(billboard.m_color), @@ -41,31 +63,61 @@ namespace Nz { } + /*! + * \brief Gets the color of the billboard + * \return Current color + */ + inline const Color& Billboard::GetColor() const { return m_color; } + /*! + * \brief Gets the material of the billboard + * \return Current material + */ + inline const MaterialRef& Billboard::GetMaterial() const { return m_material; } + /*! + * \brief Gets the rotation of the billboard + * \return Current rotation + */ + inline float Billboard::GetRotation() const { return m_rotation; } + /*! + * \brief Gets the size of the billboard + * \return Current size + */ + inline const Vector2f& Billboard::GetSize() const { return m_size; } + /*! + * \brief Sets the color of the billboard + * + * \param color Color for the billboard + */ + inline void Billboard::SetColor(const Color& color) { m_color = color; } + /*! + * \brief Sets the default material of the billboard (just default material) + */ + inline void Billboard::SetDefaultMaterial() { MaterialRef material = Material::New(); @@ -75,6 +127,13 @@ namespace Nz SetMaterial(std::move(material)); } + /*! + * \brief Sets the material of the billboard + * + * \param material Material for the billboard + * \param resizeBillboard Should billboard be resized to the material size (diffuse map) + */ + inline void Billboard::SetMaterial(MaterialRef material, bool resizeBillboard) { m_material = std::move(material); @@ -86,25 +145,51 @@ namespace Nz } } + /*! + * \brief Sets the rotation of the billboard + * + * \param rotation Rotation for the billboard + */ + inline void Billboard::SetRotation(float rotation) { m_rotation = rotation; m_sinCos.Set(std::sin(m_rotation), std::cos(m_rotation)); } + /*! + * \brief Sets the size of the billboard + * + * \param size Size for the billboard + */ + inline void Billboard::SetSize(const Vector2f& size) { m_size = size; - // On invalide la bounding box + // We invalidate the bounding volume InvalidateBoundingVolume(); } + /*! + * \brief Sets the size of the billboard + * + * \param sizeX Size in X for the billboard + * \param sizeY Size in Y for the billboard + */ + inline void Billboard::SetSize(float sizeX, float sizeY) { SetSize(Vector2f(sizeX, sizeY)); } + /*! + * \brief Sets the texture of the billboard + * + * \param texture Texture for the billboard + * \param resizeBillboard Should billboard be resized to the texture size + */ + inline void Billboard::SetTexture(TextureRef texture, bool resizeBillboard) { if (!m_material) @@ -118,6 +203,13 @@ namespace Nz m_material->SetDiffuseMap(std::move(texture)); } + /*! + * \brief Sets the current billboard with the content of the other one + * \return A reference to this + * + * \param billboard The other Billboard + */ + inline Billboard& Billboard::operator=(const Billboard& billboard) { InstancedRenderable::operator=(billboard); @@ -131,6 +223,13 @@ namespace Nz return *this; } + /*! + * \brief Creates a new billboard from the arguments + * \return A reference to the newly created billboard + * + * \param args Arguments for the billboard + */ + template BillboardRef Billboard::New(Args&&... args) { diff --git a/include/Nazara/Graphics/ColorBackground.inl b/include/Nazara/Graphics/ColorBackground.inl index 21b67d92c..67b1f2558 100644 --- a/include/Nazara/Graphics/ColorBackground.inl +++ b/include/Nazara/Graphics/ColorBackground.inl @@ -7,6 +7,13 @@ namespace Nz { + /*! + * \brief Creates a new color background from the arguments + * \return A reference to the newly created color background + * + * \param args Arguments for the color background + */ + template ColorBackgroundRef ColorBackground::New(Args&&... args) { diff --git a/include/Nazara/Graphics/Config.hpp b/include/Nazara/Graphics/Config.hpp index 77f1669c4..e47c8d3a5 100644 --- a/include/Nazara/Graphics/Config.hpp +++ b/include/Nazara/Graphics/Config.hpp @@ -27,23 +27,28 @@ #ifndef NAZARA_CONFIG_GRAPHICS_HPP #define NAZARA_CONFIG_GRAPHICS_HPP -/// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci +/*! +* \defgroup graphics (NazaraGraphics) Graphics module +* Graphics/System module including classes to handle graphical elements... +*/ -// À partir de combien d'instances d'un même mesh/matériau l'instancing doit-il être utilisé ? +/// Each modification of a paramater of the module needs a recompilation of the unit + +// How much instances are need of a same mesh/material to enable instancing ? #define NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT 10 -// Utilise un manager de mémoire pour gérer les allocations dynamiques (détecte les leaks au prix d'allocations/libérations dynamiques plus lentes) +// Use the MemoryManager to manage dynamic allocations (can detect memory leak but allocations/frees are slower) #define NAZARA_GRAPHICS_MANAGE_MEMORY 0 -// Active les tests de sécurité basés sur le code (Conseillé pour le développement) +// Activate the security tests based on the code (Advised for development) #define NAZARA_GRAPHICS_SAFE 1 -/// Chaque modification d'un paramètre ci-dessous implique une modification (souvent mineure) du code +/// Each modification of a parameter following implies a modification (often minor) of the code -// Le nombre maximum de lumières qu'un shader standard supportera +// The maximum number of lights in a standard shader #define NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS 3 -/// Vérification des valeurs et types de certaines constantes +/// Checking the values and types of certain constants #include #if defined(NAZARA_STATIC) diff --git a/include/Nazara/Graphics/ConfigCheck.hpp b/include/Nazara/Graphics/ConfigCheck.hpp index e93c8e0ec..c2bbda886 100644 --- a/include/Nazara/Graphics/ConfigCheck.hpp +++ b/include/Nazara/Graphics/ConfigCheck.hpp @@ -7,12 +7,12 @@ #ifndef NAZARA_CONFIG_CHECK_GRAPHICS_HPP #define NAZARA_CONFIG_CHECK_GRAPHICS_HPP -/// Ce fichier sert à vérifier la valeur des constantes du fichier Config.hpp +/// This file is used to check the constant values defined in Config.hpp #include #define NazaraCheckTypeAndVal(name, type, op, val, err) static_assert(std::is_ ##type ::value && name op val, #type err) -// On force la valeur de MANAGE_MEMORY en mode debug +// We fore the value of MANAGE_MEMORY in debug #if defined(NAZARA_DEBUG) && !NAZARA_GRAPHICS_MANAGE_MEMORY #undef NAZARA_GRAPHICS_MANAGE_MEMORY #define NAZARA_GRAPHICS_MANAGE_MEMORY 0 diff --git a/include/Nazara/Graphics/DebugOff.hpp b/include/Nazara/Graphics/DebugOff.hpp index 38a452aab..c90640fc0 100644 --- a/include/Nazara/Graphics/DebugOff.hpp +++ b/include/Nazara/Graphics/DebugOff.hpp @@ -2,7 +2,7 @@ // This file is part of the "Nazara Engine - Graphics module" // For conditions of distribution and use, see copyright notice in Config.hpp -// On suppose que Debug.hpp a déjà été inclus, tout comme Config.hpp +// We suppose that Debug.hpp is already included, same goes for Config.hpp #if NAZARA_GRAPHICS_MANAGE_MEMORY #undef delete #undef new diff --git a/include/Nazara/Graphics/DeferredBloomPass.hpp b/include/Nazara/Graphics/DeferredBloomPass.hpp index 603998d84..5c45a2277 100644 --- a/include/Nazara/Graphics/DeferredBloomPass.hpp +++ b/include/Nazara/Graphics/DeferredBloomPass.hpp @@ -29,7 +29,7 @@ namespace Nz float GetBrightThreshold() const; Texture* GetTexture(unsigned int i) const; - bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const; + bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const; bool Resize(const Vector2ui& dimensions); void SetBlurPassCount(unsigned int passCount); diff --git a/include/Nazara/Graphics/DeferredDOFPass.hpp b/include/Nazara/Graphics/DeferredDOFPass.hpp index 4da8824c7..c3d6e4c0f 100644 --- a/include/Nazara/Graphics/DeferredDOFPass.hpp +++ b/include/Nazara/Graphics/DeferredDOFPass.hpp @@ -23,7 +23,7 @@ namespace Nz DeferredDOFPass(); virtual ~DeferredDOFPass(); - bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const; + bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const; bool Resize(const Vector2ui& dimensions); protected: diff --git a/include/Nazara/Graphics/DeferredFXAAPass.hpp b/include/Nazara/Graphics/DeferredFXAAPass.hpp index 34fc46867..1c74ffb1c 100644 --- a/include/Nazara/Graphics/DeferredFXAAPass.hpp +++ b/include/Nazara/Graphics/DeferredFXAAPass.hpp @@ -21,7 +21,7 @@ namespace Nz DeferredFXAAPass(); virtual ~DeferredFXAAPass(); - bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const; + bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const; protected: RenderStates m_states; diff --git a/include/Nazara/Graphics/DeferredFinalPass.hpp b/include/Nazara/Graphics/DeferredFinalPass.hpp index c800d44d1..f6b633925 100644 --- a/include/Nazara/Graphics/DeferredFinalPass.hpp +++ b/include/Nazara/Graphics/DeferredFinalPass.hpp @@ -21,7 +21,7 @@ namespace Nz DeferredFinalPass(); virtual ~DeferredFinalPass(); - bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const; + bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const; protected: RenderStates m_states; diff --git a/include/Nazara/Graphics/DeferredFogPass.hpp b/include/Nazara/Graphics/DeferredFogPass.hpp index 37466305b..babccb0bf 100644 --- a/include/Nazara/Graphics/DeferredFogPass.hpp +++ b/include/Nazara/Graphics/DeferredFogPass.hpp @@ -21,7 +21,7 @@ namespace Nz DeferredFogPass(); virtual ~DeferredFogPass(); - bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const; + bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const; protected: RenderStates m_states; diff --git a/include/Nazara/Graphics/DeferredForwardPass.hpp b/include/Nazara/Graphics/DeferredForwardPass.hpp index 0b1d8aa0a..cd5341d85 100644 --- a/include/Nazara/Graphics/DeferredForwardPass.hpp +++ b/include/Nazara/Graphics/DeferredForwardPass.hpp @@ -21,7 +21,7 @@ namespace Nz virtual ~DeferredForwardPass(); void Initialize(DeferredRenderTechnique* technique); - bool Process(const SceneData& sceneData, unsigned int workTexture, unsigned sceneTexture) const; + bool Process(const SceneData& sceneData, unsigned int workTexture, unsigned int sceneTexture) const; protected: const ForwardRenderTechnique* m_forwardTechnique; diff --git a/include/Nazara/Graphics/DeferredGeometryPass.hpp b/include/Nazara/Graphics/DeferredGeometryPass.hpp index 652060b3d..15437f0d8 100644 --- a/include/Nazara/Graphics/DeferredGeometryPass.hpp +++ b/include/Nazara/Graphics/DeferredGeometryPass.hpp @@ -21,7 +21,7 @@ namespace Nz DeferredGeometryPass(); virtual ~DeferredGeometryPass(); - bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const; + bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const; bool Resize(const Vector2ui& dimensions); protected: diff --git a/include/Nazara/Graphics/DeferredPhongLightingPass.hpp b/include/Nazara/Graphics/DeferredPhongLightingPass.hpp index 40b480217..68eb96264 100644 --- a/include/Nazara/Graphics/DeferredPhongLightingPass.hpp +++ b/include/Nazara/Graphics/DeferredPhongLightingPass.hpp @@ -28,7 +28,7 @@ namespace Nz bool IsLightMeshesDrawingEnabled() const; - bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const; + bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const; protected: LightUniforms m_directionalLightUniforms; diff --git a/include/Nazara/Graphics/DeferredRenderPass.hpp b/include/Nazara/Graphics/DeferredRenderPass.hpp index d9ad69919..34a4020a6 100644 --- a/include/Nazara/Graphics/DeferredRenderPass.hpp +++ b/include/Nazara/Graphics/DeferredRenderPass.hpp @@ -38,7 +38,7 @@ namespace Nz bool IsEnabled() const; - virtual bool Process(const SceneData& sceneData, unsigned int workTexture, unsigned sceneTexture) const = 0; + virtual bool Process(const SceneData& sceneData, unsigned int workTexture, unsigned int sceneTexture) const = 0; virtual bool Resize(const Vector2ui& GBufferSize); DeferredRenderPass& operator=(const DeferredRenderPass&) = delete; diff --git a/include/Nazara/Graphics/DeferredRenderTechnique.hpp b/include/Nazara/Graphics/DeferredRenderTechnique.hpp index 99d1fc813..e9e357184 100644 --- a/include/Nazara/Graphics/DeferredRenderTechnique.hpp +++ b/include/Nazara/Graphics/DeferredRenderTechnique.hpp @@ -67,7 +67,7 @@ namespace Nz }; std::map>, RenderPassComparator> m_passes; - ForwardRenderTechnique m_forwardTechnique; // Doit être initialisé avant la RenderQueue + ForwardRenderTechnique m_forwardTechnique; // Must be initialized before the RenderQueue DeferredRenderQueue m_renderQueue; mutable RenderBufferRef m_depthStencilBuffer; mutable RenderTexture m_GBufferRTT; diff --git a/include/Nazara/Graphics/DepthRenderQueue.inl b/include/Nazara/Graphics/DepthRenderQueue.inl index 7d6c9221f..a8a8da45e 100644 --- a/include/Nazara/Graphics/DepthRenderQueue.inl +++ b/include/Nazara/Graphics/DepthRenderQueue.inl @@ -6,6 +6,14 @@ namespace Nz { + + /*! + * \brief Checks whether the material is suitable to fit in the render queue + * \return true If it is the case + * + * \param material Material to verify + */ + bool DepthRenderQueue::IsMaterialSuitable(const Material* material) const { NazaraAssert(material, "Invalid material"); diff --git a/include/Nazara/Graphics/Enums.hpp b/include/Nazara/Graphics/Enums.hpp index 6703f88a0..d378058f7 100644 --- a/include/Nazara/Graphics/Enums.hpp +++ b/include/Nazara/Graphics/Enums.hpp @@ -128,7 +128,7 @@ namespace Nz SceneNodeType_Max = SceneNodeType_User }; - // Ces paramètres sont indépendants du matériau: ils peuvent être demandés à tout moment + // These parameters are independant of the material: they can not be asked for the moment enum ShaderFlags { ShaderFlags_None = 0, @@ -139,7 +139,7 @@ namespace Nz ShaderFlags_TextureOverlay = 0x08, ShaderFlags_VertexColor = 0x10, - ShaderFlags_Max = ShaderFlags_VertexColor*2-1 + ShaderFlags_Max = ShaderFlags_VertexColor * 2 - 1 }; } diff --git a/include/Nazara/Graphics/ForwardRenderQueue.hpp b/include/Nazara/Graphics/ForwardRenderQueue.hpp index 9a17f5d2f..c358e331c 100644 --- a/include/Nazara/Graphics/ForwardRenderQueue.hpp +++ b/include/Nazara/Graphics/ForwardRenderQueue.hpp @@ -159,6 +159,7 @@ namespace Nz std::map layers; private: + BillboardData* GetBillboardData(int renderOrder, const Material* material, unsigned int count); Layer& GetLayer(int i); ///TODO: Inline void OnIndexBufferInvalidation(const IndexBuffer* indexBuffer); diff --git a/include/Nazara/Graphics/ForwardRenderTechnique.hpp b/include/Nazara/Graphics/ForwardRenderTechnique.hpp index 447818958..21b3a0899 100644 --- a/include/Nazara/Graphics/ForwardRenderTechnique.hpp +++ b/include/Nazara/Graphics/ForwardRenderTechnique.hpp @@ -31,7 +31,7 @@ namespace Nz AbstractRenderQueue* GetRenderQueue() override; RenderTechniqueType GetType() const override; - void SetMaxLightPassPerObject(unsigned int passCount); + void SetMaxLightPassPerObject(unsigned int maxLightPassPerObject); static bool Initialize(); static void Uninitialize(); @@ -70,11 +70,11 @@ namespace Nz LightUniforms lightUniforms; bool hasLightUniforms; - /// Moins coûteux en mémoire que de stocker un LightUniforms par index de lumière, - /// à voir si ça fonctionne chez tout le monde - int lightOffset; // "Distance" entre Lights[0].type et Lights[1].type + /// Less costly in memory than storing a LightUniforms by index of light, + /// this may not work everywhere + int lightOffset; // "Distance" between Lights[0].type and Lights[1].type - // Autre uniformes + // Other uniforms int eyePosition; int sceneAmbient; int textureOverlay; diff --git a/include/Nazara/Graphics/ForwardRenderTechnique.inl b/include/Nazara/Graphics/ForwardRenderTechnique.inl index bf9e5674c..6490513f8 100644 --- a/include/Nazara/Graphics/ForwardRenderTechnique.inl +++ b/include/Nazara/Graphics/ForwardRenderTechnique.inl @@ -6,6 +6,16 @@ namespace Nz { + /*! + * \brief Sens the uniforms for light + * + * \param shader Shader to send uniforms to + * \param uniforms Uniforms to send + * \param index Index of the light + * \param uniformOffset Offset for the uniform + * \param availableTextureUnit Unit texture available + */ + inline void ForwardRenderTechnique::SendLightUniforms(const Shader* shader, const LightUniforms& uniforms, unsigned int index, unsigned int uniformOffset, UInt8 availableTextureUnit) const { // If anyone got a better idea.. @@ -104,6 +114,14 @@ namespace Nz } } + /*! + * \brief Computes the score for directional light + * \return 0.f + * + * \param object Sphere symbolising the object + * \param light Light to compute + */ + inline float ForwardRenderTechnique::ComputeDirectionalLightScore(const Spheref& object, const AbstractRenderQueue::DirectionalLight& light) { NazaraUnused(object); @@ -113,18 +131,42 @@ namespace Nz return 0.f; } + /*! + * \brief Computes the score for point light + * \return Distance to the light + * + * \param object Sphere symbolising the object + * \param light Light to compute + */ + inline float ForwardRenderTechnique::ComputePointLightScore(const Spheref& object, const AbstractRenderQueue::PointLight& light) { ///TODO: Compute a score depending on the light luminosity return object.SquaredDistance(light.position); } + /*! + * \brief Computes the score for spot light + * \return Distance to the light + * + * \param object Sphere symbolising the object + * \param light Light to compute + */ + inline float ForwardRenderTechnique::ComputeSpotLightScore(const Spheref& object, const AbstractRenderQueue::SpotLight& light) { ///TODO: Compute a score depending on the light luminosity and spot direction return object.SquaredDistance(light.position); } + /*! + * \brief Checks whether the directional light is suitable for the computations + * \return true if light is enoughly close + * + * \param object Sphere symbolising the object + * \param light Light to compute + */ + inline bool ForwardRenderTechnique::IsDirectionalLightSuitable(const Spheref& object, const AbstractRenderQueue::DirectionalLight& light) { NazaraUnused(object); @@ -134,12 +176,28 @@ namespace Nz return true; } + /*! + * \brief Checks whether the point light is suitable for the computations + * \return true if light is enoughly close + * + * \param object Sphere symbolising the object + * \param light Light to compute + */ + inline bool ForwardRenderTechnique::IsPointLightSuitable(const Spheref& object, const AbstractRenderQueue::PointLight& light) { // If the object is too far away from this point light, there is not way it could light it return object.SquaredDistance(light.position) <= light.radius * light.radius; } + /*! + * \brief Checks whether the spot light is suitable for the computations + * \return true if light is enoughly close + * + * \param object Sphere symbolising the object + * \param light Light to compute + */ + inline bool ForwardRenderTechnique::IsSpotLightSuitable(const Spheref& object, const AbstractRenderQueue::SpotLight& light) { ///TODO: Exclude spot lights based on their direction and outer angle? diff --git a/include/Nazara/Graphics/InstancedRenderable.inl b/include/Nazara/Graphics/InstancedRenderable.inl index 0cc97f101..7f2537fbf 100644 --- a/include/Nazara/Graphics/InstancedRenderable.inl +++ b/include/Nazara/Graphics/InstancedRenderable.inl @@ -4,6 +4,12 @@ namespace Nz { + /*! + * \brief Constructs a InstancedRenderable object by assignation + * + * \param renderable InstancedRenderable to copy into this + */ + inline InstancedRenderable::InstancedRenderable(const InstancedRenderable& renderable) : RefCounted(), m_boundingVolume(renderable.m_boundingVolume), @@ -11,22 +17,43 @@ namespace Nz { } + /*! + * \brief Ensures that the bounding volume is up to date + */ + inline void InstancedRenderable::EnsureBoundingVolumeUpdated() const { if (!m_boundingVolumeUpdated) UpdateBoundingVolume(); } + /*! + * \brief Invalidates the bounding volume + */ + inline void InstancedRenderable::InvalidateBoundingVolume() { m_boundingVolumeUpdated = false; } + /*! + * \brief Invalidates the instance data based on flags + * + * \param flags Flags to invalidate + */ + inline void InstancedRenderable::InvalidateInstanceData(UInt32 flags) { OnInstancedRenderableInvalidateData(this, flags); } + /*! + * \brief Sets the current instanced renderable with the content of the other one + * \return A reference to this + * + * \param renderable The other InstancedRenderable + */ + inline InstancedRenderable& InstancedRenderable::operator=(const InstancedRenderable& renderable) { m_boundingVolume = renderable.m_boundingVolume; @@ -35,6 +62,10 @@ namespace Nz return *this; } + /*! + * \brief Updates the bounding volume + */ + inline void InstancedRenderable::UpdateBoundingVolume() const { MakeBoundingVolume(); diff --git a/include/Nazara/Graphics/Light.inl b/include/Nazara/Graphics/Light.inl index edff48a66..2852834b7 100644 --- a/include/Nazara/Graphics/Light.inl +++ b/include/Nazara/Graphics/Light.inl @@ -7,6 +7,10 @@ namespace Nz { + /*! + * \brief Constructs a Light object by default + */ + inline Light::Light(const Light& light) : Renderable(light), m_color(light.m_color), @@ -28,6 +32,12 @@ namespace Nz { } + /*! + * \brief Enables shadow casting + * + * \param castShadows Should shadows be cast + */ + inline void Light::EnableShadowCasting(bool castShadows) { if (m_shadowCastingEnabled != castShadows) @@ -37,72 +47,141 @@ namespace Nz } } + /*! + * \brief Ensures that the shadow map is up to date + */ + inline void Light::EnsureShadowMapUpdate() const { if (!m_shadowMapUpdated) UpdateShadowMap(); } + /*! + * \brief Gets the ambient factor + * \return Current ambient factor + */ + inline float Light::GetAmbientFactor() const { return m_ambientFactor; } + /*! + * \brief Gets the light attenuation (in 1 / R^2) + * \return Attenuation + */ + inline float Light::GetAttenuation() const { return m_attenuation; } + /*! + * \brief Gets the color of the light + * \return Light color + */ + inline Color Light::GetColor() const { return m_color; } + /*! + * \brief Gets the diffuse factor + * \return Current diffuse factor + */ + inline float Light::GetDiffuseFactor() const { return m_diffuseFactor; } + /*! + * \brief Gets the inner angle in spot light + * \return Inner angle + */ + inline float Light::GetInnerAngle() const { return m_innerAngle; } + /*! + * \brief Gets the cosine inner angle in spot light + * \return Cosine inner angle + */ + inline float Light::GetInnerAngleCosine() const { return m_innerAngleCosine; } + /*! + * \brief Gets the inverse of the radius + * \return Inverse of the radius + */ + inline float Light::GetInvRadius() const { return m_invRadius; } + /*! + * \brief Gets the type of the light + * \return Light type + */ + inline LightType Light::GetLightType() const { return m_type; } + /*! + * \brief Gets the outer angle in spot light + * \return Outer angle + */ + inline float Light::GetOuterAngle() const { return m_outerAngle; } + /*! + * \brief Gets the cosine outer angle in spot light + * \return Cosine outer angle + */ + inline float Light::GetOuterAngleCosine() const { return m_outerAngleCosine; } + /*! + * \brief Gets the tangent outer angle in spot light + * \return Tangent outer angle + */ + inline float Light::GetOuterAngleTangent() const { return m_outerAngleTangent; } + /*! + * \brief Gets the radius of the light + * \return Light radius + */ + inline float Light::GetRadius() const { return m_radius; } + /*! + * \brief Gets the shadow map + * \return Reference to the shadow map texture + */ + inline TextureRef Light::GetShadowMap() const { EnsureShadowMapUpdate(); @@ -110,47 +189,97 @@ namespace Nz return m_shadowMap; } + /*! + * \brief Gets the format of the shadow map + * \return Shadow map format + */ + inline PixelFormatType Light::GetShadowMapFormat() const { return m_shadowMapFormat; } + /*! + * \brief Gets the size of the shadow map + * \return Shadow map size + */ + inline const Vector2ui& Light::GetShadowMapSize() const { return m_shadowMapSize; } + /*! + * \brief Checks whether the shadow casting is enabled + * \return true If it is the case + */ + inline bool Light::IsShadowCastingEnabled() const { return m_shadowCastingEnabled; } + /*! + * \brief Sets the ambient factor + * + * \param factor Ambient factor + */ + inline void Light::SetAmbientFactor(float factor) { m_ambientFactor = factor; } + /*! + * \brief Sets the light attenuation (in 1 / R^2) + * + * \param attenuation Light attenuation + */ + inline void Light::SetAttenuation(float attenuation) { m_attenuation = attenuation; } + /*! + * \brief Sets the color of the light + * + * \param color Light color + */ + inline void Light::SetColor(const Color& color) { m_color = color; } + /*! + * \brief Sets the diffuse factor + * + * \param factor Diffuse factor + */ + inline void Light::SetDiffuseFactor(float factor) { m_diffuseFactor = factor; } + /*! + * \brief Sets the inner angle in spot light + * \return innerAngle Inner angle + */ + inline void Light::SetInnerAngle(float innerAngle) { m_innerAngle = innerAngle; m_innerAngleCosine = std::cos(DegreeToRadian(m_innerAngle)); } + /*! + * \brief Sets the type of light + * + * \param type Light type + */ + inline void Light::SetLightType(LightType type) { m_type = type; @@ -158,6 +287,13 @@ namespace Nz InvalidateShadowMap(); } + /*! + * \brief Sets the outer angle in spot light + * \return outerAngle Outer angle + * + * \remark Invalidates the bounding volume + */ + inline void Light::SetOuterAngle(float outerAngle) { m_outerAngle = outerAngle; @@ -167,6 +303,13 @@ namespace Nz InvalidateBoundingVolume(); } + /*! + * \brief Sets the radius of the light + * \return radius Light radius + * + * \remark Invalidates the bounding volume + */ + inline void Light::SetRadius(float radius) { m_radius = radius; @@ -176,6 +319,15 @@ namespace Nz InvalidateBoundingVolume(); } + /*! + * \brief Sets the shadow map format + * + * \param shadowFormat Shadow map format + * + * \remark Invalidates the shadow map + * \remark Produces a NazaraAssert if format is not a depth type + */ + inline void Light::SetShadowMapFormat(PixelFormatType shadowFormat) { NazaraAssert(PixelFormat::GetContent(shadowFormat) == PixelFormatContent_DepthStencil, "Shadow format type is not a depth format"); @@ -185,6 +337,15 @@ namespace Nz InvalidateShadowMap(); } + /*! + * \brief Sets the size of the shadow map + * + * \param size Shadow map size + * + * \remark Invalidates the shadow map + * \remark Produces a NazaraAssert if size is zero + */ + inline void Light::SetShadowMapSize(const Vector2ui& size) { NazaraAssert(size.x > 0 && size.y > 0, "Shadow map size must have a positive size"); @@ -194,6 +355,15 @@ namespace Nz InvalidateShadowMap(); } + /*! + * \brief Sets the current light with the content of the other one + * \return A reference to this + * + * \param light The other Light + * + * \remark Invalidates the shadow map + */ + inline Light& Light::operator=(const Light& light) { Renderable::operator=(light); @@ -218,6 +388,10 @@ namespace Nz return *this; } + /*! + * \brief Invalidates the shadow map + */ + inline void Light::InvalidateShadowMap() { m_shadowMapUpdated = false; diff --git a/include/Nazara/Graphics/Material.hpp b/include/Nazara/Graphics/Material.hpp index 4a110c64f..85c4d315c 100644 --- a/include/Nazara/Graphics/Material.hpp +++ b/include/Nazara/Graphics/Material.hpp @@ -151,7 +151,7 @@ namespace Nz inline Material& operator=(const Material& material); - static MaterialRef GetDefault(); + inline static MaterialRef GetDefault(); template static MaterialRef New(Args&&... args); // Signals: @@ -163,7 +163,7 @@ namespace Nz { const Shader* shader; UberShaderInstance* uberInstance = nullptr; - int uniforms[MaterialUniform_Max+1]; + int uniforms[MaterialUniform_Max + 1]; }; void Copy(const Material& material); @@ -187,7 +187,7 @@ namespace Nz TextureRef m_normalMap; TextureRef m_specularMap; UberShaderConstRef m_uberShader; - mutable ShaderInstance m_shaders[ShaderFlags_Max+1]; + mutable ShaderInstance m_shaders[ShaderFlags_Max + 1]; bool m_alphaTestEnabled; bool m_depthSortingEnabled; bool m_lightingEnabled; diff --git a/include/Nazara/Graphics/Material.inl b/include/Nazara/Graphics/Material.inl index c8559e11f..cdb9e0d5f 100644 --- a/include/Nazara/Graphics/Material.inl +++ b/include/Nazara/Graphics/Material.inl @@ -7,11 +7,21 @@ namespace Nz { + /*! + * \brief Constructs a Material object by default + */ + inline Material::Material() { Reset(); } + /*! + * \brief Constructs a Material object by assignation + * + * \param material Material to copy into this + */ + inline Material::Material(const Material& material) : RefCounted(), Resource(material) @@ -19,11 +29,26 @@ namespace Nz Copy(material); } + /*! + * \brief Destructs the object and calls OnMaterialRelease + * + * \see OnMaterialRelease + */ + inline Material::~Material() { OnMaterialRelease(this); } + /*! + * \brief Enables a renderer parameter + * + * \param renderParameter Parameter for the rendering + * \param enable Should the parameter be enabled + * + * \remark Produces a NazaraAssert if enumeration is invalid + */ + inline void Material::Enable(RendererParameter renderParameter, bool enable) { NazaraAssert(renderParameter <= RendererParameter_Max, "Renderer parameter out of enum"); @@ -31,6 +56,14 @@ namespace Nz m_states.parameters[renderParameter] = enable; } + /*! + * \brief Enables the alpha test + * + * \param alphaTest Should the parameter be enabled + * + * \remark Invalidates the shaders + */ + inline void Material::EnableAlphaTest(bool alphaTest) { m_alphaTestEnabled = alphaTest; @@ -38,12 +71,26 @@ namespace Nz InvalidateShaders(); } + /*! + * \brief Enables the depth sorting + * + * \param depthSorting Should the parameter be enabled + */ + inline void Material::EnableDepthSorting(bool depthSorting) { // Has no influence on shaders m_depthSortingEnabled = depthSorting; } + /*! + * \brief Enables the lighting + * + * \param lighting Should the parameter be enabled + * + * \remark Invalidates the shaders + */ + inline void Material::EnableLighting(bool lighting) { m_lightingEnabled = lighting; @@ -51,12 +98,26 @@ namespace Nz InvalidateShaders(); } + /*! + * \brief Enables the shadow casting + * + * \param castShadows Should shadow casting be enabled + */ + inline void Material::EnableShadowCasting(bool castShadows) { // Has no influence on shaders m_shadowCastingEnabled = castShadows; } + /*! + * \brief Enables the shadow on receiving object + * + * \param receiveShadow Should receiving object have shadows enabled + * + * \remark Invalidates the shaders + */ + inline void Material::EnableShadowReceive(bool receiveShadows) { m_shadowReceiveEnabled = receiveShadows; @@ -64,6 +125,14 @@ namespace Nz InvalidateShaders(); } + /*! + * \brief Enables the transformation + * + * \param transform Should the parameter be enabled + * + * \remark Invalidates the shaders + */ + inline void Material::EnableTransform(bool transform) { m_transformEnabled = transform; @@ -71,91 +140,183 @@ namespace Nz InvalidateShaders(); } + /*! + * \brief Gets the alpha map + * \return Constant reference to the current texture + */ + inline const TextureRef& Material::GetAlphaMap() const { return m_alphaMap; } + /*! + * \brief Gets the alpha threshold + * \return The threshold value for the alpha + */ + inline float Material::GetAlphaThreshold() const { return m_alphaThreshold; } + /*! + * \brief Gets the ambient color + * \return Ambient color + */ + inline Color Material::GetAmbientColor() const { return m_ambientColor; } + /*! + * \brief Gets the function to compare depth + * \return Function comparing the depth of two materials + */ + inline RendererComparison Material::GetDepthFunc() const { return m_states.depthFunc; } + /*! + * \brief Gets the depth material + * \return Constant reference to the depth material + */ + inline const MaterialRef& Material::GetDepthMaterial() const { return m_depthMaterial; } + /*! + * \brief Gets the diffuse color + * \return Diffuse color + */ + inline Color Material::GetDiffuseColor() const { return m_diffuseColor; } + /*! + * \brief Gets the diffuse sampler + * \return Reference to the current texture sampler for the diffuse + */ + inline TextureSampler& Material::GetDiffuseSampler() { return m_diffuseSampler; } + /*! + * \brief Gets the diffuse sampler + * \return Constant reference to the current texture sampler for the diffuse + */ + inline const TextureSampler& Material::GetDiffuseSampler() const { return m_diffuseSampler; } + /*! + * \brief Gets the diffuse map + * \return Constant reference to the texture + */ + const TextureRef& Material::GetDiffuseMap() const { return m_diffuseMap; } + /*! + * \brief Gets the dst in blend + * \return Function for dst blending + */ + inline BlendFunc Material::GetDstBlend() const { return m_states.dstBlend; } + /*! + * \brief Gets the emissive map + * \return Constant reference to the texture + */ + inline const TextureRef& Material::GetEmissiveMap() const { return m_emissiveMap; } + /*! + * \brief Gets the face culling + * \return Current face culling side + */ + inline FaceSide Material::GetFaceCulling() const { return m_states.faceCulling; } + /*! + * \brief Gets the face filling + * \return Current face filling + */ + inline FaceFilling Material::GetFaceFilling() const { return m_states.faceFilling; } + /*! + * \brief Gets the height map + * \return Constant reference to the texture + */ + inline const TextureRef& Material::GetHeightMap() const { return m_heightMap; } + /*! + * \brief Gets the normal map + * \return Constant reference to the texture + */ + inline const TextureRef& Material::GetNormalMap() const { return m_normalMap; } + /*! + * \brief Gets the render states + * \return Constant reference to the render states + */ + inline const RenderStates& Material::GetRenderStates() const { return m_states; } + /*! + * \brief Gets the shader of this material + * \return Constant pointer to the ubershader used + */ + inline const UberShader* Material::GetShader() const { return m_uberShader; } + /*! + * \brief Gets the shader instance based on the flag + * \return Constant pointer to the ubershader instance + * + * \param flags Flag of the shader + */ + inline const UberShaderInstance* Material::GetShaderInstance(UInt32 flags) const { const ShaderInstance& instance = m_shaders[flags]; @@ -165,81 +326,165 @@ namespace Nz return instance.uberInstance; } + /*! + * \brief Gets the shininess + * \return Current shininess + */ + inline float Material::GetShininess() const { return m_shininess; } + /*! + * \brief Gets the specular color + * \return Specular color + */ + inline Color Material::GetSpecularColor() const { return m_specularColor; } + /*! + * \brief Gets the specular map + * \return Constant reference to the texture + */ + inline const TextureRef& Material::GetSpecularMap() const { return m_specularMap; } + /*! + * \brief Gets the specular sampler + * \return Reference to the current texture sampler for the specular + */ + inline TextureSampler& Material::GetSpecularSampler() { return m_specularSampler; } + /*! + * \brief Gets the specular sampler + * \return Constant reference to the current texture sampler for the specular + */ + inline const TextureSampler& Material::GetSpecularSampler() const { return m_specularSampler; } + /*! + * \brief Gets the src in blend + * \return Function for src blending + */ + inline BlendFunc Material::GetSrcBlend() const { return m_states.srcBlend; } + /*! + * \brief Checks whether this material has an alpha map + * \return true If it is the case + */ + inline bool Material::HasAlphaMap() const { return m_alphaMap.IsValid(); } + /*! + * \brief Checks whether this material has a depth material + * \return true If it is the case + */ + inline bool Material::HasDepthMaterial() const { return m_depthMaterial.IsValid(); } + /*! + * \brief Checks whether this material has a diffuse map + * \return true If it is the case + */ + inline bool Material::HasDiffuseMap() const { return m_diffuseMap.IsValid(); } + /*! + * \brief Checks whether this material has a emissive map + * \return true If it is the case + */ + inline bool Material::HasEmissiveMap() const { return m_emissiveMap.IsValid(); } + /*! + * \brief Checks whether this material has a height map + * \return true If it is the case + */ + inline bool Material::HasHeightMap() const { return m_heightMap.IsValid(); } + /*! + * \brief Checks whether this material has a normal map + * \return true If it is the case + */ + inline bool Material::HasNormalMap() const { return m_normalMap.IsValid(); } + /*! + * \brief Checks whether this material has a specular map + * \return true If it is the case + */ + inline bool Material::HasSpecularMap() const { return m_specularMap.IsValid(); } + /*! + * \brief Checks whether this material has alpha test enabled + * \return true If it is the case + */ + inline bool Material::IsAlphaTestEnabled() const { return m_alphaTestEnabled; } + /*! + * \brief Checks whether this material has depth sorting enabled + * \return true If it is the case + */ + inline bool Material::IsDepthSortingEnabled() const { return m_depthSortingEnabled; } + /*! + * \brief Checks whether this material has the render parameter enabled + * \return true If it is the case + * + * \param parameter Parameter for the rendering + * + * \remark Produces a NazaraAssert if enumeration is invalid + */ + inline bool Material::IsEnabled(RendererParameter parameter) const { NazaraAssert(parameter <= RendererParameter_Max, "Renderer parameter out of enum"); @@ -247,41 +492,93 @@ namespace Nz return m_states.parameters[parameter]; } + /*! + * \brief Checks whether this material has lightning enabled + * \return true If it is the case + */ + inline bool Material::IsLightingEnabled() const { return m_lightingEnabled; } + /*! + * \brief Checks whether this material cast shadow + * \return true If it is the case + */ + inline bool Material::IsShadowCastingEnabled() const { return m_shadowCastingEnabled; } + /*! + * \brief Checks whether this material receive shadow + * \return true If it is the case + */ + inline bool Material::IsShadowReceiveEnabled() const { return m_shadowReceiveEnabled; } + /*! + * \brief Checks whether this material has transformation enabled + * \return true If it is the case + */ + inline bool Material::IsTransformEnabled() const { return m_transformEnabled; } + /*! + * \brief Loads the material from file + * \return true if loading is successful + * + * \param filePath Path to the file + * \param params Parameters for the material + */ + inline bool Material::LoadFromFile(const String& filePath, const MaterialParams& params) { return MaterialLoader::LoadFromFile(this, filePath, params); } + /*! + * \brief Loads the material from memory + * \return true if loading is successful + * + * \param data Raw memory + * \param size Size of the memory + * \param params Parameters for the material + */ + inline bool Material::LoadFromMemory(const void* data, std::size_t size, const MaterialParams& params) { return MaterialLoader::LoadFromMemory(this, data, size, params); } + /*! + * \brief Loads the material from stream + * \return true if loading is successful + * + * \param stream Stream to the material + * \param params Parameters for the material + */ + inline bool Material::LoadFromStream(Stream& stream, const MaterialParams& params) { return MaterialLoader::LoadFromStream(this, stream, params); } + /*! + * \brief Sets the alpha map by name + * \return true If successful + * + * \param textureName Named texture + */ + inline bool Material::SetAlphaMap(const String& textureName) { TextureRef texture = TextureLibrary::Query(textureName); @@ -296,6 +593,15 @@ namespace Nz return true; } + /*! + * \brief Sets the alpha map with a reference to a texture + * \return true If successful + * + * \param alphaMap Texture + * + * \remark Invalidates the shaders + */ + inline void Material::SetAlphaMap(TextureRef alphaMap) { m_alphaMap = std::move(alphaMap); @@ -303,31 +609,69 @@ namespace Nz InvalidateShaders(); } + /*! + * \brief Sets the alpha threshold + * + * \param alphaThreshold Threshold for the alpha + */ + inline void Material::SetAlphaThreshold(float alphaThreshold) { m_alphaThreshold = alphaThreshold; } + /*! + * \brief Sets the color for ambient + * + * \param ambient Color for ambient + */ + inline void Material::SetAmbientColor(const Color& ambient) { m_ambientColor = ambient; } + /*! + * \brief Sets the depth functor + * + * \param depthFunc + */ + inline void Material::SetDepthFunc(RendererComparison depthFunc) { m_states.depthFunc = depthFunc; } + /*! + * \brief Sets the depth material + * \return true If successful + * + * \param depthMaterial Material for depth + */ + inline void Material::SetDepthMaterial(MaterialRef depthMaterial) { m_depthMaterial = std::move(depthMaterial); } + /*! + * \brief Sets the color for diffuse + * + * \param diffuse Color for diffuse + */ + inline void Material::SetDiffuseColor(const Color& diffuse) { m_diffuseColor = diffuse; } + /*! + * \brief Sets the diffuse map by name + * \return true If successful + * + * \param textureName Named texture + */ + inline bool Material::SetDiffuseMap(const String& textureName) { TextureRef texture = TextureLibrary::Query(textureName); @@ -342,6 +686,15 @@ namespace Nz return true; } + /*! + * \brief Sets the diffuse map with a reference to a texture + * \return true If successful + * + * \param diffuseMap Texture + * + * \remark Invalidates the shaders + */ + inline void Material::SetDiffuseMap(TextureRef diffuseMap) { m_diffuseMap = std::move(diffuseMap); @@ -349,16 +702,35 @@ namespace Nz InvalidateShaders(); } + /*! + * \brief Sets the diffuse sampler + * + * \param sampler Diffuse sample + */ + inline void Material::SetDiffuseSampler(const TextureSampler& sampler) { m_diffuseSampler = sampler; } + /*! + * \brief Sets the dst in blend + * + * \param func Function for dst blending + */ + inline void Material::SetDstBlend(BlendFunc func) { m_states.dstBlend = func; } + /*! + * \brief Sets the emissive map by name + * \return true If successful + * + * \param textureName Named texture + */ + inline bool Material::SetEmissiveMap(const String& textureName) { TextureRef texture = TextureLibrary::Query(textureName); @@ -373,6 +745,15 @@ namespace Nz return true; } + /*! + * \brief Sets the emissive map with a reference to a texture + * \return true If successful + * + * \param emissiveMap Texture + * + * \remark Invalidates the shaders + */ + inline void Material::SetEmissiveMap(TextureRef emissiveMap) { m_emissiveMap = std::move(emissiveMap); @@ -380,16 +761,35 @@ namespace Nz InvalidateShaders(); } + /*! + * \brief Sets the face culling + * + * \param faceSide Face to cull + */ + inline void Material::SetFaceCulling(FaceSide faceSide) { m_states.faceCulling = faceSide; } + /*! + * \brief Sets the face filling + * + * \param filling Face to fill + */ + inline void Material::SetFaceFilling(FaceFilling filling) { m_states.faceFilling = filling; } + /*! + * \brief Sets the height map by name + * \return true If successful + * + * \param textureName Named texture + */ + inline bool Material::SetHeightMap(const String& textureName) { TextureRef texture = TextureLibrary::Query(textureName); @@ -404,6 +804,15 @@ namespace Nz return true; } + /*! + * \brief Sets the height map with a reference to a texture + * \return true If successful + * + * \param heightMap Texture + * + * \remark Invalidates the shaders + */ + inline void Material::SetHeightMap(TextureRef heightMap) { m_heightMap = std::move(heightMap); @@ -411,6 +820,13 @@ namespace Nz InvalidateShaders(); } + /*! + * \brief Sets the normal map by name + * \return true If successful + * + * \param textureName Named texture + */ + inline bool Material::SetNormalMap(const String& textureName) { TextureRef texture = TextureLibrary::Query(textureName); @@ -425,6 +841,15 @@ namespace Nz return true; } + /*! + * \brief Sets the normal map with a reference to a texture + * \return true If successful + * + * \param normalMap Texture + * + * \remark Invalidates the shaders + */ + inline void Material::SetNormalMap(TextureRef normalMap) { m_normalMap = std::move(normalMap); @@ -432,11 +857,25 @@ namespace Nz InvalidateShaders(); } + /*! + * \brief Sets the render states + * + * \param states States for the rendering + */ + inline void Material::SetRenderStates(const RenderStates& states) { m_states = states; } + /*! + * \brief Sets the shader with a constant reference to a ubershader + * + * \param uberShader Uber shader to apply + * + * \remark Invalidates the shaders + */ + inline void Material::SetShader(UberShaderConstRef uberShader) { m_uberShader = std::move(uberShader); @@ -444,6 +883,13 @@ namespace Nz InvalidateShaders(); } + /*! + * \brief Sets the shader by name + * \return true If successful + * + * \param uberShaderName Named shader + */ + inline bool Material::SetShader(const String& uberShaderName) { UberShaderConstRef uberShader = UberShaderLibrary::Get(uberShaderName); @@ -454,16 +900,35 @@ namespace Nz return true; } + /*! + * \brief Sets the shininess of the material + * + * \param shininess Value of the shininess + */ + inline void Material::SetShininess(float shininess) { m_shininess = shininess; } + /*! + * \brief Sets the color for specular + * + * \param specular Color + */ + inline void Material::SetSpecularColor(const Color& specular) { m_specularColor = specular; } + /*! + * \brief Sets the specular map by name + * \return true If successful + * + * \param textureName Named texture + */ + inline bool Material::SetSpecularMap(const String& textureName) { TextureRef texture = TextureLibrary::Query(textureName); @@ -478,6 +943,15 @@ namespace Nz return true; } + /*! + * \brief Sets the specular map with a reference to a texture + * \return true If successful + * + * \param specularMap Texture + * + * \remark Invalidates the shaders + */ + inline void Material::SetSpecularMap(TextureRef specularMap) { m_specularMap = std::move(specularMap); @@ -485,16 +959,35 @@ namespace Nz InvalidateShaders(); } + /*! + * \brief Sets the specular sampler + * + * \param sampler Specular sample + */ + inline void Material::SetSpecularSampler(const TextureSampler& sampler) { m_specularSampler = sampler; } + /*! + * \brief Sets the src in blend + * + * \param func Function for src blending + */ + inline void Material::SetSrcBlend(BlendFunc func) { m_states.srcBlend = func; } + /*! + * \brief Sets the current material with the content of the other one + * \return A reference to this + * + * \param material The other Material + */ + inline Material& Material::operator=(const Material& material) { Resource::operator=(material); @@ -503,17 +996,33 @@ namespace Nz return *this; } + /*! + * \brief Gets the default material + * \return Reference to the default material + */ + inline MaterialRef Material::GetDefault() { return s_defaultMaterial; } + /*! + * \brief Invalidates the shaders + */ + inline void Material::InvalidateShaders() { for (ShaderInstance& instance : m_shaders) instance.uberInstance = nullptr; } + /*! + * \brief Creates a new material from the arguments + * \return A reference to the newly created material + * + * \param args Arguments for the material + */ + template MaterialRef Material::New(Args&&... args) { diff --git a/include/Nazara/Graphics/Model.hpp b/include/Nazara/Graphics/Model.hpp index b4564d1b8..f119072c8 100644 --- a/include/Nazara/Graphics/Model.hpp +++ b/include/Nazara/Graphics/Model.hpp @@ -68,8 +68,6 @@ namespace Nz bool SetMaterial(unsigned int skinIndex, const String& subMeshName, Material* material); void SetMaterial(unsigned int skinIndex, unsigned int matIndex, Material* material); virtual void SetMesh(Mesh* mesh); - bool SetSequence(const String& sequenceName); - void SetSequence(unsigned int sequenceIndex); void SetSkin(unsigned int skin); void SetSkinCount(unsigned int skinCount); diff --git a/include/Nazara/Graphics/Model.inl b/include/Nazara/Graphics/Model.inl index ea30ebd72..a2b4c3967 100644 --- a/include/Nazara/Graphics/Model.inl +++ b/include/Nazara/Graphics/Model.inl @@ -7,6 +7,13 @@ namespace Nz { + /*! + * \brief Creates a new Model from the arguments + * \return A reference to the newly created model + * + * \param args Arguments for the model + */ + template ModelRef Model::New(Args&&... args) { diff --git a/include/Nazara/Graphics/ParticleDeclaration.hpp b/include/Nazara/Graphics/ParticleDeclaration.hpp index 4fd8b6c33..0edfba85f 100644 --- a/include/Nazara/Graphics/ParticleDeclaration.hpp +++ b/include/Nazara/Graphics/ParticleDeclaration.hpp @@ -62,16 +62,16 @@ namespace Nz /* ** -Lynix: - ** Il serait aussi possible de préciser le stride de façon indépendante, ce que je ne permets pas - ** pour décomplexifier l'interface en enlevant quelque chose que je juge inutile. - ** Si vous pensez que ça peut être utile, n'hésitez pas à me le faire savoir ! + ** It would be also possible to precise the stride by an independant way, what I don't allow + ** to decomplexify the interface of something I consider useless. + ** If you think that could be useful, don't hesitate to make me aware ! */ }; - Component m_components[ParticleComponent_Max+1]; + Component m_components[ParticleComponent_Max + 1]; unsigned int m_stride; - static ParticleDeclaration s_declarations[ParticleLayout_Max+1]; + static ParticleDeclaration s_declarations[ParticleLayout_Max + 1]; static ParticleDeclarationLibrary::LibraryMap s_library; }; } diff --git a/include/Nazara/Graphics/ParticleMapper.inl b/include/Nazara/Graphics/ParticleMapper.inl index a28315312..63c9c49ba 100644 --- a/include/Nazara/Graphics/ParticleMapper.inl +++ b/include/Nazara/Graphics/ParticleMapper.inl @@ -7,10 +7,20 @@ namespace Nz { + /*! + * \brief Gets a pointer to iterate through same components + * \return SparsePtr pointing to same components + * + * \param component Component to get in the declaration + * + * \remark The same components are not continguous but separated by sizeof(ParticleSize) + * \remark Produces a NazaraError if component is disabled + */ + template SparsePtr ParticleMapper::GetComponentPtr(ParticleComponent component) { - // Ensuite le composant qui nous intéresse + // Then the component that are interesting bool enabled; ComponentType type; unsigned int offset; @@ -18,7 +28,7 @@ namespace Nz if (enabled) { - ///TODO: Vérifier le rapport entre le type de l'attribut et le type template ? + ///TODO: Check the ratio between the type of the attribute and the template type ? return SparsePtr(m_ptr + offset, m_declaration->GetStride()); } else @@ -28,10 +38,20 @@ namespace Nz } } + /*! + * \brief Gets a pointer to iterate through same components + * \return SparsePtr pointing to same components + * + * \param component Component to get in the declaration + * + * \remark The same components are not continguous but separated by sizeof(ParticleSize) + * \remark Produces a NazaraError if component is disabled + */ + template SparsePtr ParticleMapper::GetComponentPtr(ParticleComponent component) const { - // Ensuite le composant qui nous intéresse + // Then the component that are interesting bool enabled; ComponentType type; unsigned int offset; @@ -39,7 +59,7 @@ namespace Nz if (enabled) { - ///TODO: Vérifier le rapport entre le type de l'attribut et le type template ? + ///TODO: Check the ratio between the type of the attribute and the template type ? return SparsePtr(m_ptr + offset, m_declaration->GetStride()); } else diff --git a/include/Nazara/Graphics/Renderable.inl b/include/Nazara/Graphics/Renderable.inl index ed445ec96..9a69329a5 100644 --- a/include/Nazara/Graphics/Renderable.inl +++ b/include/Nazara/Graphics/Renderable.inl @@ -4,17 +4,31 @@ namespace Nz { + /*! + * \brief Ensures that the bounding volume is up to date + */ + inline void Renderable::EnsureBoundingVolumeUpdated() const { if (!m_boundingVolumeUpdated) UpdateBoundingVolume(); } + /*! + * \brief Invalidates the bounding volume + */ + inline void Renderable::InvalidateBoundingVolume() { m_boundingVolumeUpdated = false; } + /*! + * \brief Updates the bounding volume by a matrix + * + * \param transformMatrix Matrix transformation for our bounding volume + */ + inline void Renderable::UpdateBoundingVolume() const { MakeBoundingVolume(); diff --git a/include/Nazara/Graphics/SkyboxBackground.inl b/include/Nazara/Graphics/SkyboxBackground.inl index 8edb694c9..6171f1e28 100644 --- a/include/Nazara/Graphics/SkyboxBackground.inl +++ b/include/Nazara/Graphics/SkyboxBackground.inl @@ -7,31 +7,62 @@ namespace Nz { + /*! + * \brief Gets the movement offset + * \return Offset of the movement + */ + inline const Vector3f& Nz::SkyboxBackground::GetMovementOffset() const { return m_movementOffset; } + /*! + * \brief Gets the movement scale + * \return Scale of the movement + */ + inline float SkyboxBackground::GetMovementScale() const { return m_movementScale; } + /*! + * \brief Gets the texture of the background + * \return Texture of the background + */ + inline const TextureRef& SkyboxBackground::GetTexture() const { return m_texture; } + /*! + * \brief Gets the texture sampler of the background + * \return A reference to the texture sampler of the background + */ + inline TextureSampler& SkyboxBackground::GetTextureSampler() { return m_sampler; } + /*! + * \brief Gets the texture sampler of the background + * \return A constant reference to the texture sampler of the background + */ + inline const TextureSampler& SkyboxBackground::GetTextureSampler() const { return m_sampler; } + /*! + * \brief Sets the movement offset + * + * \param offset Offset of the movement + */ + inline void SkyboxBackground::SetMovementOffset(const Vector3f& offset) { NazaraAssert(std::isfinite(offset.x) && std::isfinite(offset.y) && std::isfinite(offset.z), "Offset must be a finite vector"); @@ -39,6 +70,12 @@ namespace Nz m_movementOffset = offset; } + /*! + * \brief Sets the movement scale + * + * \param scale Scale of the movement + */ + inline void SkyboxBackground::SetMovementScale(float scale) { NazaraAssert(std::isfinite(scale), "Scale must be a finite value"); @@ -46,6 +83,12 @@ namespace Nz m_movementScale = scale; } + /*! + * \brief Sets the texture of the background + * + * \param cubemapTexture Texture of the background + */ + inline void SkyboxBackground::SetTexture(TextureRef cubemapTexture) { NazaraAssert(!cubemapTexture || cubemapTexture->IsValid(), "Invalid texture"); @@ -54,11 +97,24 @@ namespace Nz m_texture = std::move(cubemapTexture); } + /*! + * \brief Sets the texture sampler of the background + * + * \param sampler Texture sampler of the background + */ + void SkyboxBackground::SetTextureSampler(const TextureSampler& sampler) { m_sampler = sampler; } + /*! + * \brief Creates a new skybox background from the arguments + * \return A reference to the newly created skybox background + * + * \param args Arguments for the skybox background + */ + template SkyboxBackgroundRef SkyboxBackground::New(Args&&... args) { diff --git a/include/Nazara/Graphics/Sprite.inl b/include/Nazara/Graphics/Sprite.inl index 8969cddf0..840a930e6 100644 --- a/include/Nazara/Graphics/Sprite.inl +++ b/include/Nazara/Graphics/Sprite.inl @@ -8,6 +8,10 @@ namespace Nz { + /*! + * \brief Constructs a Sprite object by default + */ + inline Sprite::Sprite() : m_color(Color::White), m_textureCoords(0.f, 0.f, 1.f, 1.f), @@ -16,6 +20,12 @@ namespace Nz SetDefaultMaterial(); } + /*! + * \brief Constructs a Sprite object with a reference to a material + * + * \param material Reference to a material + */ + inline Sprite::Sprite(MaterialRef material) : m_color(Color::White), m_textureCoords(0.f, 0.f, 1.f, 1.f), @@ -24,6 +34,12 @@ namespace Nz SetMaterial(std::move(material), true); } + /*! + * \brief Constructs a Sprite object with a pointer to a texture + * + * \param texture Pointer to a texture + */ + inline Sprite::Sprite(Texture* texture) : m_color(Color::White), m_textureCoords(0.f, 0.f, 1.f, 1.f), @@ -32,6 +48,12 @@ namespace Nz SetTexture(texture, true); } + /*! + * \brief Constructs a Sprite object by assignation + * + * \param sprite Sprite to copy into this + */ + inline Sprite::Sprite(const Sprite& sprite) : InstancedRenderable(sprite), m_color(sprite.m_color), @@ -41,26 +63,52 @@ namespace Nz { } + /*! + * \brief Gets the color of the sprite + * \return Current color + */ + inline const Color& Sprite::GetColor() const { return m_color; } + /*! + * \brief Gets the material of the sprite + * \return Current material + */ + inline const MaterialRef& Sprite::GetMaterial() const { return m_material; } + /*! + * \brief Gets the size of the sprite + * \return Current size + */ + inline const Vector2f& Sprite::GetSize() const { return m_size; } + /*! + * \brief Gets the texture coordinates of the sprite + * \return Current texture coordinates + */ + inline const Rectf& Sprite::GetTextureCoords() const { return m_textureCoords; } + /*! + * \brief Sets the color of the billboard + * + * \param color Color for the billboard + */ + inline void Sprite::SetColor(const Color& color) { m_color = color; @@ -68,6 +116,10 @@ namespace Nz InvalidateVertices(); } + /*! + * \brief Sets the default material of the sprite (just default material) + */ + inline void Sprite::SetDefaultMaterial() { MaterialRef material = Material::New(); @@ -77,6 +129,13 @@ namespace Nz SetMaterial(std::move(material)); } + /*! + * \brief Sets the material of the sprite + * + * \param material Material for the sprite + * \param resizeSprite Should sprite be resized to the material size (diffuse map) + */ + inline void Sprite::SetMaterial(MaterialRef material, bool resizeSprite) { m_material = std::move(material); @@ -88,6 +147,12 @@ namespace Nz } } + /*! + * \brief Sets the size of the sprite + * + * \param size Size for the sprite + */ + inline void Sprite::SetSize(const Vector2f& size) { m_size = size; @@ -97,11 +162,25 @@ namespace Nz InvalidateVertices(); } + /*! + * \brief Sets the size of the sprite + * + * \param sizeX Size in X for the sprite + * \param sizeY Size in Y for the sprite + */ + inline void Sprite::SetSize(float sizeX, float sizeY) { SetSize(Vector2f(sizeX, sizeY)); } + /*! + * \brief Sets the texture of the sprite + * + * \param texture Texture for the sprite + * \param resizeSprite Should sprite be resized to the texture size + */ + inline void Sprite::SetTexture(TextureRef texture, bool resizeSprite) { if (!m_material) @@ -115,12 +194,27 @@ namespace Nz m_material->SetDiffuseMap(std::move(texture)); } + /*! + * \brief Sets the texture coordinates of the sprite + * + * \param coords Texture coordinates + */ + inline void Sprite::SetTextureCoords(const Rectf& coords) { m_textureCoords = coords; InvalidateVertices(); } + /*! + * \brief Sets the texture rectangle of the sprite + * + * \param rect Rectangles symbolizing the size of the texture + * + * \remark Produces a NazaraAssert if material is invalid + * \remark Produces a NazaraAssert if material has no diffuse map + */ + inline void Sprite::SetTextureRect(const Rectui& rect) { NazaraAssert(m_material, "Sprite has no material"); @@ -128,12 +222,19 @@ namespace Nz Texture* diffuseMap = m_material->GetDiffuseMap(); - float invWidth = 1.f/diffuseMap->GetWidth(); - float invHeight = 1.f/diffuseMap->GetHeight(); + float invWidth = 1.f / diffuseMap->GetWidth(); + float invHeight = 1.f / diffuseMap->GetHeight(); - SetTextureCoords(Rectf(invWidth*rect.x, invHeight*rect.y, invWidth*rect.width, invHeight*rect.height)); + SetTextureCoords(Rectf(invWidth * rect.x, invHeight * rect.y, invWidth * rect.width, invHeight * rect.height)); } + /*! + * \brief Sets the current sprite with the content of the other one + * \return A reference to this + * + * \param sprite The other Sprite + */ + inline Sprite& Sprite::operator=(const Sprite& sprite) { InstancedRenderable::operator=(sprite); @@ -143,18 +244,29 @@ namespace Nz m_textureCoords = sprite.m_textureCoords; m_size = sprite.m_size; - // On ne copie pas les sommets finaux car il est très probable que nos paramètres soient modifiés et qu'ils doivent être régénérés de toute façon + // We do not copy final vertices because it's highly probable that our parameters are modified and they must be regenerated InvalidateBoundingVolume(); InvalidateVertices(); return *this; } + /*! + * \brief Invalidates the vertices + */ + inline void Sprite::InvalidateVertices() { InvalidateInstanceData(0); } + /*! + * \brief Creates a new sprite from the arguments + * \return A reference to the newly created sprite + * + * \param args Arguments for the sprite + */ + template SpriteRef Sprite::New(Args&&... args) { diff --git a/include/Nazara/Graphics/TextSprite.inl b/include/Nazara/Graphics/TextSprite.inl index 312658557..baeeb50db 100644 --- a/include/Nazara/Graphics/TextSprite.inl +++ b/include/Nazara/Graphics/TextSprite.inl @@ -7,6 +7,10 @@ namespace Nz { + /*! + * \brief Constructs a TextSprite object by default + */ + inline TextSprite::TextSprite() : m_color(Color::White), m_scale(1.f) @@ -14,12 +18,24 @@ namespace Nz SetDefaultMaterial(); } + /*! + * \brief Constructs a TextSprite object with a drawer + * + * \param drawer Drawer used to compose text on the sprite + */ + inline TextSprite::TextSprite(const AbstractTextDrawer& drawer) : TextSprite() { Update(drawer); } + /*! + * \brief Constructs a TextSprite object by assignation + * + * \param sprite TextSprite to copy into this + */ + inline TextSprite::TextSprite(const TextSprite& sprite) : InstancedRenderable(sprite), m_renderInfos(sprite.m_renderInfos), @@ -40,6 +56,10 @@ namespace Nz } } + /*! + * \brief Clears the data + */ + inline void TextSprite::Clear() { m_atlases.clear(); @@ -48,21 +68,42 @@ namespace Nz m_renderInfos.clear(); } + /*! + * \brief Gets the color of the text sprite + * \return Current color + */ + inline const Color& TextSprite::GetColor() const { return m_color; } + /*! + * \brief Gets the material of the text sprite + * \return Current material + */ + inline const MaterialRef& TextSprite::GetMaterial() const { return m_material; } + /*! + * \brief Gets the current scale of the text sprite + * \return Current scale + */ + inline float TextSprite::GetScale() const { return m_scale; } + /*! + * \brief Sets the color of the text sprite + * + * \param color Color for the text sprite + */ + inline void TextSprite::SetColor(const Color& color) { m_color = color; @@ -70,6 +111,11 @@ namespace Nz InvalidateVertices(); } + /*! + * \brief Sets the default material of the text sprite (just default material) + */ + + inline void TextSprite::SetDefaultMaterial() { MaterialRef material = Material::New(); @@ -83,11 +129,23 @@ namespace Nz SetMaterial(material); } + /*! + * \brief Sets the material of the text sprite + * + * \param material Material for the text sprite + */ + inline void TextSprite::SetMaterial(MaterialRef material) { m_material = std::move(material); } + /*! + * \brief Sets the current scale of the text sprite + * + * \param scale Scale of the text sprite + */ + inline void TextSprite::SetScale(float scale) { m_scale = scale; @@ -95,10 +153,12 @@ namespace Nz InvalidateVertices(); } - inline void TextSprite::InvalidateVertices() - { - InvalidateInstanceData(0); - } + /*! + * \brief Sets the current text sprite with the content of the other one + * \return A reference to this + * + * \param text sprite The other TextSprite + */ inline TextSprite& TextSprite::operator=(const TextSprite& text) { @@ -130,6 +190,22 @@ namespace Nz return *this; } + /*! + * \brief Invalidates the vertices + */ + + inline void TextSprite::InvalidateVertices() + { + InvalidateInstanceData(0); + } + + /*! + * \brief Creates a new text sprite from the arguments + * \return A reference to the newly created text sprite + * + * \param args Arguments for the text sprite + */ + template TextSpriteRef TextSprite::New(Args&&... args) { diff --git a/include/Nazara/Graphics/TextureBackground.inl b/include/Nazara/Graphics/TextureBackground.inl index c40ad3d2d..31067f36c 100644 --- a/include/Nazara/Graphics/TextureBackground.inl +++ b/include/Nazara/Graphics/TextureBackground.inl @@ -7,11 +7,22 @@ namespace Nz { + /*! + * \brief Gets the texture of the background + * \return Texture of the background + */ + inline const TextureRef& TextureBackground::GetTexture() const { return m_texture; } + /*! + * \brief Sets the texture of the background + * + * \param texture Texture of the background + */ + inline void TextureBackground::SetTexture(TextureRef texture) { NazaraAssert(!texture || texture->IsValid(), "Invalid texture"); @@ -19,6 +30,13 @@ namespace Nz m_texture = std::move(texture); } + /*! + * \brief Creates a new texture background from the arguments + * \return A reference to the newly created texture background + * + * \param args Arguments for the texture background + */ + template TextureBackgroundRef TextureBackground::New(Args&&... args) { diff --git a/include/Nazara/Math/Frustum.inl b/include/Nazara/Math/Frustum.inl index b9f56c1e1..71f385cac 100644 --- a/include/Nazara/Math/Frustum.inl +++ b/include/Nazara/Math/Frustum.inl @@ -491,8 +491,8 @@ namespace Nz * * \remark If volume is infinite, IntersectionSide_Intersecting is returned * \remark If volume is null, IntersectionSide_Outside is returned - * \remark If enumeration of the volume is not defined in Extend, a NazaraError is thrown and false is returned - * \remark If enumeration of the intersection is not defined in IntersectionSide, a NazaraError is thrown and false is returned. This should not never happen for a user of the library + * \remark If enumeration of the volume is not defined in Extend, a NazaraError is thrown and IntersectionSide_Outside is returned + * \remark If enumeration of the intersection is not defined in IntersectionSide, a NazaraError is thrown and IntersectionSide_Outside is returned. This should not never happen for a user of the library */ template diff --git a/include/Nazara/Math/Sphere.inl b/include/Nazara/Math/Sphere.inl index b87bd51a7..0a8d1adae 100644 --- a/include/Nazara/Math/Sphere.inl +++ b/include/Nazara/Math/Sphere.inl @@ -485,7 +485,7 @@ namespace Nz template T Sphere::SquaredDistance(const Vector3& point) const { - return Vector3f::Distance(point, GetPosition()) - radius * radius; + return Vector3f::SquaredDistance(point, GetPosition() + (point - GetPosition()).Normalize() * radius); } /*! diff --git a/include/Nazara/Network/AbstractSocket.inl b/include/Nazara/Network/AbstractSocket.inl index 8bebabfdb..5b5174b98 100644 --- a/include/Nazara/Network/AbstractSocket.inl +++ b/include/Nazara/Network/AbstractSocket.inl @@ -6,31 +6,62 @@ namespace Nz { + /*! + * \brief Gets the last error + * \return Socket error + */ + inline SocketError AbstractSocket::GetLastError() const { return m_lastError; } + /*! + * \brief Gets the internal socket handle + * \return Socket handle + */ + inline SocketHandle AbstractSocket::GetNativeHandle() const { return m_handle; } + /*! + * \brief Gets the internal state + * \return Socket state + */ + inline SocketState AbstractSocket::GetState() const { return m_state; } + /*! + * \brief Gets the internal type + * \return Socket type + */ + inline SocketType AbstractSocket::GetType() const { return m_type; } + /*! + * \brief Checks whether the blocking is enabled + * \return true If successful + */ + inline bool AbstractSocket::IsBlockingEnabled() const { return m_isBlockingEnabled; } + /*! + * \brief Updates the state of the socket + * + * \param newState Next state for the socket + */ + inline void AbstractSocket::UpdateState(SocketState newState) { if (m_state != newState) diff --git a/include/Nazara/Network/Config.hpp b/include/Nazara/Network/Config.hpp index 727108061..2d73c26bb 100644 --- a/include/Nazara/Network/Config.hpp +++ b/include/Nazara/Network/Config.hpp @@ -27,17 +27,22 @@ #ifndef NAZARA_CONFIG_NETWORK_HPP #define NAZARA_CONFIG_NETWORK_HPP -/// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci +/*! +* \defgroup network (NazaraNetwork) Network module +* Network/System module including classes to handle networking elements... +*/ -// Utilise le MemoryManager pour gérer les allocations dynamiques (détecte les leaks au prix d'allocations/libérations dynamiques plus lentes) +/// Each modification of a paramater of the module needs a recompilation of the unit + +// Use the MemoryManager to manage dynamic allocations (can detect memory leak but allocations/frees are slower) #define NAZARA_NETWORK_MANAGE_MEMORY 0 -// Active les tests de sécurité basés sur le code (Conseillé pour le développement) +// Activate the security tests based on the code (Advised for development) #define NAZARA_NETWORK_SAFE 1 -/// Chaque modification d'un paramètre ci-dessous implique une modification (souvent mineure) du code +/// Each modification of a parameter following implies a modification (often minor) of the code -/// Vérification des valeurs et types de certaines constantes +/// Checking the values and types of certain constants #include #if defined(NAZARA_STATIC) diff --git a/include/Nazara/Network/ConfigCheck.hpp b/include/Nazara/Network/ConfigCheck.hpp index 73513ebc9..2f1ba1dc8 100644 --- a/include/Nazara/Network/ConfigCheck.hpp +++ b/include/Nazara/Network/ConfigCheck.hpp @@ -7,11 +7,11 @@ #ifndef NAZARA_CONFIG_CHECK_NETWORK_HPP #define NAZARA_CONFIG_CHECK_NETWORK_HPP -/// Ce fichier sert à vérifier la valeur des constantes du fichier Config.hpp +/// This file is used to check the constant values defined in Config.hpp #include -// On force la valeur de MANAGE_MEMORY en mode debug +// We fore the value of MANAGE_MEMORY in debug #if defined(NAZARA_DEBUG) && !NAZARA_NETWORK_MANAGE_MEMORY #undef NAZARA_NETWORK_MANAGE_MEMORY #define NAZARA_NETWORK_MANAGE_MEMORY 0 diff --git a/include/Nazara/Network/DebugOff.hpp b/include/Nazara/Network/DebugOff.hpp index dd45ac45c..e9df99f1f 100644 --- a/include/Nazara/Network/DebugOff.hpp +++ b/include/Nazara/Network/DebugOff.hpp @@ -2,7 +2,7 @@ // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp -// On suppose que Debug.hpp a déjà été inclus, tout comme Config.hpp +// We suppose that Debug.hpp is already included, same goes for Config.hpp #if NAZARA_NETWORK_MANAGE_MEMORY #undef delete #undef new diff --git a/include/Nazara/Network/IpAddress.inl b/include/Nazara/Network/IpAddress.inl index 3184bd34d..2fc9ac2bd 100644 --- a/include/Nazara/Network/IpAddress.inl +++ b/include/Nazara/Network/IpAddress.inl @@ -9,11 +9,22 @@ namespace Nz { + /*! + * \brief Constructs a IpAddress object by default + */ + inline IpAddress::IpAddress() : m_isValid(false) { } + /*! + * \brief Constructs a IpAddress object with an IP and a port + * + * \param ip IPv4 address + * \param port Port of the IP + */ + inline IpAddress::IpAddress(const IPv4& ip, UInt16 port) : m_ipv4(ip), m_protocol(NetProtocol_IPv4), @@ -22,6 +33,13 @@ namespace Nz { } + /*! + * \brief Constructs a IpAddress object with an IP and a port + * + * \param ip IPv6 address + * \param port Port of the IP + */ + inline IpAddress::IpAddress(const IPv6& ip, UInt16 port) : m_ipv6(ip), m_protocol(NetProtocol_IPv6), @@ -30,46 +48,100 @@ namespace Nz { } + /*! + * \brief Constructs a IpAddress object with an IP and a port + * + * \param ip IPv4 address (a.b.c.d) + * \param port Port of the IP + */ + inline IpAddress::IpAddress(const UInt8& a, const UInt8& b, const UInt8& c, const UInt8& d, UInt16 port) : IpAddress(IPv4{a, b, c, d}, port) { } + /*! + * \brief Constructs a IpAddress object with an IP and a port + * + * \param ip IPv6 address (a.b.c.d.e.f.g.h) + * \param port Port of the IP + */ + inline IpAddress::IpAddress(const UInt16& a, const UInt16& b, const UInt16& c, const UInt16& d, const UInt16& e, const UInt16& f, const UInt16& g, const UInt16& h, UInt16 port) : IpAddress(IPv6{a, b, c, d, e, f, g, h}, port) { } + /*! + * Constructs a IpAddress object with a C-string + * + * \param address Hostname or textual IP address + */ + inline IpAddress::IpAddress(const char* address) { BuildFromAddress(address); } + /*! + * Constructs a IpAddress object with a string + * + * \param address Hostname or textual IP address + */ + inline IpAddress::IpAddress(const String& address) { BuildFromAddress(address.GetConstBuffer()); } + /*! + * \brief Gets the port + * \return Port attached to the IP address + */ + inline UInt16 IpAddress::GetPort() const { return m_port; } + /*! + * \brief Gets the net protocol + * \return Protocol attached to the IP address + */ + inline NetProtocol IpAddress::GetProtocol() const { return m_protocol; } + /*! + * \brief Checks whether the IP address is valid + * \return true If successful + */ + inline bool IpAddress::IsValid() const { return m_isValid; } + /*! + * \brief Sets the port + * + * \param port Port attached to the IP address + */ + inline void IpAddress::SetPort(UInt16 port) { m_port = port; } + /*! + * \brief Converts IpAddress to IPv4 + * \return Corresponding IPv4 + * + * \remark Produces a NazaraAssert if net protocol is not IPv4 + */ + inline IpAddress::IPv4 IpAddress::ToIPv4() const { NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv4, "Address is not a valid IPv4"); @@ -77,6 +149,13 @@ namespace Nz return m_ipv4; } + /*! + * \brief Converts IpAddress to IPv6 + * \return Corresponding IPv6 + * + * \remark Produces a NazaraAssert if net protocol is not IPv6 + */ + inline IpAddress::IPv6 IpAddress::ToIPv6() const { NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv6, "IP is not a valid IPv6"); @@ -84,6 +163,13 @@ namespace Nz return m_ipv6; } + /*! + * \brief Converts IpAddress to UInt32 + * \return Corresponding UInt32 + * + * \remark Produces a NazaraAssert if net protocol is not IPv4 + */ + inline UInt32 IpAddress::ToUInt32() const { NazaraAssert(m_isValid && m_protocol == NetProtocol_IPv4, "Address is not a valid IPv4"); @@ -94,17 +180,40 @@ namespace Nz UInt32(m_ipv4[3]) << 0; } + /*! + * \brief Converts IpAddress to boolean + * \return true If IpAddress is valid + * + * \see IsValid + */ + inline IpAddress::operator bool() const { return IsValid(); } + /*! + * \brief Output operator + * \return The stream + * + * \param out The stream + * \param address The address to output + */ + inline std::ostream& operator<<(std::ostream& out, const IpAddress& address) { out << "IpAddress(" << address.ToString() << ')'; return out; } + /*! + * \brief Compares the IpAddress to other one + * \return true if the ip addresses are the same + * + * \param first First ip address to compare + * \param second Second ip address to compare with + */ + inline bool operator==(const IpAddress& first, const IpAddress& second) { // We need to check the validity of each address before comparing them @@ -146,11 +255,27 @@ namespace Nz return true; } + /*! + * \brief Compares the IpAddress to other one + * \return false if the ip addresses are the same + * + * \param first First ip address to compare + * \param second Second ip address to compare with + */ + inline bool operator!=(const IpAddress& first, const IpAddress& second) { return !operator==(first, second); } + /*! + * \brief Compares the IpAddress to other one + * \return true if this ip address is inferior to the other one + * + * \param first First ip address to compare + * \param second Second ip address to compare with + */ + inline bool operator<(const IpAddress& first, const IpAddress& second) { // If the second address is invalid, there's no way we're lower than it @@ -196,16 +321,40 @@ namespace Nz return false; //< Same address } + /*! + * \brief Compares the IpAddress to other one + * \return true if this ip address is inferior or equal to the other one + * + * \param first First ip address to compare + * \param second Second ip address to compare with + */ + inline bool operator<=(const IpAddress& first, const IpAddress& second) { return !operator<(second, first); } + /*! + * \brief Compares the IpAddress to other one + * \return true if this ip address is greather to the other one + * + * \param first First ip address to compare + * \param second Second ip address to compare with + */ + inline bool operator>(const IpAddress& first, const IpAddress& second) { return second < first; } + /*! + * \brief Compares the IpAddress to other one + * \return true if this ip address is greather or equal to the other one + * + * \param first First ip address to compare + * \param second Second ip address to compare with + */ + inline bool operator>=(const IpAddress& first, const IpAddress& second) { return !operator<(first, second); @@ -217,6 +366,13 @@ namespace std template<> struct hash { + /*! + * \brief Converts IpAddress to hash + * \return Hash of the IpAddress + * + * \param ip IpAddress to hash + */ + size_t operator()(const Nz::IpAddress& ip) const { if (!ip) @@ -224,7 +380,7 @@ namespace std // This is SDBM adapted for IP addresses, tested to generate the least collisions possible // (It doesn't mean it cannot be improved though) - std::size_t h = 0; + std::size_t hash = 0; switch (ip.GetProtocol()) { case Nz::NetProtocol_Any: @@ -233,20 +389,20 @@ namespace std case Nz::NetProtocol_IPv4: { - h = ip.ToUInt32() + (h << 6) + (h << 16) - h; + hash = ip.ToUInt32() + (hash << 6) + (hash << 16) - hash; break; } case Nz::NetProtocol_IPv6: { Nz::IpAddress::IPv6 v6 = ip.ToIPv6(); for (std::size_t i = 0; i < v6.size(); i++) - h = v6[i] + (h << 6) + (h << 16) - h; + hash = v6[i] + (hash << 6) + (hash << 16) - hash; break; } } - return ip.GetPort() + (h << 6) + (h << 16) - h; + return ip.GetPort() + (hash << 6) + (hash << 16) - hash; } }; } diff --git a/include/Nazara/Network/NetPacket.inl b/include/Nazara/Network/NetPacket.inl index c9bbed681..e9765c9dc 100644 --- a/include/Nazara/Network/NetPacket.inl +++ b/include/Nazara/Network/NetPacket.inl @@ -9,21 +9,46 @@ namespace Nz { + /*! + * \brief Constructs a NetPacket object by default + */ + inline NetPacket::NetPacket() : m_netCode(NetCode_Invalid) { } + /*! + * \brief Constructs a NetPacket object with a packet number and a minimal capacity + * + * \param netCode Packet number + * \param minCapacity Minimal capacity of the packet + */ + inline NetPacket::NetPacket(UInt16 netCode, std::size_t minCapacity) { Reset(netCode, minCapacity); } + /*! + * \brief Constructs a NetPacket object with a packet number and raw memory + * + * \param netCode Packet number + * \param ptr Raw memory + * \param size Size of the memory + */ + inline NetPacket::NetPacket(UInt16 netCode, const void* ptr, std::size_t size) { Reset(netCode, ptr, size); } + /*! + * \brief Constructs a NetPacket object with another one by move semantic + * + * \param packet NetPacket to move into this + */ + inline NetPacket::NetPacket(NetPacket&& packet) : ByteStream(std::move(packet)), m_buffer(std::move(packet.m_buffer)), @@ -35,12 +60,23 @@ namespace Nz SetStream(&m_memoryStream); } + /*! + * \brief Destructs the object + */ + inline NetPacket::~NetPacket() { FlushBits(); //< Needs to be done here as the stream will be freed before ByteStream calls it FreeStream(); } + /*! + * \brief Gets the raw buffer + * \return Constant raw buffer + * + * \remark Produces a NazaraAssert if internal buffer is invalid + */ + inline const UInt8* NetPacket::GetConstData() const { NazaraAssert(m_buffer, "Invalid buffer"); @@ -48,6 +84,13 @@ namespace Nz return m_buffer->GetConstBuffer(); } + /*! + * \brief Gets the raw buffer + * \return Raw buffer + * + * \remark Produces a NazaraAssert if internal buffer is invalid + */ + inline UInt8* NetPacket::GetData() const { NazaraAssert(m_buffer, "Invalid buffer"); @@ -55,6 +98,11 @@ namespace Nz return m_buffer->GetBuffer(); } + /*! + * \brief Gets the size of the data + * \return Size of the data + */ + inline size_t NetPacket::GetDataSize() const { if (m_buffer) @@ -63,22 +111,46 @@ namespace Nz return 0; } + /*! + * \brief Gets the packet number + * \return Packet number + */ + inline UInt16 NetPacket::GetNetCode() const { return m_netCode; } + /*! + * \brief Resets the packet + */ + inline void NetPacket::Reset() { FreeStream(); } + /*! + * \brief Resets the packet with a packet number and a minimal capacity + * + * \param netCode Packet number + * \param minCapacity Minimal capacity of the packet + */ + inline void NetPacket::Reset(UInt16 netCode, std::size_t minCapacity) { InitStream(HeaderSize + minCapacity, HeaderSize, OpenMode_ReadWrite); m_netCode = netCode; } + /*! + * \brief Resets the packet with a packet number and raw memory + * + * \param netCode Packet number + * \param ptr Raw memory + * \param size Size of the memory + */ + inline void NetPacket::Reset(UInt16 netCode, const void* ptr, std::size_t size) { InitStream(HeaderSize + size, HeaderSize, OpenMode_ReadOnly); @@ -88,6 +160,14 @@ namespace Nz m_netCode = netCode; } + /*! + * \brief Resizes the packet + * + * \param newSize Size for the resizing operation + * + * \remark Produces a NazaraAssert if internal buffer is invalid + */ + inline void NetPacket::Resize(std::size_t newSize) { NazaraAssert(m_buffer, "Invalid buffer"); @@ -95,11 +175,24 @@ namespace Nz m_buffer->Resize(newSize); } + /*! + * \brief Sets the packet number + * + * \param netCode Packet number + */ + inline void NetPacket::SetNetCode(UInt16 netCode) { m_netCode = netCode; } + /*! + * \brief Moves the NetPacket into this + * \return A reference to this + * + * \param packet NetPacket to move in this + */ + inline NetPacket& Nz::NetPacket::operator=(NetPacket&& packet) { FreeStream(); diff --git a/include/Nazara/Network/RUdpConnection.inl b/include/Nazara/Network/RUdpConnection.inl index b2372285d..48173bd77 100644 --- a/include/Nazara/Network/RUdpConnection.inl +++ b/include/Nazara/Network/RUdpConnection.inl @@ -8,31 +8,66 @@ namespace Nz { + /*! + * \brief Closes the connection + */ + inline void RUdpConnection::Close() { m_socket.Close(); } + /*! + * \brief Disconnects the connection + * + * \see Close + */ + inline void RUdpConnection::Disconnect() { Close(); } + /*! + * \brief Gets the bound address + * \return IpAddress we are linked to + */ + inline IpAddress RUdpConnection::GetBoundAddress() const { return m_socket.GetBoundAddress(); } + /*! + * \brief Gets the port of the bound address + * \return Port we are linked to + */ + inline UInt16 RUdpConnection::GetBoundPort() const { return m_socket.GetBoundPort(); } + /*! + * \brief Gets the last error + * \return Socket error + */ + inline SocketError RUdpConnection::GetLastError() const { return m_lastError; } + /*! + * \brief Listens to a socket + * \return true If successfully bound + * + * \param protocol Net protocol to listen to + * \param port Port to listen to + * + * \remark Produces a NazaraAssert if protocol is unknown or any + */ + inline bool RUdpConnection::Listen(NetProtocol protocol, UInt16 port) { NazaraAssert(protocol != NetProtocol_Any, "Any protocol not supported for Listen"); //< TODO @@ -59,16 +94,36 @@ namespace Nz return Listen(any); } + /*! + * \brief Sets the protocol id + * + * \param protocolId Protocol ID like NNet + */ + inline void RUdpConnection::SetProtocolId(UInt32 protocolId) { m_protocol = protocolId; } + /*! + * \brief Sets the time before ack + * + * \param Time before acking to send many together (in ms) + */ + inline void RUdpConnection::SetTimeBeforeAck(UInt32 ms) { m_forceAckSendTime = ms * 1000; //< Store in microseconds for easier handling } - + + /*! + * \brief Computes the difference of sequence + * \return Delta between the two sequences + * + * \param sequence First sequence + * \param sequence2 Second sequence + */ + inline unsigned int RUdpConnection::ComputeSequenceDifference(SequenceIndex sequence, SequenceIndex sequence2) { unsigned int difference; @@ -77,9 +132,16 @@ namespace Nz else difference = sequence - sequence2; - return 0; + return difference; } + /*! + * \brief Checks whether the peer has pending packets + * \return true If it is the case + * + * \param peer Data relative to the peer + */ + inline bool RUdpConnection::HasPendingPackets(PeerData& peer) { for (unsigned int priority = PacketPriority_Highest; priority <= PacketPriority_Lowest; ++priority) @@ -94,6 +156,14 @@ namespace Nz return false; } + /*! + * \brief Checks whether the ack is more recent + * \return true If it is the case + * + * \param ack First sequence + * \param ack2 Second sequence + */ + inline bool RUdpConnection::IsAckMoreRecent(SequenceIndex ack, SequenceIndex ack2) { constexpr SequenceIndex maxDifference = std::numeric_limits::max() / 2; @@ -106,6 +176,13 @@ namespace Nz return false; ///< Same ack } + /*! + * \brief Checks whether the connection is reliable + * \return true If it is the case + * + * \remark Produces a NazaraError if enumeration is invalid + */ + inline bool RUdpConnection::IsReliable(PacketReliability reliability) { switch (reliability) @@ -122,6 +199,14 @@ namespace Nz return false; } + /*! + * \brief Simulates the loss of packets on network + * + * \param packetLoss Ratio of packet loss according to bernoulli distribution + * + * \remark Produces a NazaraAssert if packetLoss is not in between 0.0 and 1.0 + */ + inline void RUdpConnection::SimulateNetwork(double packetLoss) { NazaraAssert(packetLoss >= 0.0 && packetLoss <= 1.0, "Packet loss must be in range [0..1]"); diff --git a/include/Nazara/Network/TcpClient.hpp b/include/Nazara/Network/TcpClient.hpp index 0fcedcf39..fda4671f9 100644 --- a/include/Nazara/Network/TcpClient.hpp +++ b/include/Nazara/Network/TcpClient.hpp @@ -79,8 +79,8 @@ namespace Nz PendingPacket m_pendingPacket; UInt64 m_keepAliveInterval; UInt64 m_keepAliveTime; - bool m_isKeepAliveEnabled; bool m_isLowDelayEnabled; + bool m_isKeepAliveEnabled; }; } diff --git a/include/Nazara/Network/TcpClient.inl b/include/Nazara/Network/TcpClient.inl index da292b982..23f5412da 100644 --- a/include/Nazara/Network/TcpClient.inl +++ b/include/Nazara/Network/TcpClient.inl @@ -7,6 +7,10 @@ namespace Nz { + /*! + * \brief Constructs a TcpClient object by default + */ + inline TcpClient::TcpClient() : AbstractSocket(SocketType_TCP), Stream(StreamOption_Sequential), @@ -17,31 +21,62 @@ namespace Nz { } + /*! + * \brief Disconnects the connection + * + * \see Close + */ + inline void TcpClient::Disconnect() { Close(); } + /*! + * \brief Gets the interval between two keep alive pings + * \return Interval in milliseconds between two pings + */ + inline UInt64 TcpClient::GetKeepAliveInterval() const { return m_keepAliveInterval; } + /*! + * \brief Gets the time before expiration of connection + * \return Time in milliseconds before expiration + */ + inline UInt64 TcpClient::GetKeepAliveTime() const { return m_keepAliveTime; } + /*! + * \brief Gets the remote address + * \return Address of peer + */ + inline IpAddress TcpClient::GetRemoteAddress() const { return m_peerAddress; } + /*! + * \brief Checks whether low delay is enabled + * \return true If it is the case + */ + inline bool TcpClient::IsLowDelayEnabled() const { return m_isLowDelayEnabled; } + /*! + * \brief Checks whether the keep alive flag is enabled + * \return true If it is the case + */ + inline bool TcpClient::IsKeepAliveEnabled() const { return m_isKeepAliveEnabled; diff --git a/include/Nazara/Network/TcpServer.inl b/include/Nazara/Network/TcpServer.inl index 5350a58ee..1fcb4eb32 100644 --- a/include/Nazara/Network/TcpServer.inl +++ b/include/Nazara/Network/TcpServer.inl @@ -7,27 +7,58 @@ namespace Nz { + /*! + * \brief Constructs a TcpServer object by default + */ + inline TcpServer::TcpServer() : AbstractSocket(SocketType_TCP) { } + /*! + * \brief Constructs a TcpServer object with another one by move semantic + * + * \param tcpServer TcpServer to move into this + */ + inline TcpServer::TcpServer(TcpServer&& tcpServer) : AbstractSocket(std::move(tcpServer)), m_boundAddress(std::move(tcpServer.m_boundAddress)) { } + /*! + * \brief Gets the bound address + * \return IpAddress we are linked to + */ + inline IpAddress TcpServer::GetBoundAddress() const { return m_boundAddress; } + /*! + * \brief Gets the port of the bound address + * \return Port we are linked to + */ + inline UInt16 TcpServer::GetBoundPort() const { return m_boundAddress.GetPort(); } + /*! + * \brief Listens to a socket + * \return State of the socket + * + * \param protocol Net protocol to listen to + * \param port Port to listen to + * \param queueSize Size of the queue + * + * \remark Produces a NazaraAssert if protocol is unknown or any + */ + inline SocketState TcpServer::Listen(NetProtocol protocol, UInt16 port, unsigned int queueSize) { NazaraAssert(protocol != NetProtocol_Any, "Any protocol not supported for Listen"); //< TODO diff --git a/include/Nazara/Network/UdpSocket.hpp b/include/Nazara/Network/UdpSocket.hpp index 96c391436..2aac124af 100644 --- a/include/Nazara/Network/UdpSocket.hpp +++ b/include/Nazara/Network/UdpSocket.hpp @@ -49,7 +49,6 @@ namespace Nz void OnOpened() override; IpAddress m_boundAddress; - SocketState m_state; bool m_isBroadCastingEnabled; }; } diff --git a/include/Nazara/Network/UdpSocket.inl b/include/Nazara/Network/UdpSocket.inl index 9ad4d067b..4096d8c04 100644 --- a/include/Nazara/Network/UdpSocket.inl +++ b/include/Nazara/Network/UdpSocket.inl @@ -6,24 +6,46 @@ namespace Nz { + /*! + * \brief Constructs a UdpSocket object by default + */ + inline UdpSocket::UdpSocket() : AbstractSocket(SocketType_UDP) { } + /*! + * \brief Constructs a UdpSocket object with a net protocol + * + * \param protocol Net protocol to use + */ + inline UdpSocket::UdpSocket(NetProtocol protocol) : UdpSocket() { Create(protocol); } + /*! + * \brief Constructs a UdpSocket object with another one by move semantic + * + * \param udpSocket UdpSocket to move into this + */ + inline UdpSocket::UdpSocket(UdpSocket&& udpSocket) : AbstractSocket(std::move(udpSocket)), - m_boundAddress(std::move(udpSocket.m_boundAddress)), - m_state(udpSocket.m_state) + m_boundAddress(std::move(udpSocket.m_boundAddress)) { } + /*! + * \brief Binds a specific port + * \return State of the socket + * + * \param port Port to bind + */ + inline SocketState UdpSocket::Bind(UInt16 port) { IpAddress any; @@ -47,6 +69,13 @@ namespace Nz return Bind(any); } + /*! + * \brief Creates a UDP socket + * \return true If successful + * + * \param protocol Net protocol to use + */ + bool UdpSocket::Create(NetProtocol protocol) { NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol"); @@ -54,21 +83,41 @@ namespace Nz return Open(protocol); } + /*! + * \brief Gets the bound address + * \return IpAddress we are linked to + */ + inline IpAddress UdpSocket::GetBoundAddress() const { return m_boundAddress; } + /*! + * \brief Gets the port of the bound address + * \return Port we are linked to + */ + inline UInt16 UdpSocket::GetBoundPort() const { return m_boundAddress.GetPort(); } + /*! + * \brief Gets the state of the socket + * \return State of the socket + */ + inline SocketState UdpSocket::GetState() const { return m_state; } + /*! + * \brief Checks whether the broadcasting is enabled + * \return true If it is the case + */ + inline bool UdpSocket::IsBroadcastingEnabled() const { return m_isBroadCastingEnabled; diff --git a/src/Nazara/Audio/Audio.cpp b/src/Nazara/Audio/Audio.cpp index c0e785865..6eaa86c39 100644 --- a/src/Nazara/Audio/Audio.cpp +++ b/src/Nazara/Audio/Audio.cpp @@ -16,6 +16,21 @@ namespace Nz { + /*! + * \ingroup audio + * \class Nz::Audio + * \brief Audio class that represents the module initializer of Audio + */ + + /*! + * \brief Gets the format of the audio + * \return AudioFormat Enumeration type for the format + * + * \param channelCount Number of channels + * + * \remark Produces a NazaraError if the number of channels is erroneous (3 or 5) and AudioFormat_Unknown is returned + */ + AudioFormat Audio::GetAudioFormat(unsigned int channelCount) { switch (channelCount) @@ -34,19 +49,36 @@ namespace Nz } } + /*! + * \brief Gets the factor of the doppler effect + * \return Global factor of the doppler effect + */ + float Audio::GetDopplerFactor() { return alGetFloat(AL_DOPPLER_FACTOR); } + /*! + * \brief Gets the global volume + * \return Float between [0, inf) with 100.f being the default + */ + float Audio::GetGlobalVolume() { ALfloat gain = 0.f; alGetListenerf(AL_GAIN, &gain); - return gain*100.f; + return gain * 100.f; } + /*! + * \brief Gets the direction of the listener + * \return Direction of the listener, in front of the listener + * + * \see GetListenerRotation + */ + Vector3f Audio::GetListenerDirection() { ALfloat orientation[6]; @@ -55,6 +87,13 @@ namespace Nz return Vector3f(orientation[0], orientation[1], orientation[2]); } + /*! + * \brief Gets the position of the listener + * \return Position of the listener + * + * \see GetListenerVelocity + */ + Vector3f Audio::GetListenerPosition() { Vector3f position; @@ -63,6 +102,11 @@ namespace Nz return position; } + /*! + * \brief Gets the rotation of the listener + * \return Rotation of the listener + */ + Quaternionf Audio::GetListenerRotation() { ALfloat orientation[6]; @@ -73,6 +117,13 @@ namespace Nz return Quaternionf::RotationBetween(Vector3f::Forward(), forward); } + /*! + * \brief Gets the velocity of the listener + * \return Velocity of the listener + * + * \see GetListenerPosition + */ + Vector3f Audio::GetListenerVelocity() { Vector3f velocity; @@ -81,20 +132,33 @@ namespace Nz return velocity; } + /*! + * \brief Gets the speed of sound + * \return Speed of sound + */ + float Audio::GetSpeedOfSound() { return alGetFloat(AL_SPEED_OF_SOUND); } + /*! + * \brief Initializes the Audio module + * \return true if initialization is successful + * + * \remark Produces a NazaraError if initialization of modules Core, OpenAL or SoundBuffer failed + * \remark Produces a NazaraNotice + */ + bool Audio::Initialize() { - if (s_moduleReferenceCounter > 0) + if (IsInitialized()) { s_moduleReferenceCounter++; - return true; // Déjà initialisé + return true; // Already initialized } - // Initialisation des dépendances + // Initialisation of dependencies if (!Core::Initialize()) { NazaraError("Failed to initialize core module"); @@ -103,10 +167,10 @@ namespace Nz s_moduleReferenceCounter++; - // Initialisation du module + // Initialisation of the module CallOnExit onExit(Audio::Uninitialize); - // Initialisation d'OpenAL + // Initialisation of OpenAL if (!OpenAL::Initialize()) { NazaraError("Failed to initialize OpenAL"); @@ -119,7 +183,7 @@ namespace Nz return false; } - // Définition de l'orientation par défaut + // Definition of the orientation by default SetListenerDirection(Vector3f::Forward()); // Loaders @@ -131,6 +195,13 @@ namespace Nz return true; } + /*! + * \brief Checks whether the format is supported by the engine + * \return true if it is the case + * + * \param format Format to check + */ + bool Audio::IsFormatSupported(AudioFormat format) { if (format == AudioFormat_Unknown) @@ -139,21 +210,46 @@ namespace Nz return OpenAL::AudioFormat[format] != 0; } + /*! + * \brief Checks whether the module is initialized + * \return true if module is initialized + */ + bool Audio::IsInitialized() { return s_moduleReferenceCounter != 0; } + /*! + * \brief Sets the factor of the doppler effect + * + * \param dopplerFactor Global factor of the doppler effect + */ + void Audio::SetDopplerFactor(float dopplerFactor) { alDopplerFactor(dopplerFactor); } + /*! + * \brief Sets the global volume + * + * \param volume Float between [0, inf) with 100.f being the default + */ + void Audio::SetGlobalVolume(float volume) { - alListenerf(AL_GAIN, volume*0.01f); + alListenerf(AL_GAIN, volume * 0.01f); } + /*! + * \brief Sets the direction of the listener + * + * \param direction Direction of the listener, in front of the listener + * + * \see SetListenerDirection, SetListenerRotation + */ + void Audio::SetListenerDirection(const Vector3f& direction) { Vector3f up = Vector3f::Up(); @@ -167,6 +263,14 @@ namespace Nz alListenerfv(AL_ORIENTATION, orientation); } + /*! + * \brief Sets the direction of the listener + * + * \param (dirX, dirY, dirZ) Direction of the listener, in front of the listener + * + * \see SetListenerDirection, SetListenerRotation + */ + void Audio::SetListenerDirection(float dirX, float dirY, float dirZ) { Vector3f up = Vector3f::Up(); @@ -180,16 +284,38 @@ namespace Nz alListenerfv(AL_ORIENTATION, orientation); } + /*! + * \brief Sets the position of the listener + * + * \param position Position of the listener + * + * \see SetListenerVelocity + */ + void Audio::SetListenerPosition(const Vector3f& position) { alListenerfv(AL_POSITION, position); } + /*! + * \brief Sets the position of the listener + * + * \param (x, y, z) Position of the listener + * + * \see SetListenerVelocity + */ + void Audio::SetListenerPosition(float x, float y, float z) { alListener3f(AL_POSITION, x, y, z); } + /*! + * \brief Sets the rotation of the listener + * + * \param rotation Rotation of the listener + */ + void Audio::SetListenerRotation(const Quaternionf& rotation) { Vector3f forward = rotation * Vector3f::Forward(); @@ -204,33 +330,61 @@ namespace Nz alListenerfv(AL_ORIENTATION, orientation); } + /*! + * \brief Sets the velocity of the listener + * + * \param velocity Velocity of the listener + * + * \see SetListenerPosition + */ + void Audio::SetListenerVelocity(const Vector3f& velocity) { alListenerfv(AL_VELOCITY, velocity); } + /*! + * \brief Sets the velocity of the listener + * + * \param (velX, velY, velZ) Velocity of the listener + * + * \see SetListenerPosition + */ + void Audio::SetListenerVelocity(float velX, float velY, float velZ) { alListener3f(AL_VELOCITY, velX, velY, velZ); } + /*! + * \brief Sets the speed of sound + * + * \param speed Speed of sound + */ + void Audio::SetSpeedOfSound(float speed) { alSpeedOfSound(speed); } + /*! + * \brief Uninitializes the Audio module + * + * \remark Produces a NazaraNotice + */ + void Audio::Uninitialize() { if (s_moduleReferenceCounter != 1) { - // Le module est soit encore utilisé, soit pas initialisé + // The module is still in use, or can not be uninitialized if (s_moduleReferenceCounter > 1) s_moduleReferenceCounter--; return; } - // Libération du module + // Free of module s_moduleReferenceCounter = 0; // Loaders @@ -241,7 +395,7 @@ namespace Nz NazaraNotice("Uninitialized: Audio module"); - // Libération des dépendances + // Free of dependencies Core::Uninitialize(); } diff --git a/src/Nazara/Audio/Music.cpp b/src/Nazara/Audio/Music.cpp index bbcb7d813..9e38c7114 100644 --- a/src/Nazara/Audio/Music.cpp +++ b/src/Nazara/Audio/Music.cpp @@ -14,6 +14,19 @@ namespace Nz { + /*! + * \ingroup audio + * \class Nz::Music + * \brief Audio class that represents a music + * + * \remark Module Audio needs to be initialized to use this class + */ + + /*! + * \brief Checks whether the parameters for the loading of the music are correct + * \return true If parameters are valid + */ + bool MusicParams::IsValid() const { return true; @@ -32,11 +45,26 @@ namespace Nz unsigned int sampleRate; }; + /*! + * \brief Destructs the object and calls Destroy + * + * \see Destroy + */ + Music::~Music() { Destroy(); } + /*! + * \brief Creates a music with a sound stream + * \return true if creation was succesful + * + * \param soundStream Sound stream which is the source for the music + * + * \remark Produces a NazaraError if soundStream is invalid with NAZARA_AUDIO_SAFE defined + */ + bool Music::Create(SoundStream* soundStream) { NazaraAssert(soundStream, "Invalid stream"); @@ -48,7 +76,7 @@ namespace Nz m_impl = new MusicImpl; m_impl->sampleRate = soundStream->GetSampleRate(); m_impl->audioFormat = OpenAL::AudioFormat[format]; - m_impl->chunkSamples.resize(format * m_impl->sampleRate); // Une seconde de samples + m_impl->chunkSamples.resize(format * m_impl->sampleRate); // One second of samples m_impl->stream.reset(soundStream); SetPlayingOffset(0); @@ -56,6 +84,10 @@ namespace Nz return true; } + /*! + * \brief Destroys the current music and frees resources + */ + void Music::Destroy() { if (m_impl) @@ -67,6 +99,14 @@ namespace Nz } } + /*! + * \brief Enables the looping of the music + * + * \param loop Should music loop + * + * \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined + */ + void Music::EnableLooping(bool loop) { #if NAZARA_AUDIO_SAFE @@ -80,6 +120,13 @@ namespace Nz m_impl->loop = loop; } + /*! + * \brief Gets the duration of the music + * \return Duration of the music in milliseconds + * + * \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined + */ + UInt32 Music::GetDuration() const { #if NAZARA_AUDIO_SAFE @@ -93,6 +140,13 @@ namespace Nz return m_impl->stream->GetDuration(); } + /*! + * \brief Gets the format of the music + * \return Enumeration of type AudioFormat (mono, stereo, ...) + * + * \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined + */ + AudioFormat Music::GetFormat() const { #if NAZARA_AUDIO_SAFE @@ -106,6 +160,13 @@ namespace Nz return m_impl->stream->GetFormat(); } + /*! + * \brief Gets the current offset in the music + * \return Offset in milliseconds (works with entire seconds) + * + * \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined + */ + UInt32 Music::GetPlayingOffset() const { #if NAZARA_AUDIO_SAFE @@ -125,6 +186,13 @@ namespace Nz return static_cast((1000ULL * (samples + (m_impl->processedSamples / m_impl->stream->GetFormat()))) / m_impl->sampleRate); } + /*! + * \brief Gets the number of samples in the music + * \return Count of samples (number of seconds * sample rate * channel count) + * + * \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined + */ + UInt32 Music::GetSampleCount() const { #if NAZARA_AUDIO_SAFE @@ -138,6 +206,13 @@ namespace Nz return m_impl->stream->GetSampleCount(); } + /*! + * \brief Gets the rates of sample in the music + * \return Rate of sample in Hertz (Hz) + * + * \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined + */ + UInt32 Music::GetSampleRate() const { #if NAZARA_AUDIO_SAFE @@ -151,6 +226,14 @@ namespace Nz return m_impl->sampleRate; } + /*! + * \brief Gets the status of the music + * \return Enumeration of type SoundStatus (Playing, Stopped, ...) + * + * \remark If the music is not playing, Stopped is returned + * \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined + */ + SoundStatus Music::GetStatus() const { #if NAZARA_AUDIO_SAFE @@ -163,13 +246,20 @@ namespace Nz SoundStatus status = GetInternalStatus(); - // Pour compenser les éventuels retards (ou le laps de temps entre Play() et la mise en route du thread) + // To compensate any delays (or the timelaps between Play() and the thread startup) if (m_impl->streaming && status == SoundStatus_Stopped) status = SoundStatus_Playing; return status; } + /*! + * \brief Checks whether the music is looping + * \return true if it is the case + * + * \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined + */ + bool Music::IsLooping() const { #if NAZARA_AUDIO_SAFE @@ -183,26 +273,61 @@ namespace Nz return m_impl->loop; } + /*! + * \brief Loads the music from file + * \return true if loading is successful + * + * \param filePath Path to the file + * \param params Parameters for the music + */ + bool Music::OpenFromFile(const String& filePath, const MusicParams& params) { return MusicLoader::LoadFromFile(this, filePath, params); } + /*! + * \brief Loads the music from memory + * \return true if loading is successful + * + * \param data Raw memory + * \param size Size of the memory + * \param params Parameters for the music + */ + bool Music::OpenFromMemory(const void* data, std::size_t size, const MusicParams& params) { return MusicLoader::LoadFromMemory(this, data, size, params); } + /*! + * \brief Loads the music from stream + * \return true if loading is successful + * + * \param stream Stream to the music + * \param params Parameters for the music + */ + bool Music::OpenFromStream(Stream& stream, const MusicParams& params) { return MusicLoader::LoadFromStream(this, stream, params); } + /*! + * \brief Pauses the music + */ + void Music::Pause() { alSourcePause(m_source); } + /*! + * \brief Plays the music + * + * \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined + */ + void Music::Play() { #if NAZARA_AUDIO_SAFE @@ -238,6 +363,14 @@ namespace Nz } } + /*! + * \brief Sets the playing offset for the music + * + * \param offset Offset in the music in milliseconds + * + * \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined + */ + void Music::SetPlayingOffset(UInt32 offset) { #if NAZARA_AUDIO_SAFE @@ -260,6 +393,12 @@ namespace Nz Play(); } + /*! + * \brief Stops the music + * + * \remark Produces a NazaraError if there is no music with NAZARA_AUDIO_SAFE defined + */ + void Music::Stop() { #if NAZARA_AUDIO_SAFE @@ -277,6 +416,13 @@ namespace Nz } } + /*! + * \brief Fills the buffer and queues it up + * \return true if operation was successful + * + * \param buffer Index of the buffer + */ + bool Music::FillAndQueueBuffer(unsigned int buffer) { unsigned int sampleCount = m_impl->chunkSamples.size(); @@ -304,27 +450,31 @@ namespace Nz alSourceQueueBuffers(m_source, 1, &buffer); } - return sampleRead != sampleCount; // Fin du stream (N'arrive pas en cas de loop) + return sampleRead != sampleCount; // End of stream (Does not happen when looping) } + /*! + * \brief Thread function for the music + */ + void Music::MusicThread() { - // Allocation des buffers de streaming + // Allocation of streaming buffers ALuint buffers[NAZARA_AUDIO_STREAMED_BUFFER_COUNT]; alGenBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers); for (unsigned int i = 0; i < NAZARA_AUDIO_STREAMED_BUFFER_COUNT; ++i) { if (FillAndQueueBuffer(buffers[i])) - break; // Nous avons atteint la fin du stream, inutile de rajouter des buffers + break; // We have reached the end of the stream, there is no use to add new buffers } alSourcePlay(m_source); - // Boucle de lecture (remplissage de nouveaux buffers au fur et à mesure) + // Reading loop (Filling new buffers as playing) while (m_impl->streaming) { - // La lecture s'est arrêtée, nous avons atteint la fin du stream + // The reading has stopped, we have reached the end of the stream SoundStatus status = GetInternalStatus(); if (status == SoundStatus_Stopped) { @@ -334,7 +484,7 @@ namespace Nz Nz::LockGuard lock(m_impl->bufferLock); - // On traite les buffers lus + // We treat read buffers ALint processedCount = 0; alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &processedCount); while (processedCount--) @@ -355,14 +505,14 @@ namespace Nz lock.Unlock(); - // On retourne dormir un peu + // We go back to sleep Thread::Sleep(50); } - // Arrêt de la lecture du son (dans le cas où ça ne serait pas déjà fait) + // Stop playing of the sound (in the case where it has not been already done) alSourceStop(m_source); - // On supprime les buffers du stream + // We delete buffers from the stream ALint queuedBufferCount; alGetSourcei(m_source, AL_BUFFERS_QUEUED, &queuedBufferCount); diff --git a/src/Nazara/Audio/OpenAL.cpp b/src/Nazara/Audio/OpenAL.cpp index f527b682d..489855022 100644 --- a/src/Nazara/Audio/OpenAL.cpp +++ b/src/Nazara/Audio/OpenAL.cpp @@ -23,6 +23,14 @@ namespace Nz ALCcontext* s_context = nullptr; unsigned int s_version; + /*! + * \brief Parses the devices + * \return Number of devices + * + * \param deviceString String for the device (input / output) + * \param devices List of names of the devices + */ + std::size_t ParseDevices(const char* deviceString, std::vector& devices) { if (!deviceString) @@ -41,35 +49,77 @@ namespace Nz } } + /*! + * \ingroup audio + * \class Nz::OpenAL + * \brief Audio class that represents the link with OpenAL + * + * \remark This class is meant to be used by Module Audio + */ + + /*! + * \brief Gets the entry for the function name + * \return Pointer to the function + * + * \param entryPoint Name of the entry + * + * \remark This does not produces a NazaraError if entry does not exist + */ + OpenALFunc OpenAL::GetEntry(const String& entryPoint) { return LoadEntry(entryPoint.GetConstBuffer(), false); } + /*! + * \brief Gets the name of the renderer + * \return Name of the renderer + */ + String OpenAL::GetRendererName() { return s_rendererName; } + /*! + * \brief Gets the name of the vendor + * \return Name of the vendor + */ + String OpenAL::GetVendorName() { return s_vendorName; } + /*! + * \brief Gets the version of OpenAL + * \return Version of OpenAL + */ + unsigned int OpenAL::GetVersion() { return s_version; } + /*! + * \brief Initializes the module OpenAL + * \return true if initialization is successful + * + * \param openDevice True to get information from the device + * + * \remark Produces a NazaraError if one of the entry failed + * \remark Produces a NazaraError if opening device failed with openDevice parameter set to true + */ + bool OpenAL::Initialize(bool openDevice) { - if (s_library.IsLoaded()) + if (IsInitialized()) return true; #if defined(NAZARA_PLATFORM_WINDOWS) - ///FIXME: Est-ce qu'OpenAL Soft est une meilleure implémentation que Creative ? - /// Si on pouvait se résigner à utiliser OpenAL Soft tout le temps, cela nous permettrait d'utiliser les extensions sonores - /// et de donner plus de possibilités techniques au niveau de l'audio. + ///FIXME: Is OpenAL Soft a better implementation than Creative ? + /// If we could use OpenAL Soft everytime, this would allow us to use sonorous extensions + /// and give us more technical possibilities with audio const char* libs[] = { "soft_oal.dll", "wrap_oal.dll", @@ -217,11 +267,23 @@ namespace Nz return true; } + /*! + * \brief Checks whether the module is initialized + * \return true if it is the case + */ + bool OpenAL::IsInitialized() { return s_library.IsLoaded(); } + /*! + * \brief Queries the input devices + * \return Number of devices + * + * \param devices List of names of the input devices + */ + std::size_t OpenAL::QueryInputDevices(std::vector& devices) { const char* deviceString = reinterpret_cast(alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER)); @@ -231,6 +293,13 @@ namespace Nz return ParseDevices(deviceString, devices); } + /*! + * \brief Queries the output devices + * \return Number of devices + * + * \param devices List of names of the output devices + */ + std::size_t OpenAL::QueryOutputDevices(std::vector& devices) { const char* deviceString = reinterpret_cast(alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER)); @@ -240,6 +309,13 @@ namespace Nz return ParseDevices(deviceString, devices); } + /*! + * \brief Sets the active device + * \return true if device is successfully opened + * + * \param deviceName Name of the device + */ + bool OpenAL::SetDevice(const String& deviceName) { s_deviceName = deviceName; @@ -253,6 +329,10 @@ namespace Nz return true; } + /*! + * \brief Uninitializes the module + */ + void OpenAL::Uninitialize() { CloseDevice(); @@ -262,8 +342,14 @@ namespace Nz s_library.Unload(); } - ///ATTENTION: La valeur entière est le nombre de canaux possédés par ce format - ALenum OpenAL::AudioFormat[AudioFormat_Max+1] = {0}; // Valeur ajoutées au chargement d'OpenAL + ///WARNING: The integer value is the number of canals owned by the format + ALenum OpenAL::AudioFormat[AudioFormat_Max+1] = {0}; // Added values with loading of OpenAL + + /*! + * \brief Closes the device + * + * \remark Produces a NazaraWarning if you try to close an active device + */ void OpenAL::CloseDevice() { @@ -277,24 +363,31 @@ namespace Nz } if (!alcCloseDevice(s_device)) - // Nous n'avons pas pu fermer le device, ce qui signifie qu'il est en cours d'utilisation + // We could not close the close, this means that it's still in use NazaraWarning("Failed to close device"); s_device = nullptr; } } + /*! + * \brief Opens the device + * \return true if open is successful + * + * \remark Produces a NazaraError if it could not create the context + */ + bool OpenAL::OpenDevice() { - // Initialisation du module - s_device = alcOpenDevice(s_deviceName.IsEmpty() ? nullptr : s_deviceName.GetConstBuffer()); // On choisit le device par défaut + // Initialisation of the module + s_device = alcOpenDevice(s_deviceName.IsEmpty() ? nullptr : s_deviceName.GetConstBuffer()); // We choose the default device if (!s_device) { NazaraError("Failed to open default device"); return false; } - // Un seul contexte nous suffira + // One context is enough s_context = alcCreateContext(s_device, nullptr); if (!s_context) { @@ -341,7 +434,7 @@ namespace Nz s_version = 0; } - // On complète le tableau de formats + // We complete the formats table AudioFormat[AudioFormat_Mono] = AL_FORMAT_MONO16; AudioFormat[AudioFormat_Stereo] = AL_FORMAT_STEREO16; @@ -359,6 +452,16 @@ namespace Nz return true; } + /*! + * \brief Loads the entry for the function name + * \return Pointer to the function + * + * \param name Name of the entry + * \param throwException Should throw exception if failed ? + * + * \remark Produces a std::runtime_error if entry does not exist and throwException is set to true + */ + OpenALFunc OpenAL::LoadEntry(const char* name, bool throwException) { OpenALFunc entry = reinterpret_cast(s_library.GetSymbol(name)); diff --git a/src/Nazara/Audio/Sound.cpp b/src/Nazara/Audio/Sound.cpp index 7198a01d6..d2b71318b 100644 --- a/src/Nazara/Audio/Sound.cpp +++ b/src/Nazara/Audio/Sound.cpp @@ -14,32 +14,76 @@ namespace Nz { + /*! + * \ingroup audio + * \class Nz::Sound + * \brief Audio class that represents a sound + * + * \remark Module Audio needs to be initialized to use this class + */ + + /*! + * \brief Constructs a Sound object + * + * \param soundBuffer Buffer to read sound from + */ + Sound::Sound(const SoundBuffer* soundBuffer) { SetBuffer(soundBuffer); } + /*! + * \brief Constructs a Sound object which is a copy of another + * + * \param sound Sound to copy + */ + Sound::Sound(const Sound& sound) : SoundEmitter(sound) { SetBuffer(sound.m_buffer); } + /*! + * \brief Destructs the object and calls Stop + * + * \see Stop + */ + Sound::~Sound() { Stop(); } + /*! + * \brief Enables the looping of the music + * + * \param loop Should sound loop + */ + void Sound::EnableLooping(bool loop) { alSourcei(m_source, AL_LOOPING, loop); } + /*! + * \brief Gets the internal buffer + * \return Internal buffer + */ + const SoundBuffer* Sound::GetBuffer() const { return m_buffer; } + /*! + * \brief Gets the duration of the sound + * \return Duration of the music in milliseconds + * + * \remark Produces a NazaraError if there is no buffer + */ + UInt32 Sound::GetDuration() const { NazaraAssert(m_buffer, "Invalid sound buffer"); @@ -47,6 +91,11 @@ namespace Nz return m_buffer->GetDuration(); } + /*! + * \brief Gets the current offset in the sound + * \return Offset in milliseconds (works with entire seconds) + */ + UInt32 Sound::GetPlayingOffset() const { ALint samples = 0; @@ -55,11 +104,21 @@ namespace Nz return static_cast(1000ULL * samples / m_buffer->GetSampleRate()); } + /*! + * \brief Gets the status of the music + * \return Enumeration of type SoundStatus (Playing, Stopped, ...) + */ + SoundStatus Sound::GetStatus() const { return GetInternalStatus(); } + /*! + * \brief Checks whether the sound is looping + * \return true if it is the case + */ + bool Sound::IsLooping() const { ALint loop; @@ -68,16 +127,36 @@ namespace Nz return loop != AL_FALSE; } + /*! + * \brief Checks whether the sound is playable + * \return true if it is the case + */ + bool Sound::IsPlayable() const { return m_buffer != nullptr; } + /*! + * \brief Checks whether the sound is playing + * \return true if it is the case + */ + bool Sound::IsPlaying() const { return GetStatus() == SoundStatus_Playing; } + /*! + * \brief Loads the sound from file + * \return true if loading is successful + * + * \param filePath Path to the file + * \param params Parameters for the sound + * + * \remark Produces a NazaraError if loading failed + */ + bool Sound::LoadFromFile(const String& filePath, const SoundBufferParams& params) { SoundBufferRef buffer = SoundBuffer::New(); @@ -91,6 +170,17 @@ namespace Nz return true; } + /*! + * \brief Loads the sound from memory + * \return true if loading is successful + * + * \param data Raw memory + * \param size Size of the memory + * \param params Parameters for the sound + * + * \remark Produces a NazaraError if loading failed + */ + bool Sound::LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params) { SoundBufferRef buffer = SoundBuffer::New(); @@ -104,6 +194,16 @@ namespace Nz return true; } + /*! + * \brief Loads the sound from stream + * \return true if loading is successful + * + * \param stream Stream to the sound + * \param params Parameters for the sound + * + * \remark Produces a NazaraError if loading failed + */ + bool Sound::LoadFromStream(Stream& stream, const SoundBufferParams& params) { SoundBufferRef buffer = SoundBuffer::New(); @@ -117,15 +217,25 @@ namespace Nz return true; } + /*! + * \brief Pauses the sound + */ + void Sound::Pause() { alSourcePause(m_source); } + /*! + * \brief Plays the music + * + * \remark Produces a NazaraError if the sound is not playable with NAZARA_AUDIO_SAFE defined + */ + void Sound::Play() { #if NAZARA_AUDIO_SAFE - if (!m_buffer) + if (!IsPlayable()) { NazaraError("Invalid sound buffer"); return; @@ -135,6 +245,14 @@ namespace Nz alSourcePlay(m_source); } + /*! + * \brief Sets the internal buffer + * + * \param buffer Internal buffer + * + * \remark Produces a NazaraError if buffer is invalid with NAZARA_AUDIO_SAFE defined + */ + void Sound::SetBuffer(const SoundBuffer* buffer) { #if NAZARA_AUDIO_SAFE @@ -158,11 +276,21 @@ namespace Nz alSourcei(m_source, AL_BUFFER, AL_NONE); } + /*! + * \brief Sets the playing offset for the sound + * + * \param offset Offset in the sound in milliseconds + */ + void Sound::SetPlayingOffset(UInt32 offset) { alSourcei(m_source, AL_SAMPLE_OFFSET, static_cast(offset/1000.f * m_buffer->GetSampleRate())); } + /*! + * \brief Stops the sound + */ + void Sound::Stop() { alSourceStop(m_source); diff --git a/src/Nazara/Audio/SoundBuffer.cpp b/src/Nazara/Audio/SoundBuffer.cpp index c01878383..b59e74e23 100644 --- a/src/Nazara/Audio/SoundBuffer.cpp +++ b/src/Nazara/Audio/SoundBuffer.cpp @@ -12,10 +12,23 @@ #include #include -///FIXME: Adapter la création +///FIXME: Adapt the creation namespace Nz { + /*! + * \ingroup audio + * \class Nz::SoundBuffer + * \brief Audio class that represents a buffer for sound + * + * \remark Module Audio needs to be initialized to use this class + */ + + /*! + * \brief Checks whether the parameters for the buffer' sound are correct + * \return true If parameters are valid + */ + bool SoundBufferParams::IsValid() const { return true; @@ -31,6 +44,20 @@ namespace Nz UInt32 sampleRate; }; + /*! + * \brief Constructs a SoundBuffer object + * + * \param format Format for the audio + * \param sampleCount Number of samples + * \param sampleRate Rate of samples + * \param samples Samples raw data + * + * \remark Produces a NazaraError if creation went wrong with NAZARA_AUDIO_SAFE defined + * \remark Produces a std::runtime_error if creation went wrong with NAZARA_AUDIO_SAFE defined + * + * \see Create + */ + SoundBuffer::SoundBuffer(AudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const Int16* samples) { Create(format, sampleCount, sampleRate, samples); @@ -44,6 +71,12 @@ namespace Nz #endif } + /*! + * \brief Destructs the object and calls Destroy + * + * \see Destroy + */ + SoundBuffer::~SoundBuffer() { OnSoundBufferRelease(this); @@ -51,6 +84,19 @@ namespace Nz Destroy(); } + /*! + * \brief Creates the SoundBuffer object + * \return true if creation is successful + * + * \param format Format for the audio + * \param sampleCount Number of samples + * \param sampleRate Rate of samples + * \param samples Samples raw data + * + * \remark Produces a NazaraError if creation went wrong with NAZARA_AUDIO_SAFE defined, + * this could happen if parameters are invalid or creation of OpenAL buffers failed + */ + bool SoundBuffer::Create(AudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const Int16* samples) { Destroy(); @@ -81,7 +127,7 @@ namespace Nz } #endif - // On vide le stack d'erreurs + // We empty the error stack while (alGetError() != AL_NO_ERROR); ALuint buffer; @@ -115,6 +161,10 @@ namespace Nz return true; } + /*! + * \brief Destroys the current sound buffer and frees resources + */ + void SoundBuffer::Destroy() { if (m_impl) @@ -126,6 +176,13 @@ namespace Nz } } + /*! + * \brief Gets the duration of the sound buffer + * \return Duration of the sound buffer in milliseconds + * + * \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined + */ + UInt32 SoundBuffer::GetDuration() const { #if NAZARA_AUDIO_SAFE @@ -139,6 +196,13 @@ namespace Nz return m_impl->duration; } + /*! + * \brief Gets the format of the sound buffer + * \return Enumeration of type AudioFormat (mono, stereo, ...) + * + * \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined + */ + AudioFormat SoundBuffer::GetFormat() const { #if NAZARA_AUDIO_SAFE @@ -152,6 +216,13 @@ namespace Nz return m_impl->format; } + /*! + * \brief Gets the internal raw samples + * \return Pointer to raw data + * + * \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined + */ + const Int16* SoundBuffer::GetSamples() const { #if NAZARA_AUDIO_SAFE @@ -165,6 +236,13 @@ namespace Nz return m_impl->samples.get(); } + /*! + * \brief Gets the number of samples in the sound buffer + * \return Count of samples (number of seconds * sample rate * channel count) + * + * \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined + */ + unsigned int SoundBuffer::GetSampleCount() const { #if NAZARA_AUDIO_SAFE @@ -178,6 +256,13 @@ namespace Nz return m_impl->sampleCount; } + /*! + * \brief Gets the rates of sample in the sound buffer + * \return Rate of sample in Hertz (Hz) + * + * \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined + */ + unsigned int SoundBuffer::GetSampleRate() const { #if NAZARA_AUDIO_SAFE @@ -191,31 +276,75 @@ namespace Nz return m_impl->sampleRate; } + /*! + * \brief Checks whether the sound buffer is valid + * \return true if it is the case + */ + bool SoundBuffer::IsValid() const { return m_impl != nullptr; } + /*! + * \brief Loads the sound buffer from file + * \return true if loading is successful + * + * \param filePath Path to the file + * \param params Parameters for the sound buffer + */ + bool SoundBuffer::LoadFromFile(const String& filePath, const SoundBufferParams& params) { return SoundBufferLoader::LoadFromFile(this, filePath, params); } + /*! + * \brief Loads the sound buffer from memory + * \return true if loading is successful + * + * \param data Raw memory + * \param size Size of the memory + * \param params Parameters for the sound buffer + */ + bool SoundBuffer::LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params) { return SoundBufferLoader::LoadFromMemory(this, data, size, params); } + /*! + * \brief Loads the sound buffer from stream + * \return true if loading is successful + * + * \param stream Stream to the sound buffer + * \param params Parameters for the sound buffer + */ + bool SoundBuffer::LoadFromStream(Stream& stream, const SoundBufferParams& params) { return SoundBufferLoader::LoadFromStream(this, stream, params); } + /*! + * \brief Checks whether the format is supported by the engine + * \return true if it is the case + * + * \param format Format to check + */ + bool SoundBuffer::IsFormatSupported(AudioFormat format) { return Audio::IsFormatSupported(format); } + /*! + * \brief Gets the internal OpenAL buffer + * \return The index of the OpenAL buffer + * + * \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined + */ + unsigned int SoundBuffer::GetOpenALBuffer() const { #ifdef NAZARA_DEBUG @@ -229,6 +358,13 @@ namespace Nz return m_impl->buffer; } + /*! + * \brief Initializes the libraries and managers + * \return true if initialization is successful + * + * \remark Produces a NazaraError if sub-initialization failed + */ + bool SoundBuffer::Initialize() { if (!SoundBufferLibrary::Initialize()) @@ -246,6 +382,10 @@ namespace Nz return true; } + /*! + * \brief Uninitializes the libraries and managers + */ + void SoundBuffer::Uninitialize() { SoundBufferManager::Uninitialize(); diff --git a/src/Nazara/Audio/SoundEmitter.cpp b/src/Nazara/Audio/SoundEmitter.cpp index cbee8a8f9..840c4f47d 100644 --- a/src/Nazara/Audio/SoundEmitter.cpp +++ b/src/Nazara/Audio/SoundEmitter.cpp @@ -11,11 +11,32 @@ namespace Nz { + /*! + * \ingroup audio + * \class Nz::SoundEmitter + * \brief Audio class that represents a sound source, that emits sound + * + * \remark Module Audio needs to be initialized to use this class + * \remark This class is abstract + */ + + /*! + * \brief Constructs a SoundEmitter object + */ + SoundEmitter::SoundEmitter() { alGenSources(1, &m_source); } + /*! + * \brief Constructs a SoundEmitter object which is a copy of another + * + * \param emitter SoundEmitter to copy + * + * \remark Position and velocity are not copied + */ + SoundEmitter::SoundEmitter(const SoundEmitter& emitter) { alGenSources(1, &m_source); @@ -23,20 +44,35 @@ namespace Nz SetAttenuation(emitter.GetAttenuation()); SetMinDistance(emitter.GetMinDistance()); SetPitch(emitter.GetPitch()); - // Pas de copie de position ou de vitesse + // No copy for position or velocity SetVolume(emitter.GetVolume()); } + /*! + * \brief Destructs the object + */ + SoundEmitter::~SoundEmitter() { alDeleteSources(1, &m_source); } + /*! + * \brief Enables spatialization + * + * \param spatialization True if spatialization is enabled + */ + void SoundEmitter::EnableSpatialization(bool spatialization) { alSourcei(m_source, AL_SOURCE_RELATIVE, !spatialization); } + /*! + * \brief Gets the attenuation + * \return Amount that your sound will drop off as by the inverse square law + */ + float SoundEmitter::GetAttenuation() const { ALfloat attenuation; @@ -45,6 +81,11 @@ namespace Nz return attenuation; } + /*! + * \brief Gets the minimum distance to hear + * \return Distance to begin to hear + */ + float SoundEmitter::GetMinDistance() const { ALfloat distance; @@ -53,6 +94,11 @@ namespace Nz return distance; } + /*! + * \brief Gets the pitch + * \return Pitch of the sound + */ + float SoundEmitter::GetPitch() const { ALfloat pitch; @@ -61,6 +107,11 @@ namespace Nz return pitch; } + /*! + * \brief Gets the position of the emitter + * \return Position of the sound + */ + Vector3f SoundEmitter::GetPosition() const { Vector3f position; @@ -69,6 +120,11 @@ namespace Nz return position; } + /*! + * \brief Gets the velocity of the emitter + * \return Velocity of the sound + */ + Vector3f SoundEmitter::GetVelocity() const { Vector3f velocity; @@ -77,6 +133,11 @@ namespace Nz return velocity; } + /*! + * \brief Gets the volume of the emitter + * \param volume Float between [0, inf) with 100.f being the default + */ + float SoundEmitter::GetVolume() const { ALfloat gain; @@ -85,6 +146,11 @@ namespace Nz return gain * 100.f; } + /*! + * \brief Checks whether the sound emitter has spatialization enabled + * \return true if it the case + */ + bool SoundEmitter::IsSpatialized() const { ALint relative; @@ -93,46 +159,99 @@ namespace Nz return relative == AL_FALSE; } + /*! + * \brief Sets the attenuation + * + * \param attenuation Amount that your sound will drop off as by the inverse square law + */ + void SoundEmitter::SetAttenuation(float attenuation) { alSourcef(m_source, AL_ROLLOFF_FACTOR, attenuation); } + /*! + * \brief Sets the minimum distance to hear + * + * \param minDistance to begin to hear + */ + void SoundEmitter::SetMinDistance(float minDistance) { alSourcef(m_source, AL_REFERENCE_DISTANCE, minDistance); } + /*! + * \brief Sets the pitch + * + * \param pitch of the sound + */ + void SoundEmitter::SetPitch(float pitch) { alSourcef(m_source, AL_PITCH, pitch); } + /*! + * \brief Sets the position of the emitter + * + * \param position Position of the sound + */ + void SoundEmitter::SetPosition(const Vector3f& position) { alSourcefv(m_source, AL_POSITION, position); } + /*! + * \brief Sets the position of the emitter + * + * \param position Position of the sound with (x, y, z) + */ + void SoundEmitter::SetPosition(float x, float y, float z) { alSource3f(m_source, AL_POSITION, x, y, z); } + /*! + * \brief Sets the velocity of the emitter + * + * \param velocity Velocity of the sound + */ + void SoundEmitter::SetVelocity(const Vector3f& velocity) { alSourcefv(m_source, AL_VELOCITY, velocity); } + /*! + * \brief Sets the velocity of the emitter + * + * \param velocity Velocity with (velX, velY, velZ) + */ + void SoundEmitter::SetVelocity(float velX, float velY, float velZ) { alSource3f(m_source, AL_VELOCITY, velX, velY, velZ); } + /*! + * \brief Sets the volume of the emitter + * + * \param volume Float between [0, inf) with 100.f being the default + */ + void SoundEmitter::SetVolume(float volume) { - alSourcef(m_source, AL_GAIN, volume*0.01f); + alSourcef(m_source, AL_GAIN, volume * 0.01f); } + /*! + * \brief Gets the status of the sound emitter + * \return Enumeration of type SoundStatus (Playing, Stopped, ...) + */ + SoundStatus SoundEmitter::GetInternalStatus() const { ALint state; diff --git a/src/Nazara/Audio/SoundStream.cpp b/src/Nazara/Audio/SoundStream.cpp index c243e875f..88bc0069b 100644 --- a/src/Nazara/Audio/SoundStream.cpp +++ b/src/Nazara/Audio/SoundStream.cpp @@ -6,5 +6,13 @@ namespace Nz { + /*! + * \ingroup audio + * \class Nz::SoundStream + * \brief Audio class that represents a sound stream + * + * \remark This class is abstract + */ + SoundStream::~SoundStream() = default; } diff --git a/src/Nazara/Core/Core.cpp b/src/Nazara/Core/Core.cpp index 1ccb35212..026e4a247 100644 --- a/src/Nazara/Core/Core.cpp +++ b/src/Nazara/Core/Core.cpp @@ -28,7 +28,7 @@ namespace Nz bool Core::Initialize() { - if (s_moduleReferenceCounter > 0) + if (IsInitialized()) { s_moduleReferenceCounter++; return true; // Already initialized diff --git a/src/Nazara/Core/File.cpp b/src/Nazara/Core/File.cpp index 39e873373..97504b0ee 100644 --- a/src/Nazara/Core/File.cpp +++ b/src/Nazara/Core/File.cpp @@ -385,7 +385,7 @@ namespace Nz } /*! - * \brief Sets the position of the cursor + * \brief Sets the position of the cursor * \return true if cursor is successfully positioned * * \param pos Position of the cursor @@ -404,7 +404,7 @@ namespace Nz } /*! - * \brief Sets the position of the cursor + * \brief Sets the position of the cursor * \return true if cursor is successfully positioned * * \param offset Offset according to the cursor begin position @@ -906,5 +906,5 @@ namespace Nz } return true; - } + }; } diff --git a/src/Nazara/Core/ParameterList.cpp b/src/Nazara/Core/ParameterList.cpp index 371e91b77..abe93c640 100644 --- a/src/Nazara/Core/ParameterList.cpp +++ b/src/Nazara/Core/ParameterList.cpp @@ -607,6 +607,54 @@ namespace Nz parameter.value.ptrVal = value; } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "ParameterList(Name: Type(value), ...)" + */ + String ParameterList::ToString() const + { + StringStream ss; + + ss << "ParameterList("; + for (auto it = m_parameters.cbegin(); it != m_parameters.cend();) + { + ss << it->first << ": "; + switch (it->second.type) + { + case ParameterType_Boolean: + ss << "Boolean(" << String::Boolean(it->second.value.boolVal) << ")"; + break; + case ParameterType_Color: + ss << "Color(" << it->second.value.colorVal.ToString() << ")"; + break; + case ParameterType_Float: + ss << "Float(" << it->second.value.floatVal << ")"; + break; + case ParameterType_Integer: + ss << "Integer(" << it->second.value.intVal << ")"; + break; + case ParameterType_String: + ss << "String(" << it->second.value.stringVal << ")"; + break; + case ParameterType_Pointer: + ss << "Pointer(" << String::Pointer(it->second.value.ptrVal) << ")"; + break; + case ParameterType_Userdata: + ss << "Userdata(" << String::Pointer(it->second.value.userdataVal->ptr) << ")"; + break; + case ParameterType_None: + ss << "None"; + break; + } + + if (++it != m_parameters.cend()) + ss << ", "; + } + ss << ")"; + + return ss; + } + /*! * \brief Sets a userdata parameter named `name` * @@ -724,3 +772,17 @@ namespace Nz } } } + +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param parameterList The ParameterList to output +*/ + +std::ostream& operator<<(std::ostream& out, const Nz::ParameterList& parameterList) +{ + out << parameterList.ToString(); + return out; +} diff --git a/src/Nazara/Core/Posix/FileImpl.cpp b/src/Nazara/Core/Posix/FileImpl.cpp index f6e8b3bcc..b9a6b0a31 100644 --- a/src/Nazara/Core/Posix/FileImpl.cpp +++ b/src/Nazara/Core/Posix/FileImpl.cpp @@ -143,7 +143,18 @@ namespace Nz return false; } - mode_t permissions; // TODO : get permission from first file + mode_t permissions; + struct stat sb; + if (fstat(fd1, &sb) == -1) // get permission from first file + { + NazaraWarning("Could not get permissions of source file"); + permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + } + else + { + permissions = sb.st_mode & ~S_IFMT; // S_IFMT: bit mask for the file type bit field -> ~S_IFMT: general permissions + } + int fd2 = open64(targetPath.GetConstBuffer(), O_WRONLY | O_TRUNC, permissions); if (fd2 == -1) { diff --git a/src/Nazara/Graphics/AbstractBackground.cpp b/src/Nazara/Graphics/AbstractBackground.cpp index 628819edd..28d0f0d4f 100644 --- a/src/Nazara/Graphics/AbstractBackground.cpp +++ b/src/Nazara/Graphics/AbstractBackground.cpp @@ -7,6 +7,14 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::AbstractBackground + * \brief Graphics class that represents the background for our scene + * + * \remark This class is abstract + */ + AbstractBackground::~AbstractBackground() = default; BackgroundLibrary::LibraryMap AbstractBackground::s_library; diff --git a/src/Nazara/Graphics/AbstractRenderQueue.cpp b/src/Nazara/Graphics/AbstractRenderQueue.cpp index d00816f85..1346e37ff 100644 --- a/src/Nazara/Graphics/AbstractRenderQueue.cpp +++ b/src/Nazara/Graphics/AbstractRenderQueue.cpp @@ -7,23 +7,55 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::AbstractRenderQueue + * \brief Graphics class that represents the rendering queue for our scene + * + * \remark This class is abstract + */ + AbstractRenderQueue::~AbstractRenderQueue() = default; + /*! + * \brief Adds a directional light to the rendering queue + * + * \param light Directional light + */ + void AbstractRenderQueue::AddDirectionalLight(const DirectionalLight& light) { directionalLights.push_back(light); } + /*! + * \brief Adds a point light to the rendering queue + * + * \param light Point light + */ + void AbstractRenderQueue::AddPointLight(const PointLight& light) { pointLights.push_back(light); } + /*! + * \brief Adds a spot light to the rendering queue + * + * \param light Spot light + */ + void AbstractRenderQueue::AddSpotLight(const SpotLight& light) { spotLights.push_back(light); } + /*! + * \brief Clears the rendering queue + * + * \param fully Should everything be cleared ? + */ + void AbstractRenderQueue::Clear(bool fully) { NazaraUnused(fully); diff --git a/src/Nazara/Graphics/AbstractRenderTechnique.cpp b/src/Nazara/Graphics/AbstractRenderTechnique.cpp index 11d894a00..9872178cf 100644 --- a/src/Nazara/Graphics/AbstractRenderTechnique.cpp +++ b/src/Nazara/Graphics/AbstractRenderTechnique.cpp @@ -10,6 +10,18 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::AbstractRenderTechnique + * \brief Graphics class that represents the rendering technique for our scene + * + * \remark This class is abstract + */ + + /*! + * \brief Constructs a AbstractRenderTechnique object + */ + AbstractRenderTechnique::AbstractRenderTechnique() : m_instancingEnabled(true) { @@ -17,16 +29,34 @@ namespace Nz AbstractRenderTechnique::~AbstractRenderTechnique() = default; + /*! + * \brief Enables the instancing + * + * \param instancing Should instancing be enabled + * + * \remark This may improve performances + */ + void AbstractRenderTechnique::EnableInstancing(bool instancing) { m_instancingEnabled = instancing; } + /*! + * \brief Gets the name of the actual technique + * \return Name of the technique being used + */ + String AbstractRenderTechnique::GetName() const { return RenderTechniques::ToString(GetType()); } + /*! + * \brief Checks whether the instancing is enabled + * \return true If it is the case + */ + bool AbstractRenderTechnique::IsInstancingEnabled() const { return m_instancingEnabled; diff --git a/src/Nazara/Graphics/AbstractViewer.cpp b/src/Nazara/Graphics/AbstractViewer.cpp index cc9a4b96a..bd8752bc7 100644 --- a/src/Nazara/Graphics/AbstractViewer.cpp +++ b/src/Nazara/Graphics/AbstractViewer.cpp @@ -7,5 +7,13 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::AbstractViewer + * \brief Graphics class that represents the viewer for our scene + * + * \remark This class is abstract + */ + AbstractViewer::~AbstractViewer() = default; } diff --git a/src/Nazara/Graphics/Billboard.cpp b/src/Nazara/Graphics/Billboard.cpp index 3e5173c89..6f47e9847 100644 --- a/src/Nazara/Graphics/Billboard.cpp +++ b/src/Nazara/Graphics/Billboard.cpp @@ -12,6 +12,19 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::Billboard + * \brief Graphics class that represents a billboard, a 2D surface which simulates a 3D object + */ + + /*! + * \brief Adds this billboard to the render queue + * + * \param renderQueue Queue to be added + * \param instanceData Data used for instance + */ + void Billboard::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const { if (!m_material) @@ -20,11 +33,15 @@ namespace Nz renderQueue->AddBillboard(instanceData.renderOrder, m_material, instanceData.transformMatrix.GetTranslation(), m_size, m_sinCos, m_color); } + /* + * \brief Makes the bounding volume of this billboard + */ + void Billboard::MakeBoundingVolume() const { constexpr float sqrt2 = float(M_SQRT2); - m_boundingVolume.Set(Vector3f(0.f), sqrt2*m_size.x*Vector3f::Right() + sqrt2*m_size.y*Vector3f::Down()); + m_boundingVolume.Set(Vector3f(0.f), sqrt2 * m_size.x * Vector3f::Right() + sqrt2 * m_size.y * Vector3f::Down()); } BillboardLibrary::LibraryMap Billboard::s_library; diff --git a/src/Nazara/Graphics/ColorBackground.cpp b/src/Nazara/Graphics/ColorBackground.cpp index 76f717858..33c282390 100644 --- a/src/Nazara/Graphics/ColorBackground.cpp +++ b/src/Nazara/Graphics/ColorBackground.cpp @@ -11,6 +11,11 @@ namespace Nz { namespace { + /*! + * \brief Defines render states + * \return RenderStates for the color background + */ + RenderStates BuildRenderStates() { RenderStates states; @@ -24,6 +29,18 @@ namespace Nz } } + /*! + * \ingroup graphics + * \class Nz::ColorBackground + * \brief Graphics class that represents a background with uniform color + */ + + /*! + * \brief Constructs a ColorBackground object with a color + * + * \param color Uniform color (by default Black) + */ + ColorBackground::ColorBackground(const Color& color) : m_color(color) { @@ -38,6 +55,12 @@ namespace Nz m_vertexDepthUniform = shader->GetUniformLocation("VertexDepth"); } + /*! + * \brief Draws this relatively to the viewer + * + * \param viewer Viewer for the background + */ + void ColorBackground::Draw(const AbstractViewer* viewer) const { NazaraUnused(viewer); @@ -55,16 +78,32 @@ namespace Nz Renderer::DrawFullscreenQuad(); } + /*! + * \brief Gets the background type + * \return Type of background + */ + BackgroundType ColorBackground::GetBackgroundType() const { return BackgroundType_Color; } + /*! + * \brief Gets the color of the background + * \return Background color + */ + Color ColorBackground::GetColor() const { return m_color; } + /*! + * \brief Sets the color of the background + * + * \param color Background color + */ + void ColorBackground::SetColor(const Color& color) { m_color = color; diff --git a/src/Nazara/Graphics/DeferredBloomPass.cpp b/src/Nazara/Graphics/DeferredBloomPass.cpp index 0fc80e750..c902c7615 100644 --- a/src/Nazara/Graphics/DeferredBloomPass.cpp +++ b/src/Nazara/Graphics/DeferredBloomPass.cpp @@ -9,6 +9,16 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::DeferredBloomPass + * \brief Graphics class that represents the pass for bloom in deferred rendering + */ + + /*! + * \brief Constructs a DeferredBloomPass object by default + */ + DeferredBloomPass::DeferredBloomPass() : m_uniformUpdated(false), m_brightLuminance(0.8f), @@ -32,26 +42,55 @@ namespace Nz DeferredBloomPass::~DeferredBloomPass() = default; + /*! + * \brief Gets the number of pass for blur + * \return Number of pass for blur + */ + unsigned int DeferredBloomPass::GetBlurPassCount() const { return m_blurPassCount; } + /*! + * \brief Gets the coefficiant for luminosity + * \return Luminosity of bright elements + */ + float DeferredBloomPass::GetBrightLuminance() const { return m_brightLuminance; } + /*! + * \brief Gets the coefficiant for the middle grey + * \return Luminosity of grey elements + */ + float DeferredBloomPass::GetBrightMiddleGrey() const { return m_brightMiddleGrey; } + /*! + * \brief Gets the coefficiant for things to be bright + * \return Threshold for bright elements + */ + float DeferredBloomPass::GetBrightThreshold() const { return m_brightThreshold; } + /*! + * \brief Gets the ith texture + * \return Texture computed + * + * \param i Index of the texture + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if index is invalid + */ + Texture* DeferredBloomPass::GetTexture(unsigned int i) const { #if NAZARA_GRAPHICS_SAFE @@ -65,7 +104,16 @@ namespace Nz return m_bloomTextures[i]; } - bool DeferredBloomPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const + /*! + * \brief Processes the work on the data while working with textures + * \return true + * + * \param sceneData Data for the scene + * \param firstWorkTexture Index of the first texture to work with + * \param firstWorkTexture Index of the second texture to work with + */ + + bool DeferredBloomPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const { NazaraUnused(sceneData); @@ -91,7 +139,7 @@ namespace Nz Renderer::DrawFullscreenQuad(); Renderer::SetTarget(&m_bloomRTT); - Renderer::SetViewport(Recti(0, 0, m_dimensions.x/8, m_dimensions.y/8)); + Renderer::SetViewport(Recti(0, 0, m_dimensions.x / 8, m_dimensions.y / 8)); Renderer::SetShader(m_gaussianBlurShader); @@ -124,6 +172,13 @@ namespace Nz return true; } + /*! + * \brief Resizes the texture sizes + * \return true If successful + * + * \param dimensions Dimensions for the compute texture + */ + bool DeferredBloomPass::Resize(const Vector2ui& dimensions) { DeferredRenderPass::Resize(dimensions); @@ -131,7 +186,7 @@ namespace Nz m_bloomRTT.Create(true); for (unsigned int i = 0; i < 2; ++i) { - m_bloomTextures[i]->Create(ImageType_2D, PixelFormatType_RGBA8, dimensions.x/8, dimensions.y/8); + m_bloomTextures[i]->Create(ImageType_2D, PixelFormatType_RGBA8, dimensions.x / 8, dimensions.y / 8); m_bloomRTT.AttachTexture(AttachmentPoint_Color, i, m_bloomTextures[i]); } m_bloomRTT.Unlock(); @@ -145,23 +200,47 @@ namespace Nz return true; } + /*! + * \brief Sets the number of pass for blur + * + * \param passCount Number of pass for blur + */ + void DeferredBloomPass::SetBlurPassCount(unsigned int passCount) { m_blurPassCount = passCount; // N'est pas une uniforme } + /*! + * \brief Sets the coefficiant for luminosity + * + * \param luminance Luminosity of bright elements + */ + void DeferredBloomPass::SetBrightLuminance(float luminance) { m_brightLuminance = luminance; m_uniformUpdated = false; } + /*! + * \brief Sets the coefficiant for the middle grey + * + * \param middleGrey Luminosity of grey elements + */ + void DeferredBloomPass::SetBrightMiddleGrey(float middleGrey) { m_brightMiddleGrey = middleGrey; m_uniformUpdated = false; } + /*! + * \brief Sets the coefficiant for things to be bright + * + * \param threshold Threshold for bright elements + */ + void DeferredBloomPass::SetBrightThreshold(float threshold) { m_brightThreshold = threshold; diff --git a/src/Nazara/Graphics/DeferredDOFPass.cpp b/src/Nazara/Graphics/DeferredDOFPass.cpp index f29529749..63df2c400 100644 --- a/src/Nazara/Graphics/DeferredDOFPass.cpp +++ b/src/Nazara/Graphics/DeferredDOFPass.cpp @@ -13,6 +13,10 @@ namespace Nz { namespace { + /*! + * \brief Builds the shader for the depth of field + * \return Reference to the shader newly created + */ // http://digitalerr0r.wordpress.com/2009/05/16/xna-shader-programming-tutorial-20-depth-of-field/ ShaderRef BuildDepthOfFieldShader() { @@ -92,6 +96,16 @@ namespace Nz } } + /*! + * \ingroup graphics + * \class Nz::DeferredDOFPass + * \brief Graphics class that represents the pass for depth of field in deferred rendering + */ + + /*! + * \brief Constructs a DeferredDOFPass object by default + */ + DeferredDOFPass::DeferredDOFPass() { m_dofShader = BuildDepthOfFieldShader(); @@ -118,7 +132,16 @@ namespace Nz DeferredDOFPass::~DeferredDOFPass() = default; - bool DeferredDOFPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const + /*! + * \brief Processes the work on the data while working with textures + * \return true + * + * \param sceneData Data for the scene + * \param firstWorkTexture Index of the first texture to work with + * \param firstWorkTexture Index of the second texture to work with + */ + + bool DeferredDOFPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const { NazaraUnused(sceneData); @@ -162,6 +185,13 @@ namespace Nz return true; } + /*! + * \brief Resizes the texture sizes + * \return true If successful + * + * \param dimensions Dimensions for the compute texture + */ + bool DeferredDOFPass::Resize(const Vector2ui& dimensions) { DeferredRenderPass::Resize(dimensions); @@ -181,5 +211,5 @@ namespace Nz } return true; -} + } } diff --git a/src/Nazara/Graphics/DeferredFXAAPass.cpp b/src/Nazara/Graphics/DeferredFXAAPass.cpp index 3a300392a..3f1e9395a 100644 --- a/src/Nazara/Graphics/DeferredFXAAPass.cpp +++ b/src/Nazara/Graphics/DeferredFXAAPass.cpp @@ -10,6 +10,16 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::DeferredFXAAPass + * \brief Graphics class that represents the pass for FXAA in deferred rendering + */ + + /*! + * \brief Constructs a DeferredFXAAPass object by default + */ + DeferredFXAAPass::DeferredFXAAPass() { m_fxaaShader = ShaderLibrary::Get("DeferredFXAA"); @@ -23,7 +33,16 @@ namespace Nz DeferredFXAAPass::~DeferredFXAAPass() = default; - bool DeferredFXAAPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const + /*! + * \brief Processes the work on the data while working with textures + * \return true + * + * \param sceneData Data for the scene + * \param firstWorkTexture Index of the first texture to work with + * \param firstWorkTexture Index of the second texture to work with + */ + + bool DeferredFXAAPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const { NazaraUnused(sceneData); diff --git a/src/Nazara/Graphics/DeferredFinalPass.cpp b/src/Nazara/Graphics/DeferredFinalPass.cpp index 6ca1e72c4..091c95af6 100644 --- a/src/Nazara/Graphics/DeferredFinalPass.cpp +++ b/src/Nazara/Graphics/DeferredFinalPass.cpp @@ -10,6 +10,16 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::DeferredFinalPass + * \brief Graphics class that represents the final pass in deferred rendering + */ + + /*! + * \brief Constructs a DeferredFinalPass object by default + */ + DeferredFinalPass::DeferredFinalPass() { m_pointSampler.SetAnisotropyLevel(1); @@ -34,7 +44,16 @@ namespace Nz DeferredFinalPass::~DeferredFinalPass() = default; - bool DeferredFinalPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const + /*! + * \brief Processes the work on the data while working with textures + * \return true + * + * \param sceneData Data for the scene + * \param firstWorkTexture Index of the first texture to work with + * \param firstWorkTexture Index of the second texture to work with + */ + + bool DeferredFinalPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const { NazaraAssert(sceneData.viewer, "Invalid viewer"); diff --git a/src/Nazara/Graphics/DeferredFogPass.cpp b/src/Nazara/Graphics/DeferredFogPass.cpp index af00a7c1d..f64521daf 100644 --- a/src/Nazara/Graphics/DeferredFogPass.cpp +++ b/src/Nazara/Graphics/DeferredFogPass.cpp @@ -13,6 +13,11 @@ namespace Nz { namespace { + /*! + * \brief Builds the shader for the fog + * \return Reference to the shader newly created + */ + ShaderRef BuildFogShader() { /*const UInt8 fragmentSource[] = { @@ -117,6 +122,16 @@ namespace Nz } } + /*! + * \ingroup graphics + * \class Nz::DeferredFogPass + * \brief Graphics class that represents the pass for fog in deferred rendering + */ + + /*! + * \brief Constructs a DeferredFogPass object by default + */ + DeferredFogPass::DeferredFogPass() { m_pointSampler.SetAnisotropyLevel(1); @@ -131,7 +146,16 @@ namespace Nz DeferredFogPass::~DeferredFogPass() = default; - bool DeferredFogPass::Process( const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const + /*! + * \brief Processes the work on the data while working with textures + * \return true + * + * \param sceneData Data for the scene + * \param firstWorkTexture Index of the first texture to work with + * \param firstWorkTexture Index of the second texture to work with + */ + + bool DeferredFogPass::Process( const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const { NazaraAssert(sceneData.viewer, "Invalid viewer"); diff --git a/src/Nazara/Graphics/DeferredForwardPass.cpp b/src/Nazara/Graphics/DeferredForwardPass.cpp index 35daabae8..ed7ad45d1 100644 --- a/src/Nazara/Graphics/DeferredForwardPass.cpp +++ b/src/Nazara/Graphics/DeferredForwardPass.cpp @@ -13,9 +13,21 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::DeferredForwardPass + * \brief Graphics class that represents the forward pass in deferred rendering + */ + DeferredForwardPass::DeferredForwardPass() = default; DeferredForwardPass::~DeferredForwardPass() = default; + /*! + * \brief Initializes the deferred forward pass which needs the forward technique + * + * \param technique Rendering technique + */ + void DeferredForwardPass::Initialize(DeferredRenderTechnique* technique) { DeferredRenderPass::Initialize(technique); @@ -23,7 +35,16 @@ namespace Nz m_forwardTechnique = technique->GetForwardTechnique(); } - bool DeferredForwardPass::Process(const SceneData& sceneData, unsigned int workTexture, unsigned sceneTexture) const + /*! + * \brief Processes the work on the data while working with textures + * \return true + * + * \param sceneData Data for the scene + * \param firstWorkTexture Index of the first texture to work with + * \param firstWorkTexture Index of the second texture to work with + */ + + bool DeferredForwardPass::Process(const SceneData& sceneData, unsigned int workTexture, unsigned int sceneTexture) const { NazaraAssert(sceneData.viewer, "Invalid viewer"); NazaraUnused(workTexture); diff --git a/src/Nazara/Graphics/DeferredGeometryPass.cpp b/src/Nazara/Graphics/DeferredGeometryPass.cpp index 2ae39ed9b..08b111a70 100644 --- a/src/Nazara/Graphics/DeferredGeometryPass.cpp +++ b/src/Nazara/Graphics/DeferredGeometryPass.cpp @@ -18,6 +18,16 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::DeferredGeometryPass + * \brief Graphics class that represents the pass for geometries in deferred rendering + */ + + /*! + * \brief Constructs a DeferredGeometryPass object by default + */ + DeferredGeometryPass::DeferredGeometryPass() { m_clearShader = ShaderLibrary::Get("DeferredGBufferClear"); @@ -31,7 +41,16 @@ namespace Nz DeferredGeometryPass::~DeferredGeometryPass() = default; - bool DeferredGeometryPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const + /*! + * \brief Processes the work on the data while working with textures + * \return false + * + * \param sceneData Data for the scene + * \param firstWorkTexture Index of the first texture to work with + * \param firstWorkTexture Index of the second texture to work with + */ + + bool DeferredGeometryPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const { NazaraAssert(sceneData.viewer, "Invalid viewer"); NazaraUnused(firstWorkTexture); @@ -72,22 +91,22 @@ namespace Nz bool useInstancing = instancingEnabled && matEntry.instancingEnabled; - // On commence par récupérer le programme du matériau + // We begin by getting the program for materials UInt32 flags = ShaderFlags_Deferred; if (useInstancing) flags |= ShaderFlags_Instancing; const Shader* shader = material->Apply(flags); - // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas + // The uniforms are conserved in our program, there's no point to send them back if they don't change if (shader != lastShader) { - // Index des uniformes dans le shader + // Index of uniforms in the shader shaderUniforms = GetShaderUniforms(shader); - // Couleur ambiante de la scène + // Ambient color for the scene shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); - // Position de la caméra + // Position of the camera shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); lastShader = shader; @@ -105,7 +124,7 @@ namespace Nz const IndexBuffer* indexBuffer = meshData.indexBuffer; const VertexBuffer* vertexBuffer = meshData.vertexBuffer; - // Gestion du draw call avant la boucle de rendu + // Handle draw call before rendering loop Renderer::DrawCall drawFunc; Renderer::DrawCallInstanced instancedDrawFunc; unsigned int indexCount; @@ -128,33 +147,33 @@ namespace Nz if (useInstancing) { - // On récupère le buffer d'instancing du Renderer et on le configure pour fonctionner avec des matrices + // We get the buffer for instance of Renderer and we configure it to work with matrices VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4)); const Matrix4f* instanceMatrices = &instances[0]; unsigned int instanceCount = instances.size(); - unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Le nombre de matrices que peut contenir le buffer + unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // The number of matrices that can be hold in the buffer while (instanceCount > 0) { - // On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing) + // We compute the number of instances that we will be able to show this time (Depending on the instance buffer size) unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount); instanceCount -= renderedInstanceCount; - // On remplit l'instancing buffer avec nos matrices world + // We fill the instancing buffer with our world matrices instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true); instanceMatrices += renderedInstanceCount; - // Et on affiche + // And we show instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount); } } else { - // Sans instancing, on doit effectuer un draw call pour chaque instance - // Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances - // À cause du temps de modification du buffer d'instancing + // Without instancing, we must do one draw call for each instance + // This may be faster than instancing under a threshold + // Due to the time to modify the instancing buffer for (const Matrix4f& matrix : instances) { Renderer::SetMatrix(MatrixType_World, matrix); @@ -167,16 +186,23 @@ namespace Nz } } - // Et on remet à zéro les données + // Abd we set it back data to zero matEntry.enabled = false; matEntry.instancingEnabled = false; } } } - return false; // On ne fait que remplir le G-Buffer, les work texture ne sont pas affectées + return false; // We only fill the G-Buffer, the work texture are unchanged } + /*! + * \brief Resizes the texture sizes + * \return true If successful + * + * \param dimensions Dimensions for the compute texture + */ + bool DeferredGeometryPass::Resize(const Vector2ui& dimensions) { DeferredRenderPass::Resize(dimensions); @@ -241,6 +267,13 @@ namespace Nz } } + /*! + * \brief Gets the uniforms of a shader + * \return Uniforms of the shader + * + * \param shader Shader to get uniforms from + */ + const DeferredGeometryPass::ShaderUniforms* DeferredGeometryPass::GetShaderUniforms(const Shader* shader) const { auto it = m_shaderUniforms.find(shader); @@ -260,6 +293,12 @@ namespace Nz return &it->second; } + /*! + * \brief Handle the invalidation of a shader + * + * \param shader Shader being invalidated + */ + void DeferredGeometryPass::OnShaderInvalidated(const Shader* shader) const { m_shaderUniforms.erase(shader); diff --git a/src/Nazara/Graphics/DeferredPhongLightingPass.cpp b/src/Nazara/Graphics/DeferredPhongLightingPass.cpp index c340d89a2..efcc88e75 100644 --- a/src/Nazara/Graphics/DeferredPhongLightingPass.cpp +++ b/src/Nazara/Graphics/DeferredPhongLightingPass.cpp @@ -13,6 +13,16 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::DeferredPhongLightingPass + * \brief Graphics class that represents the pass for phong lighting in deferred rendering + */ + + /*! + * \brief Constructs a DeferredPhongLightingPass object by default + */ + DeferredPhongLightingPass::DeferredPhongLightingPass() : m_lightMeshesDrawing(false) { @@ -21,7 +31,7 @@ namespace Nz m_directionalLightShaderSceneAmbientLocation = m_directionalLightShader->GetUniformLocation("SceneAmbient"); m_directionalLightUniforms.ubo = false; - m_directionalLightUniforms.locations.type = -1; // Type déjà connu + m_directionalLightUniforms.locations.type = -1; // Type already known m_directionalLightUniforms.locations.color = m_directionalLightShader->GetUniformLocation("LightColor"); m_directionalLightUniforms.locations.factors = m_directionalLightShader->GetUniformLocation("LightFactors"); m_directionalLightUniforms.locations.parameters1 = m_directionalLightShader->GetUniformLocation("LightDirection"); @@ -56,16 +66,36 @@ namespace Nz DeferredPhongLightingPass::~DeferredPhongLightingPass() = default; + /*! + * \brief Enables the drawing of meshes with light + * + * \param enable Should meshes with light parameter be drawed + */ + void DeferredPhongLightingPass::EnableLightMeshesDrawing(bool enable) { m_lightMeshesDrawing = enable; } + /*! + * \brief Checks whether the drawing of meshes with light is enabled + * \return true If it is the case + */ + bool DeferredPhongLightingPass::IsLightMeshesDrawingEnabled() const { return m_lightMeshesDrawing; } + /*! + * \brief Processes the work on the data while working with textures + * \return true + * + * \param sceneData Data for the scene + * \param firstWorkTexture Index of the first texture to work with + * \param firstWorkTexture Index of the second texture to work with + */ + bool DeferredPhongLightingPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const { NazaraAssert(sceneData.viewer, "Invalid viewer"); @@ -151,12 +181,12 @@ namespace Nz m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters1, Vector4f(light.position, light.attenuation)); m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters2, Vector4f(0.f, 0.f, 0.f, light.invRadius)); - lightMatrix.SetScale(Vector3f(light.radius * 1.1f)); // Pour corriger les imperfections liées à la sphère + lightMatrix.SetScale(Vector3f(light.radius * 1.1f)); // To correct imperfections due to the sphere lightMatrix.SetTranslation(light.position); Renderer::SetMatrix(MatrixType_World, lightMatrix); - // Rendu de la sphère dans le stencil buffer + // Sphere rendering in the stencil buffer Renderer::Enable(RendererParameter_ColorWrite, false); Renderer::Enable(RendererParameter_DepthBuffer, true); Renderer::Enable(RendererParameter_FaceCulling, false); @@ -166,7 +196,7 @@ namespace Nz Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount()); - // Rendu de la sphère comme zone d'effet + // Sphere rendering as effect zone Renderer::Enable(RendererParameter_ColorWrite, true); Renderer::Enable(RendererParameter_DepthBuffer, false); Renderer::Enable(RendererParameter_FaceCulling, true); @@ -192,7 +222,7 @@ namespace Nz Renderer::SetShader(shader); for (const auto& light : m_renderQueue->pointLights) { - lightMatrix.SetScale(Vector3f(light.radius * 1.1f)); // Pour corriger les imperfections liées à la sphère + lightMatrix.SetScale(Vector3f(light.radius * 1.1f)); // To correct imperfections due to the sphere lightMatrix.SetTranslation(light.position); Renderer::SetMatrix(MatrixType_World, lightMatrix); @@ -230,7 +260,7 @@ namespace Nz Renderer::SetMatrix(MatrixType_World, lightMatrix); - // Rendu de la sphère dans le stencil buffer + // Sphere rendering in the stencil buffer Renderer::Enable(RendererParameter_ColorWrite, false); Renderer::Enable(RendererParameter_DepthBuffer, true); Renderer::Enable(RendererParameter_FaceCulling, false); @@ -240,7 +270,7 @@ namespace Nz Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount()); - // Rendu de la sphère comme zone d'effet + // Sphere rendering as effect zone Renderer::Enable(RendererParameter_ColorWrite, true); Renderer::Enable(RendererParameter_DepthBuffer, false); Renderer::Enable(RendererParameter_FaceCulling, true); diff --git a/src/Nazara/Graphics/DeferredRenderPass.cpp b/src/Nazara/Graphics/DeferredRenderPass.cpp index 8d688c871..da40c01da 100644 --- a/src/Nazara/Graphics/DeferredRenderPass.cpp +++ b/src/Nazara/Graphics/DeferredRenderPass.cpp @@ -9,6 +9,16 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::DeferredRenderPass + * \brief Graphics class that represents the pass for rendering in deferred rendering + */ + + /*! + * \brief Constructs a DeferredRenderPass object by default + */ + DeferredRenderPass::DeferredRenderPass() : m_enabled(true) { @@ -16,11 +26,23 @@ namespace Nz DeferredRenderPass::~DeferredRenderPass() = default; + /*! + * \brief Enables the deferred rendering + * + * \param enable Should deferred rendering be activated + */ + void DeferredRenderPass::Enable(bool enable) { m_enabled = enable; } + /*! + * \brief Initializes the deferred forward pass which needs the deferred technique + * + * \param technique Rendering technique + */ + void DeferredRenderPass::Initialize(DeferredRenderTechnique* technique) { m_deferredTechnique = technique; @@ -37,11 +59,23 @@ namespace Nz m_workTextures[i] = technique->GetWorkTexture(i); } + /*! + * \brief Checks whether the deferred rendering is enabled + * \return true If it the case + */ + bool DeferredRenderPass::IsEnabled() const { return m_enabled; } + /*! + * \brief Resizes the texture sizes + * \return true If successful + * + * \param dimensions Dimensions for the compute texture + */ + bool DeferredRenderPass::Resize(const Vector2ui& dimensions) { m_dimensions = dimensions; diff --git a/src/Nazara/Graphics/DeferredRenderQueue.cpp b/src/Nazara/Graphics/DeferredRenderQueue.cpp index 5bd0931e3..738e7b799 100644 --- a/src/Nazara/Graphics/DeferredRenderQueue.cpp +++ b/src/Nazara/Graphics/DeferredRenderQueue.cpp @@ -8,69 +8,207 @@ #include #include -///TODO: Rendre les billboards via Deferred Shading si possible +///TODO: Render billboards using Deferred Shading if possible namespace Nz { + /*! + * \ingroup graphics + * \class Nz::DeferredRenderQueue + * \brief Graphics class that represents the rendering queue for deferred rendering + */ + + /*! + * \brief Constructs a DeferredRenderQueue object with the rendering queue of forward rendering + * + * \param forwardQueue Queue of data to render + */ + DeferredRenderQueue::DeferredRenderQueue(ForwardRenderQueue* forwardQueue) : m_forwardQueue(forwardQueue) { } + /*! + * \brief Adds billboard to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboard + * \param position Position of the billboard + * \param size Sizes of the billboard + * \param sinCos Rotation of the billboard + * \param color Color of the billboard + */ + void DeferredRenderQueue::AddBillboard(int renderOrder, const Material* material, const Vector3f& position, const Vector2f& size, const Vector2f& sinCos, const Color& color) { m_forwardQueue->AddBillboard(renderOrder, material, position, size, sinCos, color); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param colorPtr Color of the billboards if null, Color::White is used + */ + void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) { m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + */ + void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) { m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param colorPtr Color of the billboards if null, Color::White is used + */ + void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) { m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, colorPtr); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + */ + void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) { m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, alphaPtr); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param colorPtr Color of the billboards if null, Color::White is used + */ + void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) { m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + */ + void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) { m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param colorPtr Color of the billboards if null, Color::White is used + */ + void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) { m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, colorPtr); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + */ + void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) { m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, alphaPtr); } + /*! + * \brief Adds drawable to the queue + * + * \param renderOrder Order of rendering + * \param drawable Drawable user defined + * + * \remark Produces a NazaraError if drawable is invalid + */ + void DeferredRenderQueue::AddDrawable(int renderOrder, const Drawable* drawable) { m_forwardQueue->AddDrawable(renderOrder, drawable); } + /*! + * \brief Adds mesh to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the mesh + * \param meshData Data of the mesh + * \param meshAABB Box of the mesh + * \param transformMatrix Matrix of the mesh + */ + void DeferredRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) { if (material->IsEnabled(RendererParameter_Blend)) - // Un matériau transparent ? J'aime pas, va voir dans la forward queue si j'y suis + // One transparent material ? I don't like it, go see if I'm in the forward queue m_forwardQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix); else { @@ -103,21 +241,37 @@ namespace Nz it2 = meshMap.insert(std::make_pair(meshData, std::move(instanceEntry))).first; } - // On ajoute la matrice à la liste des instances de cet objet + // We add matrices to the list of instances of this object std::vector& instances = it2->second.instances; instances.push_back(transformMatrix); - // Avons-nous suffisamment d'instances pour que le coût d'utilisation de l'instancing soit payé ? + // Do we have enough instances to perform instancing ? if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT) - entry.instancingEnabled = true; // Apparemment oui, activons l'instancing avec ce matériau + entry.instancingEnabled = true; // Thus we can activate it } } + /*! + * \brief Adds sprites to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the sprites + * \param vertices Buffer of data for the sprites + * \param spriteCount Number of sprites + * \param overlay Texture of the sprites + */ + void DeferredRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay) { m_forwardQueue->AddSprites(renderOrder, material, vertices, spriteCount, overlay); } + /*! + * \brief Clears the queue + * + * \param fully Should everything be cleared or we can keep layers + */ + void DeferredRenderQueue::Clear(bool fully) { AbstractRenderQueue::Clear(fully); @@ -137,6 +291,13 @@ namespace Nz m_forwardQueue->Clear(fully); } + /*! + * \brief Gets the ith layer + * \return Reference to the ith layer for the queue + * + * \param i Index of the layer + */ + DeferredRenderQueue::Layer& DeferredRenderQueue::GetLayer(unsigned int i) { auto it = layers.find(i); @@ -149,6 +310,12 @@ namespace Nz return layer; } + /*! + * \brief Handle the invalidation of an index buffer + * + * \param indexBuffer Index buffer being invalidated + */ + void DeferredRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer) { for (auto& pair : layers) @@ -170,6 +337,12 @@ namespace Nz } } + /*! + * \brief Handle the invalidation of a material + * + * \param material Material being invalidated + */ + void DeferredRenderQueue::OnMaterialInvalidation(const Material* material) { for (auto& pair : layers) @@ -180,6 +353,12 @@ namespace Nz } } + /*! + * \brief Handle the invalidation of a vertex buffer + * + * \param vertexBuffer Vertex buffer being invalidated + */ + void DeferredRenderQueue::OnVertexBufferInvalidation(const VertexBuffer* vertexBuffer) { for (auto& pair : layers) @@ -201,6 +380,14 @@ namespace Nz } } + /*! + * \brief Functor to compare two batched model with material + * \return true If first material is "smaller" than the second one + * + * \param mat1 First material to compare + * \param mat2 Second material to compare + */ + bool DeferredRenderQueue::BatchedModelMaterialComparator::operator()(const Material* mat1, const Material* mat2) const { const UberShader* uberShader1 = mat1->GetShader(); @@ -221,6 +408,14 @@ namespace Nz return mat1 < mat2; } + /*! + * \brief Functor to compare two mesh data + * \return true If first mesh is "smaller" than the second one + * + * \param data1 First mesh to compare + * \param data2 Second mesh to compare + */ + bool DeferredRenderQueue::MeshDataComparator::operator()(const MeshData& data1, const MeshData& data2) const { const Buffer* buffer1; diff --git a/src/Nazara/Graphics/DeferredRenderTechnique.cpp b/src/Nazara/Graphics/DeferredRenderTechnique.cpp index 88335d92b..585091406 100644 --- a/src/Nazara/Graphics/DeferredRenderTechnique.cpp +++ b/src/Nazara/Graphics/DeferredRenderTechnique.cpp @@ -77,7 +77,18 @@ namespace Nz 3, // RenderPassType_SSAO }; - static_assert(sizeof(RenderPassPriority)/sizeof(unsigned int) == RenderPassType_Max+1, "Render pass priority array is incomplete"); + static_assert(sizeof(RenderPassPriority) / sizeof(unsigned int) == RenderPassType_Max + 1, "Render pass priority array is incomplete"); + + /*! + * \brief Registers the deferred shader + * \return Reference to the newly created shader + * + * \param name Name of the shader + * \param fragmentSource Raw data to fragment shader + * \param fragmentSourceLength Size of the fragment source + * \param vertexStage Stage of the shader + * \param err Pointer to string to contain error message + */ inline ShaderRef RegisterDeferredShader(const String& name, const UInt8* fragmentSource, unsigned int fragmentSourceLength, const ShaderStage& vertexStage, String* err) { @@ -109,6 +120,18 @@ namespace Nz } } + /*! + * \ingroup graphics + * \class Nz::DeferredRenderTechnique + * \brief Graphics class that represents the technique used in deferred rendering + */ + + /*! + * \brief Constructs a DeferredRenderTechnique object by default + * + * \remark Produces a NazaraError if one pass could not be created + */ + DeferredRenderTechnique::DeferredRenderTechnique() : m_renderQueue(static_cast(m_forwardTechnique.GetRenderQueue())), m_GBufferSize(0U) @@ -204,11 +227,27 @@ namespace Nz DeferredRenderTechnique::~DeferredRenderTechnique() = default; + /*! + * \brief Clears the data + * + * \param sceneData Data of the scene + */ + void DeferredRenderTechnique::Clear(const SceneData& sceneData) const { NazaraUnused(sceneData); } + /*! + * \brief Draws the data of the scene + * \return true If successful + * + * \param sceneData Data of the scene + * + * \remark Produces a NazaraAssert if viewer of the scene is invalid + * \remark Produces a NazaraError if updating viewport dimensions failed + */ + bool DeferredRenderTechnique::Draw(const SceneData& sceneData) const { NazaraAssert(sceneData.viewer, "Invalid viewer"); @@ -242,6 +281,14 @@ namespace Nz return true; } + /*! + * \brief Enables a pass + * + * \param renderPass Enumeration for the pass + * \param position Position of the pass + * \param enable Should the pass be enabled + */ + void DeferredRenderTechnique::EnablePass(RenderPassType renderPass, int position, bool enable) { auto it = m_passes.find(renderPass); @@ -253,11 +300,25 @@ namespace Nz } } + /*! + * \brief Gets the stencil buffer + * \return Pointer to the rendering buffer + */ + RenderBuffer* DeferredRenderTechnique::GetDepthStencilBuffer() const { return m_depthStencilBuffer; } + /*! + * \brief Gets the G-buffer + * \return Pointer to the ith texture + * + * \param i Index of the G-buffer + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if index is invalid + */ + Texture* DeferredRenderTechnique::GetGBuffer(unsigned int i) const { #if NAZARA_GRAPHICS_SAFE @@ -271,16 +332,34 @@ namespace Nz return m_GBuffer[i]; } + /*! + * \brief Gets the rendering texture of the G-buffer + * \return Pointer to the rendering buffer + */ + RenderTexture* DeferredRenderTechnique::GetGBufferRTT() const { return &m_GBufferRTT; } + /*! + * \brief Gets the forward technique + * \return Constant pointer to the forward technique + */ + const ForwardRenderTechnique* DeferredRenderTechnique::GetForwardTechnique() const { return &m_forwardTechnique; } + /*! + * \brief Gets the pass + * \return Pointer to the deferred render pass + * + * \param renderPass Enumeration for the pass + * \param position Position of the pass + */ + DeferredRenderPass* DeferredRenderTechnique::GetPass(RenderPassType renderPass, int position) { auto it = m_passes.find(renderPass); @@ -294,21 +373,45 @@ namespace Nz return nullptr; } + /*! + * \brief Gets the render queue + * \return Pointer to the render queue + */ + AbstractRenderQueue* DeferredRenderTechnique::GetRenderQueue() { return &m_renderQueue; } + /*! + * \brief Gets the type of the current technique + * \return Type of the render technique + */ + RenderTechniqueType DeferredRenderTechnique::GetType() const { return RenderTechniqueType_DeferredShading; } + /*! + * \brief Gets the render texture used to work + * \return Pointer to the rendering texture + */ + RenderTexture* DeferredRenderTechnique::GetWorkRTT() const { return &m_workRTT; } + /*! + * \brief Gets the ith texture to work + * \return Pointer to the texture + * + * \param i Index of the texture used to work + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if index is invalid + */ + Texture* DeferredRenderTechnique::GetWorkTexture(unsigned int i) const { #if NAZARA_GRAPHICS_SAFE @@ -322,6 +425,14 @@ namespace Nz return m_workTextures[i]; } + /*! + * \brief Checks whether the pass is enable + * \return true If it is the case + * + * \param renderPass Enumeration for the pass + * \param position Position of the pass + */ + bool DeferredRenderTechnique::IsPassEnabled(RenderPassType renderPass, int position) { auto it = m_passes.find(renderPass); @@ -335,9 +446,17 @@ namespace Nz return false; } + /*! + * \brief Resets the pass + * \return Pointer to the new deferred render pass + * + * \param renderPass Enumeration for the pass + * \param position Position of the pass + */ + DeferredRenderPass* DeferredRenderTechnique::ResetPass(RenderPassType renderPass, int position) { - std::unique_ptr smartPtr; // Nous évite un leak en cas d'exception + std::unique_ptr smartPtr; // We avoid to leak in case of exception switch (renderPass) { @@ -386,6 +505,14 @@ namespace Nz return smartPtr.release(); } + /*! + * \brief Sets the pass + * + * \param relativeTo Enumeration for the pass + * \param position Position of the pass + * \param pass Render pass to set + */ + void DeferredRenderTechnique::SetPass(RenderPassType relativeTo, int position, DeferredRenderPass* pass) { if (pass) @@ -400,12 +527,26 @@ namespace Nz m_passes[relativeTo].erase(position); } + /*! + * \brief Checks whether the technique is supported + * \return true if it is the case + */ + bool DeferredRenderTechnique::IsSupported() { - // Depuis qu'OpenGL 3.3 est la version minimale, le Renderer supporte ce qu'il faut, mais par acquis de conscience... + // Since OpenGL 3.3 is the minimal version, the Renderer supports what it needs, but we are never sure... return Renderer::GetMaxColorAttachments() >= 4 && Renderer::GetMaxRenderTargets() >= 4; } + /*! + * \brief Resizes the texture sizes used for the render technique + * \return true If successful + * + * \param dimensions Dimensions for the render technique + * + * \param Produces a NazaraError if one pass could not be resized + */ + bool DeferredRenderTechnique::Resize(const Vector2ui& dimensions) const { try @@ -427,6 +568,13 @@ namespace Nz } } + /*! + * \brief Initializes the deferred render technique + * \return true If successful + * + * \remark Produces a NazaraError if one shader creation failed + */ + bool DeferredRenderTechnique::Initialize() { const char vertexSource_Basic[] = @@ -560,6 +708,10 @@ namespace Nz return true; } + /*! + * \brief Uninitializes the deferred render technique + */ + void DeferredRenderTechnique::Uninitialize() { ShaderLibrary::Unregister("DeferredGBufferClear"); @@ -571,6 +723,14 @@ namespace Nz ShaderLibrary::Unregister("DeferredGaussianBlur"); } + /*! + * \brief Functor to compare two render pass + * \return true If first render pass is "smaller" than the second one + * + * \param pass1 First render pass to compare + * \param pass2 Second render pass to compare + */ + bool DeferredRenderTechnique::RenderPassComparator::operator()(RenderPassType pass1, RenderPassType pass2) const { return RenderPassPriority[pass1] < RenderPassPriority[pass2]; diff --git a/src/Nazara/Graphics/DepthRenderQueue.cpp b/src/Nazara/Graphics/DepthRenderQueue.cpp index e6fc71ae0..dc31d2a45 100644 --- a/src/Nazara/Graphics/DepthRenderQueue.cpp +++ b/src/Nazara/Graphics/DepthRenderQueue.cpp @@ -9,6 +9,16 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::DepthRenderQueue + * \brief Graphics class that represents the rendering queue for depth rendering + */ + + /*! + * \brief Constructs a DepthRenderTechnique object by default + */ + DepthRenderQueue::DepthRenderQueue() { // Material @@ -18,6 +28,19 @@ namespace Nz //m_baseMaterial->SetFaceCulling(FaceSide_Front); } + /*! + * \brief Adds billboard to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboard + * \param position Position of the billboard + * \param size Sizes of the billboard + * \param sinCos Rotation of the billboard + * \param color Color of the billboard + * + * \remark Produces a NazaraAssert if material is invalid + */ + void DepthRenderQueue::AddBillboard(int renderOrder, const Material* material, const Vector3f& position, const Vector2f& size, const Vector2f& sinCos, const Color& color) { NazaraAssert(material, "Invalid material"); @@ -34,6 +57,20 @@ namespace Nz ForwardRenderQueue::AddBillboard(0, material, position, size, sinCos, color); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param colorPtr Color of the billboards if null, Color::White is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) { NazaraAssert(material, "Invalid material"); @@ -50,6 +87,20 @@ namespace Nz ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) { NazaraAssert(material, "Invalid material"); @@ -66,6 +117,20 @@ namespace Nz ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param colorPtr Color of the billboards if null, Color::White is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) { NazaraAssert(material, "Invalid material"); @@ -82,6 +147,20 @@ namespace Nz ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, colorPtr); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) { NazaraAssert(material, "Invalid material"); @@ -98,6 +177,20 @@ namespace Nz ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, alphaPtr); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param colorPtr Color of the billboards if null, Color::White is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) { NazaraAssert(material, "Invalid material"); @@ -114,6 +207,20 @@ namespace Nz ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) { NazaraAssert(material, "Invalid material"); @@ -130,6 +237,20 @@ namespace Nz ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param colorPtr Color of the billboards if null, Color::White is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) { NazaraAssert(material, "Invalid material"); @@ -146,6 +267,20 @@ namespace Nz ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, colorPtr); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) { NazaraAssert(material, "Invalid material"); @@ -162,12 +297,32 @@ namespace Nz ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, alphaPtr); } + /*! + * \brief Adds a direcitonal light to the queue + * + * \param light Light to add + * + * \remark Produces a NazaraAssert + */ + void DepthRenderQueue::AddDirectionalLight(const DirectionalLight& light) { NazaraAssert(false, "Depth render queue doesn't handle lights"); NazaraUnused(light); } + /*! + * \brief Adds mesh to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the mesh + * \param meshData Data of the mesh + * \param meshAABB Box of the mesh + * \param transformMatrix Matrix of the mesh + * + * \remark Produces a NazaraAssert if material is invalid + */ + void DepthRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) { NazaraAssert(material, "Invalid material"); @@ -185,18 +340,46 @@ namespace Nz ForwardRenderQueue::AddMesh(0, material, meshData, meshAABB, transformMatrix); } + /*! + * \brief Adds a point light to the queue + * + * \param light Light to add + * + * \remark Produces a NazaraAssert + */ + void DepthRenderQueue::AddPointLight(const PointLight& light) { NazaraAssert(false, "Depth render queue doesn't handle lights"); NazaraUnused(light); } + /*! + * \brief Adds a spot light to the queue + * + * \param light Light to add + * + * \remark Produces a NazaraAssert + */ + void DepthRenderQueue::AddSpotLight(const SpotLight& light) { NazaraAssert(false, "Depth render queue doesn't handle lights"); NazaraUnused(light); } + /*! + * \brief Adds sprites to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the sprites + * \param vertices Buffer of data for the sprites + * \param spriteCount Number of sprites + * \param overlay Texture of the sprites + * + * \remark Produces a NazaraAssert if material is invalid + */ + void DepthRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay) { NazaraAssert(material, "Invalid material"); diff --git a/src/Nazara/Graphics/DepthRenderTechnique.cpp b/src/Nazara/Graphics/DepthRenderTechnique.cpp index 46e7fb043..233eb9c72 100644 --- a/src/Nazara/Graphics/DepthRenderTechnique.cpp +++ b/src/Nazara/Graphics/DepthRenderTechnique.cpp @@ -37,6 +37,16 @@ namespace Nz unsigned int s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB } + /*! + * \ingroup graphics + * \class Nz::DepthRenderTechnique + * \brief Graphics class that represents the technique used in depth rendering + */ + + /*! + * \brief Constructs a DepthRenderTechnique object by default + */ + DepthRenderTechnique::DepthRenderTechnique() : m_vertexBuffer(BufferType_Vertex) { @@ -48,6 +58,12 @@ namespace Nz m_spriteBuffer.Reset(VertexDeclaration::Get(VertexLayout_XYZ_Color_UV), &m_vertexBuffer); } + /*! + * \brief Clears the data + * + * \param sceneData Data of the scene + */ + void DepthRenderTechnique::Clear(const SceneData& sceneData) const { Renderer::Enable(RendererParameter_DepthBuffer, true); @@ -59,6 +75,13 @@ namespace Nz // sceneData.background->Draw(sceneData.viewer); } + /*! + * \brief Draws the data of the scene + * \return true If successful + * + * \param sceneData Data of the scene + */ + bool DepthRenderTechnique::Draw(const SceneData& sceneData) const { for (auto& pair : m_renderQueue.layers) @@ -81,16 +104,33 @@ namespace Nz return true; } + /*! + * \brief Gets the render queue + * \return Pointer to the render queue + */ + AbstractRenderQueue* DepthRenderTechnique::GetRenderQueue() { return &m_renderQueue; } + /*! + * \brief Gets the type of the current technique + * \return Type of the render technique + */ + RenderTechniqueType DepthRenderTechnique::GetType() const { return RenderTechniqueType_Depth; } + /*! + * \brief Initializes the depth render technique + * \return true If successful + * + * \remark Produces a NazaraError if one shader creation failed + */ + bool DepthRenderTechnique::Initialize() { try @@ -149,12 +189,23 @@ namespace Nz return true; } + /*! + * \brief Uninitializes the depth render technique + */ + void DepthRenderTechnique::Uninitialize() { s_quadIndexBuffer.Reset(); s_quadVertexBuffer.Reset(); } + /*! + * \brief Draws basic sprites + * + * \param sceneData Data of the scene + * \param layer Layer of the rendering + */ + void DepthRenderTechnique::DrawBasicSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const { const Shader* lastShader = nullptr; @@ -180,7 +231,7 @@ namespace Nz unsigned int spriteChainCount = spriteChainVector.size(); if (spriteChainCount > 0) { - // On commence par appliquer du matériau (et récupérer le shader ainsi activé) + // We begin to apply the material (and get the shader activated doing so) UInt32 flags = 0; if (overlay) flags |= ShaderFlags_TextureOverlay; @@ -195,26 +246,26 @@ namespace Nz Renderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler()); } - // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas + // Uniforms are conserved in our program, there's no point to send them back until they change if (shader != lastShader) { - // Index des uniformes dans le shader + // Index of uniforms in the shader shaderUniforms = GetShaderUniforms(shader); // Overlay shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit); - // Position de la caméra + // Position of the camera shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation()); lastShader = shader; } - unsigned int spriteChain = 0; // Quelle chaîne de sprite traitons-nous - unsigned int spriteChainOffset = 0; // À quel offset dans la dernière chaîne nous sommes-nous arrêtés + unsigned int spriteChain = 0; // Which chain of sprites are we treating + unsigned int spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain do { - // On ouvre le buffer en écriture + // We open the buffer in writing mode BufferMapper vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite); VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast(vertexMapper.GetPointer()); @@ -232,7 +283,7 @@ namespace Nz spriteCount += count; spriteChainOffset += count; - // Avons-nous traité la chaîne entière ? + // Have we treated the entire chain ? if (spriteChainOffset == currentChain.spriteCount) { spriteChain++; @@ -257,6 +308,13 @@ namespace Nz } } + /*! + * \brief Draws billboards + * + * \param sceneData Data of the scene + * \param layer Layer of the rendering + */ + void DepthRenderTechnique::DrawBillboards(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const { const Shader* lastShader = nullptr; @@ -278,16 +336,16 @@ namespace Nz unsigned int billboardCount = billboardVector.size(); if (billboardCount > 0) { - // On commence par appliquer du matériau (et récupérer le shader ainsi activé) + // We begin to apply the material (and get the shader activated doing so) const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor); - // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas + // Uniforms are conserved in our program, there's no point to send them back until they change if (shader != lastShader) { - // Index des uniformes dans le shader + // Index of uniforms in the shader shaderUniforms = GetShaderUniforms(shader); - // Position de la caméra + // Position of the camera shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation()); lastShader = shader; @@ -325,16 +383,16 @@ namespace Nz unsigned int billboardCount = billboardVector.size(); if (billboardCount > 0) { - // On commence par appliquer du matériau (et récupérer le shader ainsi activé) + // We begin to apply the material (and get the shader activated doing so) const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_VertexColor); - // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas + // Uniforms are conserved in our program, there's no point to send them back until they change if (shader != lastShader) { - // Index des uniformes dans le shader + // Index of uniforms in the shader shaderUniforms = GetShaderUniforms(shader); - // Position de la caméra + // Position of the camera shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation()); lastShader = shader; @@ -396,6 +454,13 @@ namespace Nz } } + /*! + * \brief Draws opaques models + * + * \param sceneData Data of the scene + * \param layer Layer of the rendering + */ + void DepthRenderTechnique::DrawOpaqueModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const { const Shader* lastShader = nullptr; @@ -415,14 +480,14 @@ namespace Nz bool instancing = m_instancingEnabled && matEntry.instancingEnabled; - // On commence par appliquer du matériau (et récupérer le shader ainsi activé) + // We begin to apply the material (and get the shader activated doing so) UInt8 freeTextureUnit; const Shader* shader = material->Apply((instancing) ? ShaderFlags_Instancing : 0, 0, &freeTextureUnit); - // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas + // Uniforms are conserved in our program, there's no point to send them back until they change if (shader != lastShader) { - // Index des uniformes dans le shader + // Index of uniforms in the shader shaderUniforms = GetShaderUniforms(shader); lastShader = shader; } @@ -441,7 +506,7 @@ namespace Nz const IndexBuffer* indexBuffer = meshData.indexBuffer; const VertexBuffer* vertexBuffer = meshData.vertexBuffer; - // Gestion du draw call avant la boucle de rendu + // Handle draw call before rendering loop Renderer::DrawCall drawFunc; Renderer::DrawCallInstanced instancedDrawFunc; unsigned int indexCount; @@ -464,33 +529,33 @@ namespace Nz if (instancing) { - // On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing) + // We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size) VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4)); const Matrix4f* instanceMatrices = &instances[0]; unsigned int instanceCount = instances.size(); - unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Le nombre maximum d'instances en une fois + unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // The maximum number of instances in one batch while (instanceCount > 0) { - // On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing) + // We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size) unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount); instanceCount -= renderedInstanceCount; - // On remplit l'instancing buffer avec nos matrices world + // We fill the instancing buffer with our world matrices instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true); instanceMatrices += renderedInstanceCount; - // Et on affiche + // And we draw instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount); } } else { - // Sans instancing, on doit effectuer un draw call pour chaque instance - // Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances - // À cause du temps de modification du buffer d'instancing + // Without instancing, we must do a draw call for each instance + // This may be faster than instancing under a certain number + // Due to the time to modify the instancing buffer for (const Matrix4f& matrix : instances) { Renderer::SetMatrix(MatrixType_World, matrix); @@ -502,13 +567,20 @@ namespace Nz } } - // Et on remet à zéro les données + // And we set the data back to zero matEntry.enabled = false; matEntry.instancingEnabled = false; } } } + /*! + * \brief Gets the shader uniforms + * \return Uniforms of the shader + * + * \param shader Shader to get uniforms from + */ + const DepthRenderTechnique::ShaderUniforms* DepthRenderTechnique::GetShaderUniforms(const Shader* shader) const { auto it = m_shaderUniforms.find(shader); @@ -527,6 +599,12 @@ namespace Nz return &it->second; } + /*! + * \brief Handle the invalidation of a shader + * + * \param shader Shader being invalidated + */ + void DepthRenderTechnique::OnShaderInvalidated(const Shader* shader) const { m_shaderUniforms.erase(shader); diff --git a/src/Nazara/Graphics/Drawable.cpp b/src/Nazara/Graphics/Drawable.cpp index baac1defb..7db121225 100644 --- a/src/Nazara/Graphics/Drawable.cpp +++ b/src/Nazara/Graphics/Drawable.cpp @@ -7,5 +7,13 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::Drawable + * \brief Graphics class that represents something drawable for our scene + * + * \remark This class is abstract + */ + Drawable::~Drawable() = default; } diff --git a/src/Nazara/Graphics/Formats/MeshLoader.cpp b/src/Nazara/Graphics/Formats/MeshLoader.cpp index ffd2b423e..6769072bb 100644 --- a/src/Nazara/Graphics/Formats/MeshLoader.cpp +++ b/src/Nazara/Graphics/Formats/MeshLoader.cpp @@ -27,6 +27,12 @@ namespace Nz String filePath; if (matData.GetStringParameter(MaterialData::FilePath, &filePath)) { + if (!File::Exists(filePath)) + { + NazaraWarning("Shader name does not refer to an existing file, \".tga\" is used by default"); + filePath += ".tga"; + } + MaterialRef material = Material::New(); if (material->LoadFromFile(filePath, parameters.material)) model->SetMaterial(i, std::move(material)); diff --git a/src/Nazara/Graphics/ForwardRenderQueue.cpp b/src/Nazara/Graphics/ForwardRenderQueue.cpp index 9f0f5d04d..0f182a185 100644 --- a/src/Nazara/Graphics/ForwardRenderQueue.cpp +++ b/src/Nazara/Graphics/ForwardRenderQueue.cpp @@ -7,10 +7,29 @@ #include #include -///TODO: Remplacer les sinus/cosinus par une lookup table (va booster les perfs d'un bon x10) +///TODO: Replace sinus/cosinus by a lookup table (which will lead to a speed up about 10x) namespace Nz { + /*! + * \ingroup graphics + * \class Nz::ForwardRenderQueue + * \brief Graphics class that represents the rendering queue for forward rendering + */ + + /*! + * \brief Adds billboard to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboard + * \param position Position of the billboard + * \param size Sizes of the billboard + * \param sinCos Rotation of the billboard + * \param color Color of the billboard + * + * \remark Produces a NazaraAssert if material is invalid + */ + void ForwardRenderQueue::AddBillboard(int renderOrder, const Material* material, const Vector3f& position, const Vector2f& size, const Vector2f& sinCos, const Color& color) { NazaraAssert(material, "Invalid material"); @@ -32,37 +51,33 @@ namespace Nz billboardVector.push_back(BillboardData{color, position, size, sinCos}); } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param colorPtr Color of the billboards if null, Color::White is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) { NazaraAssert(material, "Invalid material"); - ///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 if (!sinCosPtr) - sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile + sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile if (!colorPtr) - colorPtr.Reset(&Color::White, 0); // Pareil + colorPtr.Reset(&Color::White, 0); // Same - auto& billboards = GetLayer(renderOrder).billboards; - - auto it = billboards.find(material); - if (it == billboards.end()) - { - BatchedBillboardEntry entry; - entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation); - - it = billboards.insert(std::make_pair(material, std::move(entry))).first; - } - - BatchedBillboardEntry& entry = it->second; - - auto& billboardVector = entry.billboards; - unsigned int prevSize = billboardVector.size(); - billboardVector.resize(prevSize + count); - - BillboardData* billboardData = &billboardVector[prevSize]; + BillboardData* billboardData = GetBillboardData(renderOrder, material, count); for (unsigned int i = 0; i < count; ++i) { billboardData->center = *positionPtr++; @@ -73,39 +88,35 @@ namespace Nz } } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) { NazaraAssert(material, "Invalid material"); - ///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seront remplacés respectivement par Vector2f(0.f, 1.f) et Color::White Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 if (!sinCosPtr) - sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile + sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile float defaultAlpha = 1.f; if (!alphaPtr) - alphaPtr.Reset(&defaultAlpha, 0); // Pareil + alphaPtr.Reset(&defaultAlpha, 0); // Same - auto& billboards = GetLayer(renderOrder).billboards; - - auto it = billboards.find(material); - if (it == billboards.end()) - { - BatchedBillboardEntry entry; - entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation); - - it = billboards.insert(std::make_pair(material, std::move(entry))).first; - } - - BatchedBillboardEntry& entry = it->second; - - auto& billboardVector = entry.billboards; - unsigned int prevSize = billboardVector.size(); - billboardVector.resize(prevSize + count); - - BillboardData* billboardData = &billboardVector[prevSize]; + BillboardData* billboardData = GetBillboardData(renderOrder, material, count); for (unsigned int i = 0; i < count; ++i) { billboardData->center = *positionPtr++; @@ -116,37 +127,33 @@ namespace Nz } } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param colorPtr Color of the billboards if null, Color::White is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) { NazaraAssert(material, "Invalid material"); - ///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seront remplacés respectivement par Vector2f(0.f, 1.f) et Color::White float defaultRotation = 0.f; if (!anglePtr) - anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile + anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile if (!colorPtr) - colorPtr.Reset(&Color::White, 0); // Pareil + colorPtr.Reset(&Color::White, 0); // Same - auto& billboards = GetLayer(renderOrder).billboards; - - auto it = billboards.find(material); - if (it == billboards.end()) - { - BatchedBillboardEntry entry; - entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation); - - it = billboards.insert(std::make_pair(material, std::move(entry))).first; - } - - BatchedBillboardEntry& entry = it->second; - - auto& billboardVector = entry.billboards; - unsigned int prevSize = billboardVector.size(); - billboardVector.resize(prevSize + count); - - BillboardData* billboardData = &billboardVector[prevSize]; + BillboardData* billboardData = GetBillboardData(renderOrder, material, count); for (unsigned int i = 0; i < count; ++i) { float sin = std::sin(ToRadians(*anglePtr)); @@ -161,39 +168,35 @@ namespace Nz } } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) { NazaraAssert(material, "Invalid material"); - ///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seront remplacés respectivement par Vector2f(0.f, 1.f) et Color::White float defaultRotation = 0.f; if (!anglePtr) - anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile + anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile float defaultAlpha = 1.f; if (!alphaPtr) - alphaPtr.Reset(&defaultAlpha, 0); // Pareil + alphaPtr.Reset(&defaultAlpha, 0); // Same - auto& billboards = GetLayer(renderOrder).billboards; - - auto it = billboards.find(material); - if (it == billboards.end()) - { - BatchedBillboardEntry entry; - entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation); - - it = billboards.insert(std::make_pair(material, std::move(entry))).first; - } - - BatchedBillboardEntry& entry = it->second; - - auto& billboardVector = entry.billboards; - unsigned int prevSize = billboardVector.size(); - billboardVector.resize(prevSize + count); - - BillboardData* billboardData = &billboardVector[prevSize]; + BillboardData* billboardData = GetBillboardData(renderOrder, material, count); for (unsigned int i = 0; i < count; ++i) { float sin = std::sin(ToRadians(*anglePtr)); @@ -208,37 +211,33 @@ namespace Nz } } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param colorPtr Color of the billboards if null, Color::White is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) { NazaraAssert(material, "Invalid material"); - ///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seront remplacés respectivement par Vector2f(0.f, 1.f) et Color::White Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 if (!sinCosPtr) - sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile + sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile if (!colorPtr) - colorPtr.Reset(&Color::White, 0); // Pareil + colorPtr.Reset(&Color::White, 0); // Same - auto& billboards = GetLayer(renderOrder).billboards; - - auto it = billboards.find(material); - if (it == billboards.end()) - { - BatchedBillboardEntry entry; - entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation); - - it = billboards.insert(std::make_pair(material, std::move(entry))).first; - } - - BatchedBillboardEntry& entry = it->second; - - auto& billboardVector = entry.billboards; - unsigned int prevSize = billboardVector.size(); - billboardVector.resize(prevSize + count); - - BillboardData* billboardData = &billboardVector[prevSize]; + BillboardData* billboardData = GetBillboardData(renderOrder, material, count); for (unsigned int i = 0; i < count; ++i) { billboardData->center = *positionPtr++; @@ -249,39 +248,35 @@ namespace Nz } } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) { NazaraAssert(material, "Invalid material"); - ///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seront remplacés respectivement par Vector2f(0.f, 1.f) et Color::White Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 if (!sinCosPtr) - sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile + sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile float defaultAlpha = 1.f; if (!alphaPtr) - alphaPtr.Reset(&defaultAlpha, 0); // Pareil + alphaPtr.Reset(&defaultAlpha, 0); // Same - auto& billboards = GetLayer(renderOrder).billboards; - - auto it = billboards.find(material); - if (it == billboards.end()) - { - BatchedBillboardEntry entry; - entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation); - - it = billboards.insert(std::make_pair(material, std::move(entry))).first; - } - - BatchedBillboardEntry& entry = it->second; - - auto& billboardVector = entry.billboards; - unsigned int prevSize = billboardVector.size(); - billboardVector.resize(prevSize + count); - - BillboardData* billboardData = &billboardVector[prevSize]; + BillboardData* billboardData = GetBillboardData(renderOrder, material, count); for (unsigned int i = 0; i < count; ++i) { billboardData->center = *positionPtr++; @@ -292,37 +287,33 @@ namespace Nz } } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param colorPtr Color of the billboards if null, Color::White is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) { NazaraAssert(material, "Invalid material"); - ///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seront remplacés respectivement par Vector2f(0.f, 1.f) et Color::White float defaultRotation = 0.f; if (!anglePtr) - anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile + anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile if (!colorPtr) - colorPtr.Reset(&Color::White, 0); // Pareil + colorPtr.Reset(&Color::White, 0); // Same - auto& billboards = GetLayer(renderOrder).billboards; - - auto it = billboards.find(material); - if (it == billboards.end()) - { - BatchedBillboardEntry entry; - entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation); - - it = billboards.insert(std::make_pair(material, std::move(entry))).first; - } - - BatchedBillboardEntry& entry = it->second; - - auto& billboardVector = entry.billboards; - unsigned int prevSize = billboardVector.size(); - billboardVector.resize(prevSize + count); - - BillboardData* billboardData = &billboardVector[prevSize]; + BillboardData* billboardData = GetBillboardData(renderOrder, material, count); for (unsigned int i = 0; i < count; ++i) { float sin = std::sin(ToRadians(*anglePtr)); @@ -337,39 +328,35 @@ namespace Nz } } + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) { NazaraAssert(material, "Invalid material"); - ///DOC: sinCosPtr et alphaPtr peuvent être nuls, ils seront remplacés respectivement par Vector2f(0.f, 1.f) et Color::White float defaultRotation = 0.f; if (!anglePtr) - anglePtr.Reset(&defaultRotation, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile + anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile float defaultAlpha = 1.f; if (!alphaPtr) - alphaPtr.Reset(&defaultAlpha, 0); // Pareil + alphaPtr.Reset(&defaultAlpha, 0); // Same - auto& billboards = GetLayer(renderOrder).billboards; - - auto it = billboards.find(material); - if (it == billboards.end()) - { - BatchedBillboardEntry entry; - entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation); - - it = billboards.insert(std::make_pair(material, std::move(entry))).first; - } - - BatchedBillboardEntry& entry = it->second; - - auto& billboardVector = entry.billboards; - unsigned int prevSize = billboardVector.size(); - billboardVector.resize(prevSize + count); - - BillboardData* billboardData = &billboardVector[prevSize]; + BillboardData* billboardData = GetBillboardData(renderOrder, material, count); for (unsigned int i = 0; i < count; ++i) { float sin = std::sin(ToRadians(*anglePtr)); @@ -384,6 +371,15 @@ namespace Nz } } + /*! + * \brief Adds drawable to the queue + * + * \param renderOrder Order of rendering + * \param drawable Drawable user defined + * + * \remark Produces a NazaraError if drawable is invalid + */ + void ForwardRenderQueue::AddDrawable(int renderOrder, const Drawable* drawable) { #if NAZARA_GRAPHICS_SAFE @@ -399,15 +395,29 @@ namespace Nz otherDrawables.push_back(drawable); } + /*! + * \brief Adds mesh to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the mesh + * \param meshData Data of the mesh + * \param meshAABB Box of the mesh + * \param transformMatrix Matrix of the mesh + * + * \remark Produces a NazaraAssert if material is invalid + */ + void ForwardRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) { + NazaraAssert(material, "Invalid material"); + if (material->IsEnabled(RendererParameter_Blend)) { Layer& currentLayer = GetLayer(renderOrder); auto& transparentModels = currentLayer.transparentModels; auto& transparentModelData = currentLayer.transparentModelData; - // Le matériau est transparent, nous devons rendre ce mesh d'une autre façon (après le rendu des objets opaques et en les triant) + // The material is transparent, we must draw this mesh using another way (after the rendering of opages objects while sorting them) unsigned int index = transparentModelData.size(); transparentModelData.resize(index+1); @@ -455,14 +465,28 @@ namespace Nz std::vector& instances = it2->second.instances; instances.push_back(transformMatrix); - // Avons-nous suffisamment d'instances pour que le coût d'utilisation de l'instancing soit payé ? + // Do we have enough instances to perform instancing ? if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT) - entry.instancingEnabled = true; // Apparemment oui, activons l'instancing avec ce matériau + entry.instancingEnabled = true; // Thus we can activate it } } + /*! + * \brief Adds sprites to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the sprites + * \param vertices Buffer of data for the sprites + * \param spriteCount Number of sprites + * \param overlay Texture of the sprites + * + * \remark Produces a NazaraAssert if material is invalid + */ + void ForwardRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay) { + NazaraAssert(material, "Invalid material"); + Layer& currentLayer = GetLayer(renderOrder); auto& basicSprites = currentLayer.basicSprites; @@ -494,6 +518,12 @@ namespace Nz spriteVector.push_back(SpriteChain_XYZ_Color_UV({vertices, spriteCount})); } + /*! + * \brief Clears the queue + * + * \param fully Should everything be cleared or we can keep layers + */ + void ForwardRenderQueue::Clear(bool fully) { AbstractRenderQueue::Clear(fully); @@ -518,15 +548,21 @@ namespace Nz } } + /*! + * \brief Sorts the object according to the viewer position, furthest to nearest + * + * \param viewer Viewer of the scene + */ + void ForwardRenderQueue::Sort(const AbstractViewer* viewer) { Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near); Vector3f viewerPos = viewer->GetEyePosition(); Vector3f viewerNormal = viewer->GetForward(); - for (auto& layerPair : layers) + for (auto& pair : layers) { - Layer& layer = layerPair.second; + Layer& layer = pair.second; std::sort(layer.transparentModels.begin(), layer.transparentModels.end(), [&layer, &nearPlane, &viewerNormal] (unsigned int index1, unsigned int index2) { @@ -557,18 +593,61 @@ namespace Nz } } + /*! + * \brief Gets the billboard data + * \return Pointer to the data of the billboards + * + * \param renderOrder Order of rendering + * \param material Material of the billboard + */ + + ForwardRenderQueue::BillboardData* ForwardRenderQueue::GetBillboardData(int renderOrder, const Material* material, unsigned int count) + { + auto& billboards = GetLayer(renderOrder).billboards; + + auto it = billboards.find(material); + if (it == billboards.end()) + { + BatchedBillboardEntry entry; + entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation); + + it = billboards.insert(std::make_pair(material, std::move(entry))).first; + } + + BatchedBillboardEntry& entry = it->second; + + auto& billboardVector = entry.billboards; + unsigned int prevSize = billboardVector.size(); + billboardVector.resize(prevSize + count); + + return &billboardVector[prevSize]; + } + + /*! + * \brief Gets the ith layer + * \return Reference to the ith layer for the queue + * + * \param i Index of the layer + */ + ForwardRenderQueue::Layer& ForwardRenderQueue::GetLayer(int i) { auto it = layers.find(i); if (it == layers.end()) it = layers.insert(std::make_pair(i, Layer())).first; - + Layer& layer = it->second; layer.clearCount = 0; return layer; } + /*! + * \brief Handle the invalidation of an index buffer + * + * \param indexBuffer Index buffer being invalidated + */ + void ForwardRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer) { for (auto& pair : layers) @@ -590,6 +669,12 @@ namespace Nz } } + /*! + * \brief Handle the invalidation of a material + * + * \param material Material being invalidated + */ + void ForwardRenderQueue::OnMaterialInvalidation(const Material* material) { for (auto& pair : layers) @@ -602,6 +687,12 @@ namespace Nz } } + /*! + * \brief Handle the invalidation of a texture + * + * \param texture Texture being invalidated + */ + void ForwardRenderQueue::OnTextureInvalidation(const Texture* texture) { for (auto& pair : layers) @@ -615,6 +706,12 @@ namespace Nz } } + /*! + * \brief Handle the invalidation of a vertex buffer + * + * \param vertexBuffer Vertex buffer being invalidated + */ + void ForwardRenderQueue::OnVertexBufferInvalidation(const VertexBuffer* vertexBuffer) { for (auto& pair : layers) @@ -635,6 +732,14 @@ namespace Nz } } + /*! + * \brief Functor to compare two batched billboard with material + * \return true If first material is "smaller" than the second one + * + * \param mat1 First material to compare + * \param mat2 Second material to compare + */ + bool ForwardRenderQueue::BatchedBillboardComparator::operator()(const Material* mat1, const Material* mat2) const { const UberShader* uberShader1 = mat1->GetShader(); @@ -655,6 +760,14 @@ namespace Nz return mat1 < mat2; } + /*! + * \brief Functor to compare two batched model with material + * \return true If first material is "smaller" than the second one + * + * \param mat1 First material to compare + * \param mat2 Second material to compare + */ + bool ForwardRenderQueue::BatchedModelMaterialComparator::operator()(const Material* mat1, const Material* mat2) const { const UberShader* uberShader1 = mat1->GetShader(); @@ -675,6 +788,14 @@ namespace Nz return mat1 < mat2; } + /*! + * \brief Functor to compare two batched sprites with material + * \return true If first material is "smaller" than the second one + * + * \param mat1 First material to compare + * \param mat2 Second material to compare + */ + bool ForwardRenderQueue::BatchedSpriteMaterialComparator::operator()(const Material* mat1, const Material* mat2) { const UberShader* uberShader1 = mat1->GetShader(); @@ -695,6 +816,14 @@ namespace Nz return mat1 < mat2; } + /*! + * \brief Functor to compare two mesh data + * \return true If first mesh is "smaller" than the second one + * + * \param data1 First mesh to compare + * \param data2 Second mesh to compare + */ + bool ForwardRenderQueue::MeshDataComparator::operator()(const MeshData& data1, const MeshData& data2) const { const Buffer* buffer1; diff --git a/src/Nazara/Graphics/ForwardRenderTechnique.cpp b/src/Nazara/Graphics/ForwardRenderTechnique.cpp index 2ec95aee7..482852347 100644 --- a/src/Nazara/Graphics/ForwardRenderTechnique.cpp +++ b/src/Nazara/Graphics/ForwardRenderTechnique.cpp @@ -33,10 +33,20 @@ namespace Nz Vector2f uv; }; - unsigned int s_maxQuads = std::numeric_limits::max()/6; - unsigned int s_vertexBufferSize = 4*1024*1024; // 4 MiB + unsigned int s_maxQuads = std::numeric_limits::max() / 6; + unsigned int s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB } + /*! + * \ingroup graphics + * \class Nz::ForwardRenderTechnique + * \brief Graphics class that represents the technique used in forward rendering + */ + + /*! + * \brief Constructs a ForwardRenderTechnique object by default + */ + ForwardRenderTechnique::ForwardRenderTechnique() : m_vertexBuffer(BufferType_Vertex), m_maxLightPassPerObject(3) @@ -49,6 +59,12 @@ namespace Nz m_spriteBuffer.Reset(VertexDeclaration::Get(VertexLayout_XYZ_Color_UV), &m_vertexBuffer); } + /*! + * \brief Clears the data + * + * \param sceneData Data of the scene + */ + void ForwardRenderTechnique::Clear(const SceneData& sceneData) const { Renderer::Enable(RendererParameter_DepthBuffer, true); @@ -59,6 +75,15 @@ namespace Nz sceneData.background->Draw(sceneData.viewer); } + /*! + * \brief Draws the data of the scene + * \return true If successful + * + * \param sceneData Data of the scene + * + * \remark Produces a NazaraAssert if viewer of the scene is invalid + */ + bool ForwardRenderTechnique::Draw(const SceneData& sceneData) const { NazaraAssert(sceneData.viewer, "Invalid viewer"); @@ -88,55 +113,83 @@ namespace Nz return true; } + /*! + * \brief Gets the maximum number of lights available per pass per object + * \return Maximum number of light simulatenously per object + */ + unsigned int ForwardRenderTechnique::GetMaxLightPassPerObject() const { return m_maxLightPassPerObject; } + /*! + * \brief Gets the render queue + * \return Pointer to the render queue + */ + AbstractRenderQueue* ForwardRenderTechnique::GetRenderQueue() { return &m_renderQueue; } + /*! + * \brief Gets the type of the current technique + * \return Type of the render technique + */ + RenderTechniqueType ForwardRenderTechnique::GetType() const { return RenderTechniqueType_BasicForward; } - void ForwardRenderTechnique::SetMaxLightPassPerObject(unsigned int passCount) + /*! + * \brief Sets the maximum number of lights available per pass per object + * + * \param passCount Maximum number of light simulatenously per object + */ + + void ForwardRenderTechnique::SetMaxLightPassPerObject(unsigned int maxLightPassPerObject) { - m_maxLightPassPerObject = passCount; + m_maxLightPassPerObject = maxLightPassPerObject; } + /*! + * \brief Initializes the forward render technique + * \return true If successful + * + * \remark Produces a NazaraError if one shader creation failed + */ + bool ForwardRenderTechnique::Initialize() { try { ErrorFlags flags(ErrorFlag_ThrowException, true); - s_quadIndexBuffer.Reset(false, s_maxQuads*6, DataStorage_Hardware, BufferUsage_Static); + s_quadIndexBuffer.Reset(false, s_maxQuads * 6, DataStorage_Hardware, BufferUsage_Static); BufferMapper mapper(s_quadIndexBuffer, BufferAccess_WriteOnly); UInt16* indices = static_cast(mapper.GetPointer()); for (unsigned int i = 0; i < s_maxQuads; ++i) { - *indices++ = i*4 + 0; - *indices++ = i*4 + 2; - *indices++ = i*4 + 1; + *indices++ = i * 4 + 0; + *indices++ = i * 4 + 2; + *indices++ = i * 4 + 1; - *indices++ = i*4 + 2; - *indices++ = i*4 + 3; - *indices++ = i*4 + 1; + *indices++ = i * 4 + 2; + *indices++ = i * 4 + 3; + *indices++ = i * 4 + 1; } - mapper.Unmap(); // Inutile de garder le buffer ouvert plus longtemps + mapper.Unmap(); // No point to keep the buffer open any longer - // Quad buffer (utilisé pour l'instancing de billboard et de sprites) - //Note: Les UV sont calculés dans le shader + // Quad buffer (used for instancing of billboards and sprites) + //Note: UV are computed in the shader s_quadVertexBuffer.Reset(VertexDeclaration::Get(VertexLayout_XY), 4, DataStorage_Hardware, BufferUsage_Static); - float vertices[2*4] = { + float vertices[2 * 4] = { -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, @@ -145,14 +198,14 @@ namespace Nz s_quadVertexBuffer.FillRaw(vertices, 0, sizeof(vertices)); - // Déclaration lors du rendu des billboards par sommet + // Declaration used when rendering the vertex billboards s_billboardVertexDeclaration.EnableComponent(VertexComponent_Color, ComponentType_Color, NazaraOffsetOf(BillboardPoint, color)); s_billboardVertexDeclaration.EnableComponent(VertexComponent_Position, ComponentType_Float3, NazaraOffsetOf(BillboardPoint, position)); s_billboardVertexDeclaration.EnableComponent(VertexComponent_TexCoord, ComponentType_Float2, NazaraOffsetOf(BillboardPoint, uv)); - s_billboardVertexDeclaration.EnableComponent(VertexComponent_Userdata0, ComponentType_Float4, NazaraOffsetOf(BillboardPoint, size)); // Englobe sincos + s_billboardVertexDeclaration.EnableComponent(VertexComponent_Userdata0, ComponentType_Float4, NazaraOffsetOf(BillboardPoint, size)); // Includes sincos - // Declaration utilisée lors du rendu des billboards par instancing - // L'avantage ici est la copie directe (std::memcpy) des données de la RenderQueue vers le buffer GPU + // Declaration used when rendering the billboards with intancing + // The main advantage is the direct copy (std::memcpy) of data in the RenderQueue to the GPU buffer s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData0, ComponentType_Float3, NazaraOffsetOf(ForwardRenderQueue::BillboardData, center)); s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData1, ComponentType_Float4, NazaraOffsetOf(ForwardRenderQueue::BillboardData, size)); // Englobe sincos s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData2, ComponentType_Color, NazaraOffsetOf(ForwardRenderQueue::BillboardData, color)); @@ -169,12 +222,23 @@ namespace Nz return true; } + /*! + * \brief Uninitializes the forward render technique + */ + void ForwardRenderTechnique::Uninitialize() { s_quadIndexBuffer.Reset(); s_quadVertexBuffer.Reset(); } + /*! + * \brief Chooses the nearest lights for one object + * + * \param object Sphere symbolising the object + * \param includeDirectionalLights Should directional lights be included in the computation + */ + void ForwardRenderTechnique::ChooseLights(const Spheref& object, bool includeDirectionalLights) const { m_lights.clear(); @@ -213,6 +277,15 @@ namespace Nz }); } + /*! + * \brief Draws basic sprites + * + * \param sceneData Data of the scene + * \param layer Layer of the rendering + * + * \remark Produces a NazaraAssert is viewer is invalid + */ + void ForwardRenderTechnique::DrawBasicSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const { NazaraAssert(sceneData.viewer, "Invalid viewer"); @@ -240,7 +313,7 @@ namespace Nz unsigned int spriteChainCount = spriteChainVector.size(); if (spriteChainCount > 0) { - // On commence par appliquer du matériau (et récupérer le shader ainsi activé) + // We begin to apply the material (and get the shader activated doing so) UInt32 flags = ShaderFlags_VertexColor; if (overlay) flags |= ShaderFlags_TextureOverlay; @@ -255,46 +328,46 @@ namespace Nz Renderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler()); } - // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas + // Uniforms are conserved in our program, there's no point to send them back until they change if (shader != lastShader) { - // Index des uniformes dans le shader + // Index of uniforms in the shader shaderUniforms = GetShaderUniforms(shader); - // Couleur ambiante de la scène + // Ambiant color of the scene shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); // Overlay shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit); - // Position de la caméra + // Position of the camera shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); lastShader = shader; } - unsigned int spriteChain = 0; // Quelle chaîne de sprite traitons-nous - unsigned int spriteChainOffset = 0; // À quel offset dans la dernière chaîne nous sommes-nous arrêtés + unsigned int spriteChain = 0; // Which chain of sprites are we treating + unsigned int spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain do { - // On ouvre le buffer en écriture + // We open the buffer in writing mode BufferMapper vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite); VertexStruct_XYZ_Color_UV* vertices = static_cast(vertexMapper.GetPointer()); unsigned int spriteCount = 0; - unsigned int maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount()/4); + unsigned int maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4); do { ForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain]; unsigned int count = std::min(maxSpriteCount - spriteCount, currentChain.spriteCount - spriteChainOffset); - std::memcpy(vertices, currentChain.vertices + spriteChainOffset*4, 4*count*sizeof(VertexStruct_XYZ_Color_UV)); - vertices += count*4; + std::memcpy(vertices, currentChain.vertices + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV)); + vertices += count * 4; spriteCount += count; spriteChainOffset += count; - // Avons-nous traité la chaîne entière ? + // Have we treated the entire chain ? if (spriteChainOffset == currentChain.spriteCount) { spriteChain++; @@ -305,7 +378,7 @@ namespace Nz vertexMapper.Unmap(); - Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount*6); + Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6); } while (spriteChain < spriteChainCount); @@ -313,12 +386,21 @@ namespace Nz } } - // On remet à zéro + // We set it back to zero matEntry.enabled = false; } } } + /*! + * \brief Draws billboards + * + * \param sceneData Data of the scene + * \param layer Layer of the rendering + * + * \remark Produces a NazaraAssert is viewer is invalid + */ + void ForwardRenderTechnique::DrawBillboards(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const { NazaraAssert(sceneData.viewer, "Invalid viewer"); @@ -342,18 +424,18 @@ namespace Nz unsigned int billboardCount = billboardVector.size(); if (billboardCount > 0) { - // On commence par appliquer du matériau (et récupérer le shader ainsi activé) + // We begin to apply the material (and get the shader activated doing so) const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor); - // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas + // Uniforms are conserved in our program, there's no point to send them back until they change if (shader != lastShader) { - // Index des uniformes dans le shader + // Index of uniforms in the shader shaderUniforms = GetShaderUniforms(shader); - // Couleur ambiante de la scène + // Ambiant color of the scene shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); - // Position de la caméra + // Position of the camera shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); lastShader = shader; @@ -391,32 +473,32 @@ namespace Nz unsigned int billboardCount = billboardVector.size(); if (billboardCount > 0) { - // On commence par appliquer du matériau (et récupérer le shader ainsi activé) + // We begin to apply the material (and get the shader activated doing so) const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_VertexColor); - // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas + // Uniforms are conserved in our program, there's no point to send them back until they change if (shader != lastShader) { - // Index des uniformes dans le shader + // Index of uniforms in the shader shaderUniforms = GetShaderUniforms(shader); - // Couleur ambiante de la scène + // Ambiant color of the scene shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); - // Position de la caméra + // Position of the camera shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); lastShader = shader; } const ForwardRenderQueue::BillboardData* data = &billboardVector[0]; - unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount()/4); + unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount() / 4); do { unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw); billboardCount -= renderedBillboardCount; - BufferMapper vertexMapper(m_billboardPointBuffer, BufferAccess_DiscardAndWrite, 0, renderedBillboardCount*4); + BufferMapper vertexMapper(m_billboardPointBuffer, BufferAccess_DiscardAndWrite, 0, renderedBillboardCount * 4); BillboardPoint* vertices = static_cast(vertexMapper.GetPointer()); for (unsigned int i = 0; i < renderedBillboardCount; ++i) @@ -454,7 +536,7 @@ namespace Nz vertexMapper.Unmap(); - Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, renderedBillboardCount*6); + Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, renderedBillboardCount * 6); } while (billboardCount > 0); @@ -464,6 +546,15 @@ namespace Nz } } + /*! + * \brief Draws opaques models + * + * \param sceneData Data of the scene + * \param layer Layer of the rendering + * + * \remark Produces a NazaraAssert is viewer is invalid + */ + void ForwardRenderTechnique::DrawOpaqueModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const { NazaraAssert(sceneData.viewer, "Invalid viewer"); @@ -483,25 +574,25 @@ namespace Nz { const Material* material = matIt.first; - // Nous utilisons de l'instancing que lorsqu'aucune lumière (autre que directionnelle) n'est active - // Ceci car l'instancing n'est pas compatible avec la recherche des lumières les plus proches - // (Le deferred shading n'a pas ce problème) + // We only use instancing when no light (other than directional) is active + // This is because instancing is not compatible with the search of nearest lights + // Deferred shading does not have this problem bool noPointSpotLight = m_renderQueue.pointLights.empty() && m_renderQueue.spotLights.empty(); bool instancing = m_instancingEnabled && (!material->IsLightingEnabled() || noPointSpotLight) && matEntry.instancingEnabled; - // On commence par appliquer du matériau (et récupérer le shader ainsi activé) + // We begin to apply the material (and get the shader activated doing so) UInt8 freeTextureUnit; const Shader* shader = material->Apply((instancing) ? ShaderFlags_Instancing : 0, 0, &freeTextureUnit); - // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas + // Uniforms are conserved in our program, there's no point to send them back until they change if (shader != lastShader) { - // Index des uniformes dans le shader + // Index of uniforms in the shader shaderUniforms = GetShaderUniforms(shader); - // Couleur ambiante de la scène + // Ambiant color of the scene shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); - // Position de la caméra + // Position of the camera shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); lastShader = shader; @@ -521,7 +612,7 @@ namespace Nz const IndexBuffer* indexBuffer = meshData.indexBuffer; const VertexBuffer* vertexBuffer = meshData.vertexBuffer; - // Gestion du draw call avant la boucle de rendu + // Handle draw call before rendering loop Renderer::DrawCall drawFunc; Renderer::DrawCallInstanced instancedDrawFunc; unsigned int indexCount; @@ -544,17 +635,17 @@ namespace Nz if (instancing) { - // On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing) + // We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size) VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4)); - // Avec l'instancing, impossible de sélectionner les lumières pour chaque objet - // Du coup, il n'est activé que pour les lumières directionnelles + // With instancing, impossible to select the lights for each object + // So, it's only activated for directional lights unsigned int lightCount = m_renderQueue.directionalLights.size(); unsigned int lightIndex = 0; RendererComparison oldDepthFunc = Renderer::GetDepthFunc(); - unsigned int passCount = (lightCount == 0) ? 1 : (lightCount-1)/NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1; + unsigned int passCount = (lightCount == 0) ? 1 : (lightCount - 1) / NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1; for (unsigned int pass = 0; pass < passCount; ++pass) { if (shaderUniforms->hasLightUniforms) @@ -564,10 +655,10 @@ namespace Nz if (pass == 1) { - // Pour additionner le résultat des calculs de lumière - // Aucune chance d'interférer avec les paramètres du matériau car nous ne rendons que les objets opaques - // (Autrement dit, sans blending) - // Quant à la fonction de profondeur, elle ne doit être appliquée que la première fois + // To add the result of light computations + // We won't interfeer with materials parameters because we only render opaques objects + // (A.K.A., without blending) + // About the depth function, it must be applied only the first time Renderer::Enable(RendererParameter_Blend, true); Renderer::SetBlendFunc(BlendFunc_One, BlendFunc_One); Renderer::SetDepthFunc(RendererComparison_Equal); @@ -575,32 +666,32 @@ namespace Nz // Sends the uniforms for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) - SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset*i, freeTextureUnit + i); + SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset * i, freeTextureUnit + i); - // Et on passe à l'affichage + // And we give them to draw drawFunc(meshData.primitiveMode, 0, indexCount); } const Matrix4f* instanceMatrices = &instances[0]; unsigned int instanceCount = instances.size(); - unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Le nombre maximum d'instances en une fois + unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Maximum number of instance in one batch while (instanceCount > 0) { - // On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing) + // We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size) unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount); instanceCount -= renderedInstanceCount; - // On remplit l'instancing buffer avec nos matrices world + // We fill the instancing buffer with our world matrices instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true); instanceMatrices += renderedInstanceCount; - // Et on affiche + // And we draw instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount); } } - // On n'oublie pas de désactiver le blending pour ne pas interférer sur le reste du rendu + // We don't forget to disable the blending to avoid to interfeer with the rest of the rendering Renderer::Enable(RendererParameter_Blend, false); Renderer::SetDepthFunc(oldDepthFunc); } @@ -617,19 +708,19 @@ namespace Nz Renderer::SetMatrix(MatrixType_World, matrix); unsigned int lightIndex = 0; - RendererComparison oldDepthFunc = Renderer::GetDepthFunc(); // Dans le cas où nous aurions à le changer + RendererComparison oldDepthFunc = Renderer::GetDepthFunc(); // In the case where we have to change it - unsigned int passCount = (lightCount == 0) ? 1 : (lightCount-1)/NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1; + unsigned int passCount = (lightCount == 0) ? 1 : (lightCount - 1) / NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1; for (unsigned int pass = 0; pass < passCount; ++pass) { lightCount -= std::min(lightCount, NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U)); if (pass == 1) { - // Pour additionner le résultat des calculs de lumière - // Aucune chance d'interférer avec les paramètres du matériau car nous ne rendons que les objets opaques - // (Autrement dit, sans blending) - // Quant à la fonction de profondeur, elle ne doit être appliquée que la première fois + // To add the result of light computations + // We won't interfeer with materials parameters because we only render opaques objects + // (A.K.A., without blending) + // About the depth function, it must be applied only the first time Renderer::Enable(RendererParameter_Blend, true); Renderer::SetBlendFunc(BlendFunc_One, BlendFunc_One); Renderer::SetDepthFunc(RendererComparison_Equal); @@ -639,7 +730,7 @@ namespace Nz for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset*i, freeTextureUnit + i); - // Et on passe à l'affichage + // And we draw drawFunc(meshData.primitiveMode, 0, indexCount); } @@ -649,9 +740,9 @@ namespace Nz } else { - // Sans instancing, on doit effectuer un draw call pour chaque instance - // Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances - // À cause du temps de modification du buffer d'instancing + // Without instancing, we must do a draw call for each instance + // This may be faster than instancing under a certain number + // Due to the time to modify the instancing buffer for (const Matrix4f& matrix : instances) { Renderer::SetMatrix(MatrixType_World, matrix); @@ -664,13 +755,22 @@ namespace Nz } } - // Et on remet à zéro les données + // And we set the data back to zero matEntry.enabled = false; matEntry.instancingEnabled = false; } } } + /*! + * \brief Draws transparent models + * + * \param sceneData Data of the scene + * \param layer Layer of the rendering + * + * \remark Produces a NazaraAssert is viewer is invalid + */ + void ForwardRenderTechnique::DrawTransparentModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const { NazaraAssert(sceneData.viewer, "Invalid viewer"); @@ -683,25 +783,25 @@ namespace Nz { const ForwardRenderQueue::TransparentModelData& modelData = layer.transparentModelData[index]; - // Matériau + // Material const Material* material = modelData.material; - // On commence par appliquer du matériau (et récupérer le shader ainsi activé) + // We begin to apply the material (and get the shader activated doing so) UInt8 freeTextureUnit; const Shader* shader = material->Apply(0, 0, &freeTextureUnit); - // Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas + // Uniforms are conserved in our program, there's no point to send them back until they change if (shader != lastShader) { - // Index des uniformes dans le shader + // Index of uniforms in the shader shaderUniforms = GetShaderUniforms(shader); - // Couleur ambiante de la scène + // Ambiant color of the scene shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); - // Position de la caméra + // Position of the camera shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); - // On envoie les lumières directionnelles s'il y a (Les mêmes pour tous) + // We send the directional lights if there is one (same for all) if (shaderUniforms->hasLightUniforms) { lightCount = std::min(m_renderQueue.directionalLights.size(), static_cast(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS)); @@ -720,7 +820,7 @@ namespace Nz const IndexBuffer* indexBuffer = meshData.indexBuffer; const VertexBuffer* vertexBuffer = meshData.vertexBuffer; - // Gestion du draw call avant la boucle de rendu + // Handle draw call before the rendering loop Renderer::DrawCall drawFunc; unsigned int indexCount; @@ -754,6 +854,13 @@ namespace Nz } } + /*! + * \brief Gets the shader uniforms + * \return Uniforms of the shader + * + * \param shader Shader to get uniforms from + */ + const ForwardRenderTechnique::ShaderUniforms* ForwardRenderTechnique::GetShaderUniforms(const Shader* shader) const { auto it = m_shaderUniforms.find(shader); @@ -795,6 +902,12 @@ namespace Nz return &it->second; } + /*! + * \brief Handle the invalidation of a shader + * + * \param shader Shader being invalidated + */ + void ForwardRenderTechnique::OnShaderInvalidated(const Shader* shader) const { m_shaderUniforms.erase(shader); diff --git a/src/Nazara/Graphics/Graphics.cpp b/src/Nazara/Graphics/Graphics.cpp index b501682bc..c9cc652a8 100644 --- a/src/Nazara/Graphics/Graphics.cpp +++ b/src/Nazara/Graphics/Graphics.cpp @@ -28,15 +28,29 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::Graphics + * \brief Graphics class that represents the module initializer of Graphics + */ + + /*! + * \brief Initializes the Graphics module + * \return true if initialization is successful + * + * \remark Produces a NazaraNotice + * \remark Produces a NazaraError if one submodule failed + */ + bool Graphics::Initialize() { - if (s_moduleReferenceCounter > 0) + if (IsInitialized()) { s_moduleReferenceCounter++; - return true; // Déjà initialisé + return true; // Already initialized } - // Initialisation des dépendances + // Initialisation of dependances if (!Renderer::Initialize()) { NazaraError("Failed to initialize Renderer module"); @@ -45,7 +59,7 @@ namespace Nz s_moduleReferenceCounter++; - // Initialisation du module + // Initialisation of the module CallOnExit onExit(Graphics::Uninitialize); if (!Material::Initialize()) @@ -96,7 +110,7 @@ namespace Nz return false; } - // Loaders génériques + // Generic loaders Loaders::RegisterMesh(); Loaders::RegisterTexture(); @@ -133,43 +147,54 @@ namespace Nz return true; } + /*! + * \brief Checks whether the module is initialized + * \return true if module is initialized + */ + bool Graphics::IsInitialized() { return s_moduleReferenceCounter != 0; } + /*! + * \brief Uninitializes the Core module + * + * \remark Produces a NazaraNotice + */ + void Graphics::Uninitialize() { if (s_moduleReferenceCounter != 1) { - // Le module est soit encore utilisé, soit pas initialisé + // The module is still in use, or can not be uninitialized if (s_moduleReferenceCounter > 1) s_moduleReferenceCounter--; return; } - // Libération du module + // Free of module s_moduleReferenceCounter = 0; - // Libération de l'atlas s'il vient de nous + // Free of atlas if it is ours std::shared_ptr defaultAtlas = Font::GetDefaultAtlas(); if (defaultAtlas && defaultAtlas->GetStorage() & DataStorage_Hardware) { Font::SetDefaultAtlas(nullptr); - // La police par défaut peut faire vivre un atlas hardware après la libération du module (ce qui va être problématique) - // du coup, si la police par défaut utilise un atlas hardware, on lui enlève. - // Je n'aime pas cette solution mais je n'en ai pas de meilleure sous la main pour l'instant + // The default police can make live one hardware atlas after the free of a module (which could be problematic) + // So, if the default police use a hardware atlas, we stole it. + // I don't like this solution, but I don't have any better if (!defaultAtlas.unique()) { - // Encore au moins une police utilise l'atlas + // Still at least one police use the atlas Font* defaultFont = Font::GetDefault(); defaultFont->SetAtlas(nullptr); if (!defaultAtlas.unique()) { - // Toujours pas seuls propriétaires ? Ah ben zut. + // Still not the only one to own it ? Then crap. NazaraWarning("Default font atlas uses hardware storage and is still used"); } } @@ -195,7 +220,7 @@ namespace Nz NazaraNotice("Uninitialized: Graphics module"); - // Libération des dépendances + // Free of dependances Renderer::Uninitialize(); } diff --git a/src/Nazara/Graphics/GuillotineTextureAtlas.cpp b/src/Nazara/Graphics/GuillotineTextureAtlas.cpp index c8034d7b9..7c2122281 100644 --- a/src/Nazara/Graphics/GuillotineTextureAtlas.cpp +++ b/src/Nazara/Graphics/GuillotineTextureAtlas.cpp @@ -9,11 +9,32 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::GuillotineTextureAtlas + * \brief Graphics class that represents an atlas texture for guillotine + */ + + /*! + * \brief Gets the underlying data storage + * \return Value of the enumeration of the underlying data storage + */ + UInt32 GuillotineTextureAtlas::GetStorage() const { return DataStorage_Hardware; } + /*! + * \brief Resizes the image + * \return Updated texture + * + * \param oldImage Old image to resize + * \param size New image size + * + * \remark Produces a NazaraError if resize failed + */ + AbstractImage* GuillotineTextureAtlas::ResizeImage(AbstractImage* oldImage, const Vector2ui& size) const { std::unique_ptr newTexture(new Texture); @@ -23,8 +44,8 @@ namespace Nz { Texture* oldTexture = static_cast(oldImage); - // Copie des anciennes données - ///TODO: Copie de texture à texture + // Copy of old data + ///TODO: Copy from texture to texture Image image; if (!oldTexture->Download(&image)) { @@ -43,8 +64,7 @@ namespace Nz } else { - // Si on arrive ici c'est que la taille demandée est trop grande pour la carte graphique - // ou que nous manquons de mémoire + // If we are here, it is that the size is too big for the graphic card or we don't have enough return nullptr; } } diff --git a/src/Nazara/Graphics/InstancedRenderable.cpp b/src/Nazara/Graphics/InstancedRenderable.cpp index 780f11a67..ef5f62b96 100644 --- a/src/Nazara/Graphics/InstancedRenderable.cpp +++ b/src/Nazara/Graphics/InstancedRenderable.cpp @@ -7,16 +7,43 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::InstancedRenderable + * \brief Graphics class that represents an instancer renderable + * + * \remark This class is abstract + */ + + /*! + * \brief Destructs the object and calls OnInstancedRenderableRelease + * + * \see OnInstancedRenderableRelease + */ + InstancedRenderable::~InstancedRenderable() { OnInstancedRenderableRelease(this); } + /*! + * \brief Culls the instanced if not in the frustum + * \return true If instanced is in the frustum + * + * \param frustum Symbolizing the field of view + * \param transformMatrix Matrix transformation for our object + */ + bool InstancedRenderable::Cull(const Frustumf& frustum, const InstanceData& instanceData) const { return frustum.Contains(instanceData.volume); } + /*! + * \brief Gets the bounding volume + * \return Bounding volume of the instanced + */ + const BoundingVolumef& InstancedRenderable::GetBoundingVolume() const { EnsureBoundingVolumeUpdated(); @@ -24,11 +51,30 @@ namespace Nz return m_boundingVolume; } + /*! + * \brief Invalidates data for instanced + * + * \param instanceData Pointer to data of instances + * \param flags Flags for the instances + * + * \remark Produces a NazaraAssert if instanceData is invalid + */ + void InstancedRenderable::InvalidateData(InstanceData* instanceData, UInt32 flags) const { + NazaraAssert(instanceData, "Invalid instance data"); + instanceData->flags |= flags; } + /*! + * \brief Updates the bounding volume + * + * \param instanceData Pointer to data of instances + * + * \remark Produces a NazaraAssert if instanceData is invalid + */ + void InstancedRenderable::UpdateBoundingVolume(InstanceData* instanceData) const { NazaraAssert(instanceData, "Invalid instance data"); @@ -37,6 +83,14 @@ namespace Nz instanceData->volume.Update(instanceData->transformMatrix); } + /*! + * \brief Updates the instance data + * + * \param instanceData Pointer to data of instances + * + * \remark Produces a NazaraAssert if instanceData is invalid + */ + void InstancedRenderable::UpdateData(InstanceData* instanceData) const { NazaraAssert(instanceData, "Invalid instance data"); diff --git a/src/Nazara/Graphics/Light.cpp b/src/Nazara/Graphics/Light.cpp index 14e33100b..275d78a79 100644 --- a/src/Nazara/Graphics/Light.cpp +++ b/src/Nazara/Graphics/Light.cpp @@ -13,11 +13,23 @@ #include #include -///TODO: Utilisation des UBOs +///TODO: Use of UBOs ///TODO: Scale ? namespace Nz { + /*! + * \ingroup graphics + * \class Nz::Light + * \brief Graphics class that represents a light + */ + + /*! + * \brief Constructs a Light object with a type + * + * \param type Type of the light + */ + Light::Light(LightType type) : m_type(type), m_shadowMapFormat(PixelFormatType_Depth16), @@ -34,6 +46,15 @@ namespace Nz SetRadius(5.f); } + /*! + * \brief Adds this light to the render queue + * + * \param renderQueue Queue to be added + * \param transformMatrix Matrix transformation for this light + * + * \remark Produces a NazaraError if type is invalid + */ + void Light::AddToRenderQueue(AbstractRenderQueue* renderQueue, const Matrix4f& transformMatrix) const { static Matrix4f biasMatrix(0.5f, 0.f, 0.f, 0.f, @@ -100,16 +121,36 @@ namespace Nz } } + /*! + * \brief Clones this light + * \return Pointer to newly allocated Light + */ + Light* Light::Clone() const { return new Light(*this); } + /*! + * \brief Creates a default light + * \return Pointer to newly allocated light + */ + Light* Light::Create() const { return new Light; } + /*! + * \brief Culls the light if not in the frustum + * \return true If light is in the frustum + * + * \param frustum Symbolizing the field of view + * \param transformMatrix Matrix transformation for our object + * + * \remark Produces a NazaraError if type is invalid + */ + bool Light::Cull(const Frustumf& frustum, const Matrix4f& transformMatrix) const { switch (m_type) @@ -128,6 +169,14 @@ namespace Nz return false; } + /*! + * \brief Updates the bounding volume by a matrix + * + * \param transformMatrix Matrix transformation for our bounding volume + * + * \remark Produces a NazaraError if type is invalid + */ + void Light::UpdateBoundingVolume(const Matrix4f& transformMatrix) { switch (m_type) @@ -149,6 +198,12 @@ namespace Nz } } + /* + * \brief Makes the bounding volume of this light + * + * \remark Produces a NazaraError if type is invalid + */ + void Light::MakeBoundingVolume() const { switch (m_type) @@ -166,19 +221,19 @@ namespace Nz case LightType_Spot: { - // On forme une boite sur l'origine + // We make a box center in the origin Boxf box(Vector3f::Zero()); - // On calcule le reste des points - Vector3f base(Vector3f::Forward()*m_radius); + // We compute the other points + Vector3f base(Vector3f::Forward() * m_radius); - // Il nous faut maintenant le rayon du cercle projeté à cette distance - // Tangente = Opposé/Adjaçent <=> Opposé = Adjaçent*Tangente + // Now we need the radius of the projected circle depending on the distance + // Tangent = Opposite/Adjacent <=> Opposite = Adjacent * Tangent float radius = m_radius * m_outerAngleTangent; - Vector3f lExtend = Vector3f::Left()*radius; - Vector3f uExtend = Vector3f::Up()*radius; + Vector3f lExtend = Vector3f::Left() * radius; + Vector3f uExtend = Vector3f::Up() * radius; - // Et on ajoute ensuite les quatres extrémités de la pyramide + // And we add the four extremities of our pyramid box.ExtendTo(base + lExtend + uExtend); box.ExtendTo(base + lExtend - uExtend); box.ExtendTo(base - lExtend + uExtend); @@ -194,6 +249,10 @@ namespace Nz } } + /*! + * \brief Updates the shadow map + */ + void Light::UpdateShadowMap() const { if (m_shadowCastingEnabled) diff --git a/src/Nazara/Graphics/Material.cpp b/src/Nazara/Graphics/Material.cpp index 44ec0310d..24323960d 100644 --- a/src/Nazara/Graphics/Material.cpp +++ b/src/Nazara/Graphics/Material.cpp @@ -3,7 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #ifndef NAZARA_RENDERER_OPENGL -#define NAZARA_RENDERER_OPENGL // Nécessaire pour inclure les headers OpenGL +#define NAZARA_RENDERER_OPENGL // Mandatory to include the OpenGL headers #endif #include @@ -36,6 +36,17 @@ namespace Nz }; } + /*! + * \ingroup graphics + * \class Nz::Material + * \brief Graphics class that represents a material + */ + + /*! + * \brief Checks whether the parameters for the material are correct + * \return true If parameters are valid + */ + bool MaterialParams::IsValid() const { if (!UberShaderLibrary::Has(shaderName)) @@ -44,6 +55,15 @@ namespace Nz return true; } + /*! + * \brief Applies shader to the material + * \return Constant pointer to the shader + * + * \param shaderFlags Flags for the shader + * \param textureUnit Unit for the texture GL_TEXTURE"i" + * \param lastUsedUnit Optional argument to get the last texture unit + */ + const Shader* Material::Apply(UInt32 shaderFlags, UInt8 textureUnit, UInt8* lastUsedUnit) const { const ShaderInstance& instance = m_shaders[shaderFlags]; @@ -123,6 +143,13 @@ namespace Nz return instance.shader; } + /*! + * \brief Builds the material from parameters + * + * \param matData Data information for the material + * \param matParams Parameters for the material + */ + void Material::BuildFromParameters(const ParameterList& matData, const MaterialParams& matParams) { Color color; @@ -283,6 +310,10 @@ namespace Nz SetShader(matParams.shaderName); } + /*! + * \brief Resets the material, cleans everything + */ + void Material::Reset() { OnMaterialReset(this); @@ -319,9 +350,15 @@ namespace Nz SetShader("Basic"); } + /*! + * \brief Copies the other material + * + * \param material Material to copy into this + */ + void Material::Copy(const Material& material) { - // Copie des états de base + // Copy of base states m_alphaTestEnabled = material.m_alphaTestEnabled; m_alphaThreshold = material.m_alphaThreshold; m_ambientColor = material.m_ambientColor; @@ -337,7 +374,7 @@ namespace Nz m_states = material.m_states; m_transformEnabled = material.m_transformEnabled; - // Copie des références de texture + // Copy of reference to the textures m_alphaMap = material.m_alphaMap; m_depthMaterial = material.m_depthMaterial; m_diffuseMap = material.m_diffuseMap; @@ -347,10 +384,16 @@ namespace Nz m_specularMap = material.m_specularMap; m_uberShader = material.m_uberShader; - // On copie les instances de shader par la même occasion - std::memcpy(&m_shaders[0], &material.m_shaders[0], (ShaderFlags_Max+1)*sizeof(ShaderInstance)); + // We copy the instances of the shader too + std::memcpy(&m_shaders[0], &material.m_shaders[0], (ShaderFlags_Max + 1) * sizeof(ShaderInstance)); } + /*! + * \brief Generates the shader based on flag + * + * \param flags Flag for the shaer + */ + void Material::GenerateShader(UInt32 flags) const { ParameterList list; @@ -396,6 +439,13 @@ namespace Nz #undef CacheUniform } + /*! + * \brief Initializes the material librairies + * \return true If successful + * + * \remark Produces a NazaraError if the material library failed to be initialized + */ + bool Material::Initialize() { if (!MaterialLibrary::Initialize()) @@ -462,6 +512,10 @@ namespace Nz return true; } + /*! + * \brief Uninitializes the material librairies + */ + void Material::Uninitialize() { s_defaultMaterial.Reset(); diff --git a/src/Nazara/Graphics/Model.cpp b/src/Nazara/Graphics/Model.cpp index e8954a886..d382c77d9 100644 --- a/src/Nazara/Graphics/Model.cpp +++ b/src/Nazara/Graphics/Model.cpp @@ -12,11 +12,26 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::Model + * \brief Graphics class that represents a model + */ + + /*! + * \brief Constructs a ModelParameters object by default + */ + ModelParameters::ModelParameters() { material.shaderName = "PhongLighting"; } + /*! + * \brief Checks whether the parameters for the model are correct + * \return true If parameters are valid + */ + bool ModelParameters::IsValid() const { if (loadMaterials && !material.IsValid()) @@ -25,6 +40,10 @@ namespace Nz return mesh.IsValid(); } + /*! + * \brief Constructs a Model object by default + */ + Model::Model() : m_matCount(0), m_skin(0), @@ -32,11 +51,24 @@ namespace Nz { } + /*! + * \brief Destructs the object and calls Reset + * + * \see Reset + */ + Model::~Model() { Reset(); } + /*! + * \brief Adds this model to the render queue + * + * \param renderQueue Queue to be added + * \param instanceData Data used for this instance + */ + void Model::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const { unsigned int submeshCount = m_mesh->GetSubMeshCount(); @@ -54,6 +86,17 @@ namespace Nz } } + /*! + * \brief Gets the material of the named submesh + * \return Pointer to the current material + * + * \param subMeshName Name of the subMesh + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if there is no mesh + * \remark Produces a NazaraError if there is no subMesh with that name + * \remark Produces a NazaraError if material is invalid + */ + Material* Model::GetMaterial(const String& subMeshName) const { #if NAZARA_GRAPHICS_SAFE @@ -78,9 +121,18 @@ namespace Nz return nullptr; } - return m_materials[m_skin*m_matCount + matIndex]; + return m_materials[m_skin * m_matCount + matIndex]; } + /*! + * \brief Gets the material by index + * \return Pointer to the current material + * + * \param matIndex Index of the material + * + * \remark Produces a NazaraError if index is invalid + */ + Material* Model::GetMaterial(unsigned int matIndex) const { #if NAZARA_GRAPHICS_SAFE @@ -91,9 +143,21 @@ namespace Nz } #endif - return m_materials[m_skin*m_matCount + matIndex]; + return m_materials[m_skin * m_matCount + matIndex]; } + /*! + * \brief Gets the material by index of the named submesh + * \return Pointer to the current material + * + * \param skinIndex Index of the skin + * \param subMeshName Name of the subMesh + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if skinIndex is invalid + * \remark Produces a NazaraError if there is no subMesh with that name + * \remark Produces a NazaraError if material index is invalid + */ + Material* Model::GetMaterial(unsigned int skinIndex, const String& subMeshName) const { #if NAZARA_GRAPHICS_SAFE @@ -118,9 +182,20 @@ namespace Nz return nullptr; } - return m_materials[skinIndex*m_matCount + matIndex]; + return m_materials[skinIndex * m_matCount + matIndex]; } + /*! + * \brief Gets the material by index with skin + * \return Pointer to the current material + * + * \param skinIndex Index of the skin + * \param matIndex Index of the material + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if skinIndex is invalid + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if matIndex is invalid + */ + Material* Model::GetMaterial(unsigned int skinIndex, unsigned int matIndex) const { #if NAZARA_GRAPHICS_SAFE @@ -137,49 +212,103 @@ namespace Nz } #endif - return m_materials[skinIndex*m_matCount + matIndex]; + return m_materials[skinIndex * m_matCount + matIndex]; } + /*! + * \brief Gets the number of materials + * \return Current number of materials + */ + unsigned int Model::GetMaterialCount() const { return m_matCount; } + /*! + * \brief Gets the mesh + * \return Current mesh + */ + Mesh* Model::GetMesh() const { return m_mesh; } + /*! + * \brief Gets the skin + * \return Current skin + */ + unsigned int Model::GetSkin() const { return m_skin; } + /*! + * \brief Gets the number of skins + * \return Current number of skins + */ + unsigned int Model::GetSkinCount() const { return m_skinCount; } + /*! + * \brief Checks whether the model is animated + * \return false + */ + bool Model::IsAnimated() const { return false; } + /*! + * \brief Loads the model from file + * \return true if loading is successful + * + * \param filePath Path to the file + * \param params Parameters for the model + */ + bool Model::LoadFromFile(const String& filePath, const ModelParameters& params) { return ModelLoader::LoadFromFile(this, filePath, params); } + /*! + * \brief Loads the model from memory + * \return true if loading is successful + * + * \param data Raw memory + * \param size Size of the memory + * \param params Parameters for the model + */ + bool Model::LoadFromMemory(const void* data, std::size_t size, const ModelParameters& params) { return ModelLoader::LoadFromMemory(this, data, size, params); } + /*! + * \brief Loads the model from stream + * \return true if loading is successful + * + * \param stream Stream to the model + * \param params Parameters for the model + */ + bool Model::LoadFromStream(Stream& stream, const ModelParameters& params) { return ModelLoader::LoadFromStream(this, stream, params); } + /*! + * \brief Resets the model, cleans everything + */ + void Model::Reset() { m_matCount = 0; @@ -192,6 +321,17 @@ namespace Nz } } + /*! + * \brief Sets the material of the named submesh + * \return true If successful + * + * \param subMeshName Name of the subMesh + * \param material Pointer to the material + * + * \remark Produces a NazaraError if there is no subMesh with that name + * \remark Produces a NazaraError if material index is invalid + */ + bool Model::SetMaterial(const String& subMeshName, Material* material) { SubMesh* subMesh = m_mesh->GetSubMesh(subMeshName); @@ -208,7 +348,7 @@ namespace Nz return false; } - unsigned int index = m_skin*m_matCount + matIndex; + unsigned int index = m_skin * m_matCount + matIndex; if (material) m_materials[index] = material; @@ -218,6 +358,16 @@ namespace Nz return true; } + /*! + * \brief Sets the material by index + * \return true If successful + * + * \param matIndex Index of the material + * \param material Pointer to the material + * + * \remark Produces a NazaraError with if NAZARA_GRAPHICS_SAFE defined index is invalid + */ + void Model::SetMaterial(unsigned int matIndex, Material* material) { #if NAZARA_GRAPHICS_SAFE @@ -228,7 +378,7 @@ namespace Nz } #endif - unsigned int index = m_skin*m_matCount + matIndex; + unsigned int index = m_skin * m_matCount + matIndex; if (material) m_materials[index] = material; @@ -236,6 +386,19 @@ namespace Nz m_materials[index] = Material::GetDefault(); } + /*! + * \brief Sets the material by index of the named submesh + * \return true If successful + * + * \param skinIndex Index of the skin + * \param subMeshName Name of the subMesh + * \param material Pointer to the material + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if skinIndex is invalid + * \remark Produces a NazaraError if there is no subMesh with that name + * \remark Produces a NazaraError if material index is invalid + */ + bool Model::SetMaterial(unsigned int skinIndex, const String& subMeshName, Material* material) { #if NAZARA_GRAPHICS_SAFE @@ -260,7 +423,7 @@ namespace Nz return false; } - unsigned int index = skinIndex*m_matCount + matIndex; + unsigned int index = skinIndex * m_matCount + matIndex; if (material) m_materials[index] = material; @@ -270,6 +433,18 @@ namespace Nz return true; } + /*! + * \brief Sets the material by index with skin + * \return true If successful + * + * \param skinIndex Index of the skin + * \param matIndex Index of the material + * \param material Pointer to the material + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if skinIndex is invalid + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if matIndex is invalid + */ + void Model::SetMaterial(unsigned int skinIndex, unsigned int matIndex, Material* material) { #if NAZARA_GRAPHICS_SAFE @@ -286,7 +461,7 @@ namespace Nz } #endif - unsigned int index = skinIndex*m_matCount + matIndex; + unsigned int index = skinIndex * m_matCount + matIndex; if (material) m_materials[index] = material; @@ -294,6 +469,14 @@ namespace Nz m_materials[index] = Material::GetDefault(); } + /*! + * \brief Sets the mesh + * + * \param pointer to the mesh + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if mesh is invalid + */ + void Model::SetMesh(Mesh* mesh) { #if NAZARA_GRAPHICS_SAFE @@ -323,6 +506,14 @@ namespace Nz InvalidateBoundingVolume(); } + /*! + * \brief Sets the skin + * + * \param skin Skin to use + * + * \remark Produces a NazaraError if skin is invalid + */ + void Model::SetSkin(unsigned int skin) { #if NAZARA_GRAPHICS_SAFE @@ -336,6 +527,14 @@ namespace Nz m_skin = skin; } + /*! + * \brief Sets the number of skins + * + * \param skinCount Number of skins + * + * \remark Produces a NazaraError if skinCount equals zero + */ + void Model::SetSkinCount(unsigned int skinCount) { #if NAZARA_GRAPHICS_SAFE @@ -350,6 +549,10 @@ namespace Nz m_skinCount = skinCount; } + /* + * \brief Makes the bounding volume of this billboard + */ + void Model::MakeBoundingVolume() const { if (m_mesh) diff --git a/src/Nazara/Graphics/ParticleController.cpp b/src/Nazara/Graphics/ParticleController.cpp index 252887246..d46bb1621 100644 --- a/src/Nazara/Graphics/ParticleController.cpp +++ b/src/Nazara/Graphics/ParticleController.cpp @@ -7,17 +7,44 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::ParticleController + * \brief Graphics class which controls a flow of particles + * + * \remark This class is abstract + */ + + /*! + * \brief Constructs a ParticleController object by assignation + * + * \param controller ParticleController to copy into this + */ + ParticleController::ParticleController(const ParticleController& controller) : RefCounted() { NazaraUnused(controller); } + /*! + * \brief Destructs the object and calls OnParticleControllerRelease + * + * \see OnParticleControllerRelease + */ + ParticleController::~ParticleController() { OnParticleControllerRelease(this); } + /*! + * \brief Initializes the particle controller librairies + * \return true If successful + * + * \remark Produces a NazaraError if the particle controller library failed to be initialized + */ + bool ParticleController::Initialize() { if (!ParticleControllerLibrary::Initialize()) @@ -29,6 +56,10 @@ namespace Nz return true; } + /*! + * \brief Uninitializes the particle controller librairies + */ + void ParticleController::Uninitialize() { ParticleControllerLibrary::Uninitialize(); diff --git a/src/Nazara/Graphics/ParticleDeclaration.cpp b/src/Nazara/Graphics/ParticleDeclaration.cpp index 8d68b88ce..ecd09c752 100644 --- a/src/Nazara/Graphics/ParticleDeclaration.cpp +++ b/src/Nazara/Graphics/ParticleDeclaration.cpp @@ -15,23 +15,54 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::ParticleDeclaration + * \brief Graphics class that represents the declaration of the particle, works like an ECS + */ + + /*! + * \brief Constructs a ParticleDeclaration object by default + */ + ParticleDeclaration::ParticleDeclaration() : m_stride(0) { } + /*! + * \brief Constructs a ParticleDeclaration object by assignation + * + * \param declaration ParticleDeclaration to copy into this + */ + ParticleDeclaration::ParticleDeclaration(const ParticleDeclaration& declaration) : RefCounted(), m_stride(declaration.m_stride) { - std::memcpy(m_components, declaration.m_components, sizeof(Component)*(ParticleComponent_Max+1)); + std::memcpy(m_components, declaration.m_components, sizeof(Component) * (ParticleComponent_Max + 1)); } + /*! + * \brief Destructs the object and calls OnParticleDeclarationRelease + * + * \see OnParticleDeclarationRelease + */ + ParticleDeclaration::~ParticleDeclaration() { OnParticleDeclarationRelease(this); } + /*! + * \brief Disables a component + * + * \param component Component to disable in the declaration + * + * \remark Produces a NazaraError with NAZARA_DEBUG defined if enumeration is invalid + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if enumeration is equal to ParticleComponent_Unused + */ + void ParticleDeclaration::DisableComponent(ParticleComponent component) { #ifdef NAZARA_DEBUG @@ -58,6 +89,17 @@ namespace Nz } } + /*! + * \brief Enables a component + * + * \param component Component to enable in the declaration + * \param type Type of this component + * \param offset Offset in the declaration + * + * \remark Produces a NazaraError with NAZARA_DEBUG defined if enumeration is invalid + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if type is not supported + */ + void ParticleDeclaration::EnableComponent(ParticleComponent component, ComponentType type, unsigned int offset) { #ifdef NAZARA_DEBUG @@ -91,6 +133,18 @@ namespace Nz m_stride += Utility::ComponentStride[type]; } + /*! + * \brief Gets a component + * + * \param component Component in the declaration + * \param enabled Optional argument to get if this component is enabled + * \param type Optional argument to get if the type of the component + * \param offset Optional argument to get if the offset in the declaration + * + * \remark Produces a NazaraError with NAZARA_DEBUG defined if enumeration is invalid + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if enumeration is equal to ParticleComponent_Unused + */ + void ParticleDeclaration::GetComponent(ParticleComponent component, bool* enabled, ComponentType* type, unsigned int* offset) const { #ifdef NAZARA_DEBUG @@ -121,24 +175,51 @@ namespace Nz *offset = particleComponent.offset; } + /*! + * \brief Gets the stride of the declaration + * \return Stride of the declaration + */ + unsigned int ParticleDeclaration::GetStride() const { return m_stride; } + /*! + * \brief Sets the stride of the declaration + * + * \param stride Stride of the declaration + */ + void ParticleDeclaration::SetStride(unsigned int stride) { m_stride = stride; } + /*! + * \brief Sets the current particle declaration with the content of the other one + * \return A reference to this + * + * \param declaration The other ParticleDeclaration + */ + ParticleDeclaration& ParticleDeclaration::operator=(const ParticleDeclaration& declaration) { - std::memcpy(m_components, declaration.m_components, sizeof(Component)*(ParticleComponent_Max+1)); + std::memcpy(m_components, declaration.m_components, sizeof(Component) * (ParticleComponent_Max + 1)); m_stride = declaration.m_stride; return *this; } + /*! + * \brief Gets the particle declaration based on the layout + * \return Pointer to the declaration + * + * \param layout Layout of the particle declaration + * + * \remark Produces a NazaraError with NAZARA_DEBUG if enumeration is invalid + */ + ParticleDeclaration* ParticleDeclaration::Get(ParticleLayout layout) { #ifdef NAZARA_DEBUG @@ -152,6 +233,15 @@ namespace Nz return &s_declarations[layout]; } + /*! + * \brief Checks whether the type is supported + * \return true If it is the case + * + * \param type Type of the component + * + * \remark Produces a NazaraError if enumeration is invalid + */ + bool ParticleDeclaration::IsTypeSupported(ComponentType type) { switch (type) @@ -177,6 +267,14 @@ namespace Nz return false; } + /*! + * \brief Initializes the particle declaration librairies + * \return true If successful + * + * \remark Produces a NazaraError if the particle declaration library failed to be initialized + * \remark Produces a NazaraAssert if memory layout of declaration does not match the corresponding structure + */ + bool ParticleDeclaration::Initialize() { if (!ParticleDeclarationLibrary::Initialize()) @@ -231,11 +329,15 @@ namespace Nz return true; } + /*! + * \brief Uninitializes the particle declaration librairies + */ + void ParticleDeclaration::Uninitialize() { ParticleDeclarationLibrary::Uninitialize(); } - ParticleDeclaration ParticleDeclaration::s_declarations[ParticleLayout_Max+1]; + ParticleDeclaration ParticleDeclaration::s_declarations[ParticleLayout_Max + 1]; ParticleDeclarationLibrary::LibraryMap ParticleDeclaration::s_library; } diff --git a/src/Nazara/Graphics/ParticleEmitter.cpp b/src/Nazara/Graphics/ParticleEmitter.cpp index 9e87eb7c0..ded77d80e 100644 --- a/src/Nazara/Graphics/ParticleEmitter.cpp +++ b/src/Nazara/Graphics/ParticleEmitter.cpp @@ -14,6 +14,16 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::ParticleEmitter + * \brief Graphics class that represents an emitter of particles + */ + + /*! + * \brief Constructs a ParticleEmitter object by default + */ + ParticleEmitter::ParticleEmitter() : m_lagCompensationEnabled(false), m_emissionAccumulator(0.f), @@ -24,28 +34,35 @@ namespace Nz ParticleEmitter::~ParticleEmitter() = default; + /*! + * \brief Emits particles according to the delta time between the previous frame + * + * \param system Particle system to work on + * \param elapsedTime Delta time between the previous frame + */ + void ParticleEmitter::Emit(ParticleSystem& system, float elapsedTime) const { if (m_emissionRate > 0.f) { - // On accumule la partie réelle (pour éviter qu'un taux d'update élevé empêche des particules de se former) - m_emissionAccumulator += elapsedTime*m_emissionRate; + // We accumulate the real part (to avoid that a high emission rate prevents particles to form) + m_emissionAccumulator += elapsedTime * m_emissionRate; - float emissionCount = std::floor(m_emissionAccumulator); // Le nombre d'émissions de cette mise à jour - m_emissionAccumulator -= emissionCount; // On enlève la partie entière + float emissionCount = std::floor(m_emissionAccumulator); // The number of emissions in this update + m_emissionAccumulator -= emissionCount; // We get rid off the integer part if (emissionCount >= 1.f) { - // On calcule le nombre maximum de particules pouvant être émises cette fois-ci + // We compute the maximum number of particles which can be emitted unsigned int emissionCountInt = static_cast(emissionCount); - unsigned int maxParticleCount = emissionCountInt*m_emissionCount; + unsigned int maxParticleCount = emissionCountInt * m_emissionCount; - // On récupère le nombre de particules qu'il est possible de créer selon l'espace libre + // We get the number of particles that we are able to create (depending on the free space) unsigned int particleCount = std::min(maxParticleCount, system.GetMaxParticleCount() - system.GetParticleCount()); if (particleCount == 0) return; - // Et on émet nos particules + // And we emit our particles void* particles = system.GenerateParticles(particleCount); ParticleMapper mapper(particles, system.GetDeclaration()); @@ -53,40 +70,73 @@ namespace Nz if (m_lagCompensationEnabled) { - // On va maintenant appliquer les contrôleurs - float invEmissionRate = 1.f/m_emissionRate; + // We will now apply our controllers + float invEmissionRate = 1.f / m_emissionRate; for (unsigned int i = 1; i <= emissionCountInt; ++i) - system.ApplyControllers(mapper, std::min(m_emissionCount*i, particleCount), invEmissionRate); + system.ApplyControllers(mapper, std::min(m_emissionCount * i, particleCount), invEmissionRate); } } } } + /*! + * \brief Enables the lag compensation + * + * \param enable Should lag compensation be enabled + */ + void ParticleEmitter::EnableLagCompensation(bool enable) { m_lagCompensationEnabled = enable; } + /*! + * \brief Gets the emission count + * \return Current emission count + */ + unsigned int ParticleEmitter::GetEmissionCount() const { return m_emissionCount; } + /*! + * \brief Gets the emission rate + * \return Current emission rate + */ + float ParticleEmitter::GetEmissionRate() const { return m_emissionRate; } + /*! + * \brief Checks whether the lag compensation is enabled + * \return true If it is the case + */ + bool ParticleEmitter::IsLagCompensationEnabled() const { return m_lagCompensationEnabled; } + /*! + * \brief Sets the emission count + * + * \param count Emission count + */ + void ParticleEmitter::SetEmissionCount(unsigned int count) { m_emissionCount = count; } + /*! + * \brief Sets the emission rate + * + * \param rate Emission rate + */ + void ParticleEmitter::SetEmissionRate(float rate) { m_emissionRate = rate; diff --git a/src/Nazara/Graphics/ParticleGenerator.cpp b/src/Nazara/Graphics/ParticleGenerator.cpp index d5e3b80ff..304a99e8c 100644 --- a/src/Nazara/Graphics/ParticleGenerator.cpp +++ b/src/Nazara/Graphics/ParticleGenerator.cpp @@ -7,17 +7,44 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::ParticleGenerator + * \brief Graphics class which generates particles + * + * \remark This class is abstract + */ + + /*! + * \brief Constructs a ParticleGenerator object by assignation + * + * \param generator ParticleGenerator to copy into this + */ + ParticleGenerator::ParticleGenerator(const ParticleGenerator& generator) : RefCounted() { NazaraUnused(generator); } + /*! + * \brief Destructs the object and calls OnParticleGeneratorRelease + * + * \see OnParticleGeneratorRelease + */ + ParticleGenerator::~ParticleGenerator() { OnParticleGeneratorRelease(this); } + /*! + * \brief Initializes the particle generator librairies + * \return true If successful + * + * \remark Produces a NazaraError if the particle generator library failed to be initialized + */ + bool ParticleGenerator::Initialize() { if (!ParticleGeneratorLibrary::Initialize()) @@ -29,6 +56,10 @@ namespace Nz return true; } + /*! + * \brief Uninitializes the particle generator librairies + */ + void ParticleGenerator::Uninitialize() { ParticleGeneratorLibrary::Uninitialize(); diff --git a/src/Nazara/Graphics/ParticleMapper.cpp b/src/Nazara/Graphics/ParticleMapper.cpp index ce883e6e0..27a4b4075 100644 --- a/src/Nazara/Graphics/ParticleMapper.cpp +++ b/src/Nazara/Graphics/ParticleMapper.cpp @@ -8,6 +8,19 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::ParticleMapper + * \brief Graphics class that represents the mapping between the internal buffer and the particle declaration + */ + + /*! + * \brief Constructs a ParticleMapper object with a raw buffer and a particle declaration + * + * \param buffer Raw buffer to store particles data + * \param declaration Declaration of the particle + */ + ParticleMapper::ParticleMapper(void* buffer, const ParticleDeclaration* declaration) : m_declaration(declaration), m_ptr(static_cast(buffer)) diff --git a/src/Nazara/Graphics/ParticleRenderer.cpp b/src/Nazara/Graphics/ParticleRenderer.cpp index 96ff3dd8a..e5fa56c74 100644 --- a/src/Nazara/Graphics/ParticleRenderer.cpp +++ b/src/Nazara/Graphics/ParticleRenderer.cpp @@ -7,17 +7,42 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::ParticleRenderer + * \brief Graphics class that represents the rendering of the particle + */ + + /*! + * \brief Constructs a ParticleRenderer object by assignation + * + * \param renderer ParticleRenderer to copy into this + */ + ParticleRenderer::ParticleRenderer(const ParticleRenderer& renderer) : RefCounted() { NazaraUnused(renderer); } + /*! + * \brief Destructs the object and calls OnParticleRendererRelease + * + * \see OnParticleRendererRelease + */ + ParticleRenderer::~ParticleRenderer() { OnParticleRendererRelease(this); } + /*! + * \brief Initializes the particle renderer librairies + * \return true If successful + * + * \remark Produces a NazaraError if the particle renderer library failed to be initialized + */ + bool ParticleRenderer::Initialize() { if (!ParticleRendererLibrary::Initialize()) @@ -29,6 +54,10 @@ namespace Nz return true; } + /*! + * \brief Uninitializes the particle renderer librairies + */ + void ParticleRenderer::Uninitialize() { ParticleRendererLibrary::Uninitialize(); diff --git a/src/Nazara/Graphics/ParticleSystem.cpp b/src/Nazara/Graphics/ParticleSystem.cpp index 2ac54e4af..0783dd7fd 100644 --- a/src/Nazara/Graphics/ParticleSystem.cpp +++ b/src/Nazara/Graphics/ParticleSystem.cpp @@ -13,25 +13,51 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::ParticleSystem + * \brief Graphics class that represents the system to handle particles + */ + + /*! + * \brief Constructs a ParticleSystem object with a maximal number of particles and a layout + * + * \param maxParticleCount Maximum number of particles to generate + * \param layout Enumeration for the layout of data information for the particles + */ + ParticleSystem::ParticleSystem(unsigned int maxParticleCount, ParticleLayout layout) : ParticleSystem(maxParticleCount, ParticleDeclaration::Get(layout)) { } + /*! + * \brief Constructs a ParticleSystem object with a maximal number of particles and a particle declaration + * + * \param maxParticleCount Maximum number of particles to generate + * \param declaration Data information for the particles + */ + ParticleSystem::ParticleSystem(unsigned int maxParticleCount, ParticleDeclarationConstRef declaration) : m_declaration(std::move(declaration)), m_processing(false), m_maxParticleCount(maxParticleCount), m_particleCount(0) { - // En cas d'erreur, un constructeur ne peut que lancer une exception + // In case of error, the constructor can only throw an exception ErrorFlags flags(ErrorFlag_ThrowException, true); - m_particleSize = m_declaration->GetStride(); // La taille de chaque particule + m_particleSize = m_declaration->GetStride(); // The size of each particle ResizeBuffer(); } + /*! + * \brief Constructs a ParticleSystem object by assignation + * + * \param system ParticleSystem to copy into this + */ + ParticleSystem::ParticleSystem(const ParticleSystem& system) : Renderable(system), m_controllers(system.m_controllers), @@ -47,12 +73,20 @@ namespace Nz ResizeBuffer(); - // On ne copie que les particules vivantes + // We only copy alive particles std::memcpy(m_buffer.data(), system.m_buffer.data(), system.m_particleCount*m_particleSize); } ParticleSystem::~ParticleSystem() = default; + /*! + * \brief Adds a controller to the particles + * + * \param controller Controller for the particles + * + * \remark Produces a NazaraAssert if controller is invalid + */ + void ParticleSystem::AddController(ParticleControllerRef controller) { NazaraAssert(controller, "Invalid particle controller"); @@ -60,6 +94,14 @@ namespace Nz m_controllers.emplace_back(std::move(controller)); } + /*! + * \brief Adds an emitter to the particles + * + * \param emitter Emitter for the particles + * + * \remark Produces a NazaraAssert if emitter is invalid + */ + void ParticleSystem::AddEmitter(ParticleEmitter* emitter) { NazaraAssert(emitter, "Invalid particle emitter"); @@ -67,6 +109,14 @@ namespace Nz m_emitters.emplace_back(emitter); } + /*! + * \brief Adds a generator to the particles + * + * \param generator Generator for the particles + * + * \remark Produces a NazaraAssert if generator is invalid + */ + void ParticleSystem::AddGenerator(ParticleGeneratorRef generator) { NazaraAssert(generator, "Invalid particle generator"); @@ -74,6 +124,16 @@ namespace Nz m_generators.emplace_back(std::move(generator)); } + /*! + * \brief Adds the particle system to the rendering queue + * + * \param renderQueue Queue to be added + * \param transformMatrix Transformation matrix for the system + * + * \remark Produces a NazaraAssert if inner renderer is invalid + * \remark Produces a NazaraAssert if renderQueue is invalid + */ + void ParticleSystem::AddToRenderQueue(AbstractRenderQueue* renderQueue, const Matrix4f& transformMatrix) const { NazaraAssert(m_renderer, "Invalid particle renderer"); @@ -83,45 +143,63 @@ namespace Nz if (m_particleCount > 0) { ParticleMapper mapper(m_buffer.data(), m_declaration); - m_renderer->Render(*this, mapper, 0, m_particleCount-1, renderQueue); + m_renderer->Render(*this, mapper, 0, m_particleCount - 1, renderQueue); } } + /*! + * \brief Applies the controllers + * + * \param mapper Mapper containing layout information of each particle + * \param particleCount Number of particles + * \param elapsedTime Delta time between the previous frame + */ + void ParticleSystem::ApplyControllers(ParticleMapper& mapper, unsigned int particleCount, float elapsedTime) { m_processing = true; - // Pour éviter un verrouillage en cas d'exception + // To avoid a lock in case of exception CallOnExit onExit([this]() { m_processing = false; }); for (ParticleController* controller : m_controllers) - controller->Apply(*this, mapper, 0, particleCount-1, elapsedTime); + controller->Apply(*this, mapper, 0, particleCount - 1, elapsedTime); onExit.CallAndReset(); - // On tue maintenant les particules mortes durant la mise à jour + // We only kill now the dead particles during the update if (m_dyingParticles.size() < m_particleCount) { - // On tue les particules depuis la dernière vers la première (en terme de place), le std::set étant trié via std::greater - // La raison est simple, étant donné que la mort d'une particule signifie le déplacement de la dernière particule du buffer, - // sans cette solution certaines particules pourraient échapper à la mort + // We kill them in reverse order, std::set sorting them via std::greater + // The reason is simple, as the death of a particle means the move of the last particle in the buffer, + // without this solution, certain particles could avoid the death for (unsigned int index : m_dyingParticles) KillParticle(index); } else - KillParticles(); // Toutes les particules sont mortes, ceci est beaucoup plus rapide + KillParticles(); // Every particles are dead, this is way faster m_dyingParticles.clear(); } + /*! + * \brief Creates one particle + * \return Pointer to the particle memory buffer + */ + void* ParticleSystem::CreateParticle() { return CreateParticles(1); } + /*! + * \brief Creates multiple particles + * \return Pointer to the first particle memory buffer + */ + void* ParticleSystem::CreateParticles(unsigned int count) { if (count == 0) @@ -133,14 +211,24 @@ namespace Nz unsigned int particlesIndex = m_particleCount; m_particleCount += count; - return &m_buffer[particlesIndex*m_particleSize]; + return &m_buffer[particlesIndex * m_particleSize]; } + /*! + * \brief Generates one particle + * \return Pointer to the particle memory buffer + */ + void* ParticleSystem::GenerateParticle() { return GenerateParticles(1); } + /*! + * \brief Generates multiple particles + * \return Pointer to the first particle memory buffer + */ + void* ParticleSystem::GenerateParticles(unsigned int count) { void* ptr = CreateParticles(count); @@ -149,57 +237,108 @@ namespace Nz ParticleMapper mapper(ptr, m_declaration); for (ParticleGenerator* generator : m_generators) - generator->Generate(*this, mapper, 0, count-1); + generator->Generate(*this, mapper, 0, count - 1); return ptr; } + /*! + * \brief Gets the particle declaration + * \return Particle declaration + */ + const ParticleDeclarationConstRef& ParticleSystem::GetDeclaration() const { return m_declaration; } + /*! + * \brief Gets the fixed step size + * \return Current fixed step size + */ + float ParticleSystem::GetFixedStepSize() const { return m_stepSize; } + /*! + * \brief Gets the maximum number of particles + * \return Current maximum number + */ + unsigned int ParticleSystem::GetMaxParticleCount() const { return m_maxParticleCount; } + /*! + * \brief Gets the number of particles + * \return Current number + */ + unsigned int ParticleSystem::GetParticleCount() const { return m_particleCount; } + /*! + * \brief Gets the size of particles + * \return Current size + */ + unsigned int ParticleSystem::GetParticleSize() const { return m_particleSize; } + /*! + * \brief Checks whether the fixed step is enabled + * \return true If it is the case + */ + + bool ParticleSystem::IsFixedStepEnabled() const + { + return m_fixedStepEnabled; + } + + /*! + * \brief Kills one particle + * + * \param index Index of the particle + */ + void ParticleSystem::KillParticle(unsigned int index) { - ///FIXME: Vérifier index + ///FIXME: Verify the index if (m_processing) { - // Le buffer est en train d'être modifié, nous ne pouvons pas réduire sa taille, on place alors la particule dans une liste d'attente + // The buffer is being modified, we can not reduce its size, we put the particle in the waiting list m_dyingParticles.insert(index); return; } - // On déplace la dernière particule vivante à la place de celle-ci + // We move the last alive particle to the place of this one if (--m_particleCount > 0) - std::memcpy(&m_buffer[index*m_particleSize], &m_buffer[m_particleCount*m_particleSize], m_particleSize); + std::memcpy(&m_buffer[index * m_particleSize], &m_buffer[m_particleCount * m_particleSize], m_particleSize); } + /*! + * \brief Kills every particles + */ + void ParticleSystem::KillParticles() { m_particleCount = 0; } + /*! + * \brief Removes a controller to the particles + * + * \param controller Controller for the particles to remove + */ + void ParticleSystem::RemoveController(ParticleController* controller) { auto it = std::find(m_controllers.begin(), m_controllers.end(), controller); @@ -207,6 +346,12 @@ namespace Nz m_controllers.erase(it); } + /*! + * \brief Removes an emitter to the particles + * + * \param emitter Emitter for the particles to remove + */ + void ParticleSystem::RemoveEmitter(ParticleEmitter* emitter) { auto it = std::find(m_emitters.begin(), m_emitters.end(), emitter); @@ -214,6 +359,12 @@ namespace Nz m_emitters.erase(it); } + /*! + * \brief Removes a generator to the particles + * + * \param generator Generator for the particles to remove + */ + void ParticleSystem::RemoveGenerator(ParticleGenerator* generator) { auto it = std::find(m_generators.begin(), m_generators.end(), generator); @@ -221,31 +372,55 @@ namespace Nz m_generators.erase(it); } + /*! + * \brief Sets the fixed step size + * + * \param stepSize Fixed step size + */ + void ParticleSystem::SetFixedStepSize(float stepSize) { m_stepSize = stepSize; } + /*! + * \brief Sets the renderer of the particles + * + * \param renderer Renderer for the particles + */ + void ParticleSystem::SetRenderer(ParticleRenderer* renderer) { m_renderer = renderer; } + /*! + * \brief Updates the system + * + * \param elapsedTime Delta time between the previous frame + */ + void ParticleSystem::Update(float elapsedTime) { - // Émission + // Emission for (ParticleEmitter* emitter : m_emitters) emitter->Emit(*this, elapsedTime); - // Mise à jour + // Update if (m_particleCount > 0) { - ///TODO: Mettre à jour en utilisant des threads + ///TODO: Update using threads ParticleMapper mapper(m_buffer.data(), m_declaration); ApplyControllers(mapper, m_particleCount, elapsedTime); } } + /*! + * \brief Updates the bounding volume by a matrix + * + * \param transformMatrix Matrix transformation for our bounding volume + */ + void ParticleSystem::UpdateBoundingVolume(const Matrix4f& transformMatrix) { NazaraUnused(transformMatrix); @@ -253,6 +428,13 @@ namespace Nz // Nothing to do here (our bounding volume is global) } + /*! + * \brief Sets the current particle system with the content of the other one + * \return A reference to this + * + * \param system The other ParticleSystem + */ + ParticleSystem& ParticleSystem::operator=(const ParticleSystem& system) { ErrorFlags flags(ErrorFlag_ThrowException, true); @@ -268,29 +450,39 @@ namespace Nz m_renderer = system.m_renderer; m_stepSize = system.m_stepSize; - // La copie ne peut pas (ou plutôt ne devrait pas) avoir lieu pendant une mise à jour, inutile de copier + // The copy can not (or should not) happen during the update, there is no use to copy m_dyingParticles.clear(); m_processing = false; m_stepAccumulator = 0.f; - m_buffer.clear(); // Pour éviter une recopie lors du resize() qui ne servira pas à grand chose + m_buffer.clear(); // To avoid a copy due to resize() which will be pointless ResizeBuffer(); - // On ne copie que les particules vivantes - std::memcpy(m_buffer.data(), system.m_buffer.data(), system.m_particleCount*m_particleSize); + // We only copy alive particles + std::memcpy(m_buffer.data(), system.m_buffer.data(), system.m_particleCount * m_particleSize); return *this; } + /*! + * \brief Makes the bounding volume of this text + */ + void ParticleSystem::MakeBoundingVolume() const { - ///TODO: Calculer l'AABB (prendre la taille des particules en compte s'il y a) + ///TODO: Compute the AABB (taking into account the size of particles) m_boundingVolume.MakeInfinite(); } + /*! + * \brief Resizes the internal buffer + * + * \remark Produces a NazaraError if resize did not work + */ + void ParticleSystem::ResizeBuffer() { - // Histoire de décrire un peu mieux l'erreur en cas d'échec + // Just to have a better description of our problem in case of error try { m_buffer.resize(m_maxParticleCount*m_particleSize); diff --git a/src/Nazara/Graphics/RenderTechniques.cpp b/src/Nazara/Graphics/RenderTechniques.cpp index df3eb5582..46d84d9c4 100644 --- a/src/Nazara/Graphics/RenderTechniques.cpp +++ b/src/Nazara/Graphics/RenderTechniques.cpp @@ -23,7 +23,7 @@ namespace Nz "User" }; - static_assert(sizeof(techniquesName)/sizeof(const char*) == RenderTechniqueType_Max+1, "Render technique type name array is incomplete"); + static_assert(sizeof(techniquesName) / sizeof(const char*) == RenderTechniqueType_Max + 1, "Render technique type name array is incomplete"); struct RenderTechnique { @@ -34,6 +34,22 @@ namespace Nz std::unordered_map s_renderTechniques; } + /*! + * \ingroup graphics + * \class Nz::RenderTechniques + * \brief Graphics class that represents the techniques used in rendering + */ + + /*! + * \brief Gets the technique by enumeration + * \return A reference to the newly created technique + * + * \param renderTechnique Enumeration of the technique + * \param techniqueRanking Ranking for the technique + * + * \remark Produces a NazaraError if renderTechnique does not exist + */ + AbstractRenderTechnique* RenderTechniques::GetByEnum(RenderTechniqueType renderTechnique, int* techniqueRanking) { #ifdef NAZARA_DEBUG @@ -47,6 +63,16 @@ namespace Nz return GetByName(techniquesName[renderTechnique], techniqueRanking); } + /*! + * \brief Gets the technique by index + * \return A reference to the newly created technique + * + * \param index Index of the technique + * \param techniqueRanking Ranking for the technique + * + * \remark Produces a NazaraError if index is out or range + */ + AbstractRenderTechnique* RenderTechniques::GetByIndex(unsigned int index, int* techniqueRanking) { #if NAZARA_GRAPHICS_SAFE @@ -66,6 +92,16 @@ namespace Nz return it->second.factory(); } + /*! + * \brief Gets the technique by name + * \return A reference to the newly created technique + * + * \param name Name of the technique + * \param techniqueRanking Ranking for the technique + * + * \remark Produces a NazaraError if name does not exist or is invalid + */ + AbstractRenderTechnique* RenderTechniques::GetByName(const String& name, int* techniqueRanking) { #if NAZARA_GRAPHICS_SAFE @@ -89,6 +125,16 @@ namespace Nz return it->second.factory(); } + /*! + * \brief Gets the technique by ranking + * \return A reference to the newly created technique + * + * \param maxRanking Ranking maximum of the technique + * \param techniqueRanking Ranking for the technique + * + * \remark Produces a NazaraError if name does not exist or is invalid + */ + AbstractRenderTechnique* RenderTechniques::GetByRanking(int maxRanking, int* techniqueRanking) { if (maxRanking < 0) @@ -119,11 +165,28 @@ namespace Nz return technique->factory(); } + /*! + * \brief Gets the number of techniques available + * \return Number of techniques + */ + unsigned int RenderTechniques::GetCount() { return s_renderTechniques.size(); } + /*! + * \brief Registers a technique + * + * \param name Name of the technique + * \param ranking Ranking of the technique + * \param factory Factory to create the technique + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if name is empty + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if ranking is negative + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if factory is invalid is invalid + */ + void RenderTechniques::Register(const String& name, int ranking, RenderTechniqueFactory factory) { #if NAZARA_GRAPHICS_SAFE @@ -149,6 +212,15 @@ namespace Nz s_renderTechniques[name] = {factory, ranking}; } + /*! + * \brief Converts the enumeration to string + * \return String symbolizing the technique + * + * \param renderTechnique Enumeration of the technique + * + * \remark Produces a NazaraError if renderTechnique does not exist and returns "Error" + */ + String RenderTechniques::ToString(RenderTechniqueType renderTechnique) { #ifdef NAZARA_DEBUG @@ -162,6 +234,12 @@ namespace Nz return techniquesName[renderTechnique]; } + /*! + * \brief Unregisters a technique + * + * \param name Name of the technique + */ + void RenderTechniques::Unregister(const String& name) { s_renderTechniques.erase(name); diff --git a/src/Nazara/Graphics/Renderable.cpp b/src/Nazara/Graphics/Renderable.cpp index 932a8d127..5b02cd5cb 100644 --- a/src/Nazara/Graphics/Renderable.cpp +++ b/src/Nazara/Graphics/Renderable.cpp @@ -7,8 +7,24 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::Renderable + * \brief Graphics class that represents a renderable element for our scene + * + * \remark This class is abstract + */ + Renderable::~Renderable() = default; + /*! + * \brief Culls the model if not in the frustum + * \return true If renderable is in the frustum + * + * \param frustum Symbolizing the field of view + * \param transformMatrix Matrix transformation for our object + */ + bool Renderable::Cull(const Frustumf& frustum, const Matrix4f& transformMatrix) const { NazaraUnused(transformMatrix); @@ -16,6 +32,11 @@ namespace Nz return frustum.Contains(m_boundingVolume); } + /*! + * \brief Gets the bounding volume + * \return Bounding volume of the renderable element + */ + const BoundingVolumef& Renderable::GetBoundingVolume() const { EnsureBoundingVolumeUpdated(); @@ -23,6 +44,12 @@ namespace Nz return m_boundingVolume; } + /*! + * \brief Updates the bounding volume by a matrix + * + * \param transformMatrix Matrix transformation for our bounding volume + */ + void Renderable::UpdateBoundingVolume(const Matrix4f& transformMatrix) { m_boundingVolume.Update(transformMatrix); diff --git a/src/Nazara/Graphics/SkeletalModel.cpp b/src/Nazara/Graphics/SkeletalModel.cpp index 12bf10b6d..b91ac0076 100644 --- a/src/Nazara/Graphics/SkeletalModel.cpp +++ b/src/Nazara/Graphics/SkeletalModel.cpp @@ -14,6 +14,17 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::SkeletalModel + * \brief Graphics class that represents a model with a skeleton + */ + + /*! + * \brief Checks whether the parameters for the skeletal mesh are correct + * \return true If parameters are valid + */ + bool SkeletalModelParameters::IsValid() const { if (!ModelParameters::IsValid()) @@ -25,12 +36,23 @@ namespace Nz return true; } + /*! + * \brief Constructs a SkeletalModel object by default + */ + SkeletalModel::SkeletalModel() : m_currentSequence(nullptr), m_animationEnabled(true) { } + /*! + * \brief Adds the skeletal mesh to the rendering queue + * + * \param renderQueue Queue to be added + * \param instanceData Data for the instance + */ + void SkeletalModel::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const { if (!m_mesh) @@ -51,6 +73,14 @@ namespace Nz } } + /*! + * \brief Updates the animation of the mesh + * + * \param elapsedTime Delta time between two frames + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if there is no animation + */ + void SkeletalModel::AdvanceAnimation(float elapsedTime) { #if NAZARA_GRAPHICS_SAFE @@ -67,7 +97,7 @@ namespace Nz m_interpolation -= 1.f; unsigned lastFrame = m_currentSequence->firstFrame + m_currentSequence->frameCount - 1; - if (m_nextFrame+1 > lastFrame) + if (m_nextFrame + 1 > lastFrame) { if (m_animation->IsLoopPointInterpolationEnabled()) { @@ -77,7 +107,7 @@ namespace Nz else { m_currentFrame = m_currentSequence->firstFrame; - m_nextFrame = m_currentFrame+1; + m_nextFrame = m_currentFrame + 1; } } else @@ -92,26 +122,52 @@ namespace Nz InvalidateBoundingVolume(); } + /*! + * \brief Clones this skeletal model + * \return Pointer to newly allocated SkeletalModel + */ + SkeletalModel* SkeletalModel::Clone() const { return new SkeletalModel(*this); } + /*! + * \brief Creates a default skeletal model + * \return Pointer to newly allocated SkeletalModel + */ + SkeletalModel* SkeletalModel::Create() const { return new SkeletalModel; } + /*! + * \brief Enables the animation of the model + * + * \param animation Should the model be animated + */ + void SkeletalModel::EnableAnimation(bool animation) { m_animationEnabled = animation; } + /*! + * \brief Gets the animation of the model + * \return Pointer to the animation + */ + Animation* SkeletalModel::GetAnimation() const { return m_animation; } + /*! + * \brief Gets the skeleton of the model + * \return Pointer to the skeleton + */ + Skeleton* SkeletalModel::GetSkeleton() { InvalidateBoundingVolume(); @@ -119,41 +175,96 @@ namespace Nz return &m_skeleton; } + /*! + * \brief Gets the skeleton of the model + * \return Constant pointer to the skeleton + */ + const Skeleton* SkeletalModel::GetSkeleton() const { return &m_skeleton; } + /*! + * \brief Checks whether the skeleton has an animation + * \return true If it is the case + * + * \see IsAnimated, IsAnimationEnabled + */ + bool SkeletalModel::HasAnimation() const { return m_animation != nullptr; } + /*! + * \brief Checks whether the skeleton is animated + * \return true + * + * \see HasAnimation, IsAnimationEnabled + */ + bool SkeletalModel::IsAnimated() const { return true; } + /*! + * \brief Checks whether the skeleton is currently animated + * \return true If it is the case + * + * \see HasAnimation, IsAnimated + */ + bool SkeletalModel::IsAnimationEnabled() const { return m_animationEnabled; } + /*! + * \brief Loads the skeleton model from file + * \return true if loading is successful + * + * \param filePath Path to the file + * \param params Parameters for the skeleton model + */ + bool SkeletalModel::LoadFromFile(const String& filePath, const SkeletalModelParameters& params) { return SkeletalModelLoader::LoadFromFile(this, filePath, params); } + /*! + * \brief Loads the skeleton model from memory + * \return true if loading is successful + * + * \param data Raw memory + * \param size Size of the memory + * \param params Parameters for the skeleton model + */ + bool SkeletalModel::LoadFromMemory(const void* data, std::size_t size, const SkeletalModelParameters& params) { return SkeletalModelLoader::LoadFromMemory(this, data, size, params); } + /*! + * \brief Loads the skeleton model from stream + * \return true if loading is successful + * + * \param stream Stream to the skeleton model + * \param params Parameters for the skeleton model + */ + bool SkeletalModel::LoadFromStream(Stream& stream, const SkeletalModelParameters& params) { return SkeletalModelLoader::LoadFromStream(this, stream, params); } + /*! + * \brief Resets the model + */ + void SkeletalModel::Reset() { Model::Reset(); @@ -161,6 +272,16 @@ namespace Nz m_skeleton.Destroy(); } + /*! + * \brief Sets the animation for the model + * \return true If successful + * + * \param animation Animation for the model + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if there is no mesh + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if animation is invalid + */ + bool SkeletalModel::SetAnimation(Animation* animation) { #if NAZARA_GRAPHICS_SAFE @@ -204,6 +325,14 @@ namespace Nz return true; } + /*! + * \brief Sets the mesh for the model + * + * \param mesh Mesh for the model + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if there is no mesh or if invalid + */ + void SkeletalModel::SetMesh(Mesh* mesh) { #if NAZARA_GRAPHICS_SAFE @@ -224,13 +353,23 @@ namespace Nz SetAnimation(nullptr); } - m_skeleton = *m_mesh->GetSkeleton(); // Copie du squelette template + m_skeleton = *m_mesh->GetSkeleton(); // Copy of skeleton template } } + /*! + * \brief Sets the sequence for the model + * \return true If successful + * + * \param sequenceName Name for the sequence animation + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if there is no animation + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if sequence name does not exist for the current animation + */ + bool SkeletalModel::SetSequence(const String& sequenceName) { - ///TODO: Rendre cette erreur "safe" avec le nouveau système de gestions d'erreur (No-log) + ///TODO: Make this error "safe" with the new system of error handling (No-log) #if NAZARA_GRAPHICS_SAFE if (!m_animation) { @@ -240,11 +379,13 @@ namespace Nz #endif const Sequence* currentSequence = m_animation->GetSequence(sequenceName); + #if NAZARA_GRAPHICS_SAFE if (!currentSequence) { NazaraError("Sequence not found"); return false; } + #endif m_currentSequence = currentSequence; m_nextFrame = m_currentSequence->firstFrame; @@ -252,6 +393,15 @@ namespace Nz return true; } + /*! + * \brief Sets the sequence for the model + * + * \param sequenceIndex Index for the sequence animation + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if there is no animation + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE if sequence name does not exist for the current animation + */ + void SkeletalModel::SetSequence(unsigned int sequenceIndex) { #if NAZARA_GRAPHICS_SAFE @@ -275,13 +425,22 @@ namespace Nz m_nextFrame = m_currentSequence->firstFrame; } + /* + * \brief Makes the bounding volume of this text + */ + void SkeletalModel::MakeBoundingVolume() const { m_boundingVolume.Set(m_skeleton.GetAABB()); } + /*! + * \brief Updates the model + */ + void SkeletalModel::Update() { + ///TODO /*if (m_animationEnabled && m_animation) AdvanceAnimation(m_scene->GetUpdateTime());*/ } diff --git a/src/Nazara/Graphics/SkinningManager.cpp b/src/Nazara/Graphics/SkinningManager.cpp index 0f4b3140a..7391eeea6 100644 --- a/src/Nazara/Graphics/SkinningManager.cpp +++ b/src/Nazara/Graphics/SkinningManager.cpp @@ -46,6 +46,13 @@ namespace Nz SkeletonMap s_cache; std::vector s_skinningQueue; + /*! + * \brief Skins the mesh for a single thread context + * + * \param mesh Skeletal mesh to get vertex buffer from + * \param skeleton Skeleton to consider for getting data + * \param buffer Vertex buffer symbolizing the transition + */ void Skin_MonoCPU(const SkeletalMesh* mesh, const Skeleton* skeleton, VertexBuffer* buffer) { @@ -60,6 +67,14 @@ namespace Nz SkinPositionNormalTangent(skinningData, 0, mesh->GetVertexCount()); } + /*! + * \brief Skins the mesh for a multi-threaded context + * + * \param mesh Skeletal mesh to get vertex buffer from + * \param skeleton Skeleton to consider for getting data + * \param buffer Vertex buffer symbolizing the transition + */ + void Skin_MultiCPU(const SkeletalMesh* mesh, const Skeleton* skeleton, VertexBuffer* buffer) { BufferMapper inputMapper(mesh->GetVertexBuffer(), BufferAccess_ReadOnly); @@ -70,8 +85,8 @@ namespace Nz skinningData.outputVertex = static_cast(outputMapper.GetPointer()); skinningData.joints = skeleton->GetJoints(); - // Afin d'empêcher les différents threads de vouloir mettre à jour la même matrice en même temps, - // on se charge de la mettre à jour avant de les lancer + // To avoid different threads to update the same matrix at the same time + // We try to update them before launching the tasks unsigned int jointCount = skeleton->GetJointCount(); for (unsigned int i = 0; i < jointCount; ++i) skinningData.joints[i].EnsureSkinningMatrixUpdate(); @@ -87,6 +102,23 @@ namespace Nz } } + /*! + * \ingroup graphics + * \class Nz::SkinningManager + * \brief Graphics class that represents the management of skinning + */ + + /*! + * \brief Gets the vertex buffer from a skeletal mesh with its skeleton + * \return A pointer to the vertex buffer newly created + * + * \param mesh Skeletal mesh to get vertex buffer from + * \param skeleton Skeleton to consider for getting data + * + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if mesh is invalid + * \remark Produces a NazaraError with NAZARA_GRAPHICS_SAFE defined if skeleton is invalid + */ + VertexBuffer* SkinningManager::GetBuffer(const SkeletalMesh* mesh, const Skeleton* skeleton) { #if NAZARA_GRAPHICS_SAFE @@ -149,6 +181,10 @@ namespace Nz return buffer; } + /*! + * \brief Skins the skeletal mesh + */ + void SkinningManager::Skin() { for (QueueData& data : s_skinningQueue) @@ -157,6 +193,11 @@ namespace Nz s_skinningQueue.clear(); } + /*! + * \brief Initializes the skinning librairies + * \return true + */ + bool SkinningManager::Initialize() { ///TODO: GPU Skinning @@ -165,9 +206,15 @@ namespace Nz else s_skinFunc = Skin_MonoCPU; - return true; // Rien de particulier à faire + return true; // Nothing particular to do } + /*! + * \brief Handle the destruction of a skeletal mesh + * + * \param mesh SkeletalMesh being destroyed + */ + void SkinningManager::OnSkeletalMeshDestroy(const SkeletalMesh* mesh) { for (auto& pair : s_cache) @@ -177,17 +224,33 @@ namespace Nz } } + /*! + * \brief Handle the invalidation of a skeletal mesh + * + * \param mesh SkeletalMesh being invalidated + */ + void SkinningManager::OnSkeletonInvalidated(const Skeleton* skeleton) { for (auto& pair : s_cache.at(skeleton).meshMap) pair.second.updated = false; } + /*! + * \brief Handle the release of a skeletal mesh + * + * \param skeleton SkeletalMesh being released + */ + void SkinningManager::OnSkeletonRelease(const Skeleton* skeleton) { s_cache.erase(skeleton); } + /*! + * \brief Uninitializes the skinning librairies + */ + void SkinningManager::Uninitialize() { s_cache.clear(); diff --git a/src/Nazara/Graphics/SkyboxBackground.cpp b/src/Nazara/Graphics/SkyboxBackground.cpp index a70a9dd2d..75bc0cc12 100644 --- a/src/Nazara/Graphics/SkyboxBackground.cpp +++ b/src/Nazara/Graphics/SkyboxBackground.cpp @@ -22,6 +22,18 @@ namespace Nz static VertexBufferRef s_vertexBuffer; } + /*! + * \ingroup graphics + * \class Nz::SkyboxBackground + * \brief Graphics class that represents a background with a cubemap texture + */ + + /*! + * \brief Constructs a SkyboxBackground object with a cubemap texture + * + * \param cubemapTexture Cubemap texture + */ + SkyboxBackground::SkyboxBackground(TextureRef cubemapTexture) : m_movementOffset(Vector3f::Zero()), m_movementScale(0.f) @@ -31,6 +43,12 @@ namespace Nz SetTexture(std::move(cubemapTexture)); } + /*! + * \brief Draws this relatively to the viewer + * + * \param viewer Viewer for the background + */ + void SkyboxBackground::Draw(const AbstractViewer* viewer) const { Matrix4f skyboxMatrix(viewer->GetViewMatrix()); @@ -65,14 +83,26 @@ namespace Nz Renderer::SetMatrix(MatrixType_View, viewer->GetViewMatrix()); } + /*! + * \brief Gets the background type + * \return Type of background + */ + BackgroundType SkyboxBackground::GetBackgroundType() const { return BackgroundType_Skybox; } + /*! + * \brief Initializes the skybox + * \return true If successful + * + * \remark Produces a NazaraError if initialization failed + */ + bool SkyboxBackground::Initialize() { - const UInt16 indices[6*6] = + const UInt16 indices[6 * 6] = { 0, 1, 2, 0, 2, 3, 3, 2, 6, 3, 6, 7, @@ -170,6 +200,10 @@ namespace Nz return true; } + /*! + * \brief Uninitializes the skybox + */ + void SkyboxBackground::Uninitialize() { s_indexBuffer.Reset(); diff --git a/src/Nazara/Graphics/Sprite.cpp b/src/Nazara/Graphics/Sprite.cpp index fd4ab758f..76bf5fff2 100644 --- a/src/Nazara/Graphics/Sprite.cpp +++ b/src/Nazara/Graphics/Sprite.cpp @@ -11,6 +11,19 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::Sprite + * \brief Graphics class that represents the rendering of a sprite + */ + + /*! + * \brief Adds the sprite to the rendering queue + * + * \param renderQueue Queue to be added + * \param instanceData Data for the instance + */ + void Sprite::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const { if (!m_material) @@ -20,11 +33,21 @@ namespace Nz renderQueue->AddSprites(instanceData.renderOrder, m_material, vertices, 1); } + /*! + * \brief Makes the bounding volume of this text + */ + void Sprite::MakeBoundingVolume() const { m_boundingVolume.Set(Vector3f(0.f), m_size.x*Vector3f::Right() + m_size.y*Vector3f::Down()); } + /*! + * \brief Updates the data of the sprite + * + * \param instanceData Data of the instance + */ + void Sprite::UpdateData(InstanceData* instanceData) const { instanceData->data.resize(4 * sizeof(VertexStruct_XYZ_Color_UV)); @@ -51,6 +74,13 @@ namespace Nz *texCoordPtr++ = m_textureCoords.GetCorner(RectCorner_RightBottom); } + /*! + * \brief Initializes the sprite librairies + * \return true If successful + * + * \remark Produces a NazaraError if the sprite library failed to be initialized + */ + bool Sprite::Initialize() { if (!SpriteLibrary::Initialize()) @@ -62,6 +92,10 @@ namespace Nz return true; } + /*! + * \brief Uninitializes the sprite librairies + */ + void Sprite::Uninitialize() { SpriteLibrary::Uninitialize(); diff --git a/src/Nazara/Graphics/TextSprite.cpp b/src/Nazara/Graphics/TextSprite.cpp index 6d0e41f52..3459b22cd 100644 --- a/src/Nazara/Graphics/TextSprite.cpp +++ b/src/Nazara/Graphics/TextSprite.cpp @@ -13,6 +13,19 @@ namespace Nz { + /*! + * \ingroup graphics + * \class Nz::TextSprite + * \brief Graphics class that represents the rendering of a sprite containing text + */ + + /*! + * \brief Adds the text to the rendering queue + * + * \param renderQueue Queue to be added + * \param instanceData Data for the instance + */ + void TextSprite::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const { if (!m_material) @@ -26,11 +39,19 @@ namespace Nz if (indices.count > 0) { const VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast(instanceData.data.data()); - renderQueue->AddSprites(instanceData.renderOrder, m_material, &vertices[indices.first*4], indices.count, overlay); + renderQueue->AddSprites(instanceData.renderOrder, m_material, &vertices[indices.first * 4], indices.count, overlay); } } } + /*! + * \brief Updates the text + * + * \param drawer Drawer used to compose the text + * + * \remark Produces a NazaraAssert if atlas does not use a hardware storage + */ + void TextSprite::Update(const AbstractTextDrawer& drawer) { CallOnExit clearOnFail([this]() @@ -138,8 +159,8 @@ namespace Nz // First, compute the uv coordinates from our atlas rect Vector2ui size(texture->GetSize()); - float invWidth = 1.f/size.x; - float invHeight = 1.f/size.y; + float invWidth = 1.f / size.x; + float invHeight = 1.f / size.y; Rectf uvRect(glyph.atlasRect); uvRect.x *= invWidth; @@ -155,9 +176,9 @@ namespace Nz for (unsigned int j = 0; j < 4; ++j) { // Remember that indices->count is a counter here, not a count value - m_localVertices[indices->count*4 + j].color = glyph.color; - m_localVertices[indices->count*4 + j].position.Set(glyph.corners[j]); - m_localVertices[indices->count*4 + j].uv.Set(uvRect.GetCorner((glyph.flipped) ? flippedCorners[j] : normalCorners[j])); + m_localVertices[indices->count * 4 + j].color = glyph.color; + m_localVertices[indices->count * 4 + j].position.Set(glyph.corners[j]); + m_localVertices[indices->count * 4 + j].uv.Set(uvRect.GetCorner((glyph.flipped) ? flippedCorners[j] : normalCorners[j])); } // Increment the counter, go to next glyph @@ -172,15 +193,25 @@ namespace Nz clearOnFail.Reset(); } + /* + * \brief Makes the bounding volume of this text + */ + void TextSprite::MakeBoundingVolume() const { Rectf bounds(m_localBounds); Vector2f max = bounds.GetMaximum(); Vector2f min = bounds.GetMinimum(); - m_boundingVolume.Set(min.x*Vector3f::Right() + min.y*Vector3f::Down(), max.x*Vector3f::Right() + max.y*Vector3f::Down()); + m_boundingVolume.Set(min.x * Vector3f::Right() + min.y * Vector3f::Down(), max.x * Vector3f::Right() + max.y * Vector3f::Down()); } + /*! + * \brief Handle the invalidation of an atlas + * + * \param atlas Atlas being invalidated + */ + void TextSprite::OnAtlasInvalidated(const AbstractAtlas* atlas) { #ifdef NAZARA_DEBUG @@ -195,6 +226,14 @@ namespace Nz Clear(); } + /*! + * \brief Handle the invalidation of an atlas layer + * + * \param atlas Atlas being invalidated + * \param oldLayer Pointer to the previous layer + * \param newLayer Pointer to the new layer + */ + void TextSprite::OnAtlasLayerChange(const AbstractAtlas* atlas, AbstractImage* oldLayer, AbstractImage* newLayer) { NazaraUnused(atlas); @@ -207,23 +246,23 @@ namespace Nz } #endif - // La texture d'un atlas vient d'être recréée (changement de taille) - // nous devons ajuster les coordonnées de textures et la texture du rendu + // The texture of an atlas have just been recreated (size change) + // we have to adjust the coordinates of the texture and the rendering texture Texture* oldTexture = static_cast(oldLayer); Texture* newTexture = static_cast(newLayer); - // Il est possible que nous n'utilisions pas la texture en question (l'atlas nous prévenant pour chacun de ses layers) + // It is possible that we don't use the texture (the atlas warning us for each of its layers) auto it = m_renderInfos.find(oldTexture); if (it != m_renderInfos.end()) { - // Nous utilisons bien cette texture, nous devons mettre à jour les coordonnées de texture + // We indeed use this texture, we have to update its coordinates RenderIndices indices = std::move(it->second); Vector2ui oldSize(oldTexture->GetSize()); Vector2ui newSize(newTexture->GetSize()); - Vector2f scale = Vector2f(oldSize)/Vector2f(newSize); // ratio ancienne et nouvelle taille + Vector2f scale = Vector2f(oldSize) / Vector2f(newSize); // ratio of the old one to the new one - // On va maintenant parcourir toutes les coordonnées de texture concernées pour les multiplier par ce ratio + // Now we will iterate through each coordinates of the concerned texture to multiply them by the ratio SparsePtr texCoordPtr(&m_localVertices[indices.first].uv, sizeof(VertexStruct_XYZ_Color_UV)); for (unsigned int i = 0; i < indices.count; ++i) { @@ -231,12 +270,18 @@ namespace Nz m_localVertices[i*4 + j].uv *= scale; } - // Nous enlevons l'ancienne texture et rajoutons la nouvelle à sa place (pour les mêmes indices) + // We get rid off the old texture and we set the new one at the place (same for indices) m_renderInfos.erase(it); m_renderInfos.insert(std::make_pair(newTexture, std::move(indices))); } } + /*! + * \brief Updates the data of the sprite + * + * \param instanceData Data of the instance + */ + void TextSprite::UpdateData(InstanceData* instanceData) const { instanceData->data.resize(m_localVertices.size() * sizeof(VertexStruct_XYZ_Color_UV)); @@ -246,18 +291,18 @@ namespace Nz SparsePtr posPtr(&vertices[0].position, sizeof(VertexStruct_XYZ_Color_UV)); SparsePtr texCoordPtr(&vertices[0].uv, sizeof(VertexStruct_XYZ_Color_UV)); - // Nous allons maintenant initialiser les sommets finaux (ceux envoyés à la RenderQueue) - // à l'aide du repère, de la matrice et de notre attribut de couleur + // We will not initialize the final vertices (those send to the RenderQueue) + // With the help of the coordinates axis, the matrix and our color attribute for (auto& pair : m_renderInfos) { RenderIndices& indices = pair.second; if (indices.count == 0) continue; //< Ignore empty render indices - SparsePtr color = colorPtr + indices.first*4; - SparsePtr pos = posPtr + indices.first*4; - SparsePtr uv = texCoordPtr + indices.first*4; - VertexStruct_XY_Color_UV* localVertex = &m_localVertices[indices.first*4]; + SparsePtr color = colorPtr + indices.first * 4; + SparsePtr pos = posPtr + indices.first * 4; + SparsePtr uv = texCoordPtr + indices.first * 4; + VertexStruct_XY_Color_UV* localVertex = &m_localVertices[indices.first * 4]; for (unsigned int i = 0; i < indices.count; ++i) { for (unsigned int j = 0; j < 4; ++j) diff --git a/src/Nazara/Graphics/TextureBackground.cpp b/src/Nazara/Graphics/TextureBackground.cpp index 9ceb633e6..1b2e53e72 100644 --- a/src/Nazara/Graphics/TextureBackground.cpp +++ b/src/Nazara/Graphics/TextureBackground.cpp @@ -11,6 +11,11 @@ namespace Nz { namespace { + /*! + * \brief Defines render states + * \return RenderStates for the color background + */ + RenderStates BuildRenderStates() { RenderStates states; @@ -24,6 +29,18 @@ namespace Nz } } + /*! + * \ingroup graphics + * \class Nz::TextureBackground + * \brief Graphics class that represents a background with a texture + */ + + /*! + * \brief Constructs a TextureBackground object with a texture + * + * \param texture Texture + */ + TextureBackground::TextureBackground(TextureRef texture) { m_uberShader = UberShaderLibrary::Get("Basic"); @@ -43,6 +60,12 @@ namespace Nz SetTexture(std::move(texture)); } + /*! + * \brief Draws this relatively to the viewer + * + * \param viewer Viewer for the background + */ + void TextureBackground::Draw(const AbstractViewer* viewer) const { NazaraUnused(viewer); @@ -62,6 +85,11 @@ namespace Nz Renderer::DrawFullscreenQuad(); } + /*! + * \brief Gets the background type + * \return Type of background + */ + BackgroundType TextureBackground::GetBackgroundType() const { return BackgroundType_Texture; diff --git a/src/Nazara/Network/AbstractSocket.cpp b/src/Nazara/Network/AbstractSocket.cpp index e46a5906a..516364373 100644 --- a/src/Nazara/Network/AbstractSocket.cpp +++ b/src/Nazara/Network/AbstractSocket.cpp @@ -17,6 +17,18 @@ namespace Nz { + /*! + * \ingroup network + * \class Nz::AbstractSocket + * \brief Network class that represents the base of socket + * + * \remark This class is abstract + */ + + /*! + * \brief Constructs a AbstractSocket object with a type + */ + AbstractSocket::AbstractSocket(SocketType type) : m_lastError(SocketError_NoError), m_handle(SocketImpl::InvalidHandle), @@ -26,6 +38,12 @@ namespace Nz { } + /*! + * \brief Constructs a AbstractSocket object with another one by move semantic + * + * \param abstractSocket AbstractSocket to move into this + */ + AbstractSocket::AbstractSocket(AbstractSocket&& abstractSocket) : m_protocol(abstractSocket.m_protocol), m_lastError(abstractSocket.m_lastError), @@ -37,11 +55,21 @@ namespace Nz abstractSocket.m_handle = SocketImpl::InvalidHandle; } + /*! + * \brief Destructs the object and calls Close + * + * \see Close + */ + AbstractSocket::~AbstractSocket() { Close(); } + /*! + * \brief Closes the socket + */ + void AbstractSocket::Close() { if (m_handle != SocketImpl::InvalidHandle) @@ -53,6 +81,12 @@ namespace Nz } } + /*! + * \brief Enables blocking + * + * \param blocking Should the read block + */ + void AbstractSocket::EnableBlocking(bool blocking) { if (m_isBlockingEnabled != blocking) @@ -64,6 +98,11 @@ namespace Nz } } + /*! + * \brief Queries the available bytes + * \return Number of bytes which can be read + */ + std::size_t AbstractSocket::QueryAvailableBytes() const { if (m_handle == SocketImpl::InvalidHandle) @@ -72,11 +111,21 @@ namespace Nz return SocketImpl::QueryAvailableBytes(m_handle); } + /*! + * \brief Operation to do when closing socket + */ + void AbstractSocket::OnClose() { UpdateState(SocketState_NotConnected); } + /*! + * \brief Operation to do when opening socket + * + * \remark Produces a NazaraWarning if blocking failed + */ + void AbstractSocket::OnOpened() { SocketError errorCode; @@ -84,6 +133,11 @@ namespace Nz NazaraWarning("Failed to set socket blocking mode (0x" + String::Number(errorCode, 16) + ')'); } + /*! + * \brief Opens the socket according to a net protocol + * \return true If successful + */ + bool AbstractSocket::Open(NetProtocol protocol) { if (m_handle == SocketImpl::InvalidHandle || m_protocol != protocol) @@ -99,6 +153,13 @@ namespace Nz return true; } + /*! + * \brief Opens the socket according to a socket handle + * \return true If successful + * + * \remark Produces a NazaraAssert if handle is invalid + */ + void AbstractSocket::Open(SocketHandle handle) { NazaraAssert(handle != SocketImpl::InvalidHandle, "Invalid handle"); @@ -109,6 +170,13 @@ namespace Nz OnOpened(); } + /*! + * \brief Moves the AbstractSocket into this + * \return A reference to this + * + * \param abstractSocket AbstractSocket to move in this + */ + AbstractSocket& AbstractSocket::operator=(AbstractSocket&& abstractSocket) { Close(); diff --git a/src/Nazara/Network/AlgorithmNetwork.cpp b/src/Nazara/Network/AlgorithmNetwork.cpp index 273169005..307ac679a 100644 --- a/src/Nazara/Network/AlgorithmNetwork.cpp +++ b/src/Nazara/Network/AlgorithmNetwork.cpp @@ -11,6 +11,15 @@ namespace Nz { namespace Detail { + /*! + * \brief Parses a decimal number + * \return true If successful + * + * \param str C-string symbolizing the string to parse + * \param number Optional argument to return the number parsed + * \param endOfRead Optional argument to determine where parsing stopped + */ + bool ParseDecimal(const char* str, unsigned int* number, const char** endOfRead) { const char* ptr = str; @@ -35,6 +44,15 @@ namespace Nz return true; } + /*! + * \brief Parses a hexadecimal number + * \return true If successful + * + * \param str C-string symbolizing the string to parse + * \param number Optional argument to return the number parsed + * \param endOfRead Optional argument to determine where parsing stopped + */ + bool ParseHexadecimal(const char* str, unsigned int* number, const char** endOfRead) { const char* ptr = str; @@ -60,10 +78,26 @@ namespace Nz } } - // From http://rosettacode.org/wiki/Parse_an_IP_Address - // Parse a textual IPv4 or IPv6 address, optionally with port, into a binary - // array (for the address, in host order), and an optionally provided port. - // Also, indicate which of those forms (4 or 6) was parsed. + /*! + * \ingroup network + * \brief Parse a textual IPv4 or IPv6 address + * \return true If successful + * + * From http://rosettacode.org/wiki/Parse_an_IP_Address + * Parse a textual IPv4 or IPv6 address, optionally with port, into a binary + * array (for the address, in host order), and an optionally provided port. + * Also, indicate which of those forms (4 or 6) was parsed. + * + * \param addressPtr C-string which symbolizes the ip adress + * \param result Byte array to return the result in + * \param port Optional argument to resolve according to a specific port + * \param isIPv6 Optional argument to determine if the address is IPv6 + * \param endOfRead Optional argument to determine where parsing stopped + * + * \remark Produces a NazaraAssert if addressPtr is invalid + * \remark Produces a NazaraAssert if result is invalid + */ + bool ParseIPAddress(const char* addressPtr, UInt8 result[16], UInt16* port, bool* isIPv6, const char** endOfRead) { NazaraAssert(addressPtr, "Invalid address string"); diff --git a/src/Nazara/Network/IpAddress.cpp b/src/Nazara/Network/IpAddress.cpp index d40e2a581..29be756ea 100644 --- a/src/Nazara/Network/IpAddress.cpp +++ b/src/Nazara/Network/IpAddress.cpp @@ -22,6 +22,19 @@ namespace Nz { + /*! + * \ingroup network + * \class Nz::IpAddress + * \brief Network class that represents an IP address + */ + + /*! + * \brief Builds the IP from a hostname + * \return true If successful + * + * \remark address C-string symbolizing the IP address or hostname + */ + bool IpAddress::BuildFromAddress(const char* address) { m_isValid = false; @@ -50,6 +63,13 @@ namespace Nz return true; } + /*! + * \brief Checks whether the IP address is loopback + * \return true If it is the case + * + * \remark Produces a NazaraAssert if internal protocol is invalid (should never happen) + */ + bool IpAddress::IsLoopback() const { if (!m_isValid) @@ -73,6 +93,13 @@ namespace Nz return false; } + /*! + * \brief Gives a string representation + * \return A string representation of the object + * + * \remark Produces a NazaraAssert if internal protocol is invalid (should never happen) + */ + String IpAddress::ToString() const { StringStream stream; @@ -153,6 +180,17 @@ namespace Nz return stream; } + /*! + * \brief Resolves the address based on the IP + * \return Hostname of the address + * + * \param address IP address to resolve + * \param service Optional argument to specify the protocol used + * \param error Optional argument to get the error + * + * \remark Produces a NazaraAssert if address is invalid + */ + String IpAddress::ResolveAddress(const IpAddress& address, String* service, ResolveError* error) { NazaraAssert(address.IsValid(), "Invalid address"); @@ -163,6 +201,18 @@ namespace Nz return hostname; } + /*! + * \brief Resolves the address based on the hostname + * \return Informations about the host: IP(s) of the address, names, ... + * + * \param protocol Net protocol to use + * \param hostname Hostname to resolve + * \param service Specify the service used (http, ...) + * \param error Optional argument to get the error + * + * \remark Produces a NazaraAssert if net protocol is set to unknown + */ + std::vector IpAddress::ResolveHostname(NetProtocol protocol, const String& hostname, const String& service, ResolveError* error) { NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol"); diff --git a/src/Nazara/Network/NetPacket.cpp b/src/Nazara/Network/NetPacket.cpp index 7a1c0d7f5..0823f5258 100644 --- a/src/Nazara/Network/NetPacket.cpp +++ b/src/Nazara/Network/NetPacket.cpp @@ -9,11 +9,36 @@ namespace Nz { + /*! + * \ingroup network + * \class Nz::NetPacket + * \brief Network class that represents a packet + */ + + /*! + * \brief Operation to do when receiving data + * + * \param netCode Packet number + * \param data Raw memory + * \param size Size of the memory + */ + void NetPacket::OnReceive(UInt16 netCode, const void* data, std::size_t size) { Reset(netCode, data, size); } + /*! + * \brief Operation to do when sending data + * \return Beggining of the raw memory + * + * \param newSize Size of the memory to send + * + * \remark Produces a NazaraAssert if newSize is invalid + * \remark Produces a NazaraAssert if net code is invalid + * \remark Produces a NazaraError if header could not be encoded + */ + const void* NetPacket::OnSend(std::size_t* newSize) const { NazaraAssert(newSize, "Invalid size pointer"); @@ -30,6 +55,15 @@ namespace Nz return m_buffer->GetBuffer(); } + /*! + * \brief Decodes the header of the packet + * \return true If successful + * + * \param data Raw memory + * \param packetSize Size of the packet + * \param netCode Packet number + */ + bool NetPacket::DecodeHeader(const void* data, UInt16* packetSize, UInt16* netCode) { MemoryView stream(data, HeaderSize); @@ -40,6 +74,15 @@ namespace Nz return Unserialize(context, packetSize) && Unserialize(context, netCode); } + /*! + * \brief Encodes the header of the packet + * \return true If successful + * + * \param data Raw memory + * \param packetSize Size of the packet + * \param netCode Packet number + */ + bool NetPacket::EncodeHeader(void* data, UInt16 packetSize, UInt16 netCode) { MemoryView stream(data, HeaderSize); @@ -50,11 +93,19 @@ namespace Nz return Serialize(context, packetSize) && Serialize(context, netCode); } + /*! + * \brief Operation to do when stream is empty + */ + void NetPacket::OnEmptyStream() { Reset(0); } + /*! + * \brief Frees the stream + */ + void NetPacket::FreeStream() { if (!m_buffer) @@ -66,6 +117,16 @@ namespace Nz s_availableBuffers.emplace_back(std::make_pair(size, std::move(m_buffer))); } + /*! + * \brief Inits the internal stream + * + * \param minCapacity Minimal capacity of the stream + * \param cursorPos Position of the cursor in the stream + * \param openMode Flag of the stream + * + * \remark Produces a NazaraAssert if cursor position is greather than the capacity + */ + void NetPacket::InitStream(std::size_t minCapacity, UInt64 cursorPos, UInt32 openMode) { NazaraAssert(minCapacity >= cursorPos, "Cannot init stream with a smaller capacity than wanted cursor pos"); @@ -92,12 +153,21 @@ namespace Nz SetStream(&m_memoryStream); } + /*! + * \brief Initializes the NetPacket class + * \return true If initialization is successful + */ + bool NetPacket::Initialize() { s_availableBuffersMutex = std::make_unique(); return true; } + /*! + * \brief Uninitializes the NetPacket class + */ + void NetPacket::Uninitialize() { s_availableBuffers.clear(); diff --git a/src/Nazara/Network/Network.cpp b/src/Nazara/Network/Network.cpp index 41868b79b..fa3813dd4 100644 --- a/src/Nazara/Network/Network.cpp +++ b/src/Nazara/Network/Network.cpp @@ -24,9 +24,23 @@ namespace Nz { + /*! + * \ingroup network + * \class Nz::Network + * \brief Network class that represents the module initializer of Network + */ + + /*! + * \brief Initializes the Network module + * \return true if initialization is successful + * + * \remark Produces a NazaraNotice + * \remark Produces a NazaraError if one submodule failed + */ + bool Network::Initialize() { - if (s_moduleReferenceCounter > 0) + if (IsInitialized()) { s_moduleReferenceCounter++; return true; // Already initialized @@ -68,11 +82,22 @@ namespace Nz return true; } + /*! + * \brief Checks whether the module is initialized + * \return true if module is initialized + */ + bool Network::IsInitialized() { return s_moduleReferenceCounter != 0; } + /*! + * \brief Uninitializes the Core module + * + * \remark Produces a NazaraNotice + */ + void Network::Uninitialize() { if (s_moduleReferenceCounter != 1) diff --git a/src/Nazara/Network/RUdpConnection.cpp b/src/Nazara/Network/RUdpConnection.cpp index 451d08f1e..1b374d604 100644 --- a/src/Nazara/Network/RUdpConnection.cpp +++ b/src/Nazara/Network/RUdpConnection.cpp @@ -10,6 +10,16 @@ namespace Nz { + /*! + * \ingroup network + * \class Nz::RUdpConnection + * \brief Network class that represents a reliable UDP connection + */ + + /*! + * \brief Constructs a RUdpConnection object by default + */ + RUdpConnection::RUdpConnection() : m_peerIterator(0), m_forceAckSendTime(10'000), //< 10ms @@ -23,9 +33,20 @@ namespace Nz { } + /*! + * \brief Connects to the IpAddress + * \return true + * + * \param remoteAddress Address to connect to + * + * \remark Produces a NazaraAssert if socket is not bound + * \remark Produces a NazaraAssert if remote is invalid + * \remark Produces a NazaraAssert if port is not specified + */ + bool RUdpConnection::Connect(const IpAddress& remoteAddress) { - NazaraAssert(m_socket.GetState() != SocketState_Bound, "Socket must be bound first"); + NazaraAssert(m_socket.GetState() == SocketState_Bound, "Socket must be bound first"); NazaraAssert(remoteAddress.IsValid(), "Invalid remote address"); NazaraAssert(remoteAddress.GetPort() != 0, "Remote address has no port"); @@ -39,6 +60,16 @@ namespace Nz return true; } + /*! + * \brief Connects to the hostname + * \return true If successful + * + * \param hostName Hostname of the remote + * \param protocol Net protocol to use + * \param service Specify the protocol used + * \param error Optional argument to get the error + */ + bool RUdpConnection::Connect(const String& hostName, NetProtocol protocol, const String& service, ResolveError* error) { std::vector results = IpAddress::ResolveHostname(protocol, hostName, service, error); @@ -64,6 +95,13 @@ namespace Nz return Connect(hostnameAddress); } + /*! + * \brief Listens to a socket + * \return true If successfully bound + * + * \param remoteAddress Address to listen to + */ + bool RUdpConnection::Listen(const IpAddress& address) { if (!InitSocket(address.GetProtocol())) @@ -72,8 +110,19 @@ namespace Nz return m_socket.Bind(address) == SocketState_Bound; } + /*! + * \brief Polls the message + * \return true If there is a message + * + * \param message Message to poll + * + * \remark Produces a NazaraAssert if message is invalid + */ + bool RUdpConnection::PollMessage(RUdpMessage* message) { + NazaraAssert(message, "Invalid message"); + if (m_receivedMessages.empty()) return false; @@ -82,6 +131,16 @@ namespace Nz return true; } + /*! + * \brief Sends the packet to a peer + * \return true If peer exists (false may result from disconnected client) + * + * \param peerIp IpAddress of the peer + * \param priority Priority of the packet + * \param reliability Policy of reliability of the packet + * \param packet Packet to send + */ + bool RUdpConnection::Send(const IpAddress& peerIp, PacketPriority priority, PacketReliability reliability, const NetPacket& packet) { auto it = m_peerByIP.find(peerIp); @@ -92,6 +151,10 @@ namespace Nz return true; } + /*! + * \brief Updates the reliable connection + */ + void RUdpConnection::Update() { m_currentTime = m_clock.GetMicroseconds(); @@ -156,6 +219,14 @@ namespace Nz //m_activeClients.Reset(); } + /*! + * \brief Disconnects a peer + * + * \param peerIndex Index of the peer + * + * \remark Produces a NazaraNotice + */ + void RUdpConnection::DisconnectPeer(std::size_t peerIndex) { PeerData& peer = m_peers[peerIndex]; @@ -193,6 +264,15 @@ namespace Nz m_peers.pop_back(); } + /*! + * \brief Enqueues a packet in the sending list + * + * \param peer Data relative to the peer + * \param priority Priority of the packet + * \param reliability Policy of reliability of the packet + * \param packet Packet to send + */ + void RUdpConnection::EnqueuePacket(PeerData& peer, PacketPriority priority, PacketReliability reliability, const NetPacket& packet) { UInt16 protocolBegin = static_cast(m_protocol & 0xFFFF); @@ -208,6 +288,15 @@ namespace Nz EnqueuePacketInternal(peer, priority, reliability, std::move(data)); } + /*! + * \brief Enqueues internally a packet in the sending list + * + * \param peer Data relative to the peer + * \param priority Priority of the packet + * \param reliability Policy of reliability of the packet + * \param packet Packet to send + */ + void RUdpConnection::EnqueuePacketInternal(PeerData& peer, PacketPriority priority, PacketReliability reliability, NetPacket&& data) { PendingPacket pendingPacket; @@ -219,6 +308,13 @@ namespace Nz m_activeClients.UnboundedSet(peer.index); } + /*! + * \brief Inits the internal socket + * \return true If successful + * + * \param protocol Net protocol to use + */ + bool RUdpConnection::InitSocket(NetProtocol protocol) { CallOnExit updateLastError([this] @@ -233,6 +329,14 @@ namespace Nz return true; } + /*! + * \brief Processes the acks + * + * \param peer Data relative to the peer + * \param lastAck Last index of the ack + * \param ackBits Bits for acking + */ + void RUdpConnection::ProcessAcks(PeerData& peer, SequenceIndex lastAck, UInt32 ackBits) { auto it = peer.pendingAckQueue.begin(); @@ -257,6 +361,14 @@ namespace Nz } } + /*! + * \brief Registers a peer + * \return Data relative to the peer + * + * \param address Address of the peer + * \param state Status of the peer + */ + RUdpConnection::PeerData& RUdpConnection::RegisterPeer(const IpAddress& address, PeerState state) { PeerData data; @@ -266,7 +378,7 @@ namespace Nz data.index = m_peers.size(); data.lastPacketTime = m_currentTime; data.lastPingTime = m_currentTime; - data.roundTripTime = 1000000; ///< Okay that's quite a lot + data.roundTripTime = 1'000'000; ///< Okay that's quite a lot data.state = state; m_activeClients.UnboundedSet(data.index); @@ -276,6 +388,14 @@ namespace Nz return m_peers.back(); } + /*! + * \brief Operation to do when client requests a connection + * + * \param address Address of the peer + * \param sequenceId Sequence index for the ack + * \param token Token for connection + */ + void RUdpConnection::OnClientRequestingConnection(const IpAddress& address, SequenceIndex sequenceId, UInt64 token) { // Call hook to check if client should be accepted or not @@ -292,6 +412,13 @@ namespace Nz EnqueuePacket(client, PacketPriority_Immediate, PacketReliability_Reliable, connectionAcceptedPacket); } + /*! + * \brief Operation to do when a packet is lost + * + * \param peer Data relative to the peer + * \param packet Pending packet + */ + void RUdpConnection::OnPacketLost(PeerData& peer, PendingAckPacket&& packet) { //NazaraNotice(m_socket.GetBoundAddress().ToString() + ": Lost packet " + String::Number(packet.sequenceId)); @@ -300,6 +427,14 @@ namespace Nz EnqueuePacketInternal(peer, packet.priority, packet.reliability, std::move(packet.data)); } + /*! + * \brief Operation to do when receiving a packet + * + * \param peerIndex Index of the peer + * + * \remark Produces a NazaraNotice + */ + void RUdpConnection::OnPacketReceived(const IpAddress& peerIp, NetPacket&& packet) { UInt16 protocolBegin; @@ -436,6 +571,13 @@ namespace Nz } } + /*! + * \brief Sends a packet to a peer + * + * \param peer Data relative to the peer + * \param packet Pending packet + */ + void RUdpConnection::SendPacket(PeerData& peer, PendingPacket&& packet) { if (peer.state == PeerState_WillAck) @@ -448,7 +590,7 @@ namespace Nz { if (ack == remoteSequence) continue; - + unsigned int difference = ComputeSequenceDifference(remoteSequence, ack); if (difference <= 32U) previousAcks |= (1U << (difference - 1)); @@ -473,6 +615,11 @@ namespace Nz peer.pendingAckQueue.emplace_back(std::move(pendingAckPacket)); } + /*! + * \brief Initializes the RUdpConnection class + * \return true + */ + bool RUdpConnection::Initialize() { std::random_device device; @@ -481,6 +628,10 @@ namespace Nz return true; } + /*! + * \brief Uninitializes the RUdpConnection class + */ + void RUdpConnection::Uninitialize() { } diff --git a/src/Nazara/Network/TcpClient.cpp b/src/Nazara/Network/TcpClient.cpp index a134cf870..cf123ff89 100644 --- a/src/Nazara/Network/TcpClient.cpp +++ b/src/Nazara/Network/TcpClient.cpp @@ -20,6 +20,22 @@ namespace Nz { + /*! + * \ingroup network + * \class Nz::TcpClient + * \brief Network class that represents a client in a TCP connection + */ + + /*! + * \brief Connects to the IpAddress + * \return State of the socket + * + * \param remoteAddress Address to connect to + * + * \remark Produces a NazaraAssert if remote is invalid + * \remark Produces a NazaraAssert if remote's port is not specified + */ + SocketState TcpClient::Connect(const IpAddress& remoteAddress) { NazaraAssert(remoteAddress.IsValid(), "Invalid remote address"); @@ -45,6 +61,17 @@ namespace Nz return state; } + + /*! + * \brief Connects to the hostname + * \return State of the socket + * + * \param hostName Hostname of the remote + * \param protocol Net protocol to use + * \param service Specify the protocol used + * \param error Optional argument to get the error + */ + SocketState TcpClient::Connect(const String& hostName, NetProtocol protocol, const String& service, ResolveError* error) { UpdateState(SocketState_Resolving); @@ -73,6 +100,14 @@ namespace Nz return Connect(hostnameAddress); } + /*! + * \brief Enables low delay in emitting + * + * \param lowDelay Should low delay be used + * + * \remark This may produce lag + */ + void TcpClient::EnableLowDelay(bool lowDelay) { if (m_isLowDelayEnabled != lowDelay) @@ -84,6 +119,14 @@ namespace Nz } } + /*! + * \brief Enables the keep alive flag + * + * \param keepAlive Should the connection be kept alive + * \param msTime Time in milliseconds before expiration + * \param msInterval Interval in milliseconds between two pings + */ + void TcpClient::EnableKeepAlive(bool keepAlive, UInt64 msTime, UInt64 msInterval) { if (m_isKeepAliveEnabled != keepAlive || m_keepAliveTime != msTime || m_keepAliveInterval != msInterval) @@ -97,22 +140,51 @@ namespace Nz } } + /*! + * \brief Checks whether the stream reached the end of the stream + * \return true if there is no more available bytes + */ + bool TcpClient::EndOfStream() const { return QueryAvailableBytes() == 0; } + /*! + * \brief Gets the position of the cursor + * \return 0 + * + * \remark Produces a NazaraError because it is a special stream + */ + UInt64 TcpClient::GetCursorPos() const { NazaraError("GetCursorPos() cannot be used on sequential streams"); return 0; } + /*! + * \brief Gets the size of the raw memory available + * \return Size of the memory available + */ + UInt64 TcpClient::GetSize() const { return QueryAvailableBytes(); } + /*! + * \brief Receives the data available + * \return true If data received + * + * \param buffer Raw memory to write + * \param size Size of the buffer + * \param received Optional argument to get the number of bytes received + * + * \remark Produces a NazaraAssert if socket is invalid + * \remark Produces a NazaraAssert if buffer and its size is invalid + */ + bool TcpClient::Receive(void* buffer, std::size_t size, std::size_t* received) { NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle"); @@ -142,6 +214,17 @@ namespace Nz return true; } + /*! + * \brief Receives the packet available + * \return true If packet received + * + * \param packet Packet to receive + * + * \remark Produces a NazaraAssert if packet is invalid + * \remark Produces a NazaraAssert if packet size is inferior to the header size + * \remark Produces a NazaraWarning if packet's header is invalid + */ + bool TcpClient::ReceivePacket(NetPacket* packet) { //TODO: Every packet requires at least two Receive call, using an internal buffer of a fixed size would prevent this @@ -157,6 +240,7 @@ namespace Nz m_pendingPacket.received += received; + //TODO: Should never happen in production ! NazaraAssert(m_pendingPacket.received <= NetPacket::HeaderSize, "Received more data than header size"); if (m_pendingPacket.received >= NetPacket::HeaderSize) { @@ -185,6 +269,7 @@ namespace Nz m_pendingPacket.received += received; + //TODO: Should never happen in production ! NazaraAssert(m_pendingPacket.received <= packetSize, "Received more data than packet size"); if (m_pendingPacket.received >= packetSize) { @@ -202,6 +287,19 @@ namespace Nz return false; } + /*! + * \brief Sends the data available + * \return true If data sended + * + * \param buffer Raw memory to read + * \param size Size of the buffer + * \param sent Optional argument to get the number of bytes sent + * + * \remark Large sending are handled, you do not need to call this multiple time + * \remark Produces a NazaraAssert if socket is invalid + * \remark Produces a NazaraAssert if buffer and its size is invalid + */ + bool TcpClient::Send(const void* buffer, std::size_t size, std::size_t* sent) { NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle"); @@ -244,6 +342,15 @@ namespace Nz return true; } + /*! + * \brief Sends the packet available + * \return true If packet sent + * + * \param packet Packet to send + * + * \remark Produces a NazaraError if packet could not be prepared for sending + */ + bool TcpClient::SendPacket(const NetPacket& packet) { std::size_t size = 0; @@ -258,12 +365,30 @@ namespace Nz return Send(ptr, size, nullptr); } + /*! + * \brief Sets the position of the cursor + * \return false + * + * \param offset Offset according to the beginning of the stream + * + * \remark Produces a NazaraError because it is a special stream + */ + bool TcpClient::SetCursorPos(UInt64 offset) { NazaraError("SetCursorPos() cannot be used on sequential streams"); return false; } + /*! + * \brief Waits for being connected before time out + * \return true If connection is successful + * + * \param msTimeout Time in milliseconds before time out + * + * \remark Produces a NazaraAssert if socket is invalid + */ + bool TcpClient::WaitForConnected(UInt64 msTimeout) { switch (m_state) @@ -308,10 +433,18 @@ namespace Nz return false; } + /*! + * \brief Flushes the stream + */ + void TcpClient::FlushStream() { } + /*! + * \brief Operation to do when closing socket + */ + void TcpClient::OnClose() { AbstractSocket::OnClose(); @@ -320,6 +453,12 @@ namespace Nz m_peerAddress = IpAddress::Invalid; } + /*! + * \brief Operation to do when opening socket + * + * \remark Produces a NazaraWarning if delay mode or keep alive failed + */ + void TcpClient::OnOpened() { AbstractSocket::OnOpened(); @@ -336,6 +475,16 @@ namespace Nz m_openMode = OpenMode_ReadWrite; } + /*! + * \brief Reads blocks + * \return Number of blocks read + * + * \param buffer Preallocated buffer to contain information read + * \param size Size of the read and thus of the buffer + * + * \remark Produces a NazaraAssert if socket is invalid + */ + std::size_t TcpClient::ReadBlock(void* buffer, std::size_t size) { NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle"); @@ -357,6 +506,13 @@ namespace Nz return received; } + /*! + * \brief Resets the connection with a new socket and a peer address + * + * \param handle Socket to connect + * \param peerAddress Address to connect to + */ + void TcpClient::Reset(SocketHandle handle, const IpAddress& peerAddress) { Open(handle); @@ -365,8 +521,20 @@ namespace Nz UpdateState(SocketState_Connected); } + /*! + * \brief Writes blocks + * \return Number of blocks written + * + * \param buffer Preallocated buffer containing information to write + * \param size Size of the writting and thus of the buffer + * + * \remark Produces a NazaraAssert if buffer is nullptr + * \remark Produces a NazaraAssert if socket is invalid + */ + std::size_t TcpClient::WriteBlock(const void* buffer, std::size_t size) { + NazaraAssert(buffer, "Invalid buffer"); NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle"); CallOnExit restoreBlocking; diff --git a/src/Nazara/Network/TcpServer.cpp b/src/Nazara/Network/TcpServer.cpp index b5995b6f5..7a33c066b 100644 --- a/src/Nazara/Network/TcpServer.cpp +++ b/src/Nazara/Network/TcpServer.cpp @@ -19,6 +19,22 @@ namespace Nz { + /*! + * \ingroup network + * \class Nz::TcpServer + * \brief Network class that represents a server in a TCP connection + */ + + /*! + * \brief Accepts a client + * \return true If client'socket is valid + * + * \param newClient Client connection + * + * \remark Produces a NazaraAssert if socket is invalid + * \remark Produces a NazaraAssert if newClient is invalid + */ + bool TcpServer::AcceptClient(TcpClient* newClient) { NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Server isn't listening"); @@ -35,6 +51,16 @@ namespace Nz return false; } + /*! + * \brief Listens to a socket + * \return State of the socket + * + * \param address Address to listen to + * \param queueSize Size of the queue + * + * \remark Produces a NazaraAssert if address is invalid + */ + SocketState TcpServer::Listen(const IpAddress& address, unsigned int queueSize) { NazaraAssert(address.IsValid(), "Invalid address"); @@ -49,6 +75,10 @@ namespace Nz return state; } + /*! + * \brief Operation to do when closing socket + */ + void TcpServer::OnClose() { AbstractSocket::OnClose(); @@ -56,6 +86,10 @@ namespace Nz m_boundAddress = IpAddress::Invalid; } + /*! + * \brief Operation to do when opening socket + */ + void TcpServer::OnOpened() { AbstractSocket::OnOpened(); diff --git a/src/Nazara/Network/UdpSocket.cpp b/src/Nazara/Network/UdpSocket.cpp index a233881ea..b49aedcf3 100644 --- a/src/Nazara/Network/UdpSocket.cpp +++ b/src/Nazara/Network/UdpSocket.cpp @@ -17,6 +17,16 @@ namespace Nz { + /*! + * \brief Binds a specific IpAddress + * \return State of the socket + * + * \param address Address to bind + * + * \remark Produces a NazaraAssert if socket is invalid + * \remark Produces a NazaraAssert if address is invalid + */ + SocketState UdpSocket::Bind(const IpAddress& address) { NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Socket hasn't been created"); @@ -30,6 +40,14 @@ namespace Nz return state; } + /*! + * \brief Enables broadcasting + * + * \param broadcasting Should the UDP broadcast + * + * \remark Produces a NazaraAssert if socket is invalid + */ + void UdpSocket::EnableBroadcasting(bool broadcasting) { NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Invalid handle"); @@ -41,6 +59,13 @@ namespace Nz } } + /*! + * \brief Gets the maximum datagram size allowed + * \return Number of bytes + * + * \remark Produces a NazaraAssert if socket is invalid + */ + std::size_t UdpSocket::QueryMaxDatagramSize() { NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Socket hasn't been created"); @@ -48,8 +73,22 @@ namespace Nz return SocketImpl::QueryMaxDatagramSize(m_handle, &m_lastError); } + /*! + * \brief Receives the data available + * \return true If data received + * + * \param buffer Raw memory to write + * \param size Size of the buffer + * \param from IpAddress of the peer + * \param received Optional argument to get the number of bytes received + * + * \remark Produces a NazaraAssert if socket is invalid + * \remark Produces a NazaraAssert if buffer and its size is invalid + */ + bool UdpSocket::Receive(void* buffer, std::size_t size, IpAddress* from, std::size_t* received) { + NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Socket hasn't been created"); NazaraAssert(buffer && size > 0, "Invalid buffer"); int read; @@ -62,8 +101,21 @@ namespace Nz return true; } + /*! + * \brief Receives the packet available + * \return true If packet received + * + * \param packet Packet to receive + * \param from IpAddress of the peer + * + * \remark Produces a NazaraAssert if packet is invalid + * \remark Produces a NazaraWarning if packet's header is invalid + */ + bool UdpSocket::ReceivePacket(NetPacket* packet, IpAddress* from) { + NazaraAssert(packet, "Invalid packet"); + // I'm not sure what's the best between having a 65k bytes buffer ready for any datagram size // or querying the next datagram size every time, for now I'll leave it as is packet->Reset(NetCode_Invalid, std::numeric_limits::max()); @@ -97,6 +149,20 @@ namespace Nz return true; } + /*! + * \brief Sends the data available + * \return true If data sended + * + * \param to IpAddress of the peer + * \param buffer Raw memory to read + * \param size Size of the buffer + * \param sent Optional argument to get the number of bytes sent + * + * \remark Produces a NazaraAssert if peer address is invalid + * \remark Produces a NazaraAssert if protocol of communication is not the same than the peer + * \remark Produces a NazaraAssert if buffer and its size is invalid + */ + bool UdpSocket::Send(const IpAddress& to, const void* buffer, std::size_t size, std::size_t* sent) { NazaraAssert(to.IsValid(), "Invalid ip address"); @@ -113,6 +179,16 @@ namespace Nz return true; } + /*! + * \brief Sends the packet available + * \return true If packet sent + * + * \param to IpAddress of the peer + * \param packet Packet to send + * + * \remark Produces a NazaraError if packet could not be prepared for sending + */ + bool UdpSocket::SendPacket(const IpAddress& to, const NetPacket& packet) { std::size_t size = 0; @@ -127,6 +203,10 @@ namespace Nz return Send(to, ptr, size, nullptr); } + /*! + * \brief Operation to do when closing socket + */ + void UdpSocket::OnClose() { AbstractSocket::OnClose(); @@ -134,6 +214,10 @@ namespace Nz m_boundAddress = IpAddress::Invalid; } + /*! + * \brief Operation to do when opening socket + */ + void UdpSocket::OnOpened() { AbstractSocket::OnOpened(); diff --git a/src/Nazara/Utility/AlgorithmUtility.cpp b/src/Nazara/Utility/AlgorithmUtility.cpp index 7f4dbaf44..d82af98af 100644 --- a/src/Nazara/Utility/AlgorithmUtility.cpp +++ b/src/Nazara/Utility/AlgorithmUtility.cpp @@ -333,21 +333,20 @@ namespace Nz } private: - float CalculateVertexScore(unsigned int vertex) const + float CalculateVertexScore(VertexCacheData& vertex) const { - const VertexCacheData* v = &m_vertices[vertex]; - if (v->remaining_valence <= 0) + if (vertex.remaining_valence <= 0) // No tri needs this vertex! return -1.0f; float ret = 0.0f; - if (v->position_in_cache < 0) + if (vertex.position_in_cache < 0) { // Vertex is not in FIFO cache - no score. } else { - if (v->position_in_cache < 3) + if (vertex.position_in_cache < 3) { // This vertex was used in the last triangle, // so it has a fixed score, whichever of the three @@ -360,14 +359,14 @@ namespace Nz { // Points for being high in the cache. const float Scaler = 1.0f / (32 - 3); - ret = 1.0f - (v->position_in_cache - 3) * Scaler; + ret = 1.0f - (vertex.position_in_cache - 3) * Scaler; ret = std::pow(ret, m_cacheDecayPower); } } // Bonus points for having a low number of tris still to // use the vert, so we get rid of lone verts quickly. - float valence_boost = std::pow(static_cast(v->remaining_valence), -m_valenceBoostPower); + float valence_boost = std::pow(static_cast(vertex.remaining_valence), -m_valenceBoostPower); ret += m_valenceBoostScale * valence_boost; return ret; @@ -378,8 +377,8 @@ namespace Nz int FullScoreRecalculation() { // calculate score for all vertices - for (unsigned int i = 0; i < m_vertices.size(); ++i) - m_vertices[i].current_score = CalculateVertexScore(i); + for (VertexCacheData& vertex : m_vertices) + vertex.current_score = CalculateVertexScore(vertex); // calculate scores for all active triangles float max_score = std::numeric_limits::lowest(); @@ -548,13 +547,13 @@ namespace Nz float sum = 0.f; for (unsigned int i = 0; i < 3; ++i) { - VertexCacheData* v = &m_vertices[t->verts[i]]; - float sc = v->current_score; - if (!v->calculated) - sc = CalculateVertexScore(t->verts[i]); + VertexCacheData& v = m_vertices[t->verts[i]]; + float sc = v.current_score; + if (!v.calculated) + sc = CalculateVertexScore(v); - v->current_score = sc; - v->calculated = true; + v.current_score = sc; + v.calculated = true; sum += sc; } diff --git a/src/Nazara/Utility/Animation.cpp b/src/Nazara/Utility/Animation.cpp index bbd57b1df..62591344b 100644 --- a/src/Nazara/Utility/Animation.cpp +++ b/src/Nazara/Utility/Animation.cpp @@ -37,6 +37,8 @@ namespace Nz Animation::~Animation() { OnAnimationRelease(this); + + Destroy(); } bool Animation::AddSequence(const Sequence& sequence) diff --git a/src/Nazara/Utility/Formats/MD5AnimParser.cpp b/src/Nazara/Utility/Formats/MD5AnimParser.cpp index 321ee8692..9cd930c2e 100644 --- a/src/Nazara/Utility/Formats/MD5AnimParser.cpp +++ b/src/Nazara/Utility/Formats/MD5AnimParser.cpp @@ -285,7 +285,8 @@ namespace Nz if (!Advance()) return false; - if (std::sscanf(&m_currentLine[0], "( %f %f %f ) ( %f %f %f )", &m_joints[i].bindPos.x, &m_joints[i].bindPos.y, &m_joints[i].bindPos.z, + // Space is important for the buffer of \n + if (std::sscanf(&m_currentLine[0], " ( %f %f %f ) ( %f %f %f )", &m_joints[i].bindPos.x, &m_joints[i].bindPos.y, &m_joints[i].bindPos.z, &m_joints[i].bindOrient.x, &m_joints[i].bindOrient.y, &m_joints[i].bindOrient.z) != 6) { UnrecognizedLine(true); @@ -324,7 +325,8 @@ namespace Nz return false; Vector3f min, max; - if (std::sscanf(&m_currentLine[0], "( %f %f %f ) ( %f %f %f )", &min.x, &min.y, &min.z, &max.x, &max.y, &max.z) != 6) + // Space is important for the buffer of \n + if (std::sscanf(&m_currentLine[0], " ( %f %f %f ) ( %f %f %f )", &min.x, &min.y, &min.z, &max.x, &max.y, &max.z) != 6) { UnrecognizedLine(true); return false; diff --git a/tests/Engine/Audio/AlgorithmAudio.cpp b/tests/Engine/Audio/AlgorithmAudio.cpp new file mode 100644 index 000000000..dfcfeee56 --- /dev/null +++ b/tests/Engine/Audio/AlgorithmAudio.cpp @@ -0,0 +1,19 @@ +#include +#include + +#include + +TEST_CASE("MixToMono", "[AUDIO][ALGORITHM]") +{ + SECTION("Mix two channels together") + { + std::array input{ 1, 3, 5, 3 }; + std::array output{ 0, 0 }; + + // Two channels and two frames ! + Nz::MixToMono(input.data(), output.data(), 2, 2); + + std::array theoric{ 2, 4 }; // It's the mean of the two channels + REQUIRE(output == theoric); + } +} diff --git a/tests/Engine/Audio/Music.cpp b/tests/Engine/Audio/Music.cpp new file mode 100644 index 000000000..404c57c5f --- /dev/null +++ b/tests/Engine/Audio/Music.cpp @@ -0,0 +1,49 @@ +#include +#include + +#include +#include + +SCENARIO("Music", "[AUDIO][MUSIC]") +{ + GIVEN("A music") + { + Nz::Music music; + + WHEN("We load our music") + { + REQUIRE(music.OpenFromFile("resources/Engine/Audio/The_Brabanconne.ogg")); + + THEN("We can ask the informations of the file") + { + REQUIRE(music.GetDuration() <= 64000); // 1 min 03 = 63s = 63000ms + REQUIRE(music.GetDuration() >= 63000); + REQUIRE(music.GetFormat() == Nz::AudioFormat_Stereo); + REQUIRE(music.GetPlayingOffset() == 0); + REQUIRE(music.GetSampleCount() <= 5644800); // 64s * 44100 Hz * 2 (stereo) + REQUIRE(music.GetSampleCount() >= 5556600); // 63s * 44100 Hz * 2 (stereo) + REQUIRE(music.GetSampleRate() == 44100 /* Hz */); + REQUIRE(music.GetStatus() == Nz::SoundStatus_Stopped); + REQUIRE(music.IsLooping() == false); + } + + THEN("We can play it and get the time offset") + { + Nz::Audio::SetGlobalVolume(0.f); + + music.Play(); + Nz::Thread::Sleep(1000); + REQUIRE(music.GetPlayingOffset() >= 950); + Nz::Thread::Sleep(200); + REQUIRE(music.GetPlayingOffset() <= 1300); + music.Pause(); + REQUIRE(music.GetStatus() == Nz::SoundStatus_Paused); + + music.SetPlayingOffset(3500); + REQUIRE(music.GetPlayingOffset() >= 3500); + + Nz::Audio::SetGlobalVolume(100.f); + } + } + } +} diff --git a/tests/Engine/Audio/Sound.cpp b/tests/Engine/Audio/Sound.cpp new file mode 100644 index 000000000..684138ccd --- /dev/null +++ b/tests/Engine/Audio/Sound.cpp @@ -0,0 +1,44 @@ +#include +#include + +#include +#include + +SCENARIO("Sound", "[AUDIO][SOUND]") +{ + GIVEN("A sound") + { + Nz::Sound sound; + + WHEN("We load our sound") + { + REQUIRE(sound.LoadFromFile("resources/Engine/Audio/Cat.flac")); + + THEN("We can ask the informations of the file") + { + REQUIRE(sound.GetDuration() <= 8500); // 8s = 8000ms + REQUIRE(sound.GetDuration() >= 8000); + REQUIRE(sound.GetStatus() == Nz::SoundStatus_Stopped); + REQUIRE(sound.IsLooping() == false); + } + + THEN("We can play it and get the time offset") + { + Nz::Audio::SetGlobalVolume(0.f); + + sound.Play(); + Nz::Thread::Sleep(1000); + REQUIRE(sound.GetPlayingOffset() >= 950); + Nz::Thread::Sleep(200); + REQUIRE(sound.GetPlayingOffset() <= 1300); + sound.Pause(); + REQUIRE(sound.GetStatus() == Nz::SoundStatus_Paused); + + sound.SetPlayingOffset(3500); + REQUIRE(sound.GetPlayingOffset() >= 3500); + + Nz::Audio::SetGlobalVolume(100.f); + } + } + } +} diff --git a/tests/Engine/Audio/SoundBuffer.cpp b/tests/Engine/Audio/SoundBuffer.cpp new file mode 100644 index 000000000..ed5f2f6c6 --- /dev/null +++ b/tests/Engine/Audio/SoundBuffer.cpp @@ -0,0 +1,21 @@ +#include +#include + +SCENARIO("SoundBuffer", "[AUDIO][SOUNDBUFFER]") +{ + GIVEN("A sound buffer") + { + Nz::SoundBuffer soundBuffer; + + WHEN("We load our sound") + { + REQUIRE(soundBuffer.LoadFromFile("resources/Engine/Audio/Cat.flac")); + + THEN("We can ask the informations of the file") + { + REQUIRE(soundBuffer.GetDuration() <= 8500); // 8s = 8000ms + REQUIRE(soundBuffer.GetDuration() >= 8000); + } + } + } +} diff --git a/tests/Engine/Audio/SoundEmitter.cpp b/tests/Engine/Audio/SoundEmitter.cpp new file mode 100644 index 000000000..baac41eb3 --- /dev/null +++ b/tests/Engine/Audio/SoundEmitter.cpp @@ -0,0 +1,41 @@ +#include +#include + +#include + +SCENARIO("SoundEmitter", "[AUDIO][SOUNDEMITTER]") +{ + GIVEN("A sound emitter") + { + Nz::Sound sound; + + WHEN("We load our sound") + { + REQUIRE(sound.LoadFromFile("resources/Engine/Audio/Cat.flac")); + + THEN("We can ask information about position and velocity") + { + sound.EnableSpatialization(true); + sound.SetPosition(Nz::Vector3f::Zero()); + sound.SetVelocity(Nz::Vector3f::UnitX()); + + REQUIRE(sound.IsSpatialized()); + REQUIRE(sound.GetPosition() == Nz::Vector3f::Zero()); + REQUIRE(sound.GetVelocity() == Nz::Vector3f::UnitX()); + } + + THEN("We can ask information about attenuation, pitch, ...") + { + sound.SetAttenuation(0.4f); + sound.SetMinDistance(40.f); + sound.SetPitch(0.8f); + sound.SetVolume(50.f); + + REQUIRE(Approx(sound.GetAttenuation()) == 0.4f); + REQUIRE(Approx(sound.GetMinDistance()) == 40.f); + REQUIRE(Approx(sound.GetPitch()) == 0.8f); + REQUIRE(Approx(sound.GetVolume()) == 50.f); + } + } + } +} diff --git a/tests/Engine/Core/ByteArray.cpp b/tests/Engine/Core/ByteArray.cpp index 476643d5e..d085585a5 100644 --- a/tests/Engine/Core/ByteArray.cpp +++ b/tests/Engine/Core/ByteArray.cpp @@ -213,4 +213,24 @@ SCENARIO("ByteArray", "[CORE][BYTEARRAY]") } } } + + GIVEN("A default byte array") + { + Nz::ByteArray defaultByteArray; + + WHEN("We resize") + { + Nz::UInt64 oldSize = defaultByteArray.GetSize(); + REQUIRE(oldSize == 0); + defaultByteArray.Resize(10); + + THEN("Capacity has increased") + { + REQUIRE(defaultByteArray[oldSize] == 0); + + REQUIRE(defaultByteArray.GetCapacity() >= 10); + REQUIRE(defaultByteArray.GetSize() == 10); + } + } + } } diff --git a/tests/Engine/Core/File.cpp b/tests/Engine/Core/File.cpp index 2ddbfebbf..1163a8aad 100644 --- a/tests/Engine/Core/File.cpp +++ b/tests/Engine/Core/File.cpp @@ -32,12 +32,22 @@ SCENARIO("File", "[CORE][FILE]") REQUIRE(Nz::String(message) == "Test String"); } + AND_THEN("We can get its size") + { + REQUIRE(file.GetSize() == 33U); + } + AND_THEN("We close it") { file.Close(); - REQUIRE(file.GetSize() == 33U); CHECK(!file.IsOpen()); } + + AND_THEN("Change its size") + { + file.SetSize(50U); + REQUIRE(file.GetSize() == 50U); + } } WHEN("We delete this file") diff --git a/tests/Engine/Core/String.cpp b/tests/Engine/Core/String.cpp index eac5eaef6..fe9c80c30 100644 --- a/tests/Engine/Core/String.cpp +++ b/tests/Engine/Core/String.cpp @@ -122,5 +122,25 @@ SCENARIO("String", "[CORE][STRING]") } } }*/ + + GIVEN("A string") + { + Nz::String replaceAny("abapeilomuky"); + Nz::String replaceAnyWithCase("abapEilOmuky"); + + WHEN("We replace any of vowels after character 3") + { + unsigned int nbrOfChanges = replaceAny.ReplaceAny("aeiouy", '$', 3); + unsigned int nbrOfChangesWithCase = replaceAnyWithCase.ReplaceAny("AEIOUY", '$', 3); + + THEN("These results are expected") + { + REQUIRE(replaceAny == "abap$$l$m$k$"); + REQUIRE(nbrOfChanges == 5); + REQUIRE(replaceAnyWithCase == "abap$il$muky"); + REQUIRE(nbrOfChangesWithCase == 2); + } + } + } } diff --git a/tests/Engine/Graphics/Billboard.cpp b/tests/Engine/Graphics/Billboard.cpp new file mode 100644 index 000000000..5136e3af6 --- /dev/null +++ b/tests/Engine/Graphics/Billboard.cpp @@ -0,0 +1,34 @@ +#include +#include + +SCENARIO("Billboard", "[GRAPHICS][BILLBOARD]") +{ + GIVEN("A default billboard") + { + Nz::Billboard billboard; + + WHEN("We assign it to another") + { + Nz::MaterialRef materialRef = Nz::Material::New(); + materialRef->LoadFromFile("resources/Engine/Graphics/Nazara.png"); + Nz::Color materialColor = materialRef->GetDiffuseColor(); + Nz::BillboardRef otherBillboard = Nz::Billboard::New(materialRef); + + billboard = *otherBillboard; + + THEN("The old one has the same properties than the new one") + { + REQUIRE(billboard.GetColor() == materialColor); + REQUIRE(billboard.GetMaterial().Get() == materialRef.Get()); + REQUIRE(billboard.GetRotation() == Approx(0.f)); + REQUIRE(billboard.GetSize() == Nz::Vector2f(64.f, 64.f)); // Default sizes + } + + THEN("We set it with our new material and ask for its real size") + { + billboard.SetMaterial(materialRef, true); + REQUIRE(billboard.GetSize() == Nz::Vector2f(765.f, 212.f)); // Nazara.png sizes + } + } + } +} diff --git a/tests/Engine/Graphics/ColorBackground.cpp b/tests/Engine/Graphics/ColorBackground.cpp new file mode 100644 index 000000000..f4a88eb30 --- /dev/null +++ b/tests/Engine/Graphics/ColorBackground.cpp @@ -0,0 +1,20 @@ +#include +#include + +SCENARIO("ColorBackground", "[GRAPHICS][COLORBACKGROUND]") +{ + GIVEN("A default color background") + { + Nz::ColorBackground colorBackground; + + WHEN("We assign it a color") + { + colorBackground.SetColor(Nz::Color::Red); + + THEN("We can get it") + { + REQUIRE(colorBackground.GetColor() == Nz::Color::Red); + } + } + } +} diff --git a/tests/Engine/Graphics/DeferredRenderTechnique.cpp b/tests/Engine/Graphics/DeferredRenderTechnique.cpp new file mode 100644 index 000000000..f61c9800c --- /dev/null +++ b/tests/Engine/Graphics/DeferredRenderTechnique.cpp @@ -0,0 +1,29 @@ +#include +#include + +SCENARIO("DeferredRenderTechnique", "[GRAPHICS][DEFERREDRENDERTECHNIQUE]") +{ + GIVEN("A default deferred render technique") + { + Nz::DeferredRenderTechnique deferredRenderTechnique; + + WHEN("We can disable a pass") + { + REQUIRE(deferredRenderTechnique.IsPassEnabled(Nz::RenderPassType::RenderPassType_AA, 0)); + deferredRenderTechnique.EnablePass(Nz::RenderPassType::RenderPassType_AA, 0, false); + + THEN("It is disabled") + { + REQUIRE(!deferredRenderTechnique.IsPassEnabled(Nz::RenderPassType::RenderPassType_AA, 0)); + } + + AND_THEN("We reset it, it is disabled and not the same as the old one") + { + Nz::DeferredRenderPass* oldPass = deferredRenderTechnique.GetPass(Nz::RenderPassType::RenderPassType_AA, 0); + deferredRenderTechnique.ResetPass(Nz::RenderPassType::RenderPassType_AA, 0); + REQUIRE(!deferredRenderTechnique.IsPassEnabled(Nz::RenderPassType::RenderPassType_AA, 0)); + REQUIRE(deferredRenderTechnique.GetPass(Nz::RenderPassType::RenderPassType_AA, 0) != oldPass); + } + } + } +} diff --git a/tests/Engine/Graphics/Light.cpp b/tests/Engine/Graphics/Light.cpp new file mode 100644 index 000000000..bd5f1c7f9 --- /dev/null +++ b/tests/Engine/Graphics/Light.cpp @@ -0,0 +1,31 @@ +#include +#include + +SCENARIO("Light", "[GRAPHICS][LIGHT]") +{ + GIVEN("Different light") + { + Nz::Light directionalLight(Nz::LightType_Directional); + Nz::Light pointLight(Nz::LightType_Point); + Nz::Light spotLight(Nz::LightType_Spot); + + WHEN("We try to cull") + { + Nz::Frustumf frustum; + frustum.Build(90.f, 16.f / 9.f, 1.f, 1000.f, Nz::Vector3f::Zero(), Nz::Vector3f::UnitX()); + Nz::Matrix4f Unit3InX = Nz::Matrix4f::Translate(Nz::Vector3f::UnitX() * 3.f); + Nz::Matrix4f rotationTowardsY = Unit3InX * Nz::Matrix4f::Rotate(Nz::EulerAnglesf(Nz::FromDegrees(90.f), 0.f, 0.f).ToQuaternion()); + + THEN("These results are expected") + { + REQUIRE(directionalLight.Cull(frustum, Unit3InX)); + REQUIRE(pointLight.Cull(frustum, Unit3InX)); + REQUIRE(!spotLight.Cull(frustum, Unit3InX)); + + REQUIRE(directionalLight.Cull(frustum, rotationTowardsY)); + REQUIRE(pointLight.Cull(frustum, rotationTowardsY)); + REQUIRE(!spotLight.Cull(frustum, rotationTowardsY)); + } + } + } +} diff --git a/tests/Engine/Graphics/Model.cpp b/tests/Engine/Graphics/Model.cpp new file mode 100644 index 000000000..d67a261bb --- /dev/null +++ b/tests/Engine/Graphics/Model.cpp @@ -0,0 +1,24 @@ +#include +#include + +SCENARIO("Model", "[GRAPHICS][MODEL]") +{ + GIVEN("The standford dragon model") + { + WHEN("We get general informations") + { + THEN("These results are expected") + { + Nz::ModelRef model = Nz::Model::New(); + REQUIRE(model->LoadFromFile("resources/Engine/Graphics/dragon_recon/dragon_vrip_res4.obj")); + + REQUIRE(model->GetMaterialCount() == 2); + REQUIRE(model->GetSkin() == 0); + REQUIRE(model->GetSkinCount() == 1); + + Nz::Material* material = model->GetMaterial(0); + REQUIRE(material->GetAmbientColor() == Nz::Color(128)); + } + } + } +} diff --git a/tests/Engine/Graphics/ParticleDeclaration.cpp b/tests/Engine/Graphics/ParticleDeclaration.cpp new file mode 100644 index 000000000..1bc1739d3 --- /dev/null +++ b/tests/Engine/Graphics/ParticleDeclaration.cpp @@ -0,0 +1,29 @@ +#include +#include + +SCENARIO("ParticleDeclaration", "[GRAPHICS][PARTICLEDECLARATION]") +{ + GIVEN("A particle declaration of a model") + { + Nz::ParticleDeclaration* particleDeclaration = Nz::ParticleDeclaration::Get(Nz::ParticleLayout_Model); + + WHEN("We disable a component") + { + bool enabled; + Nz::ComponentType type; + unsigned int offset; + particleDeclaration->GetComponent(Nz::ParticleComponent_Position, &enabled, &type, &offset); + REQUIRE(enabled); + unsigned int oldStride = particleDeclaration->GetStride(); + + particleDeclaration->DisableComponent(Nz::ParticleComponent_Position); + REQUIRE(oldStride != particleDeclaration->GetStride()); + + THEN("We can enable it and the stride is back") + { + particleDeclaration->EnableComponent(Nz::ParticleComponent_Position, type, offset); + REQUIRE(oldStride == particleDeclaration->GetStride()); + } + } + } +} diff --git a/tests/Engine/Graphics/ParticleSystem.cpp b/tests/Engine/Graphics/ParticleSystem.cpp new file mode 100644 index 000000000..32f5f01f9 --- /dev/null +++ b/tests/Engine/Graphics/ParticleSystem.cpp @@ -0,0 +1,103 @@ +#include +#include + +#include +#include + +class TestParticleController : public Nz::ParticleController +{ + public: + // Be aware that the interval is [startId, endId] and NOT [startId, endId) + void Apply(Nz::ParticleSystem& system, Nz::ParticleMapper& mapper, unsigned int startId, unsigned int endId, float elapsedTime) override + { + Nz::SparsePtr positionPtr = mapper.GetComponentPtr(Nz::ParticleComponent_Position); + Nz::SparsePtr velocityPtr = mapper.GetComponentPtr(Nz::ParticleComponent_Velocity); + Nz::SparsePtr lifePtr = mapper.GetComponentPtr(Nz::ParticleComponent_Life); + + for (unsigned int i = startId; i <= endId; ++i) + { + Nz::Vector3f& particlePosition = positionPtr[i]; + Nz::Vector3f& particleVelocity = velocityPtr[i]; + float& particleLife = lifePtr[i]; + + particleLife -= elapsedTime; + if (particleLife <= 0.f) + system.KillParticle(i); + } + } +}; + +class TestParticleEmitter : public Nz::ParticleEmitter +{ + public: + ~TestParticleEmitter() override = default; + + void Emit(Nz::ParticleSystem& system, float elapsedTime) const override + { + system.GenerateParticles(GetEmissionCount()); + } + + private: + void SetupParticles(Nz::ParticleMapper& mapper, unsigned int count) const override + { + } +}; + +class TestParticleGenerator : public Nz::ParticleGenerator +{ + public: + ~TestParticleGenerator() override = default; + + // Be aware that the interval is [startId, endId] and NOT [startId, endId) + void Generate(Nz::ParticleSystem& system, Nz::ParticleMapper& mapper, unsigned int startId, unsigned int endId) override + { + Nz::SparsePtr positionPtr = mapper.GetComponentPtr(Nz::ParticleComponent_Position); + Nz::SparsePtr velocityPtr = mapper.GetComponentPtr(Nz::ParticleComponent_Velocity); + Nz::SparsePtr lifePtr = mapper.GetComponentPtr(Nz::ParticleComponent_Life); + + for (unsigned int i = startId; i <= endId; ++i) + { + Nz::Vector3f& particlePosition = positionPtr[i]; + Nz::Vector3f& particleVelocity = velocityPtr[i]; + float& particleLife = lifePtr[i]; + + particlePosition = Nz::Vector3f::Zero(); + particleVelocity = Nz::Vector3f::UnitX(); + particleLife = 1.3f; + } + } +}; + +SCENARIO("ParticleSystem", "[GRAPHICS][PARTICLESYSTEM]") +{ + GIVEN("A particle system of maximum 10 billboards with its generators") + { + // These need to be alive longer than the particle system + TestParticleController particleController; + TestParticleGenerator particleGenerator; + Nz::ParticleSystem particleSystem(10, Nz::ParticleLayout_Billboard); + + particleSystem.AddController(&particleController); + TestParticleEmitter particleEmitter; + particleEmitter.SetEmissionCount(10); + particleSystem.AddEmitter(&particleEmitter); + + particleSystem.AddGenerator(&particleGenerator); + + WHEN("We update to generate 10 particles") + { + particleSystem.Update(1.f); + + THEN("There must be 10 particles") + { + REQUIRE(particleSystem.GetParticleCount() == 10); + } + + AND_THEN("We update to make them die") + { + particleSystem.Update(2.f); + REQUIRE(particleSystem.GetParticleCount() == 0); + } + } + } +} diff --git a/tests/Engine/Graphics/RenderTechniques.cpp b/tests/Engine/Graphics/RenderTechniques.cpp new file mode 100644 index 000000000..ac5849da9 --- /dev/null +++ b/tests/Engine/Graphics/RenderTechniques.cpp @@ -0,0 +1,47 @@ +#include +#include + +#include +#include + +SCENARIO("RenderTechniques", "[GRAPHICS][RENDERTECHNIQUES]") +{ + GIVEN("Nothing") + { + WHEN("We try to get a technique") + { + THEN("We should get it") + { + std::unique_ptr forwardByEnum(Nz::RenderTechniques::GetByEnum(Nz::RenderTechniqueType_BasicForward)); + REQUIRE(forwardByEnum->GetType() == Nz::RenderTechniqueType_BasicForward); + + std::unique_ptr forwardByIndex(Nz::RenderTechniques::GetByIndex(1)); + REQUIRE(forwardByIndex->GetType() == Nz::RenderTechniqueType_BasicForward); + + std::unique_ptr forwardByName(Nz::RenderTechniques::GetByName(Nz::RenderTechniques::ToString(Nz::RenderTechniqueType_BasicForward))); + REQUIRE(forwardByName->GetType() == Nz::RenderTechniqueType_BasicForward); + } + + THEN("We can register a render technique") + { + unsigned int previousCount = Nz::RenderTechniques::GetCount(); + + Nz::RenderTechniques::Register("test", 23, []() -> Nz::AbstractRenderTechnique* { + return new Nz::ForwardRenderTechnique; + }); + + REQUIRE(previousCount < Nz::RenderTechniques::GetCount()); + + std::unique_ptr forwardByRanking(Nz::RenderTechniques::GetByRanking(23)); + REQUIRE(forwardByRanking->GetType() == Nz::RenderTechniqueType_BasicForward); + + std::unique_ptr forwardByName(Nz::RenderTechniques::GetByName("test")); + REQUIRE(forwardByName->GetType() == Nz::RenderTechniqueType_BasicForward); + + Nz::RenderTechniques::Unregister("test"); + + REQUIRE(previousCount == Nz::RenderTechniques::GetCount()); + } + } + } +} \ No newline at end of file diff --git a/tests/Engine/Graphics/SkeletalModel.cpp b/tests/Engine/Graphics/SkeletalModel.cpp new file mode 100644 index 000000000..87d2e43f1 --- /dev/null +++ b/tests/Engine/Graphics/SkeletalModel.cpp @@ -0,0 +1,26 @@ +#include +#include + +SCENARIO("SkeletalModel", "[GRAPHICS][SKELETALMODEL]") +{ + GIVEN("A default skeletal model") + { + Nz::SkeletalModel skeletalModel; + Nz::AnimationRef animation = Nz::Animation::New(); + + WHEN("We can load the bob lamp") + { + REQUIRE(skeletalModel.LoadFromFile("resources/Engine/Graphics/Bob lamp/bob_lamp_update.md5mesh")); + REQUIRE(animation->LoadFromFile("resources/Engine/Graphics/Bob lamp/bob_lamp_update.md5anim")); + skeletalModel.SetAnimation(animation); + + THEN("We can enable its animation") + { + REQUIRE(skeletalModel.HasAnimation()); + skeletalModel.EnableAnimation(true); + skeletalModel.AdvanceAnimation(0.10f); + REQUIRE(skeletalModel.IsAnimationEnabled()); + } + } + } +} diff --git a/tests/Engine/Graphics/SkyboxBackground.cpp b/tests/Engine/Graphics/SkyboxBackground.cpp new file mode 100644 index 000000000..36ceb0db5 --- /dev/null +++ b/tests/Engine/Graphics/SkyboxBackground.cpp @@ -0,0 +1,25 @@ +#include +#include + +SCENARIO("SkyboxBackground", "[GRAPHICS][SKYBOXBACKGROUND]") +{ + GIVEN("A skybox background with a loaded image") + { + Nz::TextureRef textureRef = Nz::Texture::New(); + textureRef->LoadCubemapFromFile("resources/Engine/Graphics/skybox.png"); + Nz::SkyboxBackgroundRef skyboxBackgroundRef = Nz::SkyboxBackground::New(textureRef); + + WHEN("We assign it parameters") + { + skyboxBackgroundRef->SetMovementOffset(Nz::Vector3f::Unit()); + skyboxBackgroundRef->SetMovementScale(1.f); + + THEN("We can get it") + { + REQUIRE(skyboxBackgroundRef->GetMovementOffset() == Nz::Vector3f::Unit()); + REQUIRE(skyboxBackgroundRef->GetMovementScale() == Approx(1.f)); + REQUIRE(skyboxBackgroundRef->GetTexture().Get() == textureRef.Get()); + } + } + } +} diff --git a/tests/Engine/Graphics/TextureBackground.cpp b/tests/Engine/Graphics/TextureBackground.cpp new file mode 100644 index 000000000..33178d87f --- /dev/null +++ b/tests/Engine/Graphics/TextureBackground.cpp @@ -0,0 +1,20 @@ +#include +#include + +SCENARIO("TextureBackground", "[GRAPHICS][TEXTUREBACKGROUND]") +{ + GIVEN("A default texture background") + { + Nz::TextureRef textureRef = Nz::Texture::New(); + textureRef->LoadFromFile("resources/Engine/Graphics/skybox.png"); + Nz::TextureBackgroundRef textureBackgroundRef = Nz::TextureBackground::New(textureRef); + + WHEN("We assign it parameters") + { + THEN("We can get it") + { + REQUIRE(textureBackgroundRef->GetTexture().Get() == textureRef.Get()); + } + } + } +} \ No newline at end of file diff --git a/tests/Engine/Math/Sphere.cpp b/tests/Engine/Math/Sphere.cpp index 1820acd35..ef13ffb38 100644 --- a/tests/Engine/Math/Sphere.cpp +++ b/tests/Engine/Math/Sphere.cpp @@ -39,14 +39,14 @@ SCENARIO("Sphere", "[MATH][SPHERE]") WHEN("We ask for distance") { - THEN("These results are expected") + THEN("These results are expected because we don't take into account the border") { - REQUIRE(firstCenterAndUnit.Distance(Nz::Vector3f::UnitX()) == Approx(1.f)); - REQUIRE(firstCenterAndUnit.SquaredDistance(Nz::Vector3f::UnitX()) == Approx(1.f)); + REQUIRE(firstCenterAndUnit.Distance(Nz::Vector3f::UnitX() * 2.f) == Approx(1.f)); + REQUIRE(firstCenterAndUnit.SquaredDistance(Nz::Vector3f::UnitX() * 2.f) == Approx(1.f)); Nz::Spheref tmp(Nz::Vector3f::UnitX(), 1.f); - REQUIRE(tmp.Distance(Nz::Vector3f::UnitX() * 4.f) == Approx(3.f)); - REQUIRE(tmp.SquaredDistance(Nz::Vector3f::UnitX() * 4.f) == Approx(9.f)); + REQUIRE(tmp.Distance(Nz::Vector3f::UnitX() * 4.f) == Approx(2.f)); + REQUIRE(tmp.SquaredDistance(Nz::Vector3f::UnitX() * 4.f) == Approx(4.f)); } } @@ -84,7 +84,7 @@ SCENARIO("Sphere", "[MATH][SPHERE]") THEN("Sphere must contain it and distance should be good") { CHECK(firstCenterAndUnit.Contains(point)); - REQUIRE(firstCenterAndUnit.Distance(point) == 2.f); + REQUIRE(firstCenterAndUnit.Distance(point) == 1.f); } } diff --git a/tests/Engine/Network/IpAddress.cpp b/tests/Engine/Network/IpAddress.cpp new file mode 100644 index 000000000..8bb3e7d16 --- /dev/null +++ b/tests/Engine/Network/IpAddress.cpp @@ -0,0 +1,47 @@ +#include +#include + +SCENARIO("IpAddress", "[NETWORK][IPADDRESS]") +{ + GIVEN("Two default IpAddress") + { + Nz::IpAddress ipAddressV4; + Nz::IpAddress ipAddressV6; + + WHEN("We parse localhost") + { + Nz::String localhostIPv4 = "127.0.0.1"; + Nz::String localhostIPv6 = "::1"; + REQUIRE(ipAddressV4.BuildFromAddress(localhostIPv4.GetConstBuffer())); + REQUIRE(ipAddressV6.BuildFromAddress(localhostIPv6.GetConstBuffer())); + + THEN("It's the loop back") + { + REQUIRE(ipAddressV4.IsLoopback()); + REQUIRE(ipAddressV6.IsLoopback()); + } + } + } + + GIVEN("No IpAddress") + { + WHEN("We get the IP of Nazara") + { + std::vector hostnameInfos = Nz::IpAddress::ResolveHostname(Nz::NetProtocol_IPv4, "nazara.digitalpulsesoftware.net"); + + THEN("Result is not null") + { + REQUIRE(!hostnameInfos.empty()); + } + } + + WHEN("We convert IP to hostname") + { + Nz::IpAddress google(8, 8, 8, 8); + THEN("Google (DNS) is 8.8.8.8") + { + REQUIRE(Nz::IpAddress::ResolveAddress(google) == "google-public-dns-a.google.com"); + } + } + } +} diff --git a/tests/Engine/Network/RUdpConnection.cpp b/tests/Engine/Network/RUdpConnection.cpp new file mode 100644 index 000000000..a39100e94 --- /dev/null +++ b/tests/Engine/Network/RUdpConnection.cpp @@ -0,0 +1,40 @@ +#include +#include + +#include + +SCENARIO("RUdpConnection", "[NETWORK][RUDPCONNECTION]") +{ + GIVEN("Two RUdpConnection, one client, one server") + { + Nz::UInt16 port = 64266; + Nz::RUdpConnection server; + REQUIRE(server.Listen(Nz::NetProtocol_IPv4, port)); + Nz::IpAddress serverIP = server.GetBoundAddress(); + REQUIRE(serverIP.IsValid()); + Nz::RUdpConnection client; + REQUIRE(client.Listen(Nz::NetProtocol_IPv4, port + 1)); + Nz::IpAddress clientIP = client.GetBoundAddress(); + REQUIRE(client.Connect(serverIP)); + REQUIRE(clientIP.IsValid()); + + WHEN("We send data from client") + { + Nz::NetPacket packet(1); + Nz::Vector3f vector123(1.f, 2.f, 3.f); + packet << vector123; + REQUIRE(client.Send(serverIP, Nz::PacketPriority_Immediate, Nz::PacketReliability_Reliable, packet)); + client.Update(); + + THEN("We should get it on the server") + { + Nz::RUdpMessage rudpMessage; + server.Update(); + REQUIRE(server.PollMessage(&rudpMessage)); + Nz::Vector3f result; + rudpMessage.data >> result; + REQUIRE(result == vector123); + } + } + } +} diff --git a/tests/Engine/Network/TCP.cpp b/tests/Engine/Network/TCP.cpp new file mode 100644 index 000000000..63b4fe2df --- /dev/null +++ b/tests/Engine/Network/TCP.cpp @@ -0,0 +1,49 @@ +#include +#include +#include + +#include +#include + +#include + +SCENARIO("TCP", "[NETWORK][TCP]") +{ + GIVEN("Two TCP, one client, one server") + { + // Avoid reusing the same socket + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> dis(1025, 64245); + + Nz::UInt16 port = dis(gen); + Nz::TcpServer server; + REQUIRE(server.Listen(Nz::NetProtocol_IPv4, port) == Nz::SocketState_Bound); + Nz::IpAddress serverIP = server.GetBoundAddress(); + REQUIRE(serverIP.IsValid()); + Nz::TcpClient client; + REQUIRE(client.Connect(serverIP) == Nz::SocketState_Connecting); + Nz::IpAddress clientIP = client.GetRemoteAddress(); + REQUIRE(clientIP.IsValid()); + + Nz::TcpClient serverToClient; + REQUIRE(server.AcceptClient(&serverToClient)); + + WHEN("We send data from client") + { + Nz::NetPacket packet(1); + Nz::Vector3f vector123(1.f, 2.f, 3.f); + packet << vector123; + REQUIRE(client.SendPacket(packet)); + + THEN("We should get it on the server") + { + Nz::NetPacket resultPacket; + REQUIRE(serverToClient.ReceivePacket(&resultPacket)); + Nz::Vector3f result; + resultPacket >> result; + REQUIRE(result == vector123); + } + } + } +} diff --git a/tests/Engine/Network/UdpSocket.cpp b/tests/Engine/Network/UdpSocket.cpp new file mode 100644 index 000000000..3f199f09e --- /dev/null +++ b/tests/Engine/Network/UdpSocket.cpp @@ -0,0 +1,39 @@ +#include +#include + +#include +#include + +SCENARIO("UdpSocket", "[NETWORK][UDPSOCKET]") +{ + GIVEN("Two UdpSocket, one client, one server") + { + Nz::UInt16 port = 64256; + Nz::UdpSocket server(Nz::NetProtocol_IPv4); + REQUIRE(server.Bind(port) == Nz::SocketState_Bound); + Nz::IpAddress serverIP = server.GetBoundAddress(); + REQUIRE(serverIP.IsValid()); + Nz::UdpSocket client(Nz::NetProtocol_IPv4); + REQUIRE(client.Bind(port + 1) == Nz::SocketState_Bound); + Nz::IpAddress clientIP = client.GetBoundAddress(); + REQUIRE(clientIP.IsValid()); + + WHEN("We send data from client") + { + Nz::NetPacket packet(1); + Nz::Vector3f vector123(1.f, 2.f, 3.f); + packet << vector123; + REQUIRE(client.SendPacket(serverIP, packet)); + + THEN("We should get it on the server") + { + Nz::NetPacket resultPacket; + Nz::IpAddress fromIp; + REQUIRE(server.ReceivePacket(&resultPacket, &fromIp)); + Nz::Vector3f result; + resultPacket >> result; + REQUIRE(result == vector123); + } + } + } +} diff --git a/tests/main.cpp b/tests/main.cpp index 7be81a57e..5ba9e8e01 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -1,2 +1,16 @@ -#define CATCH_CONFIG_MAIN +#define CATCH_CONFIG_RUNNER #include + +#include +#include +#include +#include + +int main(int argc, char* const argv[]) +{ + Nz::Initializer modules; + + int result = Catch::Session().run(argc, argv); + + return result; +} diff --git a/tests/resources/Engine/Audio/Cat.flac.REMOVED.git-id b/tests/resources/Engine/Audio/Cat.flac.REMOVED.git-id new file mode 100644 index 000000000..a686bc57d --- /dev/null +++ b/tests/resources/Engine/Audio/Cat.flac.REMOVED.git-id @@ -0,0 +1 @@ +6993cbcca9ac596667135cb0f30bea4841178d3b \ No newline at end of file diff --git a/tests/resources/Engine/Audio/The_Brabanconne.ogg.REMOVED.git-id b/tests/resources/Engine/Audio/The_Brabanconne.ogg.REMOVED.git-id new file mode 100644 index 000000000..bfd8dbd70 --- /dev/null +++ b/tests/resources/Engine/Audio/The_Brabanconne.ogg.REMOVED.git-id @@ -0,0 +1 @@ +94b2c47c9143adbac0fb7e81df5cc87f969f7150 \ No newline at end of file diff --git a/tests/resources/Engine/Audio/copyrights.txt b/tests/resources/Engine/Audio/copyrights.txt new file mode 100644 index 000000000..7b01b7090 --- /dev/null +++ b/tests/resources/Engine/Audio/copyrights.txt @@ -0,0 +1,54 @@ +The_Brabanconne.ogg + +https://en.wikipedia.org/wiki/File:The_Brabanconne.ogg + +Original file: +The_Brabanconne.ogg ‎(Ogg Vorbis sound file, length 1 min 3 s, 378 kbps) + +Summary: + +Description: The Belgian national anthem (instrumental version) performed by the United States Navy Band. Direct link is at http://www.navyband.navy.mil/anthems/ANTHEMS/Belgium.mp3. +Date: 19 October 2004 +Source: http://www.navyband.navy.mil/anthems/national_anthems.htm +Author: United States Navy Band (rendition), uploaded to Wikimedia by Keith Lehwald + +Licencing: + +This file is a work of a sailor or employee of the U.S. Navy, taken or made as part of that person's official duties. As a work of the U.S. federal government, the image is in the public domain. +This file has been identified as being free of known restrictions under copyright law, including all related and neighboring rights. + +------------------------------------------------------------------------------------------------- + +Cat.flac: + +http://www.freesound.org/people/EARR/sounds/148013/ + +Original file: +148013__earr__angry-cat.flac (Flac sound file, length 8 s, 96000 Hz, 24 bit depth) + +Author: + +EARR + +Description: + +Slightly angry cat. She is a beautiful Siamese cat called Agostina. She is angry for the recording because i pressed his tail. + +Information about the recording and equipment: + +-Location: Living room. +-Type of acoustic environment: Small, diffuse, moderately reflective. +-Distance from sound source to microphones: Approx a few centimeters. +-Miking technique: Jecklin disk. + +-Microphones: 2 Brüel & Kjaer type 4190 capsules with type 2669L head amplifier. +-Microphone preamps: Modified Brüel & Kjaer type 5935L. +-ADC: Echo Audiofire 4. (line inputs 3 & 4). +-Recorder: Echo Audiofire 4 and Dell D630C running Samplitude 10. + +Eq: Compensation only for the response of the microphones (In this case for flat response at 60º. See Brüel & Kjaer type 4190 datasheet). +No reverb, no compression, no fx. + +Licencing: + +Creative commons diff --git a/tests/resources/Engine/Graphics/Bob lamp/Readme.txt b/tests/resources/Engine/Graphics/Bob lamp/Readme.txt new file mode 100644 index 000000000..bd605ec7d --- /dev/null +++ b/tests/resources/Engine/Graphics/Bob lamp/Readme.txt @@ -0,0 +1,24 @@ +############################# +MD5 sample mesh and animation +############################# + +INFORMATION & USAGE +=================== +File includes *.blend source files and TGA format textures for MD5 animated mesh testing. +For extensive information and usage instructions visit http://www.katsbits.com/smforum/index.php?topic=178.0 + + - bob_lamp_update.blend contain mesh and armature as would be prior to preparation for export. + - bob_lamp_update_export contains triangulated mesh ready for export. + +NOTES +===== +Included files are for use in **Blender 2.69** or above; opening files in older versions may result in errors dues to internal differences between Blender versions. +Files and media are provided "as is" without any warranties of functionality. + +COPYRIGHT & DISTRIBUTION +======================== +Copyright © 2014 KatsBits. All Rights Reserved. +For more information visit http://www.katsbits.com/ or email info@katsbits.com + +For NON-COMMERCIAL USE ONLY. This file and/or its contents and/or associated materials may not be reproduced, duplicated, distributed or otherwise 'monetised' without prior consent. +Contact info@katsbits.com or visit http://copyright.katsbits.com/ for further details regarding this material and/or distribution/copyright. diff --git a/tests/resources/Engine/Graphics/copyrights.txt b/tests/resources/Engine/Graphics/copyrights.txt new file mode 100644 index 000000000..7cd13413c --- /dev/null +++ b/tests/resources/Engine/Graphics/copyrights.txt @@ -0,0 +1,82 @@ +skybox.png + +https://commons.wikimedia.org/wiki/File:Skybox_example.png + +Original file: +Skybox example.ogg ‎(Ogg Vorbis sound file, length 1 min 3 s, 378 kbps) + +Summary: + +Description: English: An example of a skybox and how the faces can be aligned +Date: 8 June 2011 +Source: Own work +Author: Creator:Arieee + +Description: The Belgian national anthem (instrumental version) performed by the United States Navy Band. Direct link is at http://www.navyband.navy.mil/anthems/ANTHEMS/Belgium.mp3. +Date: 19 October 2004 +Source: http://www.navyband.navy.mil/anthems/national_anthems.htm +Author: United States Navy Band (rendition), uploaded to Wikimedia by Keith Lehwald + +Licencing: + +This file is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported license. + + You are free: + + to share – to copy, distribute and transmit the work + to remix – to adapt the work + + Under the following conditions: + + attribution – You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work). + share alike – If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one. + +------------------------------------------------------------------------------------------------- + +Bob lamp + +http://www.katsbits.com/download/models/md5-example.php + +Original file: +bob_lamp_update.zip (Animated MD5 sample file) + +Summary: + +Description: Updated version of "Bob", a low-poly character mesh for general export and testing of MD5 mesh and animation - "*.md5mesh" and "*.md5anim". File and it's contents should be opened in Blender 2.69 or above to avoid compatibility issues with older versions of Blender and/or resulting MD5 exports (md5mesh & md5anim). + +File includes two versions of the source file, one 'working' - mesh is intact with surfaces in 'quad' form; and one 'prepped' (exported) - mesh has been tessilated (triangulated) for export. +Date: Januari 2014 +Source: http://www.katsbits.com/download/models/md5-example.php +Author: KatsBits + +Licencing: + +Please, refer to "Bob lamp/Readme.txt" file. + +------------------------------------------------------------------------------------------------- + +Standford dragon + +http://graphics.stanford.edu/data/3Dscanrep/ + +Original file: +dragon_recon.tar.gz (PLY files) + +Summary: + +Dragon +Source: Stanford University Computer Graphics Laboratory +Scanner: Cyberware 3030 MS + spacetime analysis +Number of scans: ~70 +Total size of scans: 2,748,318 points (about 5,500,000 triangles) +Reconstruction: vrip (conservatively decimated) +Size of reconstruction: 566,098 vertices, 1,132,830 triangles +Comments: contains numerous small holes +Date: 1996 +Source: http://graphics.stanford.edu/data/3Dscanrep/ +Author: Stanford University Computer Graphics Laboratory + +Licencing: + +Please be sure to acknowledge the source of the data and models you take from this repository. In each of the listings below, we have cited the source of the range data and reconstructed models. You are welcome to use the data and models for research purposes. You are also welcome to mirror or redistribute them for free. Finally, you may publish images made using these models, or the images on this web site, in a scholarly article or book - as long as credit is given to the Stanford Computer Graphics Laboratory. However, such models or images are not to be used for commercial purposes, nor should they appear in a product for sale (with the exception of scholarly journals or books), without our permission. +Please, refer to "dragon_recon/README" file. diff --git a/tests/resources/Engine/Graphics/dragon_recon/README b/tests/resources/Engine/Graphics/dragon_recon/README new file mode 100644 index 000000000..af64a50fe --- /dev/null +++ b/tests/resources/Engine/Graphics/dragon_recon/README @@ -0,0 +1,27 @@ + Surface Reconstructions + + Stanford Range Repository + Computer Graphics Laboratory + Stanford University + + August 4, 1996 + + +These files are the result of reconstructing a set of range images +using the "vrip" program. The first file is the high resolution +result, while the "_res*" files are decimated versions. Note that +these decimations were performed using a crude algorithm that does not +necessarily preserve mesh topology. While they are not beautiful, +they are suitable for interactive rendering. + +Note that this model is a decimated version of the original which was +constructed at the voxel resolution of 0.35 mm. The original model +has no holes in it, however, the decimated model has some holes that +we detected with software, but not by inspection. Apparently, the +decimation software introduced these holes. + +For more information, consult the web pages of the Stanford Graphics +Laboratory: + + http://www-graphics.stanford.edu +