From 13e1cadcdd83cd3b8defb4c72fabc69628c931c9 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 15 Jun 2014 01:13:40 +0200 Subject: [PATCH 01/12] Alphabetical commit Former-commit-id: 88c2aad1451a941f7b3afa83063d9383fc8b40d2 --- src/Nazara/Audio/Music.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Audio/Music.cpp b/src/Nazara/Audio/Music.cpp index aa25ac2bf..4e3a62c44 100644 --- a/src/Nazara/Audio/Music.cpp +++ b/src/Nazara/Audio/Music.cpp @@ -22,8 +22,8 @@ struct NzMusicImpl NzSoundStream* stream; NzThread thread; bool loop = false; - bool streaming = false; bool paused = false; + bool streaming = false; unsigned int sampleRate; }; From f55b151c8ed2cfbd13ac1838ef218c2349a4cd13 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 15 Jun 2014 01:17:57 +0200 Subject: [PATCH 02/12] Improved MemoryPool class It's size is now dynamic (defaulted to 1024) Added MemoryPool::GetFreeBlocks() Added MemoryPool::GetSize() Tried to make it thread-safe It supports dynamics allocations (in case where it can't allocate memory from the pool for some reasons) Former-commit-id: 1cc6cb2bc118556363a5c8ba1d18b3b1ce734862 --- include/Nazara/Core/MemoryPool.hpp | 12 +++-- include/Nazara/Core/MemoryPool.inl | 77 +++++++++++++++++------------- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/include/Nazara/Core/MemoryPool.hpp b/include/Nazara/Core/MemoryPool.hpp index 0e9fb32e9..64efc4ccd 100644 --- a/include/Nazara/Core/MemoryPool.hpp +++ b/include/Nazara/Core/MemoryPool.hpp @@ -8,27 +8,33 @@ #define NAZARA_MEMORYPOOL_HPP #include +#include #include -template +template class NzMemoryPool { public: - NzMemoryPool(); + NzMemoryPool(unsigned int size = 1024); ~NzMemoryPool() = default; template T* Allocate(); void* Allocate(unsigned int size); + void Free(void* ptr); + unsigned int GetFreeBlocks() const; + unsigned int GetSize() const; + private: NzMemoryPool(NzMemoryPool* pool); std::unique_ptr m_freeList; std::unique_ptr m_pool; std::unique_ptr m_next; + std::atomic_uint m_freeCount; NzMemoryPool* m_previous; - unsigned int m_freeCount; + unsigned int m_size; }; #include diff --git a/include/Nazara/Core/MemoryPool.inl b/include/Nazara/Core/MemoryPool.inl index 592fb38fc..1d44075ad 100644 --- a/include/Nazara/Core/MemoryPool.inl +++ b/include/Nazara/Core/MemoryPool.inl @@ -5,70 +5,67 @@ #include #include -template -NzMemoryPool::NzMemoryPool() : +template +NzMemoryPool::NzMemoryPool(unsigned int count) : +m_freeCount(count), m_previous(nullptr), -m_freeCount(count) +m_size(count) { - m_pool.reset(new nzUInt8[typeSize * count]); + m_pool.reset(new nzUInt8[blockSize * count]); m_freeList.reset(new void*[count]); // Remplissage de la free list for (unsigned int i = 0; i < count; ++i) - m_freeList[i] = &m_pool[typeSize * (count-i-1)]; + m_freeList[i] = &m_pool[blockSize * (count-i-1)]; } -template -NzMemoryPool::NzMemoryPool(NzMemoryPool* pool) : -NzMemoryPool() +template +NzMemoryPool::NzMemoryPool(NzMemoryPool* pool) : +NzMemoryPool(pool->m_size) { m_previous = pool; } -template +template template -T* NzMemoryPool::Allocate() +T* NzMemoryPool::Allocate() { - static_assert(sizeof(T) <= typeSize, "This type is too large for this memory pool"); + static_assert(sizeof(T) <= blockSize, "This type is too large for this memory pool"); return static_cast(Allocate(sizeof(T))); } -template -void* NzMemoryPool::Allocate(unsigned int size) +template +void* NzMemoryPool::Allocate(unsigned int size) { - if (size > typeSize) + if (size <= blockSize) { - throw std::bad_alloc(); - return nullptr; + if (m_freeCount > 0) + return m_freeList[--m_freeCount]; + else if (canGrow) + { + if (!m_next) + m_next.reset(new NzMemoryPool(this)); + + return m_next->Allocate(size); + } } - if (m_freeCount > 0) - return m_freeList[--m_freeCount]; - else if (canGrow) - { - if (!m_next) - m_next.reset(new NzMemoryPool(this)); - - return m_next->Allocate(size); - } - - throw std::bad_alloc(); - return nullptr; + return operator new(size); } -template -void NzMemoryPool::Free(void* ptr) +template +void NzMemoryPool::Free(void* ptr) { if (ptr) { // Le pointer nous appartient-il ? nzUInt8* freePtr = static_cast(ptr); nzUInt8* poolPtr = m_pool.get(); - if (freePtr >= poolPtr && freePtr < poolPtr + typeSize*count) + if (freePtr >= poolPtr && freePtr < poolPtr + blockSize*m_size) { #if NAZARA_CORE_SAFE - if ((freePtr - poolPtr) % typeSize != 0) + if ((freePtr - poolPtr) % blockSize != 0) { throw std::runtime_error("Pointer does not belong to memory pool"); return; @@ -78,7 +75,7 @@ void NzMemoryPool::Free(void* ptr) m_freeList[m_freeCount++] = ptr; // Si nous sommes vide et l'extension d'un autre pool, on se suicide - if (m_freeCount == count && m_previous && !m_next) + if (m_freeCount == m_size && m_previous && !m_next) { m_previous->m_next.release(); delete this; // Suicide @@ -89,9 +86,21 @@ void NzMemoryPool::Free(void* ptr) if (m_next) m_next->Free(ptr); else - throw std::runtime_error("Pointer does not belong to memory pool"); + operator delete(ptr); } } } +template +unsigned int NzMemoryPool::GetFreeBlocks() const +{ + return m_freeCount; +} + +template +unsigned int NzMemoryPool::GetSize() const +{ + return m_size; +} + #include From eceabcd241500d4bb35f68ea7be8a4c9631f1024 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 15 Jun 2014 01:55:07 +0200 Subject: [PATCH 03/12] Fixed some of the pull request code in order to merge it Former-commit-id: 76d71f15b335535e7dfcaf986440a00e85e45c1b --- examples/HardwareInfo/main.cpp | 8 ++- include/Nazara/Math/Box.inl | 8 +-- include/Nazara/Math/Frustum.inl | 4 +- include/Nazara/Math/Matrix4.inl | 4 +- include/Nazara/Math/OrientedBox.inl | 17 ++----- include/Nazara/Math/Rect.hpp | 2 +- include/Nazara/Math/Rect.inl | 2 + include/Nazara/Math/Sphere.hpp | 1 - include/Nazara/Math/Sphere.inl | 54 +++++++++++++-------- src/Nazara/Core/Win32/TaskSchedulerImpl.cpp | 4 +- 10 files changed, 56 insertions(+), 48 deletions(-) diff --git a/examples/HardwareInfo/main.cpp b/examples/HardwareInfo/main.cpp index 07beced54..d1a12dade 100644 --- a/examples/HardwareInfo/main.cpp +++ b/examples/HardwareInfo/main.cpp @@ -24,9 +24,6 @@ int main() // On va afficher le tout via un ostringstream, pour écrire dans la console et aussi dans un fichier std::ostringstream oss; - - char accentAigu = static_cast(130); // C'est crade, mais ça marche chez 95% des Windowsiens - oss << "--Processeur--" << std::endl; // Plutôt que d'initialiser le Renderer de Nazara, nous initialisons les deux classes utilisées ici // Elles sont compatibles avec NzInitialiser et seront donc libérées automatiquement @@ -44,7 +41,7 @@ int main() oss << std::endl; // Ensuite, Nazara récupère les capacités du processeur, dont des jeux d'extensions supplémentaires - oss << "Report des capacit" << accentAigu << "s: " << std::endl; + oss << "Rapport des capacites: " << std::endl;// Pas d'accent car écriture dans un fichier (et on ne va pas s'embêter avec ça) printCap(oss, "-64bits", NzHardwareInfo::HasCapability(nzProcessorCap_x64)); printCap(oss, "-AVX", NzHardwareInfo::HasCapability(nzProcessorCap_AVX)); printCap(oss, "-FMA3", NzHardwareInfo::HasCapability(nzProcessorCap_FMA3)); @@ -81,7 +78,7 @@ int main() oss << std::endl; // Ainsi qu'un report des capacités de la carte graphique (avec le driver actuel) - oss << "Report des capacit" << accentAigu << "s: " << std::endl; + oss << "Rapport des capacites: " << std::endl; // Pas d'accent car écriture dans un fichier (et on ne va pas s'embêter avec ça) printCap(oss, "-Calculs 64bits", NzOpenGL::IsSupported(nzOpenGLExtension_FP64)); printCap(oss, "-Compression de textures (s3tc)", NzOpenGL::IsSupported(nzOpenGLExtension_TextureCompression_s3tc)); printCap(oss, "-Filtrage anisotrope", NzOpenGL::IsSupported(nzOpenGLExtension_AnisotropicFilter)); @@ -108,6 +105,7 @@ int main() reportFile.Write(oss.str()); // Conversion implicite en NzString reportFile.Close(); + char accentAigu = static_cast(130); // C'est crade, mais ça marche chez 95% des Windowsiens std::cout << "Un fichier (RapportHardwareInfo.txt) contenant le rapport a " << accentAigu << 't' << accentAigu << " cr" << accentAigu << accentAigu << std::endl; } else diff --git a/include/Nazara/Math/Box.inl b/include/Nazara/Math/Box.inl index 989e7108e..e8f9b8fed 100644 --- a/include/Nazara/Math/Box.inl +++ b/include/Nazara/Math/Box.inl @@ -159,7 +159,7 @@ NzSphere NzBox::GetBoundingSphere() const template NzVector3 NzBox::GetCenter() const { - return GetPosition() + F(0.5)*GetLengths(); + return GetPosition() + GetLengths()/F(2.0); } template @@ -237,7 +237,7 @@ template T NzBox::GetSquaredRadius() const { NzVector3 size(GetLengths()); - size *= F(0.5); // La taille étant relative à la position (minimum) de la boite et non pas à son centre + size /= F(2.0); // La taille étant relative à la position (minimum) de la boite et non pas à son centre return size.GetSquaredLength(); } @@ -394,7 +394,7 @@ template NzBox& NzBox::Transform(const NzMatrix4& matrix, bool applyTranslation) { NzVector3 center = matrix.Transform(GetCenter(), (applyTranslation) ? F(1.0) : F(0.0)); // Valeur multipliant la translation - NzVector3 halfSize = GetLengths() * F(0.5); + NzVector3 halfSize = GetLengths()/F(2.0); halfSize.Set(std::fabs(matrix(0,0))*halfSize.x + std::fabs(matrix(1,0))*halfSize.y + std::fabs(matrix(2,0))*halfSize.z, std::fabs(matrix(0,1))*halfSize.x + std::fabs(matrix(1,1))*halfSize.y + std::fabs(matrix(2,1))*halfSize.z, @@ -465,6 +465,7 @@ NzBox& NzBox::operator*=(T scalar) width *= scalar; height *= scalar; depth *= scalar; + return *this; } @@ -474,6 +475,7 @@ NzBox& NzBox::operator*=(const NzVector3& vec) width *= vec.x; height *= vec.y; depth *= vec.z; + return *this; } diff --git a/include/Nazara/Math/Frustum.inl b/include/Nazara/Math/Frustum.inl index 300031d88..8541a34f1 100644 --- a/include/Nazara/Math/Frustum.inl +++ b/include/Nazara/Math/Frustum.inl @@ -24,9 +24,9 @@ template NzFrustum& NzFrustum::Build(T angle, T ratio, T zNear, T zFar, const NzVector3& eye, const NzVector3& target, const NzVector3& up) { #if NAZARA_MATH_ANGLE_RADIAN - angle *= F(0.5); + angle /= F(2.0); #else - angle = NzDegreeToRadian(angle * F(0.5)); + angle = NzDegreeToRadian(angle/F(2.0)); #endif T tangent = std::tan(angle); diff --git a/include/Nazara/Math/Matrix4.inl b/include/Nazara/Math/Matrix4.inl index 173653ebb..2531b51dd 100644 --- a/include/Nazara/Math/Matrix4.inl +++ b/include/Nazara/Math/Matrix4.inl @@ -573,9 +573,9 @@ NzMatrix4& NzMatrix4::MakePerspective(T angle, T ratio, T zNear, T zFar) { // http://msdn.microsoft.com/en-us/library/windows/desktop/bb204945(v=vs.85).aspx #if NAZARA_MATH_ANGLE_RADIAN - angle *= F(0.5); + angle /= F(2.0); #else - angle = NzDegreeToRadian(angle * F(0.5)); + angle = NzDegreeToRadian(angle/F(2.0)); #endif T yScale = F(1.0) / std::tan(angle); diff --git a/include/Nazara/Math/OrientedBox.inl b/include/Nazara/Math/OrientedBox.inl index fcc91e4d1..33a131c72 100644 --- a/include/Nazara/Math/OrientedBox.inl +++ b/include/Nazara/Math/OrientedBox.inl @@ -7,6 +7,8 @@ #include #include +///DOC: Pour que les coins soient valides, la méthode Update doit être appelée + #define F(a) static_cast(a) template @@ -60,8 +62,7 @@ template NzOrientedBox& NzOrientedBox::MakeZero() { localBox.MakeZero(); - for (unsigned int i = 0; i <= nzCorner_Max; ++i) - m_corners[i].Set(NzVector3::Zero()); + return *this; } @@ -70,8 +71,6 @@ NzOrientedBox& NzOrientedBox::Set(T X, T Y, T Z, T Width, T Height, T Dept { localBox.Set(X, Y, Z, Width, Height, Depth); - for (unsigned int i = 0; i <= nzCorner_Max; ++i) - m_corners[i].Set(localBox.GetCorner(static_cast(i))); return *this; } @@ -80,8 +79,6 @@ NzOrientedBox& NzOrientedBox::Set(const NzBox& box) { localBox.Set(box); - for (unsigned int i = 0; i <= nzCorner_Max; ++i) - m_corners[i].Set(localBox.GetCorner(static_cast(i))); return *this; } @@ -98,8 +95,6 @@ NzOrientedBox& NzOrientedBox::Set(const NzVector3& vec1, const NzVector { localBox.Set(vec1, vec2); - for (unsigned int i = 0; i <= nzCorner_Max; ++i) - m_corners[i].Set(localBox.GetCorner(static_cast(i))); return *this; } @@ -134,7 +129,7 @@ template void NzOrientedBox::Update(const NzMatrix4& transformMatrix) { for (unsigned int i = 0; i <= nzCorner_Max; ++i) - m_corners[i] = transformMatrix.Transform(m_corners[i]); + m_corners[i] = transformMatrix.Transform(localBox.GetCorner(static_cast(i))); } template @@ -189,8 +184,6 @@ NzOrientedBox NzOrientedBox::operator*(T scalar) const NzOrientedBox box(*this); box *= scalar; - for (unsigned int i = 0; i <= nzCorner_Max; ++i) - box.m_corners[i].Set(box.GetCorner(static_cast(i))); return box; } @@ -199,8 +192,6 @@ NzOrientedBox& NzOrientedBox::operator*=(T scalar) { localBox *= scalar; - for (unsigned int i = 0; i <= nzCorner_Max; ++i) - m_corners[i].Set(localBox.GetCorner(static_cast(i))); return *this; } diff --git a/include/Nazara/Math/Rect.hpp b/include/Nazara/Math/Rect.hpp index df7611b13..a133b7ed6 100644 --- a/include/Nazara/Math/Rect.hpp +++ b/include/Nazara/Math/Rect.hpp @@ -68,7 +68,7 @@ class NzRect NzRect& operator*=(T scalar); NzRect& operator*=(const NzVector2& vec); - NzRect& operator/=(T scalar); + NzRect& operator/=(T scalar); NzRect& operator/=(const NzVector2& vec); bool operator==(const NzRect& rect) const; diff --git a/include/Nazara/Math/Rect.inl b/include/Nazara/Math/Rect.inl index b2fd3a3e4..ab35b30c5 100644 --- a/include/Nazara/Math/Rect.inl +++ b/include/Nazara/Math/Rect.inl @@ -353,6 +353,7 @@ NzRect& NzRect::operator*=(T scalar) { width *= scalar; height *= scalar; + return *this; } @@ -361,6 +362,7 @@ NzRect& NzRect::operator*=(const NzVector2& vec) { width *= vec.x; height *= vec.y; + return *this; } diff --git a/include/Nazara/Math/Sphere.hpp b/include/Nazara/Math/Sphere.hpp index 975893076..64378a949 100644 --- a/include/Nazara/Math/Sphere.hpp +++ b/include/Nazara/Math/Sphere.hpp @@ -8,7 +8,6 @@ #define NAZARA_SPHERE_HPP #include -#include #include template diff --git a/include/Nazara/Math/Sphere.inl b/include/Nazara/Math/Sphere.inl index 2f74945dc..9c56fac16 100644 --- a/include/Nazara/Math/Sphere.inl +++ b/include/Nazara/Math/Sphere.inl @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -81,7 +82,6 @@ template NzSphere& NzSphere::ExtendTo(T X, T Y, T Z) { T distance = SquaredDistance(X, Y, Z); - if (distance > radius*radius) radius = std::sqrt(distance); @@ -120,32 +120,48 @@ NzVector3 NzSphere::GetPositiveVertex(const NzVector3& normal) const template bool NzSphere::Intersect(const NzBox& box) const { - // Arvo's algorithm. - T dmin = T(0); - if (x < box.x) - dmin += (x - box.x) * (x - box.x); - else if (x > box.x + box.width) - dmin += (x - (box.x + box.width)) * (x - (box.x + box.width)); + // Arvo's algorithm. + T squaredDistance = T(0.0); + if (x < box.x) + { + T diff = x - box.x; + squaredDistance += diff*diff; + } + else if (x > box.x + box.width) + { + T diff = x - (box.x + box.width); + squaredDistance += diff*diff; + } - if (y < box.y) - dmin += (y - box.y) * (y - box.y); - else if (x > box.x + box.width) - dmin += (y - (box.y + box.height)) * (y - (box.y + box.height)); + if (y < box.y) + { + T diff = y - box.y; + squaredDistance += diff*diff; + } + else if (y > box.y + box.height) + { + T diff = y - (box.y + box.height); + squaredDistance += diff*diff; + } - if (z < box.z) - dmin += (z - box.z) * (z - box.z); - else if (x > box.x + box.width) - dmin += (z - (box.z + box.depth)) * (z - (box.z + box.depth)); + if (z < box.z) + { + T diff = z - box.z; + squaredDistance += diff*diff; + } + else if (z > box.z + box.depth) + { + T diff = z - (box.z + box.depth); + squaredDistance += diff*diff; + } - if (dmin <= radius * radius) - return true; - return false; + return squaredDistance <= radius * radius; } template bool NzSphere::Intersect(const NzSphere& sphere) const { - return std::abs(SquaredDistance(sphere.x, sphere.y, sphere.z) - radius*radius) <= sphere.radius*sphere.radius; + return SquaredDistance(sphere.x, sphere.y, sphere.z) - radius*radius <= sphere.radius*sphere.radius; } template diff --git a/src/Nazara/Core/Win32/TaskSchedulerImpl.cpp b/src/Nazara/Core/Win32/TaskSchedulerImpl.cpp index 0dccbff11..c55d84202 100644 --- a/src/Nazara/Core/Win32/TaskSchedulerImpl.cpp +++ b/src/Nazara/Core/Win32/TaskSchedulerImpl.cpp @@ -4,10 +4,10 @@ #include #include -#include #include -#include +#include // std::ldiv #include +#include bool NzTaskSchedulerImpl::Initialize(unsigned int workerCount) { From 68eae7cb2f77506385f0d93ebe09f94ddcad1ad6 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 17 Jun 2014 11:38:47 +0200 Subject: [PATCH 04/12] Added Gawaboumga to the "Thanks to" list Former-commit-id: 874d6d5fcda53de7f1b24fe66d924681c692a73c --- readme.md | 7 ++++--- readme_fr.md | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 8aa970dc2..759f901e9 100644 --- a/readme.md +++ b/readme.md @@ -31,7 +31,7 @@ Contribute - Extending the [wiki](http://wiki.digitalpulsesoftware.com/index.php?title=Nazara) (**\*Broken link***) - Submitting a patch to GitHub - Post suggestions/bugs on the forum or the [GitHub tracker](https://github.com/DigitalPulseSoftware/NazaraEngine/issues) -- [Fork the project](https://github.com/DigitalPulseSoftware/NazaraEngine/fork) on GitHub and [pull your changes](https://github.com/DigitalPulseSoftware/NazaraEngine/pulls) +- [Fork the project](https://github.com/DigitalPulseSoftware/NazaraEngine/fork) on GitHub and [push your changes](https://github.com/DigitalPulseSoftware/NazaraEngine/pulls) - Talking about Nazara Engine to other people - Doing anything else that might help us @@ -43,5 +43,6 @@ Links ###Thanks to:### - **RafBill** and **Raakz:** Finding bugs and/or testing -- **Fissal "DrFisher" Hannoun**: Helped a lot in architecture design -- **Alexandre "Danman" Janniaux**: Made the Core POSIX implementation +- **Fissal "DrFisher" Hannoun**: Helping a lot in architecture design +- **Alexandre "Danman" Janniaux**: Helping making the POSIX implementation +- **Gawaboumga**: Improving the engine code by merging on GitHub diff --git a/readme_fr.md b/readme_fr.md index 60fa62a7d..fd8aaaf91 100644 --- a/readme_fr.md +++ b/readme_fr.md @@ -44,4 +44,5 @@ Liens ###Remerciements:### - **RafBill** et **Raakz:** Recherche de bugs et/ou tests - **Fissal "DrFisher" Hannoun**: Aide et conseils lors de la conception de l'architecture du moteur -- **Alexandre "Danman" Janniaux**: Implémentation POSIX du noyau +- **Alexandre "Danman" Janniaux**: Aide sur l'implémentation POSIX +- **Gawaboumga**: Amélioration du code via le merging sur GitHub From a6d6213b9d1c0b53f7f5ce4fbb02e72cb09320c6 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 17 Jun 2014 15:53:57 +0200 Subject: [PATCH 06/12] Commited missing file (from 7dfb82) Former-commit-id: 4961498d557dea7101960beb4f2eb6b0a3060368 --- include/Nazara/Math/Quaternion.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Nazara/Math/Quaternion.inl b/include/Nazara/Math/Quaternion.inl index 216f2dbb5..3e27982f6 100644 --- a/include/Nazara/Math/Quaternion.inl +++ b/include/Nazara/Math/Quaternion.inl @@ -213,7 +213,7 @@ NzQuaternion& NzQuaternion::Set(T angle, const NzVector3& axis) angle = NzDegreeToRadian(angle); #endif - angle *= F(0.5); + angle /= F(2.0); NzVector3 normalizedAxis = axis.GetNormal(); From 81672a5ff68680c8e8628d2e14dc563ca06463a9 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 18 Jun 2014 17:39:16 +0200 Subject: [PATCH 07/12] Clarified source code Former-commit-id: 669b6c52c05d87ff8e84d9c1148bc649431cc724 --- src/Nazara/Utility/Win32/WindowImpl.cpp | 91 +++++++++---------------- 1 file changed, 34 insertions(+), 57 deletions(-) diff --git a/src/Nazara/Utility/Win32/WindowImpl.cpp b/src/Nazara/Utility/Win32/WindowImpl.cpp index 2fd43ee54..43cf89fb2 100644 --- a/src/Nazara/Utility/Win32/WindowImpl.cpp +++ b/src/Nazara/Utility/Win32/WindowImpl.cpp @@ -36,6 +36,30 @@ namespace { + LPTSTR windowsCursors[] = + { + IDC_CROSS, // nzWindowCursor_Crosshair + IDC_ARROW, // nzWindowCursor_Default + IDC_HAND, // nzWindowCursor_Hand + IDC_HAND, // nzWindowCursor_Pointer + IDC_HELP, // nzWindowCursor_Help + IDC_SIZEALL, // nzWindowCursor_Move + nullptr, // nzWindowCursor_None + IDC_APPSTARTING, // nzWindowCursor_Progress + IDC_SIZENS, // nzWindowCursor_ResizeN + IDC_SIZENS, // nzWindowCursor_ResizeS + IDC_SIZENWSE, // nzWindowCursor_ResizeNW + IDC_SIZENWSE, // nzWindowCursor_ResizeSE + IDC_SIZENESW, // nzWindowCursor_ResizeNE + IDC_SIZENESW, // nzWindowCursor_ResizeSW + IDC_SIZEWE, // nzWindowCursor_ResizeE + IDC_SIZEWE, // nzWindowCursor_ResizeW + IDC_IBEAM, // nzWindowCursor_Text + IDC_WAIT // nzWindowCursor_Wait + }; + + static_assert(sizeof(windowsCursors)/sizeof(LPTSTR) == nzWindowCursor_Max+1, "Cursor type array is incomplete"); + const wchar_t* className = L"Nazara Window"; NzWindowImpl* fullscreenWindow = nullptr; } @@ -307,65 +331,18 @@ void NzWindowImpl::ProcessEvents(bool block) void NzWindowImpl::SetCursor(nzWindowCursor cursor) { - switch (cursor) + #ifdef NAZARA_DEBUG + if (cursor > nzWindowCursor_Max) { - case nzWindowCursor_Crosshair: - m_cursor = reinterpret_cast(LoadImage(nullptr, IDC_CROSS, IMAGE_CURSOR, 0, 0, LR_SHARED)); - break; - - case nzWindowCursor_Default: - m_cursor = reinterpret_cast(LoadImage(nullptr, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED)); - break; - - case nzWindowCursor_Hand: - case nzWindowCursor_Pointer: - m_cursor = reinterpret_cast(LoadImage(nullptr, IDC_HAND, IMAGE_CURSOR, 0, 0, LR_SHARED)); - break; - - case nzWindowCursor_Help: - m_cursor = reinterpret_cast(LoadImage(nullptr, IDC_HELP, IMAGE_CURSOR, 0, 0, LR_SHARED)); - break; - - case nzWindowCursor_Move: - m_cursor = reinterpret_cast(LoadImage(nullptr, IDC_SIZEALL, IMAGE_CURSOR, 0, 0, LR_SHARED)); - break; - - case nzWindowCursor_None: - m_cursor = nullptr; - break; - - case nzWindowCursor_Progress: - m_cursor = reinterpret_cast(LoadImage(nullptr, IDC_APPSTARTING, IMAGE_CURSOR, 0, 0, LR_SHARED)); - break; - - case nzWindowCursor_ResizeN: - case nzWindowCursor_ResizeS: - m_cursor = reinterpret_cast(LoadImage(nullptr, IDC_SIZENS, IMAGE_CURSOR, 0, 0, LR_SHARED)); - break; - - case nzWindowCursor_ResizeNW: - case nzWindowCursor_ResizeSE: - m_cursor = reinterpret_cast(LoadImage(nullptr, IDC_SIZENWSE, IMAGE_CURSOR, 0, 0, LR_SHARED)); - break; - - case nzWindowCursor_ResizeNE: - case nzWindowCursor_ResizeSW: - m_cursor = reinterpret_cast(LoadImage(nullptr, IDC_SIZENESW, IMAGE_CURSOR, 0, 0, LR_SHARED)); - break; - - case nzWindowCursor_ResizeE: - case nzWindowCursor_ResizeW: - m_cursor = reinterpret_cast(LoadImage(nullptr, IDC_SIZEWE, IMAGE_CURSOR, 0, 0, LR_SHARED)); - break; - - case nzWindowCursor_Text: - m_cursor = reinterpret_cast(LoadImage(nullptr, IDC_IBEAM, IMAGE_CURSOR, 0, 0, LR_SHARED)); - break; - - case nzWindowCursor_Wait: - m_cursor = reinterpret_cast(LoadImage(nullptr, IDC_WAIT, IMAGE_CURSOR, 0, 0, LR_SHARED)); - break; + NazaraError("Window cursor out of enum"); + return false; } + #endif + + if (cursor != nzWindowCursor_None) + m_cursor = reinterpret_cast(LoadImage(nullptr, windowsCursors[cursor], IMAGE_CURSOR, 0, 0, LR_SHARED)); + else + m_cursor = nullptr; // Pas besoin de libérer le curseur par la suite s'il est partagé // http://msdn.microsoft.com/en-us/library/windows/desktop/ms648045(v=vs.85).aspx From 9ba6258478e16b51726ae0ce61e3e973e5d7d243 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 18 Jun 2014 20:34:05 +0200 Subject: [PATCH 08/12] Made context creation exception-safe Former-commit-id: d55687cea712a34e905b3f2f2d85611d1d0b1b74 --- src/Nazara/Renderer/Win32/ContextImpl.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Nazara/Renderer/Win32/ContextImpl.cpp b/src/Nazara/Renderer/Win32/ContextImpl.cpp index ee78e81a6..1ae61bd3e 100644 --- a/src/Nazara/Renderer/Win32/ContextImpl.cpp +++ b/src/Nazara/Renderer/Win32/ContextImpl.cpp @@ -5,6 +5,7 @@ // Code inspiré de NeHe (Lesson1) et de la SFML par Laurent Gomila #include +#include #include #include #include @@ -42,11 +43,16 @@ bool NzContextImpl::Create(NzContextParameters& parameters) m_ownsWindow = true; } + // En cas d'exception, la ressource sera quand même libérée + NzCallOnExit onExit([this] () + { + Destroy(); + }); + m_deviceContext = GetDC(m_window); if (!m_deviceContext) { NazaraError("Failed to get device context"); - Destroy(); return false; } @@ -116,8 +122,6 @@ bool NzContextImpl::Create(NzContextParameters& parameters) if (pixelFormat == 0) { NazaraError("Failed to choose pixel format"); - Destroy(); - return false; } } @@ -125,7 +129,6 @@ bool NzContextImpl::Create(NzContextParameters& parameters) if (!SetPixelFormat(m_deviceContext, pixelFormat, &descriptor)) { NazaraError("Failed to set pixel format"); - Destroy(); return false; } @@ -191,10 +194,11 @@ bool NzContextImpl::Create(NzContextParameters& parameters) if (!m_context) { NazaraError("Failed to create context"); - Destroy(); return false; } + onExit.Reset(); + return true; } From f5833aa2d4a6339f9eb6184392f8323c4875435d Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 21 Jun 2014 15:38:24 +0200 Subject: [PATCH 09/12] Improved rendertechnique fallback (will no longer loop) Former-commit-id: 1aeb737432de1d2a8f205e547404b3f140967a16 --- src/Nazara/Graphics/Scene.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Graphics/Scene.cpp b/src/Nazara/Graphics/Scene.cpp index 8c01521d1..9f8509677 100644 --- a/src/Nazara/Graphics/Scene.cpp +++ b/src/Nazara/Graphics/Scene.cpp @@ -33,7 +33,7 @@ struct NzSceneImpl NzSceneRoot root; NzAbstractViewer* viewer = nullptr; bool backgroundEnabled = true; - bool update; + bool update = false; float frameTime; float updateTime; int renderTechniqueRanking; @@ -99,8 +99,18 @@ void NzScene::Draw() catch (const std::exception& e) { NzString oldName = m_impl->renderTechnique->GetName(); - m_impl->renderTechnique.reset(NzRenderTechniques::GetByRanking(m_impl->renderTechniqueRanking-1, &m_impl->renderTechniqueRanking)); - NazaraError("Render technique \"" + oldName + "\" failed, switched to \"" + m_impl->renderTechnique->GetName() + '"'); + + if (m_impl->renderTechniqueRanking > 0) + { + m_impl->renderTechnique.reset(NzRenderTechniques::GetByRanking(m_impl->renderTechniqueRanking-1, &m_impl->renderTechniqueRanking)); + NazaraError("Render technique \"" + oldName + "\" failed, fallback to \"" + m_impl->renderTechnique->GetName() + '"'); + } + else + { + NzErrorFlags errFlags(nzErrorFlag_ThrowException); + NazaraError("Render technique \"" + oldName + "\" failed and no fallback is available"); + } + return; } } From 5310c8b0d6069c7463f0ee3729e830391cf1b22a Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 21 Jun 2014 16:21:33 +0200 Subject: [PATCH 10/12] Moved skinning to algorithms Former-commit-id: ab31467438f55e8381daa8f238c201c46ba96f52 --- include/Nazara/Utility/Algorithm.hpp | 14 ++ include/Nazara/Utility/SkeletalMesh.hpp | 3 - src/Nazara/Utility/Algorithm.cpp | 107 ++++++++++++++- src/Nazara/Utility/SkeletalMesh.cpp | 172 ------------------------ 4 files changed, 119 insertions(+), 177 deletions(-) diff --git a/include/Nazara/Utility/Algorithm.hpp b/include/Nazara/Utility/Algorithm.hpp index da9326cff..d168cbe94 100644 --- a/include/Nazara/Utility/Algorithm.hpp +++ b/include/Nazara/Utility/Algorithm.hpp @@ -14,6 +14,16 @@ #include #include #include +#include + +struct NzSkinningData +{ + const NzJoint* joints; + const NzMeshVertex* inputVertex; + NzMeshVertex* outputVertex; + const NzVertexWeight* vertexWeights; + const NzWeight* weights; +}; NAZARA_API void NzComputeBoxIndexVertexCount(const NzVector3ui& subdivision, unsigned int* indexCount, unsigned int* vertexCount); NAZARA_API unsigned int NzComputeCacheMissCount(NzIndexIterator indices, unsigned int indexCount); @@ -33,6 +43,10 @@ NAZARA_API void NzGenerateUvSphere(float size, unsigned int sliceCount, unsigned NAZARA_API void NzOptimizeIndices(NzIndexIterator indices, unsigned int indexCount); +NAZARA_API void NzSkinPosition(const NzSkinningData& data, unsigned int startVertex, unsigned int vertexCount); +NAZARA_API void NzSkinPositionNormal(const NzSkinningData& data, unsigned int startVertex, unsigned int vertexCount); +NAZARA_API void NzSkinPositionNormalTangent(const NzSkinningData& data, unsigned int startVertex, unsigned int vertexCount); + template void NzTransformVertices(T* vertices, unsigned int vertexCount, const NzMatrix4f& matrix); #include diff --git a/include/Nazara/Utility/SkeletalMesh.hpp b/include/Nazara/Utility/SkeletalMesh.hpp index 1237d6db9..c8c60a19c 100644 --- a/include/Nazara/Utility/SkeletalMesh.hpp +++ b/include/Nazara/Utility/SkeletalMesh.hpp @@ -55,9 +55,6 @@ class NAZARA_API NzSkeletalMesh final : public NzSubMesh bool IsAnimated() const final; bool IsValid() const; - void Skin(NzMeshVertex* outputBuffer) const; - void Skin(NzMeshVertex* outputBuffer, const NzSkeleton* skeleton) const; - void SetIndexBuffer(const NzIndexBuffer* indexBuffer); private: diff --git a/src/Nazara/Utility/Algorithm.cpp b/src/Nazara/Utility/Algorithm.cpp index e7559a3b9..d1f203977 100644 --- a/src/Nazara/Utility/Algorithm.cpp +++ b/src/Nazara/Utility/Algorithm.cpp @@ -818,7 +818,7 @@ void NzGenerateCone(float length, float radius, unsigned int subdivision, const NzVector3f lExtend = NzVector3f::Left()*radius; NzVector3f fExtend = NzVector3f::Forward()*radius; - // Et on ajoute ensuite les quatres extrémités de la pyramide + // Et on ajoute ensuite les quatres extrémités de la pyramide aabb->ExtendTo(base + lExtend + fExtend); aabb->ExtendTo(base + lExtend - fExtend); aabb->ExtendTo(base - lExtend + fExtend); @@ -961,7 +961,7 @@ void NzGenerateUvSphere(float size, unsigned int sliceCount, unsigned int stackC } } -/************************************Autres***********************************/ +/************************************NzOptimize***********************************/ void NzOptimizeIndices(NzIndexIterator indices, unsigned int indexCount) { @@ -969,3 +969,106 @@ void NzOptimizeIndices(NzIndexIterator indices, unsigned int indexCount) if (optimizer.Optimize(indices, indexCount) != VertexCacheOptimizer::Success) NazaraWarning("Indices optimizer failed"); } + +/************************************NzSkin***********************************/ + +void NzSkinPosition(const NzSkinningData& data, unsigned int startVertex, unsigned int vertexCount) +{ + const NzMeshVertex* inputVertex = &data.inputVertex[startVertex]; + NzMeshVertex* outputVertex = &data.outputVertex[startVertex]; + + unsigned int endVertex = startVertex + vertexCount - 1; + for (unsigned int i = startVertex; i <= endVertex; ++i) + { + NzVector3f finalPosition(NzVector3f::Zero()); + + unsigned int weightCount = data.vertexWeights[i].weights.size(); + for (unsigned int j = 0; j < weightCount; ++j) + { + const NzWeight& weight = data.weights[data.vertexWeights[i].weights[j]]; + + NzMatrix4f mat(data.joints[weight.jointIndex].GetSkinningMatrix()); + mat *= weight.weight; + + finalPosition += mat.Transform(inputVertex->position); + } + + outputVertex->position = finalPosition; + outputVertex->uv = inputVertex->uv; + + inputVertex++; + outputVertex++; + } +} + +void NzSkinPositionNormal(const NzSkinningData& skinningInfos, unsigned int startVertex, unsigned int vertexCount) +{ + const NzMeshVertex* inputVertex = &skinningInfos.inputVertex[startVertex]; + NzMeshVertex* outputVertex = &skinningInfos.outputVertex[startVertex]; + + unsigned int endVertex = startVertex + vertexCount - 1; + for (unsigned int i = startVertex; i <= endVertex; ++i) + { + NzVector3f finalPosition(NzVector3f::Zero()); + NzVector3f finalNormal(NzVector3f::Zero()); + + unsigned int weightCount = skinningInfos.vertexWeights[i].weights.size(); + for (unsigned int j = 0; j < weightCount; ++j) + { + const NzWeight& weight = skinningInfos.weights[skinningInfos.vertexWeights[i].weights[j]]; + + NzMatrix4f mat(skinningInfos.joints[weight.jointIndex].GetSkinningMatrix()); + mat *= weight.weight; + + finalPosition += mat.Transform(inputVertex->position); + finalNormal += mat.Transform(inputVertex->normal, 0.f); + } + + finalNormal.Normalize(); + + outputVertex->normal = finalNormal; + outputVertex->position = finalPosition; + outputVertex->uv = inputVertex->uv; + + inputVertex++; + outputVertex++; + } +} + +void NzSkinPositionNormalTangent(const NzSkinningData& skinningInfos, unsigned int startVertex, unsigned int vertexCount) +{ + const NzMeshVertex* inputVertex = &skinningInfos.inputVertex[startVertex]; + NzMeshVertex* outputVertex = &skinningInfos.outputVertex[startVertex]; + + unsigned int endVertex = startVertex + vertexCount - 1; + for (unsigned int i = startVertex; i <= endVertex; ++i) + { + NzVector3f finalPosition(NzVector3f::Zero()); + NzVector3f finalNormal(NzVector3f::Zero()); + NzVector3f finalTangent(NzVector3f::Zero()); + + unsigned int weightCount = skinningInfos.vertexWeights[i].weights.size(); + for (unsigned int j = 0; j < weightCount; ++j) + { + const NzWeight& weight = skinningInfos.weights[skinningInfos.vertexWeights[i].weights[j]]; + + NzMatrix4f mat(skinningInfos.joints[weight.jointIndex].GetSkinningMatrix()); + mat *= weight.weight; + + finalPosition += mat.Transform(inputVertex->position); + finalNormal += mat.Transform(inputVertex->normal, 0.f); + finalTangent += mat.Transform(inputVertex->tangent, 0.f); + } + + finalNormal.Normalize(); + finalTangent.Normalize(); + + outputVertex->normal = finalNormal; + outputVertex->position = finalPosition; + outputVertex->tangent = finalTangent; + outputVertex->uv = inputVertex->uv; + + inputVertex++; + outputVertex++; + } +} diff --git a/src/Nazara/Utility/SkeletalMesh.cpp b/src/Nazara/Utility/SkeletalMesh.cpp index 735f30b33..314d0a46a 100644 --- a/src/Nazara/Utility/SkeletalMesh.cpp +++ b/src/Nazara/Utility/SkeletalMesh.cpp @@ -2,135 +2,13 @@ // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include - #include -#include -#include #include #include -#include -#include #include #include #include -namespace -{ - struct SkinningInfos - { - const NzJoint* joints; - const NzMeshVertex* inputVertex; - NzMeshVertex* outputVertex; - const NzVertexWeight* vertexWeights; - const NzWeight* weights; - }; - - void Skin_Position(const SkinningInfos& skinningInfos, unsigned int startVertex, unsigned int vertexCount) - { - const NzMeshVertex* inputVertex = &skinningInfos.inputVertex[startVertex]; - NzMeshVertex* outputVertex = &skinningInfos.outputVertex[startVertex]; - - unsigned int endVertex = startVertex + vertexCount - 1; - for (unsigned int i = startVertex; i <= endVertex; ++i) - { - NzVector3f finalPosition(NzVector3f::Zero()); - - unsigned int weightCount = skinningInfos.vertexWeights[i].weights.size(); - for (unsigned int j = 0; j < weightCount; ++j) - { - const NzWeight& weight = skinningInfos.weights[skinningInfos.vertexWeights[i].weights[j]]; - - NzMatrix4f mat(skinningInfos.joints[weight.jointIndex].GetInverseBindMatrix()); - mat.ConcatenateAffine(skinningInfos.joints[weight.jointIndex].GetTransformMatrix()); - mat *= weight.weight; - - finalPosition += mat.Transform(inputVertex->position); - } - - outputVertex->position = finalPosition; - outputVertex->uv = inputVertex->uv; - - inputVertex++; - outputVertex++; - } - } - - void Skin_PositionNormal(const SkinningInfos& skinningInfos, unsigned int startVertex, unsigned int vertexCount) - { - const NzMeshVertex* inputVertex = &skinningInfos.inputVertex[startVertex]; - NzMeshVertex* outputVertex = &skinningInfos.outputVertex[startVertex]; - - unsigned int endVertex = startVertex + vertexCount - 1; - for (unsigned int i = startVertex; i <= endVertex; ++i) - { - NzVector3f finalPosition(NzVector3f::Zero()); - NzVector3f finalNormal(NzVector3f::Zero()); - - unsigned int weightCount = skinningInfos.vertexWeights[i].weights.size(); - for (unsigned int j = 0; j < weightCount; ++j) - { - const NzWeight& weight = skinningInfos.weights[skinningInfos.vertexWeights[i].weights[j]]; - - NzMatrix4f mat(skinningInfos.joints[weight.jointIndex].GetInverseBindMatrix()); - mat.ConcatenateAffine(skinningInfos.joints[weight.jointIndex].GetTransformMatrix()); - mat *= weight.weight; - - finalPosition += mat.Transform(inputVertex->position); - finalNormal += mat.Transform(inputVertex->normal, 0.f); - } - - finalNormal.Normalize(); - - outputVertex->normal = finalNormal; - outputVertex->position = finalPosition; - outputVertex->uv = inputVertex->uv; - - inputVertex++; - outputVertex++; - } - } - - void Skin_PositionNormalTangent(const SkinningInfos& skinningInfos, unsigned int startVertex, unsigned int vertexCount) - { - const NzMeshVertex* inputVertex = &skinningInfos.inputVertex[startVertex]; - NzMeshVertex* outputVertex = &skinningInfos.outputVertex[startVertex]; - - unsigned int endVertex = startVertex + vertexCount - 1; - for (unsigned int i = startVertex; i <= endVertex; ++i) - { - NzVector3f finalPosition(NzVector3f::Zero()); - NzVector3f finalNormal(NzVector3f::Zero()); - NzVector3f finalTangent(NzVector3f::Zero()); - - unsigned int weightCount = skinningInfos.vertexWeights[i].weights.size(); - for (unsigned int j = 0; j < weightCount; ++j) - { - const NzWeight& weight = skinningInfos.weights[skinningInfos.vertexWeights[i].weights[j]]; - - NzMatrix4f mat(skinningInfos.joints[weight.jointIndex].GetInverseBindMatrix()); - mat.ConcatenateAffine(skinningInfos.joints[weight.jointIndex].GetTransformMatrix()); - mat *= weight.weight; - - finalPosition += mat.Transform(inputVertex->position); - finalNormal += mat.Transform(inputVertex->normal, 0.f); - finalTangent += mat.Transform(inputVertex->tangent, 0.f); - } - - finalNormal.Normalize(); - finalTangent.Normalize(); - - outputVertex->normal = finalNormal; - outputVertex->position = finalPosition; - outputVertex->tangent = finalTangent; - outputVertex->uv = inputVertex->uv; - - inputVertex++; - outputVertex++; - } - } -} - struct NzSkeletalMeshImpl { std::unique_ptr bindPoseBuffer; @@ -336,56 +214,6 @@ bool NzSkeletalMesh::IsValid() const return m_impl != nullptr; } -void NzSkeletalMesh::Skin(NzMeshVertex* outputBuffer) const -{ - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Skeletal mesh not created"); - return; - } - #endif - - Skin(outputBuffer, m_parent->GetSkeleton()); -} - -void NzSkeletalMesh::Skin(NzMeshVertex* outputBuffer, const NzSkeleton* skeleton) const -{ - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Skeletal mesh not created"); - return; - } - #endif - - SkinningInfos skinningInfos; - skinningInfos.inputVertex = m_impl->bindPoseBuffer.get(); - skinningInfos.outputVertex = outputBuffer; - skinningInfos.joints = skeleton->GetJoints(); - skinningInfos.vertexWeights = &m_impl->vertexWeights[0]; - skinningInfos.weights = &m_impl->weights[0]; - - #if NAZARA_UTILITY_MULTITHREADED_SKINNING - unsigned int jointCount = skeleton->GetJointCount(); - for (unsigned int i = 0; i < jointCount; ++i) - skinningInfos.joints[i].EnsureTransformMatrixUpdate(); - - unsigned int workerCount = NzTaskScheduler::GetWorkerCount(); - - std::ldiv_t div = std::ldiv(m_impl->vertexCount, workerCount); // Qui sait, peut-être que ça permet des optimisations plus efficaces - for (unsigned int i = 0; i < workerCount; ++i) - NzTaskScheduler::AddTask(Skin_PositionNormalTangent, skinningInfos, i*div.quot, (i == workerCount-1) ? div.quot + div.rem : div.quot); - - NzTaskScheduler::Run(); - NzTaskScheduler::WaitForTasks(); - #else - Skin_PositionNormalTangent(skinningInfos, 0, m_impl->vertexCount); - #endif - - m_impl->aabb = skeleton->GetAABB(); ///FIXME: Qu'est-ce que ça fait encore là ça ? -} - void NzSkeletalMesh::SetIndexBuffer(const NzIndexBuffer* indexBuffer) { m_impl->indexBuffer = indexBuffer; From 774df28d8786af87fc587e38cd7058b8a0d883b1 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 21 Jun 2014 16:22:34 +0200 Subject: [PATCH 11/12] Cached skinning matrix Former-commit-id: c5aeb09778f5696906eb764f600c4a152ab7ba48 --- include/Nazara/Utility/Joint.hpp | 10 +++++++- src/Nazara/Utility/Joint.cpp | 40 +++++++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/include/Nazara/Utility/Joint.hpp b/include/Nazara/Utility/Joint.hpp index 6740d1e52..64f48f034 100644 --- a/include/Nazara/Utility/Joint.hpp +++ b/include/Nazara/Utility/Joint.hpp @@ -21,18 +21,26 @@ class NAZARA_API NzJoint : public NzNode NzJoint(const NzJoint& joint); ~NzJoint() = default; - NzMatrix4f GetInverseBindMatrix() const; + void EnsureSkinningMatrixUpdate() const; + + const NzMatrix4f& GetInverseBindMatrix() const; NzString GetName() const; NzSkeleton* GetSkeleton(); const NzSkeleton* GetSkeleton() const; + const NzMatrix4f& GetSkinningMatrix() const; void SetInverseBindMatrix(const NzMatrix4f& matrix); void SetName(const NzString& name); private: + void InvalidateNode(); + void UpdateSkinningMatrix() const; + NzMatrix4f m_inverseBindMatrix; + mutable NzMatrix4f m_skinningMatrix; NzString m_name; NzSkeleton* m_skeleton; + mutable bool m_skinningMatrixUpdated; }; #endif // NAZARA_JOINT_HPP diff --git a/src/Nazara/Utility/Joint.cpp b/src/Nazara/Utility/Joint.cpp index 060b5eb52..8a46ff227 100644 --- a/src/Nazara/Utility/Joint.cpp +++ b/src/Nazara/Utility/Joint.cpp @@ -7,7 +7,8 @@ #include NzJoint::NzJoint(NzSkeleton* skeleton) : -m_skeleton(skeleton) +m_skeleton(skeleton), +m_skinningMatrixUpdated(false) { } @@ -15,11 +16,18 @@ NzJoint::NzJoint(const NzJoint& joint) : NzNode(joint), m_inverseBindMatrix(joint.m_inverseBindMatrix), m_name(joint.m_name), -m_skeleton(joint.m_skeleton) +m_skeleton(joint.m_skeleton), +m_skinningMatrixUpdated(false) { } -NzMatrix4f NzJoint::GetInverseBindMatrix() const +void NzJoint::EnsureSkinningMatrixUpdate() const +{ + if (!m_skinningMatrixUpdated) + UpdateSkinningMatrix(); +} + +const NzMatrix4f& NzJoint::GetInverseBindMatrix() const { return m_inverseBindMatrix; } @@ -39,9 +47,18 @@ const NzSkeleton* NzJoint::GetSkeleton() const return m_skeleton; } +const NzMatrix4f& NzJoint::GetSkinningMatrix() const +{ + if (!m_skinningMatrixUpdated) + UpdateSkinningMatrix(); + + return m_skinningMatrix; +} + void NzJoint::SetInverseBindMatrix(const NzMatrix4f& matrix) { m_inverseBindMatrix = matrix; + m_skinningMatrixUpdated = false; } void NzJoint::SetName(const NzString& name) @@ -50,3 +67,20 @@ void NzJoint::SetName(const NzString& name) m_skeleton->InvalidateJointMap(); } + +void NzJoint::InvalidateNode() +{ + NzNode::InvalidateNode(); + + m_skinningMatrixUpdated = false; +} + +void NzJoint::UpdateSkinningMatrix() const +{ + if (!m_transformMatrixUpdated) + UpdateTransformMatrix(); + + m_skinningMatrix.Set(m_inverseBindMatrix); + m_skinningMatrix.ConcatenateAffine(m_transformMatrix); + m_skinningMatrixUpdated = true; +} From 6c1852299da2fe53ed57682b0b58532f3c727571 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 21 Jun 2014 16:23:38 +0200 Subject: [PATCH 12/12] Added SkinningManager Former-commit-id: ca3648dc16f5b1654cb8e3f5480d04f7fd22a3bc --- include/Nazara/Graphics/SkinningManager.hpp | 36 +++ src/Nazara/Graphics/Graphics.cpp | 13 +- src/Nazara/Graphics/Scene.cpp | 3 + src/Nazara/Graphics/SkinningManager.cpp | 237 ++++++++++++++++++++ 4 files changed, 286 insertions(+), 3 deletions(-) create mode 100644 include/Nazara/Graphics/SkinningManager.hpp create mode 100644 src/Nazara/Graphics/SkinningManager.cpp diff --git a/include/Nazara/Graphics/SkinningManager.hpp b/include/Nazara/Graphics/SkinningManager.hpp new file mode 100644 index 000000000..5b015c066 --- /dev/null +++ b/include/Nazara/Graphics/SkinningManager.hpp @@ -0,0 +1,36 @@ +// Copyright (C) 2014 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SKINNINGMANAGER_HPP +#define NAZARA_SKINNINGMANAGER_HPP + +#include + +class NzSkeleton; +class NzSkeletalMesh; +class NzVertexBuffer; + +class NAZARA_API NzSkinningManager +{ + friend class NzGraphics; + + public: + using SkinFunction = void (*)(const NzSkeletalMesh* mesh, const NzSkeleton* skeleton, NzVertexBuffer* buffer); + + NzSkinningManager() = delete; + ~NzSkinningManager() = delete; + + static NzVertexBuffer* GetBuffer(const NzSkeletalMesh* mesh, const NzSkeleton* skeleton); + static void Skin(); + + private: + static bool Initialize(); + static void Uninitialize(); + + static SkinFunction s_skinFunc; +}; + +#endif // NAZARA_SKINNINGMANAGER_HPP diff --git a/src/Nazara/Graphics/Graphics.cpp b/src/Nazara/Graphics/Graphics.cpp index 333162fb1..cc23fa2a6 100644 --- a/src/Nazara/Graphics/Graphics.cpp +++ b/src/Nazara/Graphics/Graphics.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,13 @@ bool NzGraphics::Initialize() if (!NzMaterial::Initialize()) { - NazaraError("Failed to create material"); + NazaraError("Failed to initialize materials"); + return false; + } + + if (!NzSkinningManager::Initialize()) + { + NazaraError("Failed to initialize skinning cache"); return false; } @@ -89,9 +96,9 @@ void NzGraphics::Uninitialize() NzLoaders_OBJ_Unregister(); NzLoaders_Texture_Unregister(); - NzMaterial::Uninitialize(); - NzDeferredRenderTechnique::Uninitialize(); + NzMaterial::Uninitialize(); + NzSkinningManager::Uninitialize(); NazaraNotice("Uninitialized: Graphics module"); diff --git a/src/Nazara/Graphics/Scene.cpp b/src/Nazara/Graphics/Scene.cpp index 1c9a438e2..15d7a5d4a 100644 --- a/src/Nazara/Graphics/Scene.cpp +++ b/src/Nazara/Graphics/Scene.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -219,6 +220,8 @@ void NzScene::Update() void NzScene::UpdateVisible() { + NzSkinningManager::Skin(); + if (m_impl->update) { for (NzUpdatable* node : m_impl->visibleUpdateList) diff --git a/src/Nazara/Graphics/SkinningManager.cpp b/src/Nazara/Graphics/SkinningManager.cpp new file mode 100644 index 000000000..9a756ea03 --- /dev/null +++ b/src/Nazara/Graphics/SkinningManager.cpp @@ -0,0 +1,237 @@ +// Copyright (C) 2014 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + enum ResourceType + { + ResourceType_SkeletalMesh, + ResourceType_Skeleton, + }; + + struct BufferData + { + NzVertexBufferRef buffer; + bool updated; + }; + + struct SkinningData + { + const NzSkeletalMesh* mesh; + const NzSkeleton* skeleton; + NzVertexBuffer* buffer; + }; + + using MeshMap = std::unordered_map; + using SkeletonMap = std::unordered_map; + SkeletonMap s_cache; + std::vector s_skinningQueue; + + class ResourceListener : public NzResourceListener + { + public: + bool OnResourceDestroy(const NzResource* resource, int index) + { + switch (index) + { + case ResourceType_SkeletalMesh: + { + for (auto& pair : s_cache) + { + MeshMap& meshMap = pair.second; + meshMap.erase(static_cast(resource)); + } + break; + } + + case ResourceType_Skeleton: + s_cache.erase(static_cast(resource)); + break; + } + + return false; + } + + bool OnResourceModified(const NzResource* resource, int index, unsigned int code) + { + NazaraUnused(code); + + switch (index) + { + case ResourceType_SkeletalMesh: + { + for (auto& pair : s_cache) + { + MeshMap& meshMap = pair.second; + for (auto& pair2 : meshMap) + pair2.second.updated = false; + } + break; + } + + case ResourceType_Skeleton: + { + for (auto& pair : s_cache.at(static_cast(resource))) + pair.second.updated = false; + break; + } + } + + return true; + } + + void OnResourceReleased(const NzResource* resource, int index) + { + OnResourceDestroy(resource, index); + } + }; + + ResourceListener listener; + + void Skin_MonoCPU(const NzSkeletalMesh* mesh, const NzSkeleton* skeleton, NzVertexBuffer* buffer) + { + NzBufferMapper mapper(buffer, nzBufferAccess_DiscardAndWrite); + + NzSkinningData skinningData; + skinningData.inputVertex = mesh->GetBindPoseBuffer(); + skinningData.outputVertex = static_cast(mapper.GetPointer()); + skinningData.joints = skeleton->GetJoints(); + skinningData.vertexWeights = mesh->GetVertexWeight(0); + skinningData.weights = mesh->GetWeight(0); + + NzSkinPositionNormalTangent(skinningData, 0, mesh->GetVertexCount()); + } + + void Skin_MultiCPU(const NzSkeletalMesh* mesh, const NzSkeleton* skeleton, NzVertexBuffer* buffer) + { + NzBufferMapper mapper(buffer, nzBufferAccess_DiscardAndWrite); + + NzSkinningData skinningData; + skinningData.inputVertex = mesh->GetBindPoseBuffer(); + skinningData.outputVertex = static_cast(mapper.GetPointer()); + skinningData.joints = skeleton->GetJoints(); + skinningData.vertexWeights = mesh->GetVertexWeight(0); + skinningData.weights = mesh->GetWeight(0); + + // 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 + unsigned int jointCount = skeleton->GetJointCount(); + for (unsigned int i = 0; i < jointCount; ++i) + skinningData.joints[i].EnsureSkinningMatrixUpdate(); + + unsigned int workerCount = NzTaskScheduler::GetWorkerCount(); + + std::ldiv_t div = std::ldiv(mesh->GetVertexCount(), workerCount); + for (unsigned int i = 0; i < workerCount; ++i) + NzTaskScheduler::AddTask(NzSkinPositionNormalTangent, skinningData, i*div.quot, (i == workerCount-1) ? div.quot + div.rem : div.quot); + + NzTaskScheduler::Run(); + NzTaskScheduler::WaitForTasks(); + } +} + +NzVertexBuffer* NzSkinningManager::GetBuffer(const NzSkeletalMesh* mesh, const NzSkeleton* skeleton) +{ + #if NAZARA_GRAPHICS_SAFE + if (!mesh) + { + NazaraError("Invalid mesh"); + return nullptr; + } + + if (!skeleton) + { + NazaraError("Invalid skeleton"); + return nullptr; + } + #endif + + NzErrorFlags flags(nzErrorFlag_ThrowException); + + SkeletonMap::iterator it = s_cache.find(skeleton); + if (it == s_cache.end()) + { + it = s_cache.insert(std::make_pair(skeleton, SkeletonMap::mapped_type())).first; + skeleton->AddResourceListener(&listener, ResourceType_Skeleton); + } + + NzVertexBuffer* buffer; + + MeshMap& meshMap = it->second; + MeshMap::iterator it2 = meshMap.find(mesh); + if (it2 == meshMap.end()) + { + std::unique_ptr vertexBuffer(new NzVertexBuffer); + vertexBuffer->SetPersistent(false); + vertexBuffer->Reset(NzVertexDeclaration::Get(nzVertexLayout_XYZ_Normal_UV_Tangent), mesh->GetVertexCount(), nzBufferStorage_Hardware, nzBufferUsage_Dynamic); + + BufferData data({vertexBuffer.get(), true}); + meshMap.insert(std::make_pair(mesh, data)); + + mesh->AddResourceListener(&listener, ResourceType_SkeletalMesh); + + s_skinningQueue.push_back(SkinningData{mesh, skeleton, vertexBuffer.get()}); + + buffer = vertexBuffer.release(); + } + else + { + BufferData& data = it2->second; + if (!data.updated) + { + s_skinningQueue.push_back(SkinningData{mesh, skeleton, data.buffer}); + data.updated = true; + } + + buffer = data.buffer; + } + + return buffer; +} + +void NzSkinningManager::Skin() +{ + for (SkinningData& data : s_skinningQueue) + s_skinFunc(data.mesh, data.skeleton, data.buffer); + + s_skinningQueue.clear(); +} + +bool NzSkinningManager::Initialize() +{ + ///TODO: GPU Skinning + if (NzTaskScheduler::Initialize()) + s_skinFunc = Skin_MultiCPU; + else + s_skinFunc = Skin_MonoCPU; + + return true; // Rien de particulier à faire +} + +void NzSkinningManager::Uninitialize() +{ + for (auto& pair : s_cache) + { + pair.first->RemoveResourceListener(&listener); + MeshMap& meshMap = pair.second; + for (auto& pair2 : meshMap) + pair2.first->RemoveResourceListener(&listener); + } + s_cache.clear(); + s_skinningQueue.clear(); +} + +NzSkinningManager::SkinFunction NzSkinningManager::s_skinFunc = nullptr;