From 70ef4229504ab06d11306deac7d8a6a35e01ddd9 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 21 Nov 2012 17:23:50 +0100 Subject: [PATCH] Big skeletal animation update Added MeshInfos demo Added MD5Mesh/MD5Anim loader support Added Node class Fixed ResourceParams not being exported Added support for skeletal animation (Animation/Mesh/Joint/SkeletalMesh/Skeleton) Meshes are now only stored with VertexStruct_XYZ_Normal_UV_Tangent type Moved Sequence declaration to Sequence.hpp -Animation: Renamed Create to Create[Keyframe|Skeletal] -AxisAlignedBox: Added Contains method Added GetCorner method Added GetCube method Added Transform method -Cube/Rect: Added GetPosition method Added GetSize method (Almost) Fixed ExtendTo method Fixed GetCenter method -File: Added GetDirectory static function Added GetPath method Renamed GetDirectoryPath method to GetDirectory -Math module: Fixed constructor/methods taking a non-const array GetNormal/Normalize methods now takes an optionnal integer pointer (returning length) Made all classes default constructor trivial Inverse, MakeIdentity, MakeZero, Normalize, Set methods now returns reference to object -Matrix4: Modified methods to avoid copies Removed COW (Too much overhead) Removed Concatenate[Affine] static function -Mesh: Renamed Create to Create[Keyframe|Skeletal|Static] Renamed Skin to Material -MeshParams: No longer takes declaration argument Renamed loadAnimations to animated Storage default to BufferStorage_Hardware if supported and BufferStorage_Software otherwise -OpenGL: Added glGetBooleanv function Added glIsEnabled function -Quaternion: Added ComputeW method Added Conjugate method -Renderer: Added IsEnabled static function Fixed GetLineWidth function not being static Removed SetVertexDeclaration -RenderWindow: Made CopyTo[Image|Texture] method constant -Resource Fixed RemoveResourceListener crash -ResourceLoader: Loaders are now used in a LIFO context -Stream: Renamed GetLine method to ReadLine -String: Fixed Simplified -Utility module Added configuration define for strict resource parsing -VertexBuffer Now takes a VertexDeclaration pointer -VertexDeclaration No longer throw an error when getting a non-existing element Former-commit-id: f7358c1231d6af48b799d2f24f077a001e16785b --- examples/ListSequences/main.cpp | 49 - .../{ListSequences => MeshInfos}/build.lua | 0 examples/MeshInfos/main.cpp | 164 +++ include/Nazara/Audio.hpp | 5 + include/Nazara/Core.hpp | 7 +- include/Nazara/Core/Config.hpp | 29 +- include/Nazara/Core/File.hpp | 7 +- include/Nazara/Core/InputStream.hpp | 4 +- include/Nazara/Core/ResourceLoader.hpp | 3 +- include/Nazara/Core/ResourceLoader.inl | 4 +- include/Nazara/Core/Stream.hpp | 3 + include/Nazara/Math.hpp | 5 + include/Nazara/Math/Basic.hpp | 1 + include/Nazara/Math/Basic.inl | 5 +- include/Nazara/Math/Config.hpp | 9 +- include/Nazara/Math/Cube.hpp | 20 +- include/Nazara/Math/Cube.inl | 99 +- include/Nazara/Math/EulerAngles.hpp | 6 +- include/Nazara/Math/EulerAngles.inl | 15 +- include/Nazara/Math/Matrix4.hpp | 59 +- include/Nazara/Math/Matrix4.inl | 1163 ++++++----------- include/Nazara/Math/Quaternion.hpp | 31 +- include/Nazara/Math/Quaternion.inl | 128 +- include/Nazara/Math/Rect.hpp | 18 +- include/Nazara/Math/Rect.inl | 61 +- include/Nazara/Math/Vector2.hpp | 27 +- include/Nazara/Math/Vector2.inl | 94 +- include/Nazara/Math/Vector3.hpp | 34 +- include/Nazara/Math/Vector3.inl | 114 +- include/Nazara/Math/Vector4.hpp | 28 +- include/Nazara/Math/Vector4.inl | 107 +- include/Nazara/Noise.hpp | 5 + include/Nazara/Renderer.hpp | 6 + include/Nazara/Renderer/DebugDrawer.hpp | 44 + include/Nazara/Renderer/OpenGL.hpp | 6 +- include/Nazara/Renderer/RenderWindow.hpp | 6 +- include/Nazara/Renderer/Renderer.hpp | 4 +- include/Nazara/Utility.hpp | 12 + include/Nazara/Utility/Animation.hpp | 18 +- include/Nazara/Utility/AxisAlignedBox.hpp | 6 + include/Nazara/Utility/Config.hpp | 5 +- include/Nazara/Utility/Enums.hpp | 22 + include/Nazara/Utility/Image.hpp | 2 +- include/Nazara/Utility/Joint.hpp | 38 + include/Nazara/Utility/KeyframeMesh.hpp | 37 +- include/Nazara/Utility/Mesh.hpp | 33 +- include/Nazara/Utility/Node.hpp | 85 ++ include/Nazara/Utility/Sequence.hpp | 29 + include/Nazara/Utility/SkeletalMesh.hpp | 62 + include/Nazara/Utility/Skeleton.hpp | 53 + include/Nazara/Utility/StaticMesh.hpp | 23 +- include/Nazara/Utility/SubMesh.hpp | 20 +- include/Nazara/Utility/VertexBuffer.hpp | 7 +- include/Nazara/Utility/VertexStruct.hpp | 113 ++ src/Nazara/Core/File.cpp | 50 +- src/Nazara/Core/InputStream.cpp | 2 +- src/Nazara/Core/Log.cpp | 2 +- src/Nazara/Core/Resource.cpp | 41 +- src/Nazara/Core/Stream.cpp | 10 + src/Nazara/Core/String.cpp | 6 +- src/Nazara/Core/Win32/SemaphoreImpl.cpp | 2 - src/Nazara/Renderer/DebugDrawer.cpp | 411 ++++++ src/Nazara/Renderer/GLSLShader.cpp | 12 +- src/Nazara/Renderer/GLSLShader.hpp | 2 +- src/Nazara/Renderer/OpenGL.cpp | 10 +- src/Nazara/Renderer/RenderTexture.cpp | 2 + src/Nazara/Renderer/RenderWindow.cpp | 46 +- src/Nazara/Renderer/Renderer.cpp | 178 ++- src/Nazara/Renderer/Texture.cpp | 4 +- src/Nazara/Utility/Animation.cpp | 184 ++- src/Nazara/Utility/AxisAlignedBox.cpp | 85 +- src/Nazara/Utility/Buffer.cpp | 27 +- src/Nazara/Utility/Cursor.cpp | 2 + src/Nazara/Utility/Icon.cpp | 2 + src/Nazara/Utility/Joint.cpp | 52 + src/Nazara/Utility/KeyframeMesh.cpp | 447 ++++++- src/Nazara/Utility/Loaders/MD2/Constants.hpp | 9 - src/Nazara/Utility/Loaders/MD2/Loader.cpp | 187 ++- src/Nazara/Utility/Loaders/MD2/Mesh.cpp | 292 ----- src/Nazara/Utility/Loaders/MD2/Mesh.hpp | 65 - src/Nazara/Utility/Loaders/MD5Anim.hpp | 15 + src/Nazara/Utility/Loaders/MD5Anim/Loader.cpp | 32 + src/Nazara/Utility/Loaders/MD5Anim/Parser.cpp | 529 ++++++++ src/Nazara/Utility/Loaders/MD5Anim/Parser.hpp | 72 + src/Nazara/Utility/Loaders/MD5Mesh.hpp | 15 + src/Nazara/Utility/Loaders/MD5Mesh/Loader.cpp | 32 + src/Nazara/Utility/Loaders/MD5Mesh/Parser.cpp | 756 +++++++++++ src/Nazara/Utility/Loaders/MD5Mesh/Parser.hpp | 78 ++ src/Nazara/Utility/Loaders/PCX/Loader.cpp | 2 + src/Nazara/Utility/Mesh.cpp | 275 +++- src/Nazara/Utility/Node.cpp | 429 ++++++ src/Nazara/Utility/PixelFormat.cpp | 5 +- src/Nazara/Utility/SkeletalMesh.cpp | 311 +++++ src/Nazara/Utility/Skeleton.cpp | 384 ++++++ src/Nazara/Utility/StaticMesh.cpp | 111 +- src/Nazara/Utility/SubMesh.cpp | 66 +- src/Nazara/Utility/Utility.cpp | 22 +- src/Nazara/Utility/VertexBuffer.cpp | 37 +- src/Nazara/Utility/VertexDeclaration.cpp | 17 - 99 files changed, 6270 insertions(+), 1983 deletions(-) delete mode 100644 examples/ListSequences/main.cpp rename examples/{ListSequences => MeshInfos}/build.lua (100%) create mode 100644 examples/MeshInfos/main.cpp create mode 100644 include/Nazara/Renderer/DebugDrawer.hpp create mode 100644 include/Nazara/Utility/Joint.hpp create mode 100644 include/Nazara/Utility/Node.hpp create mode 100644 include/Nazara/Utility/Sequence.hpp create mode 100644 include/Nazara/Utility/SkeletalMesh.hpp create mode 100644 include/Nazara/Utility/Skeleton.hpp create mode 100644 include/Nazara/Utility/VertexStruct.hpp create mode 100644 src/Nazara/Renderer/DebugDrawer.cpp create mode 100644 src/Nazara/Utility/Joint.cpp delete mode 100644 src/Nazara/Utility/Loaders/MD2/Mesh.cpp delete mode 100644 src/Nazara/Utility/Loaders/MD2/Mesh.hpp create mode 100644 src/Nazara/Utility/Loaders/MD5Anim.hpp create mode 100644 src/Nazara/Utility/Loaders/MD5Anim/Loader.cpp create mode 100644 src/Nazara/Utility/Loaders/MD5Anim/Parser.cpp create mode 100644 src/Nazara/Utility/Loaders/MD5Anim/Parser.hpp create mode 100644 src/Nazara/Utility/Loaders/MD5Mesh.hpp create mode 100644 src/Nazara/Utility/Loaders/MD5Mesh/Loader.cpp create mode 100644 src/Nazara/Utility/Loaders/MD5Mesh/Parser.cpp create mode 100644 src/Nazara/Utility/Loaders/MD5Mesh/Parser.hpp create mode 100644 src/Nazara/Utility/Node.cpp create mode 100644 src/Nazara/Utility/SkeletalMesh.cpp create mode 100644 src/Nazara/Utility/Skeleton.cpp diff --git a/examples/ListSequences/main.cpp b/examples/ListSequences/main.cpp deleted file mode 100644 index e58184466..000000000 --- a/examples/ListSequences/main.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include - -int main() -{ - // Pour charger des ressources, il est impératif d'initialiser le module utilitaire - NzInitializer utility; - if (!utility) - { - // Ça n'a pas fonctionné, le pourquoi se trouve dans le fichier NazaraLog.log - std::cout << "Failed to initialize Nazara, see NazaraLog.log for further informations" << std::endl; - std::getchar(); // On laise le temps de voir l'erreur - return EXIT_FAILURE; - } - - // Le Renderer n'étant pas chargé, nous devons indiquer que nous désirons un stockage software de notre mesh - NzMeshParams parameters; - parameters.storage = nzBufferStorage_Software; - - NzMesh drfreak; - if (!drfreak.LoadFromFile("resources/drfreak.md2", parameters)) - { - std::cout << "Failed to load Dr. Freak's mesh" << std::endl; - std::getchar(); - return EXIT_FAILURE; - } - - if (drfreak.HasAnimation()) // Si le mesh possède des animations - { - std::cout << "Mesh has animation" << std::endl; - - // Un objet NzAnimation représente un ensemble d'informations sur des animations - const NzAnimation* animation = drfreak.GetAnimation(); - - // Une séquence définit une "action", chaque séquence possède un nom, une frame de départ, une d'arrivée ainsi qu'un framerate - unsigned int sequenceCount = animation->GetSequenceCount(); - std::cout << sequenceCount << " sequences:" << std::endl; - for (unsigned int i = 0; i < sequenceCount; ++i) - std::cout << "-" << (i+1) << ": " << animation->GetSequence(i)->name << std::endl; - } - else - std::cout << "Mesh has no animation" << std::endl; - - std::getchar(); // Une attente pour avoir le temps de lire :-) - - // Le module utilitaire et le mesh sont déchargés automatiquement - return EXIT_SUCCESS; -} diff --git a/examples/ListSequences/build.lua b/examples/MeshInfos/build.lua similarity index 100% rename from examples/ListSequences/build.lua rename to examples/MeshInfos/build.lua diff --git a/examples/MeshInfos/main.cpp b/examples/MeshInfos/main.cpp new file mode 100644 index 000000000..e64786a36 --- /dev/null +++ b/examples/MeshInfos/main.cpp @@ -0,0 +1,164 @@ +#include +#include +#include +#include +#include +#include +#include + +int main() +{ + // Pour charger des ressources, il est impératif d'initialiser le module utilitaire + NzInitializer utility; + if (!utility) + { + // Ça n'a pas fonctionné, le pourquoi se trouve dans le fichier NazaraLog.log + std::cout << "Failed to initialize Nazara, see NazaraLog.log for further informations" << std::endl; + std::getchar(); // On laise le temps de voir l'erreur + return EXIT_FAILURE; + } + + for (;;) + { + NzDirectory resourceDirectory("resources/"); + if (!resourceDirectory.Open()) + { + std::cerr << "Failed to open resource directory" << std::endl; + std::getchar(); + return EXIT_FAILURE; + } + + std::vector models; + while (resourceDirectory.NextResult(true)) + { + NzString path = resourceDirectory.GetResultName(); + if (path.EndsWith(".md2") || path.EndsWith(".md5mesh")) + models.push_back(path); + } + + resourceDirectory.Close(); + + if (models.empty()) + { + std::cout << "No loadable mesh found in resource directory" << std::endl; + std::getchar(); + return EXIT_FAILURE; + } + + std::cout << "Choose:" << std::endl; + std::cout << "0: exit" << std::endl; + for (unsigned int i = 0; i < models.size(); ++i) + std::cout << (i+1) << ": " << models[i] << std::endl; + + std::cout << std::endl; + + unsigned int iChoice; + do + { + std::cout << '-'; + std::cin >> iChoice; + std::cin.ignore(std::numeric_limits::max(), '\n'); + } + while (iChoice > models.size()); + + if (iChoice == 0) + break; + + NzMesh mesh; + if (!mesh.LoadFromFile("resources/" + models[iChoice-1])) + { + std::cout << "Failed to load mesh" << std::endl; + std::getchar(); + return EXIT_FAILURE; + } + + switch (mesh.GetAnimationType()) + { + case nzAnimationType_Keyframe: + std::cout << "This is a keyframe-animated mesh" << std::endl; + break; + + case nzAnimationType_Skeletal: + std::cout << "This is a skeletal-animated mesh" << std::endl; + break; + + case nzAnimationType_Static: + std::cout << "This is a static mesh" << std::endl; + break; + + // Inutile de faire un case default (GetAnimationType renverra toujours une valeur correcte) + } + + std::cout << "It has a total of " << mesh.GetVertexCount() << " vertices for " << mesh.GetSubMeshCount() << " submesh(es)." << std::endl; + + if (mesh.IsAnimable()) + { + if (mesh.GetAnimationType() == nzAnimationType_Skeletal) + { + const NzSkeleton* skeleton = mesh.GetSkeleton(); + unsigned int jointCount = skeleton->GetJointCount(); + std::cout << "It has a skeleton made of " << skeleton->GetJointCount() << " joint(s)." << std::endl; + std::cout << "Print joints ? (Y/N) "; + + char cChoice; + std::cin >> cChoice; + std::cin.ignore(std::numeric_limits::max(), '\n'); + + if (std::tolower(cChoice) == 'y') + { + for (unsigned int i = 0; i < jointCount; ++i) + { + const NzJoint* joint = skeleton->GetJoint(i); + std::cout << "\t" << (i+1) << ": " << joint->GetName(); + + const NzJoint* parent = static_cast(joint->GetParent()); + if (parent) + std::cout << " (Parent: " << parent->GetName() << ')'; + + std::cin.ignore(std::numeric_limits::max(), '\n'); + } + } + } + + if (mesh.HasAnimation()) + { + const NzAnimation* animation = mesh.GetAnimation(); + unsigned int sequenceCount = animation->GetSequenceCount(); + std::cout << "It has an animation made of " << animation->GetFrameCount() << " frame(s) for " << sequenceCount << " sequence(s)." << std::endl; + std::cout << "Print sequences ? (Y/N) "; + + char cChoice; + std::cin >> cChoice; + std::cin.ignore(std::numeric_limits::max(), '\n'); + + if (std::tolower(cChoice) == 'y') + { + for (unsigned int i = 0; i < sequenceCount; ++i) + { + const NzSequence* sequence = animation->GetSequence(i); + std::cout << "\t" << (i+1) << ": " << sequence->name << std::endl; + std::cout << "\t\tStart frame: " << sequence->firstFrame << std::endl; + std::cout << "\t\tFrame count: " << sequence->frameCount << std::endl; + std::cout << "\t\tFrame rate: " << sequence->frameRate << std::endl; + std::cin.ignore(std::numeric_limits::max(), '\n'); + } + } + } + else + std::cout << "It's animable but has no loaded animation" << std::endl; + } + + /*NzCubef cube = mesh.GetAABB().GetCube(); + std::cout << "Mesh is " << cube.width << " unit wide, " << cube.height << "unit height and " << cube.depth << " unit depth" << std::endl; + + unsigned int materialCount = mesh.GetMaterialCount(); + std::cout << "It has " << materialCount << " materials registred" << std::endl; + for (unsigned int i = 0; i < materialCount; ++i) + std::cout << "\t" << (i+1) << ": " << mesh.GetMaterial(i) << std::endl;*/ + + std::cout << std::endl << std::endl; + } + + // Le module utilitaire et le mesh sont déchargés automatiquement + return EXIT_SUCCESS; +} diff --git a/include/Nazara/Audio.hpp b/include/Nazara/Audio.hpp index 3dbc52270..c1381421f 100644 --- a/include/Nazara/Audio.hpp +++ b/include/Nazara/Audio.hpp @@ -26,9 +26,14 @@ #pragma once +#ifndef NAZARA_GLOBAL_AUDIO_HPP +#define NAZARA_GLOBAL_AUDIO_HPP + #include #include #include #include #include #include + +#endif // NAZARA_GLOBAL_AUDIO_HPP diff --git a/include/Nazara/Core.hpp b/include/Nazara/Core.hpp index 51d88be63..8e66dbe3a 100644 --- a/include/Nazara/Core.hpp +++ b/include/Nazara/Core.hpp @@ -3,7 +3,7 @@ /* Nazara Engine - Core module - Copyright (C) 2012 Jérôme "Lynix" Leclercq (Lynix680@gmail.com) + Copyright (C) 2012 Jérôme "Lynix" Leclercq (Lynix680@gmail.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -26,6 +26,9 @@ #pragma once +#ifndef NAZARA_GLOBAL_CORE_HPP +#define NAZARA_GLOBAL_CORE_HPP + #include #include #include @@ -61,3 +64,5 @@ #include #include #include + +#endif // NAZARA_GLOBAL_CORE_HPP diff --git a/include/Nazara/Core/Config.hpp b/include/Nazara/Core/Config.hpp index be4f2c6cd..cb6e8ff36 100644 --- a/include/Nazara/Core/Config.hpp +++ b/include/Nazara/Core/Config.hpp @@ -1,7 +1,7 @@ /* Nazara Engine - Core module - Copyright (C) 2012 Jérôme "Lynix" Leclercq (Lynix680@gmail.com) + Copyright (C) 2012 Jérôme "Lynix" Leclercq (Lynix680@gmail.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -27,39 +27,36 @@ #ifndef NAZARA_CONFIG_CORE_HPP #define NAZARA_CONFIG_CORE_HPP -/// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci +/// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci -// Appelle exit dès qu'une assertion est invalide +// Appelle exit dès qu'une assertion est invalide #define NAZARA_CORE_EXIT_ON_ASSERT_FAILURE 1 // Teste les assertions #define NAZARA_CORE_ENABLE_ASSERTS 0 -// Taille du buffer lors d'une lecture complète d'un fichier (ex: Hash) +// Taille du buffer lors d'une lecture complète d'un fichier (ex: Hash) #define NAZARA_CORE_FILE_BUFFERSIZE 4096 -// Le moteur doit-il incorporer les Unicode Character Data (Nécessaires pour faire fonctionner le flag NzString::HandleUTF8) +// Incorpore la table Unicode Character Data (Nécessaires pour faire fonctionner le flag NzString::HandleUTF8) #define NAZARA_CORE_INCLUDE_UNICODEDATA 0 -// Utilise un tracker pour repérer les éventuels leaks (Ralentit l'exécution) +// Utilise un tracker pour repérer les éventuels leaks (Ralentit l'exécution) #define NAZARA_CORE_MEMORYLEAKTRACKER 0 -// Standardise les séparateurs des dossiers selon le système d'exploitation courant (Léger coût à l'exécution) -#define NAZARA_CORE_NORMALIZE_DIRECTORY_SEPARATORS 1 - -// Précision des réels lors de la transformation en texte (Max. chiffres après la virgule) +// Précision des réels lors de la transformation en texte (Max. chiffres après la virgule) #define NAZARA_CORE_REAL_PRECISION 6 // Duplique la sortie du log sur le flux de sortie standard (cout) #define NAZARA_CORE_DUPLICATE_TO_COUT 0 -// Active les tests de sécurité basés sur le code (Conseillé pour le développement) +// Active les tests de sécurité basés sur le code (Conseillé pour le développement) #define NAZARA_CORE_SAFE 1 -// Protège les classes des accès concurrentiels +// Protège les classes des accès concurrentiels #define NAZARA_CORE_THREADSAFE 1 -// Les classes à protéger des accès concurrentiels +// Les classes à protéger des accès concurrentiels #define NAZARA_THREADSAFETY_BYTEARRAY 1 // NzByteArray (COW) #define NAZARA_THREADSAFETY_CLOCK 0 // NzClock #define NAZARA_THREADSAFETY_DIRECTORY 1 // NzDirectory @@ -71,14 +68,14 @@ #define NAZARA_THREADSAFETY_STRING 1 // NzString (COW) #define NAZARA_THREADSAFETY_STRINGSTREAM 0 // NzStringStream -// Le nombre de spinlocks à utiliser avec les critical sections de Windows (0 pour désactiver) +// Le nombre de spinlocks à utiliser avec les critical sections de Windows (0 pour désactiver) #define NAZARA_CORE_WINDOWS_CS_SPINLOCKS 4096 -// Optimise certaines parties du code avec certaines avancées venues de Windows Vista (Casse la compatibilité XP mais n'affecte pas les autres OS) +// Optimise l'implémentation Windows avec certaines avancées de Windows vista (Casse la compatibilité XP) #define NAZARA_CORE_WINDOWS_VISTA 0 /* -// Règle le temps entre le réveil du thread des timers et l'activation d'un timer (En millisecondes) +// Règle le temps entre le réveil du thread des timers et l'activation d'un timer (En millisecondes) #define NAZARA_CORE_TIMER_WAKEUPTIME 10 */ diff --git a/include/Nazara/Core/File.hpp b/include/Nazara/Core/File.hpp index bcab9c24f..716efe283 100644 --- a/include/Nazara/Core/File.hpp +++ b/include/Nazara/Core/File.hpp @@ -67,11 +67,11 @@ class NAZARA_API NzFile : public NzHashable, public NzInputStream, NzNonCopyable time_t GetCreationTime() const; nzUInt64 GetCursorPos() const; - NzString GetDirectoryPath() const; - NzString GetFilePath() const; + NzString GetDirectory() const; NzString GetFileName() const; time_t GetLastAccessTime() const; time_t GetLastWriteTime() const; + NzString GetPath() const; nzUInt64 GetSize() const; bool IsOpen() const; @@ -99,12 +99,13 @@ class NAZARA_API NzFile : public NzHashable, public NzInputStream, NzNonCopyable static bool Delete(const NzString& filePath); static bool Exists(const NzString& filePath); static time_t GetCreationTime(const NzString& filePath); + static NzString GetDirectory(const NzString& filePath); static time_t GetLastAccessTime(const NzString& filePath); static time_t GetLastWriteTime(const NzString& filePath); static NzHashDigest GetHash(const NzString& filePath, nzHash hash); static NzHashDigest GetHash(const NzString& filePath, NzHashImpl* hash); static nzUInt64 GetSize(const NzString& filePath); - static bool IsAbsolute(const NzString& path); + static bool IsAbsolute(const NzString& filePath); static NzString NormalizePath(const NzString& filePath); static NzString NormalizeSeparators(const NzString& filePath); static bool Rename(const NzString& sourcePath, const NzString& targetPath); diff --git a/include/Nazara/Core/InputStream.hpp b/include/Nazara/Core/InputStream.hpp index 4c99311ff..90b9a3187 100644 --- a/include/Nazara/Core/InputStream.hpp +++ b/include/Nazara/Core/InputStream.hpp @@ -10,8 +10,6 @@ #include #include -class NzString; - class NAZARA_API NzInputStream : public NzStream { public: @@ -19,10 +17,10 @@ class NAZARA_API NzInputStream : public NzStream virtual bool EndOfStream() const = 0; - virtual NzString GetLine(unsigned int lineSize = 0); virtual nzUInt64 GetSize() const = 0; virtual std::size_t Read(void* buffer, std::size_t size) = 0; + virtual NzString ReadLine(unsigned int lineSize = 0); }; #endif // NAZARA_INPUTSTREAM_HPP diff --git a/include/Nazara/Core/ResourceLoader.hpp b/include/Nazara/Core/ResourceLoader.hpp index 3d2d23117..eed9f0055 100644 --- a/include/Nazara/Core/ResourceLoader.hpp +++ b/include/Nazara/Core/ResourceLoader.hpp @@ -8,6 +8,7 @@ #define NAZARA_RESOURCELOADER_HPP #include +#include #include #include @@ -28,7 +29,7 @@ class NzResourceLoader static void UnregisterLoader(const NzString& fileExtensions, CheckFunction checkFunc, LoadFunction loadfunc); using Loader = std::tuple, CheckFunction, LoadFunction>; - using LoaderList = std::set; + using LoaderList = std::list; }; #include diff --git a/include/Nazara/Core/ResourceLoader.inl b/include/Nazara/Core/ResourceLoader.inl index 244a18a92..730ab1073 100644 --- a/include/Nazara/Core/ResourceLoader.inl +++ b/include/Nazara/Core/ResourceLoader.inl @@ -124,7 +124,7 @@ void NzResourceLoader::RegisterLoader(const NzString& fileExte std::set extensions; std::copy(exts.begin(), exts.end(), std::inserter(extensions, extensions.begin())); - Type::s_loaders.insert(std::make_tuple(std::move(extensions), checkFunc, loadFunc)); + Type::s_loaders.push_front(std::make_tuple(std::move(extensions), checkFunc, loadFunc)); } template @@ -136,7 +136,7 @@ void NzResourceLoader::UnregisterLoader(const NzString& fileEx std::set extensions; std::copy(exts.begin(), exts.end(), std::inserter(extensions, extensions.begin())); - Type::s_loaders.erase(std::make_tuple(std::move(extensions), checkFunc, loadFunc)); + Type::s_loaders.remove(std::make_tuple(std::move(extensions), checkFunc, loadFunc)); } #include diff --git a/include/Nazara/Core/Stream.hpp b/include/Nazara/Core/Stream.hpp index 79e9f88a7..7c7e63761 100644 --- a/include/Nazara/Core/Stream.hpp +++ b/include/Nazara/Core/Stream.hpp @@ -9,6 +9,7 @@ #include #include +#include class NAZARA_API NzStream { @@ -17,6 +18,8 @@ class NAZARA_API NzStream virtual ~NzStream(); virtual nzUInt64 GetCursorPos() const = 0; + virtual NzString GetDirectory() const; + virtual NzString GetPath() const; unsigned int GetStreamOptions() const; virtual bool SetCursorPos(nzUInt64 offset) = 0; diff --git a/include/Nazara/Math.hpp b/include/Nazara/Math.hpp index 33747808b..95867b279 100644 --- a/include/Nazara/Math.hpp +++ b/include/Nazara/Math.hpp @@ -27,6 +27,9 @@ #pragma once +#ifndef NAZARA_GLOBAL_MATH_HPP +#define NAZARA_GLOBAL_MATH_HPP + #include #include #include @@ -37,3 +40,5 @@ #include #include #include + +#endif // NAZARA_GLOBAL_MATH_HPP diff --git a/include/Nazara/Math/Basic.hpp b/include/Nazara/Math/Basic.hpp index 41f695235..a0db178a6 100644 --- a/include/Nazara/Math/Basic.hpp +++ b/include/Nazara/Math/Basic.hpp @@ -9,6 +9,7 @@ #include #include +#include #ifndef M_PI #define M_PI 3.141592653589793238462643 diff --git a/include/Nazara/Math/Basic.inl b/include/Nazara/Math/Basic.inl index fa5d8bb70..d7bf572cb 100644 --- a/include/Nazara/Math/Basic.inl +++ b/include/Nazara/Math/Basic.inl @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -73,7 +72,7 @@ unsigned int NzGetNumberLength(signed char number) unsigned int NzGetNumberLength(unsigned char number) { // Le standard définit le char comme étant codé sur un octet - static_assert(sizeof(number) == 1, "Signed char must be one byte-sized"); + static_assert(sizeof(number) == 1, "Unsigned char must be one byte-sized"); if (number >= 100) return 3; @@ -204,7 +203,7 @@ NzString NzNumberToString(long long number, nzUInt8 radix) negative = false; NzString str; - str.Reserve(NzGetNumberLength(number)); + str.Reserve(NzGetNumberLength(number)); // Prends en compte le signe négatif do { diff --git a/include/Nazara/Math/Config.hpp b/include/Nazara/Math/Config.hpp index 2683c0c9b..cc0422d8c 100644 --- a/include/Nazara/Math/Config.hpp +++ b/include/Nazara/Math/Config.hpp @@ -33,17 +33,10 @@ // Définit le radian comme l'unité utilisée pour les angles #define NAZARA_MATH_ANGLE_RADIAN 0 -// Optimise les opérations entre matrices affines (Demande plusieurs comparaisons pour déterminer si une matrice est affine) +// Optimise automatiquement les opérations entre matrices affines (Demande plusieurs comparaisons pour déterminer si une matrice est affine) #define NAZARA_MATH_MATRIX4_CHECK_AFFINE 0 // Active les tests de sécurité basés sur le code (Conseillé pour le développement) #define NAZARA_MATH_SAFE 1 -// Protège les classes des accès concurrentiels -#define NAZARA_MATH_THREADSAFE 1 - -// Les classes à protéger des accès concurrentiels -#define NAZARA_THREADSAFETY_MATRIX3 1 // NzMatrix3 (COW) -#define NAZARA_THREADSAFETY_MATRIX4 1 // NzMatrix4 (COW) - #endif // NAZARA_CONFIG_MATH_HPP diff --git a/include/Nazara/Math/Cube.hpp b/include/Nazara/Math/Cube.hpp index 0d3de354d..ed6988915 100644 --- a/include/Nazara/Math/Cube.hpp +++ b/include/Nazara/Math/Cube.hpp @@ -15,7 +15,7 @@ template class NzCube { public: - NzCube(); + NzCube() = default; NzCube(T X, T Y, T Z, T Width, T Height, T Depth); NzCube(const T cube[6]); NzCube(const NzRect& rect); @@ -28,22 +28,24 @@ class NzCube bool Contains(const NzVector3& point) const; bool Contains(const NzCube& cube) const; - void ExtendTo(const NzVector3& point); - void ExtendTo(const NzCube& cube); + NzCube& ExtendTo(const NzVector3& point); + NzCube& ExtendTo(const NzCube& cube); NzVector3 GetCenter() const; + NzVector3 GetPosition() const; + NzVector3 GetSize() const; bool Intersect(const NzCube& cube, NzCube* intersection = nullptr) const; bool IsValid() const; - void MakeZero(); + NzCube& MakeZero(); - void Set(T X, T Y, T Z, T Width, T Height, T Depth); - void Set(const T cube[6]); - void Set(const NzRect& rect); - void Set(const NzVector3& vec1, const NzVector3& vec2); - template void Set(const NzCube& cube); + NzCube& Set(T X, T Y, T Z, T Width, T Height, T Depth); + NzCube& Set(const T cube[6]); + NzCube& Set(const NzRect& rect); + NzCube& Set(const NzVector3& vec1, const NzVector3& vec2); + template NzCube& Set(const NzCube& cube); NzString ToString() const; diff --git a/include/Nazara/Math/Cube.inl b/include/Nazara/Math/Cube.inl index 3d02c2327..7be978993 100644 --- a/include/Nazara/Math/Cube.inl +++ b/include/Nazara/Math/Cube.inl @@ -8,23 +8,12 @@ #define F(a) static_cast(a) -template -NzCube::NzCube() -{ -} - template NzCube::NzCube(T X, T Y, T Z, T Width, T Height, T Depth) { Set(X, Y, Z, Width, Height, Depth); } -template -NzCube::NzCube(const T vec[6]) -{ - Set(vec); -} - template NzCube::NzCube(const NzRect& rect) { @@ -37,6 +26,12 @@ NzCube::NzCube(const NzVector3& vec1, const NzVector3& vec2) Set(vec1, vec2); } +template +NzCube::NzCube(const T vec[6]) +{ + Set(vec); +} + template template NzCube::NzCube(const NzCube& cube) @@ -66,42 +61,58 @@ bool NzCube::Contains(const NzCube& cube) const } template -void NzCube::ExtendTo(const NzVector3& point) +NzCube& NzCube::ExtendTo(const NzVector3& point) { x = std::min(x, point.x); y = std::min(y, point.y); z = std::min(z, point.z); - width = std::max(x+width, point.x)-x; - height = std::max(y+height, point.x)-y; - depth = std::max(z+depth, point.x)-z; + width = std::max(x + width, point.x) - x; + height = std::max(y + height, point.y) - y; + depth = std::max(z + depth, point.z) - z; + + return *this; } template -void NzCube::ExtendTo(const NzCube& cube) +NzCube& NzCube::ExtendTo(const NzCube& cube) { x = std::min(x, cube.x); y = std::min(y, cube.y); - z = std::min(y, cube.z); - width = std::max(x+width, cube.x+cube.width)-x; - height = std::max(x+height, cube.y+cube.height)-y; - depth = std::max(x+depth, cube.z+cube.depth)-z; + z = std::min(z, cube.z); + width = std::max(x + width, cube.x + cube.width) - x; + height = std::max(y + height, cube.y + cube.height) - y; + depth = std::max(z + depth, cube.z + cube.depth) - z; + + return *this; } template NzVector3 NzCube::GetCenter() const { - return NzVector3((x+width)/F(2.0), (y+height)/F(2.0), (z+depth)/F(2.0)); + return NzVector3(x + width/F(2.0), y + height/F(2.0), z + depth/F(2.0)); +} + +template +NzVector3 NzCube::GetPosition() const +{ + return NzVector3(x, y, z); +} + +template +NzVector3 NzCube::GetSize() const +{ + return NzVector3(width, height, depth); } template bool NzCube::Intersect(const NzCube& cube, NzCube* intersection) const { T left = std::max(x, cube.x); - T right = std::min(x+width, cube.x+cube.width); + T right = std::min(x + width, cube.x + cube.width); T top = std::max(y, cube.y); - T bottom = std::min(y+height, cube.y+cube.height); + T bottom = std::min(y + height, cube.y + cube.height); T up = std::max(z, cube.z); - T down = std::min(z+depth, cube.z+cube.depth); + T down = std::min(z + depth, cube.z + cube.depth); if (left < right && top < bottom && up < down) { @@ -110,9 +121,9 @@ bool NzCube::Intersect(const NzCube& cube, NzCube* intersection) const intersection->x = left; intersection->y = top; intersection->z = up; - intersection->width = right-left; - intersection->height = bottom-top; - intersection->depth = down-up; + intersection->width = right - left; + intersection->height = bottom - top; + intersection->depth = down - up; } return true; @@ -128,7 +139,7 @@ bool NzCube::IsValid() const } template -void NzCube::MakeZero() +NzCube& NzCube::MakeZero() { x = F(0.0); y = F(0.0); @@ -136,10 +147,12 @@ void NzCube::MakeZero() width = F(0.0); height = F(0.0); depth = F(0.0); + + return *this; } template -void NzCube::Set(T X, T Y, T Z, T Width, T Height, T Depth) +NzCube& NzCube::Set(T X, T Y, T Z, T Width, T Height, T Depth) { x = X; y = Y; @@ -147,10 +160,12 @@ void NzCube::Set(T X, T Y, T Z, T Width, T Height, T Depth) width = Width; height = Height; depth = Depth; + + return *this; } template -void NzCube::Set(const T cube[6]) +NzCube& NzCube::Set(const T cube[6]) { x = cube[0]; y = cube[1]; @@ -158,21 +173,25 @@ void NzCube::Set(const T cube[6]) width = cube[3]; height = cube[4]; depth = cube[5]; + + return *this; } template -void NzCube::Set(const NzRect& rect) +NzCube& NzCube::Set(const NzRect& rect) { x = rect.x; y = rect.y; - z = 0; + z = F(0.0); width = rect.width; height = rect.height; - depth = 1; + depth = F(1.0); + + return *this; } template -void NzCube::Set(const NzVector3& vec1, const NzVector3& vec2) +NzCube& NzCube::Set(const NzVector3& vec1, const NzVector3& vec2) { x = std::min(vec1.x, vec2.x); y = std::min(vec1.y, vec2.y); @@ -180,11 +199,13 @@ void NzCube::Set(const NzVector3& vec1, const NzVector3& vec2) width = (vec2.x > vec1.x) ? vec2.x-vec1.x : vec1.x-vec2.x; height = (vec2.y > vec1.y) ? vec2.y-vec1.y : vec1.y-vec2.y; depth = (vec2.z > vec1.z) ? vec2.z-vec1.z : vec1.z-vec2.z; + + return *this; } template template -void NzCube::Set(const NzCube& cube) +NzCube& NzCube::Set(const NzCube& cube) { x = F(cube.x); y = F(cube.y); @@ -192,6 +213,8 @@ void NzCube::Set(const NzCube& cube) width = F(cube.width); height = F(cube.height); depth = F(cube.depth); + + return *this; } template @@ -215,8 +238,9 @@ T& NzCube::operator[](unsigned int i) if (i >= 6) { NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Index out of range (" << i << " >= 6)"; + ss << "Index out of range: (" << i << " >= 6)"; + NazaraError(ss); throw std::domain_error(ss.ToString()); } #endif @@ -231,8 +255,9 @@ T NzCube::operator[](unsigned int i) const if (i >= 6) { NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Index out of range (" << i << " >= 6)"; + ss << "Index out of range: (" << i << " >= 6)"; + NazaraError(ss); throw std::domain_error(ss.ToString()); } #endif diff --git a/include/Nazara/Math/EulerAngles.hpp b/include/Nazara/Math/EulerAngles.hpp index 1fb14aa52..a36fba40d 100644 --- a/include/Nazara/Math/EulerAngles.hpp +++ b/include/Nazara/Math/EulerAngles.hpp @@ -14,9 +14,9 @@ template class NzEulerAngles { public: - NzEulerAngles(); + NzEulerAngles() = default; NzEulerAngles(T P, T Y, T R); - NzEulerAngles(T angles[3]); + NzEulerAngles(const T angles[3]); //NzEulerAngles(const NzMatrix3& mat); NzEulerAngles(const NzQuaternion& quat); template explicit NzEulerAngles(const NzEulerAngles& angles); @@ -28,7 +28,7 @@ template class NzEulerAngles void Normalize(); void Set(T P, T Y, T R); - void Set(T angles[3]); + void Set(const T angles[3]); void Set(const NzEulerAngles& angles); //void Set(const NzMatrix3& mat); void Set(const NzQuaternion& quat); diff --git a/include/Nazara/Math/EulerAngles.inl b/include/Nazara/Math/EulerAngles.inl index 8797d3310..5d7c327d0 100644 --- a/include/Nazara/Math/EulerAngles.inl +++ b/include/Nazara/Math/EulerAngles.inl @@ -11,11 +11,6 @@ #define F(a) static_cast(a) -template -NzEulerAngles::NzEulerAngles() -{ -} - template NzEulerAngles::NzEulerAngles(T P, T Y, T R) { @@ -23,7 +18,7 @@ NzEulerAngles::NzEulerAngles(T P, T Y, T R) } template -NzEulerAngles::NzEulerAngles(T angles[3]) +NzEulerAngles::NzEulerAngles(const T angles[3]) { Set(angles); } @@ -64,7 +59,7 @@ void NzEulerAngles::Set(T P, T Y, T R) } template -void NzEulerAngles::Set(T angles[3]) +void NzEulerAngles::Set(const T angles[3]) { pitch = angles[0]; yaw = angles[1]; @@ -97,9 +92,9 @@ void NzEulerAngles::Set(const NzEulerAngles& angles) template NzQuaternion NzEulerAngles::ToQuaternion() const { - NzQuaternion rotX(pitch, NzVector3(F(1.0), F(0.0), F(0.0))); - NzQuaternion rotY(yaw, NzVector3(F(0.0), F(1.0), F(0.0))); - NzQuaternion rotZ(roll, NzVector3(F(0.0), F(0.0), F(1.0))); + NzQuaternion rotX(pitch, NzVector3::UnitX()); + NzQuaternion rotY(yaw, NzVector3::UnitY()); + NzQuaternion rotZ(roll, NzVector3::UnitZ()); return rotY * rotX * rotZ; } diff --git a/include/Nazara/Math/Matrix4.hpp b/include/Nazara/Math/Matrix4.hpp index b9163d396..ff57e293e 100644 --- a/include/Nazara/Math/Matrix4.hpp +++ b/include/Nazara/Math/Matrix4.hpp @@ -10,12 +10,6 @@ #include #include -#if NAZARA_MATH_THREADSAFE && NAZARA_THREADSAFETY_MATRIX4 -#include -#else -#include -#endif - template class NzEulerAngles; template class NzQuaternion; template class NzVector2; @@ -26,31 +20,30 @@ template class NzMatrix4 { public: - NzMatrix4(); + NzMatrix4() = default; NzMatrix4(T r11, T r12, T r13, T r14, T r21, T r22, T r23, T r24, T r31, T r32, T r33, T r34, T r41, T r42, T r43, T r44); - NzMatrix4(const T matrix[16]); //NzMatrix4(const NzMatrix3& matrix); + NzMatrix4(const T matrix[16]); template explicit NzMatrix4(const NzMatrix4& matrix); - NzMatrix4(const NzMatrix4& matrix); - NzMatrix4(NzMatrix4&& matrix) noexcept; - ~NzMatrix4(); + NzMatrix4(const NzMatrix4& matrix) = default; + ~NzMatrix4() = default; NzMatrix4& ApplyScale(const NzVector3& scale); - NzMatrix4 Concatenate(const NzMatrix4& matrix) const; - NzMatrix4 ConcatenateAffine(const NzMatrix4& matrix) const; + NzMatrix4& Concatenate(const NzMatrix4& matrix); + NzMatrix4& ConcatenateAffine(const NzMatrix4& matrix); T GetDeterminant() const; - NzMatrix4 GetInverse(bool* succeeded = nullptr) const; - NzMatrix4 GetInverseAffine(bool* succeeded = nullptr) const; + bool GetInverse(NzMatrix4* dest) const; + bool GetInverseAffine(NzMatrix4* dest) const; NzQuaternion GetRotation() const; //NzMatrix3 GetRotationMatrix() const; NzVector3 GetScale() const; NzVector3 GetTranslation() const; - NzMatrix4 GetTransposed() const; + void GetTransposed(NzMatrix4* dest) const; bool HasNegativeScale() const; bool HasScale() const; @@ -59,7 +52,6 @@ class NzMatrix4 NzMatrix4& InverseAffine(bool* succeeded = nullptr); bool IsAffine() const; - bool IsDefined() const; NzMatrix4& MakeIdentity(); NzMatrix4& MakeLookAt(const NzVector3& eye, const NzVector3& target, const NzVector3& up = NzVector3::Up()); @@ -72,9 +64,9 @@ class NzMatrix4 NzMatrix4& MakeZero(); NzMatrix4& Set(T r11, T r12, T r13, T r14, - T r21, T r22, T r23, T r24, - T r31, T r32, T r33, T r34, - T r41, T r42, T r43, T r44); + T r21, T r22, T r23, T r24, + T r31, T r32, T r33, T r34, + T r41, T r42, T r43, T r44); NzMatrix4& Set(const T matrix[16]); //NzMatrix4(const NzMatrix3& matrix); NzMatrix4& Set(const NzMatrix4& matrix); @@ -92,8 +84,6 @@ class NzMatrix4 NzMatrix4& Transpose(); - NzMatrix4& Undefine(); - operator NzString() const; operator T*(); @@ -102,8 +92,7 @@ class NzMatrix4 T& operator()(unsigned int x, unsigned int y); const T& operator()(unsigned int x, unsigned int y) const; - NzMatrix4& operator=(const NzMatrix4& matrix); - NzMatrix4& operator=(NzMatrix4&& matrix) noexcept; + NzMatrix4& operator=(const NzMatrix4& matrix) = default; NzMatrix4 operator*(const NzMatrix4& matrix) const; NzVector2 operator*(const NzVector2& vector) const; @@ -117,8 +106,6 @@ class NzMatrix4 bool operator==(const NzMatrix4& mat) const; bool operator!=(const NzMatrix4& mat) const; - static NzMatrix4 Concatenate(const NzMatrix4& m1, const NzMatrix4& m2); - static NzMatrix4 ConcatenateAffine(const NzMatrix4& m1, const NzMatrix4& m2); static NzMatrix4 Identity(); static NzMatrix4 LookAt(const NzVector3& eye, const NzVector3& target, const NzVector3& up = NzVector3::Up()); static NzMatrix4 Ortho(T left, T top, T width, T height, T zNear = -1.0, T zFar = 1.0); @@ -129,22 +116,10 @@ class NzMatrix4 static NzMatrix4 Transform(const NzVector3& translation, const NzVector3& scale, const NzQuaternion& rotation); static NzMatrix4 Zero(); - struct SharedMatrix - { - T m11, m12, m13, m14, - m21, m22, m23, m24, - m31, m32, m33, m34, - m41, m42, m43, m44; - - unsigned short refCount = 1; - NazaraMutex(mutex) - }; - - private: - void EnsureOwnership(); - void ReleaseMatrix(); - - SharedMatrix* m_sharedMatrix = nullptr; + T m11, m12, m13, m14, + m21, m22, m23, m24, + m31, m32, m33, m34, + m41, m42, m43, m44; }; template std::ostream& operator<<(std::ostream& out, const NzMatrix4& matrix); diff --git a/include/Nazara/Math/Matrix4.inl b/include/Nazara/Math/Matrix4.inl index ae8c0c0af..135d7584c 100644 --- a/include/Nazara/Math/Matrix4.inl +++ b/include/Nazara/Math/Matrix4.inl @@ -15,16 +15,10 @@ #include #include #include -//#include -///FIXME: Le MLT détecte des leaks ici, mais dont la véracité n'a pu être prouvée (Problème lié aux classes inlines ?) +#include #define F(a) static_cast(a) -template -NzMatrix4::NzMatrix4() -{ -} - template NzMatrix4::NzMatrix4(T r11, T r12, T r13, T r14, T r21, T r22, T r23, T r24, @@ -50,132 +44,356 @@ NzMatrix4::NzMatrix4(const NzMatrix4& matrix) Set(matrix); } -template -NzMatrix4::NzMatrix4(const NzMatrix4& matrix) -{ - Set(matrix); -} - -template -NzMatrix4::NzMatrix4(NzMatrix4&& matrix) noexcept -{ - Set(matrix); -} - -template -NzMatrix4::~NzMatrix4() -{ - ReleaseMatrix(); -} - template NzMatrix4& NzMatrix4::ApplyScale(const NzVector3& scale) { - m_sharedMatrix->m11 *= scale.x; - m_sharedMatrix->m12 *= scale.x; - m_sharedMatrix->m13 *= scale.x; + m11 *= scale.x; + m12 *= scale.x; + m13 *= scale.x; - m_sharedMatrix->m21 *= scale.y; - m_sharedMatrix->m22 *= scale.y; - m_sharedMatrix->m23 *= scale.y; + m21 *= scale.y; + m22 *= scale.y; + m23 *= scale.y; - m_sharedMatrix->m31 *= scale.z; - m_sharedMatrix->m32 *= scale.z; - m_sharedMatrix->m33 *= scale.z; + m31 *= scale.z; + m32 *= scale.z; + m33 *= scale.z; return *this; } template -NzMatrix4 NzMatrix4::Concatenate(const NzMatrix4& matrix) const +NzMatrix4& NzMatrix4::Concatenate(const NzMatrix4& matrix) { - return Concatenate(*this, matrix); + #if NAZARA_MATH_MATRIX4_CHECK_AFFINE + if (IsAffine() && matrix.IsAffine()) + return ConcatenateAffine(matrix); + #endif + + return Set(m11*matrix.m11 + m12*matrix.m21 + m13*matrix.m31 + m14*matrix.m41, + m11*matrix.m12 + m12*matrix.m22 + m13*matrix.m32 + m14*matrix.m42, + m11*matrix.m13 + m12*matrix.m23 + m13*matrix.m33 + m14*matrix.m43, + m11*matrix.m14 + m12*matrix.m24 + m13*matrix.m34 + m14*matrix.m44, + + m21*matrix.m11 + m22*matrix.m21 + m23*matrix.m31 + m24*matrix.m41, + m21*matrix.m12 + m22*matrix.m22 + m23*matrix.m32 + m24*matrix.m42, + m21*matrix.m13 + m22*matrix.m23 + m23*matrix.m33 + m24*matrix.m43, + m21*matrix.m14 + m22*matrix.m24 + m23*matrix.m34 + m24*matrix.m44, + + m31*matrix.m11 + m32*matrix.m21 + m33*matrix.m31 + m34*matrix.m41, + m31*matrix.m12 + m32*matrix.m22 + m33*matrix.m32 + m34*matrix.m42, + m31*matrix.m13 + m32*matrix.m23 + m33*matrix.m33 + m34*matrix.m43, + m31*matrix.m14 + m32*matrix.m24 + m33*matrix.m34 + m34*matrix.m44, + + m41*matrix.m11 + m42*matrix.m21 + m43*matrix.m31 + m44*matrix.m41, + m41*matrix.m12 + m42*matrix.m22 + m43*matrix.m32 + m44*matrix.m42, + m41*matrix.m13 + m42*matrix.m23 + m43*matrix.m33 + m44*matrix.m43, + m41*matrix.m14 + m42*matrix.m24 + m43*matrix.m34 + m44*matrix.m44); } template -NzMatrix4 NzMatrix4::ConcatenateAffine(const NzMatrix4& matrix) const +NzMatrix4& NzMatrix4::ConcatenateAffine(const NzMatrix4& matrix) { - return ConcatenateAffine(*this, matrix); + #ifdef NAZARA_DEBUG + if (!IsAffine()) + { + NazaraError("First matrix not affine"); + return *this; + } + + if (!matrix.IsAffine()) + { + NazaraError("Second matrix not affine"); + return *this; + } + #endif + + return Set(m11*matrix.m11 + m12*matrix.m21 + m13*matrix.m31, + m11*matrix.m12 + m12*matrix.m22 + m13*matrix.m32, + m11*matrix.m13 + m12*matrix.m23 + m13*matrix.m33, + F(0.0), + + m21*matrix.m11 + m22*matrix.m21 + m23*matrix.m31, + m21*matrix.m12 + m22*matrix.m22 + m23*matrix.m32, + m21*matrix.m13 + m22*matrix.m23 + m23*matrix.m33, + F(0.0), + + m31*matrix.m11 + m32*matrix.m21 + m33*matrix.m31, + m31*matrix.m12 + m32*matrix.m22 + m33*matrix.m32, + m31*matrix.m13 + m32*matrix.m23 + m33*matrix.m33, + F(0.0), + + m41*matrix.m11 + m42*matrix.m21 + m43*matrix.m31 + matrix.m41, + m41*matrix.m12 + m42*matrix.m22 + m43*matrix.m32 + matrix.m42, + m41*matrix.m13 + m42*matrix.m23 + m43*matrix.m33 + matrix.m43, + F(1.0)); } template T NzMatrix4::GetDeterminant() const { - #if NAZARA_MATH_SAFE - if (!IsDefined()) + T A = m22*(m33*m44 - m43*m34) - m32*(m23*m44 - m43*m24) + m42*(m23*m34 - m33*m24); + T B = m12*(m33*m44 - m43*m34) - m32*(m13*m44 - m43*m14) + m42*(m13*m34 - m33*m14); + T C = m12*(m23*m44 - m43*m24) - m22*(m13*m44 - m43*m14) + m42*(m13*m24 - m23*m14); + T D = m12*(m23*m34 - m33*m24) - m22*(m13*m34 - m33*m14) + m32*(m13*m24 - m23*m14); + + return m11*A - m21*B + m31*C - m41*D; +} + +template +bool NzMatrix4::GetInverse(NzMatrix4* dest) const +{ + ///DOC: Il est possible d'appeler cette méthode avec la même matrice en argument qu'en appelant + #ifdef NAZARA_DEBUG + if (!dest) { - NazaraError("Matrix not defined"); - return F(0.0); + NazaraError("Destination matrix must be valid"); + return false; } #endif - T A = m_sharedMatrix->m22*(m_sharedMatrix->m33*m_sharedMatrix->m44 - m_sharedMatrix->m43*m_sharedMatrix->m34) - m_sharedMatrix->m32*(m_sharedMatrix->m23*m_sharedMatrix->m44 - m_sharedMatrix->m43*m_sharedMatrix->m24) + m_sharedMatrix->m42*(m_sharedMatrix->m23*m_sharedMatrix->m34 - m_sharedMatrix->m33*m_sharedMatrix->m24); - T B = m_sharedMatrix->m12*(m_sharedMatrix->m33*m_sharedMatrix->m44 - m_sharedMatrix->m43*m_sharedMatrix->m34) - m_sharedMatrix->m32*(m_sharedMatrix->m13*m_sharedMatrix->m44 - m_sharedMatrix->m43*m_sharedMatrix->m14) + m_sharedMatrix->m42*(m_sharedMatrix->m13*m_sharedMatrix->m34 - m_sharedMatrix->m33*m_sharedMatrix->m14); - T C = m_sharedMatrix->m12*(m_sharedMatrix->m23*m_sharedMatrix->m44 - m_sharedMatrix->m43*m_sharedMatrix->m24) - m_sharedMatrix->m22*(m_sharedMatrix->m13*m_sharedMatrix->m44 - m_sharedMatrix->m43*m_sharedMatrix->m14) + m_sharedMatrix->m42*(m_sharedMatrix->m13*m_sharedMatrix->m24 - m_sharedMatrix->m23*m_sharedMatrix->m14); - T D = m_sharedMatrix->m12*(m_sharedMatrix->m23*m_sharedMatrix->m34 - m_sharedMatrix->m33*m_sharedMatrix->m24) - m_sharedMatrix->m22*(m_sharedMatrix->m13*m_sharedMatrix->m34 - m_sharedMatrix->m33*m_sharedMatrix->m14) + m_sharedMatrix->m32*(m_sharedMatrix->m13*m_sharedMatrix->m24 - m_sharedMatrix->m23*m_sharedMatrix->m14); + T det = GetDeterminant(); + if (!NzNumberEquals(det, F(0.0))) + { + // http://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix + T inv[16]; + inv[0] = m22 * m33 * m44 - + m22 * m34 * m43 - + m32 * m23 * m44 + + m32 * m24 * m43 + + m42 * m23 * m34 - + m42 * m24 * m33; - return m_sharedMatrix->m11*A - m_sharedMatrix->m21*B + m_sharedMatrix->m31*C - m_sharedMatrix->m41*D; + inv[1] = -m12 * m33 * m44 + + m12 * m34 * m43 + + m32 * m13 * m44 - + m32 * m14 * m43 - + m42 * m13 * m34 + + m42 * m14 * m33; + + inv[2] = m12 * m23 * m44 - + m12 * m24 * m43 - + m22 * m13 * m44 + + m22 * m14 * m43 + + m42 * m13 * m24 - + m42 * m14 * m23; + + inv[3] = -m12 * m23 * m34 + + m12 * m24 * m33 + + m22 * m13 * m34 - + m22 * m14 * m33 - + m32 * m13 * m24 + + m32 * m14 * m23; + + inv[4] = -m21 * m33 * m44 + + m21 * m34 * m43 + + m31 * m23 * m44 - + m31 * m24 * m43 - + m41 * m23 * m34 + + m41 * m24 * m33; + + inv[5] = m11 * m33 * m44 - + m11 * m34 * m43 - + m31 * m13 * m44 + + m31 * m14 * m43 + + m41 * m13 * m34 - + m41 * m14 * m33; + + inv[6] = -m11 * m23 * m44 + + m11 * m24 * m43 + + m21 * m13 * m44 - + m21 * m14 * m43 - + m41 * m13 * m24 + + m41 * m14 * m23; + + inv[7] = m11 * m23 * m34 - + m11 * m24 * m33 - + m21 * m13 * m34 + + m21 * m14 * m33 + + m31 * m13 * m24 - + m31 * m14 * m23; + + inv[8] = m21 * m32 * m44 - + m21 * m34 * m42 - + m31 * m22 * m44 + + m31 * m24 * m42 + + m41 * m22 * m34 - + m41 * m24 * m32; + + inv[9] = -m11 * m32 * m44 + + m11 * m34 * m42 + + m31 * m12 * m44 - + m31 * m14 * m42 - + m41 * m12 * m34 + + m41 * m14 * m32; + + inv[10] = m11 * m22 * m44 - + m11 * m24 * m42 - + m21 * m12 * m44 + + m21 * m14 * m42 + + m41 * m12 * m24 - + m41 * m14 * m22; + + inv[11] = -m11 * m22 * m34 + + m11 * m24 * m32 + + m21 * m12 * m34 - + m21 * m14 * m32 - + m31 * m12 * m24 + + m31 * m14 * m22; + + inv[12] = -m21 * m32 * m43 + + m21 * m33 * m42 + + m31 * m22 * m43 - + m31 * m23 * m42 - + m41 * m22 * m33 + + m41 * m23 * m32; + + inv[13] = m11 * m32 * m43 - + m11 * m33 * m42 - + m31 * m12 * m43 + + m31 * m13 * m42 + + m41 * m12 * m33 - + m41 * m13 * m32; + + inv[14] = -m11 * m22 * m43 + + m11 * m23 * m42 + + m21 * m12 * m43 - + m21 * m13 * m42 - + m41 * m12 * m23 + + m41 * m13 * m22; + + inv[15] = m11 * m22 * m33 - + m11 * m23 * m32 - + m21 * m12 * m33 + + m21 * m13 * m32 + + m31 * m12 * m23 - + m31 * m13 * m22; + + T invDet = F(1.0) / det; + for (unsigned int i = 0; i < 16; ++i) + inv[i] *= invDet; + + dest->Set(inv); + return true; + } + else + { + NazaraError("Matrix has no inverse"); + return false; + } } template -NzMatrix4 NzMatrix4::GetInverse(bool* succeeded) const +bool NzMatrix4::GetInverseAffine(NzMatrix4* dest) const { - NzMatrix4f matInv(*this); - return matInv.Inverse(succeeded); + ///DOC: Il est possible d'appeler cette méthode avec la même matrice en argument qu'en appelant + #ifdef NAZARA_DEBUG + if (!dest) + { + NazaraError("Destination matrix must be valid"); + return false; + } + #endif + + T det = GetDeterminant(); + if (!NzNumberEquals(det, F(0.0))) + { + // http://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix + T inv[16]; + inv[0] = m22 * m33 - + m32 * m23; + + inv[1] = -m12 * m33 + + m32 * m13; + + inv[2] = m12 * m23 - + m22 * m13; + + inv[3] = F(0.0); + + inv[4] = -m21 * m33 + + m31 * m23; + + inv[5] = m11 * m33 - + m31 * m13; + + inv[6] = -m11 * m23 + + m21 * m13; + + inv[7] = F(0.0); + + inv[8] = m21 * m32 - + m31 * m22; + + inv[9] = -m11 * m32 + + m31 * m12; + + inv[10] = m11 * m22 - + m21 * m12; + + inv[11] = F(0.0); + + inv[12] = -m21 * m32 * m43 + + m21 * m33 * m42 + + m31 * m22 * m43 - + m31 * m23 * m42 - + m41 * m22 * m33 + + m41 * m23 * m32; + + inv[13] = m11 * m32 * m43 - + m11 * m33 * m42 - + m31 * m12 * m43 + + m31 * m13 * m42 + + m41 * m12 * m33 - + m41 * m13 * m32; + + inv[14] = -m11 * m22 * m43 + + m11 * m23 * m42 + + m21 * m12 * m43 - + m21 * m13 * m42 - + m41 * m12 * m23 + + m41 * m13 * m22; + + inv[15] = F(0.0); + + T invDet = F(1.0) / det; + for (unsigned int i = 0; i < 16; ++i) + inv[i] *= invDet; + + inv[15] = F(1.0); + + dest->Set(inv); + return true; + } + else + { + NazaraError("Matrix has no inverse"); + return false; + } } -template -NzMatrix4 NzMatrix4::GetInverseAffine(bool* succeeded) const -{ - NzMatrix4f matInv(*this); - return matInv.InverseAffine(succeeded); -} template NzVector3 NzMatrix4::GetScale() const { - #if NAZARA_MATH_SAFE - if (!IsDefined()) - { - NazaraError("Matrix not defined"); - return NzVector3(); - } - #endif - - return NzVector3(std::sqrt(m_sharedMatrix->m11*m_sharedMatrix->m11 + m_sharedMatrix->m21*m_sharedMatrix->m21 + m_sharedMatrix->m31*m_sharedMatrix->m31), - std::sqrt(m_sharedMatrix->m12*m_sharedMatrix->m12 + m_sharedMatrix->m22*m_sharedMatrix->m22 + m_sharedMatrix->m32*m_sharedMatrix->m32), - std::sqrt(m_sharedMatrix->m13*m_sharedMatrix->m13 + m_sharedMatrix->m23*m_sharedMatrix->m23 + m_sharedMatrix->m33*m_sharedMatrix->m33)); + return NzVector3(std::sqrt(m11*m11 + m21*m21 + m31*m31), + std::sqrt(m12*m12 + m22*m22 + m32*m32), + std::sqrt(m13*m13 + m23*m23 + m33*m33)); } template NzVector3 NzMatrix4::GetTranslation() const { - #if NAZARA_MATH_SAFE - if (!IsDefined()) - { - NazaraError("Matrix not defined"); - return NzVector3(); - } - #endif - - return NzVector3(m_sharedMatrix->m41, m_sharedMatrix->m42, m_sharedMatrix->m43); + return NzVector3(m41, m42, m43); } template -NzMatrix4 NzMatrix4::GetTransposed() const +void NzMatrix4::GetTransposed(NzMatrix4* dest) const { - #if NAZARA_MATH_SAFE - if (!IsDefined()) - { - NazaraError("Matrix not defined"); - return NzMatrix4(); - } - #endif - - return NzMatrix4(m_sharedMatrix->m11, m_sharedMatrix->m21, m_sharedMatrix->m31, m_sharedMatrix->m41, - m_sharedMatrix->m12, m_sharedMatrix->m22, m_sharedMatrix->m32, m_sharedMatrix->m42, - m_sharedMatrix->m13, m_sharedMatrix->m23, m_sharedMatrix->m33, m_sharedMatrix->m43, - m_sharedMatrix->m14, m_sharedMatrix->m24, m_sharedMatrix->m34, m_sharedMatrix->m44); + dest->Set(m11, m21, m31, m41, + m12, m22, m32, m42, + m13, m23, m33, m43, + m14, m24, m34, m44); } template @@ -187,23 +405,15 @@ bool NzMatrix4::HasNegativeScale() const template bool NzMatrix4::HasScale() const { - #if NAZARA_MATH_SAFE - if (!IsDefined()) - { - NazaraError("Matrix not defined"); - return false; - } - #endif - - T t = m_sharedMatrix->m11*m_sharedMatrix->m11 + m_sharedMatrix->m21*m_sharedMatrix->m21 + m_sharedMatrix->m31*m_sharedMatrix->m31; + T t = m11*m11 + m21*m21 + m31*m31; if (!NzNumberEquals(t, F(1.0))) return true; - t = m_sharedMatrix->m12*m_sharedMatrix->m12 + m_sharedMatrix->m22*m_sharedMatrix->m22 + m_sharedMatrix->m32*m_sharedMatrix->m32; + t = m12*m12 + m22*m22 + m32*m32; if (!NzNumberEquals(t, F(1.0))) return true; - t = m_sharedMatrix->m13*m_sharedMatrix->m13 + m_sharedMatrix->m23*m_sharedMatrix->m23 + m_sharedMatrix->m33*m_sharedMatrix->m33; + t = m13*m13 + m23*m23 + m33*m33; if (!NzNumberEquals(t, F(1.0))) return true; @@ -213,148 +423,9 @@ bool NzMatrix4::HasScale() const template NzMatrix4& NzMatrix4::Inverse(bool* succeeded) { - #if NAZARA_MATH_SAFE - if (!IsDefined()) - { - NazaraError("Matrix not defined"); - if (succeeded) - *succeeded = false; - - return *this; - } - #endif - - T det = GetDeterminant(); - if (!NzNumberEquals(det, F(0.0))) - { - // http://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix - T inv[16]; - inv[0] = m_sharedMatrix->m22 * m_sharedMatrix->m33 * m_sharedMatrix->m44 - - m_sharedMatrix->m22 * m_sharedMatrix->m34 * m_sharedMatrix->m43 - - m_sharedMatrix->m32 * m_sharedMatrix->m23 * m_sharedMatrix->m44 + - m_sharedMatrix->m32 * m_sharedMatrix->m24 * m_sharedMatrix->m43 + - m_sharedMatrix->m42 * m_sharedMatrix->m23 * m_sharedMatrix->m34 - - m_sharedMatrix->m42 * m_sharedMatrix->m24 * m_sharedMatrix->m33; - - inv[1] = -m_sharedMatrix->m12 * m_sharedMatrix->m33 * m_sharedMatrix->m44 + - m_sharedMatrix->m12 * m_sharedMatrix->m34 * m_sharedMatrix->m43 + - m_sharedMatrix->m32 * m_sharedMatrix->m13 * m_sharedMatrix->m44 - - m_sharedMatrix->m32 * m_sharedMatrix->m14 * m_sharedMatrix->m43 - - m_sharedMatrix->m42 * m_sharedMatrix->m13 * m_sharedMatrix->m34 + - m_sharedMatrix->m42 * m_sharedMatrix->m14 * m_sharedMatrix->m33; - - inv[2] = m_sharedMatrix->m12 * m_sharedMatrix->m23 * m_sharedMatrix->m44 - - m_sharedMatrix->m12 * m_sharedMatrix->m24 * m_sharedMatrix->m43 - - m_sharedMatrix->m22 * m_sharedMatrix->m13 * m_sharedMatrix->m44 + - m_sharedMatrix->m22 * m_sharedMatrix->m14 * m_sharedMatrix->m43 + - m_sharedMatrix->m42 * m_sharedMatrix->m13 * m_sharedMatrix->m24 - - m_sharedMatrix->m42 * m_sharedMatrix->m14 * m_sharedMatrix->m23; - - inv[3] = -m_sharedMatrix->m12 * m_sharedMatrix->m23 * m_sharedMatrix->m34 + - m_sharedMatrix->m12 * m_sharedMatrix->m24 * m_sharedMatrix->m33 + - m_sharedMatrix->m22 * m_sharedMatrix->m13 * m_sharedMatrix->m34 - - m_sharedMatrix->m22 * m_sharedMatrix->m14 * m_sharedMatrix->m33 - - m_sharedMatrix->m32 * m_sharedMatrix->m13 * m_sharedMatrix->m24 + - m_sharedMatrix->m32 * m_sharedMatrix->m14 * m_sharedMatrix->m23; - - inv[4] = -m_sharedMatrix->m21 * m_sharedMatrix->m33 * m_sharedMatrix->m44 + - m_sharedMatrix->m21 * m_sharedMatrix->m34 * m_sharedMatrix->m43 + - m_sharedMatrix->m31 * m_sharedMatrix->m23 * m_sharedMatrix->m44 - - m_sharedMatrix->m31 * m_sharedMatrix->m24 * m_sharedMatrix->m43 - - m_sharedMatrix->m41 * m_sharedMatrix->m23 * m_sharedMatrix->m34 + - m_sharedMatrix->m41 * m_sharedMatrix->m24 * m_sharedMatrix->m33; - - inv[5] = m_sharedMatrix->m11 * m_sharedMatrix->m33 * m_sharedMatrix->m44 - - m_sharedMatrix->m11 * m_sharedMatrix->m34 * m_sharedMatrix->m43 - - m_sharedMatrix->m31 * m_sharedMatrix->m13 * m_sharedMatrix->m44 + - m_sharedMatrix->m31 * m_sharedMatrix->m14 * m_sharedMatrix->m43 + - m_sharedMatrix->m41 * m_sharedMatrix->m13 * m_sharedMatrix->m34 - - m_sharedMatrix->m41 * m_sharedMatrix->m14 * m_sharedMatrix->m33; - - inv[6] = -m_sharedMatrix->m11 * m_sharedMatrix->m23 * m_sharedMatrix->m44 + - m_sharedMatrix->m11 * m_sharedMatrix->m24 * m_sharedMatrix->m43 + - m_sharedMatrix->m21 * m_sharedMatrix->m13 * m_sharedMatrix->m44 - - m_sharedMatrix->m21 * m_sharedMatrix->m14 * m_sharedMatrix->m43 - - m_sharedMatrix->m41 * m_sharedMatrix->m13 * m_sharedMatrix->m24 + - m_sharedMatrix->m41 * m_sharedMatrix->m14 * m_sharedMatrix->m23; - - inv[7] = m_sharedMatrix->m11 * m_sharedMatrix->m23 * m_sharedMatrix->m34 - - m_sharedMatrix->m11 * m_sharedMatrix->m24 * m_sharedMatrix->m33 - - m_sharedMatrix->m21 * m_sharedMatrix->m13 * m_sharedMatrix->m34 + - m_sharedMatrix->m21 * m_sharedMatrix->m14 * m_sharedMatrix->m33 + - m_sharedMatrix->m31 * m_sharedMatrix->m13 * m_sharedMatrix->m24 - - m_sharedMatrix->m31 * m_sharedMatrix->m14 * m_sharedMatrix->m23; - - inv[8] = m_sharedMatrix->m21 * m_sharedMatrix->m32 * m_sharedMatrix->m44 - - m_sharedMatrix->m21 * m_sharedMatrix->m34 * m_sharedMatrix->m42 - - m_sharedMatrix->m31 * m_sharedMatrix->m22 * m_sharedMatrix->m44 + - m_sharedMatrix->m31 * m_sharedMatrix->m24 * m_sharedMatrix->m42 + - m_sharedMatrix->m41 * m_sharedMatrix->m22 * m_sharedMatrix->m34 - - m_sharedMatrix->m41 * m_sharedMatrix->m24 * m_sharedMatrix->m32; - - inv[9] = -m_sharedMatrix->m11 * m_sharedMatrix->m32 * m_sharedMatrix->m44 + - m_sharedMatrix->m11 * m_sharedMatrix->m34 * m_sharedMatrix->m42 + - m_sharedMatrix->m31 * m_sharedMatrix->m12 * m_sharedMatrix->m44 - - m_sharedMatrix->m31 * m_sharedMatrix->m14 * m_sharedMatrix->m42 - - m_sharedMatrix->m41 * m_sharedMatrix->m12 * m_sharedMatrix->m34 + - m_sharedMatrix->m41 * m_sharedMatrix->m14 * m_sharedMatrix->m32; - - inv[10] = m_sharedMatrix->m11 * m_sharedMatrix->m22 * m_sharedMatrix->m44 - - m_sharedMatrix->m11 * m_sharedMatrix->m24 * m_sharedMatrix->m42 - - m_sharedMatrix->m21 * m_sharedMatrix->m12 * m_sharedMatrix->m44 + - m_sharedMatrix->m21 * m_sharedMatrix->m14 * m_sharedMatrix->m42 + - m_sharedMatrix->m41 * m_sharedMatrix->m12 * m_sharedMatrix->m24 - - m_sharedMatrix->m41 * m_sharedMatrix->m14 * m_sharedMatrix->m22; - - inv[11] = -m_sharedMatrix->m11 * m_sharedMatrix->m22 * m_sharedMatrix->m34 + - m_sharedMatrix->m11 * m_sharedMatrix->m24 * m_sharedMatrix->m32 + - m_sharedMatrix->m21 * m_sharedMatrix->m12 * m_sharedMatrix->m34 - - m_sharedMatrix->m21 * m_sharedMatrix->m14 * m_sharedMatrix->m32 - - m_sharedMatrix->m31 * m_sharedMatrix->m12 * m_sharedMatrix->m24 + - m_sharedMatrix->m31 * m_sharedMatrix->m14 * m_sharedMatrix->m22; - - inv[12] = -m_sharedMatrix->m21 * m_sharedMatrix->m32 * m_sharedMatrix->m43 + - m_sharedMatrix->m21 * m_sharedMatrix->m33 * m_sharedMatrix->m42 + - m_sharedMatrix->m31 * m_sharedMatrix->m22 * m_sharedMatrix->m43 - - m_sharedMatrix->m31 * m_sharedMatrix->m23 * m_sharedMatrix->m42 - - m_sharedMatrix->m41 * m_sharedMatrix->m22 * m_sharedMatrix->m33 + - m_sharedMatrix->m41 * m_sharedMatrix->m23 * m_sharedMatrix->m32; - - inv[13] = m_sharedMatrix->m11 * m_sharedMatrix->m32 * m_sharedMatrix->m43 - - m_sharedMatrix->m11 * m_sharedMatrix->m33 * m_sharedMatrix->m42 - - m_sharedMatrix->m31 * m_sharedMatrix->m12 * m_sharedMatrix->m43 + - m_sharedMatrix->m31 * m_sharedMatrix->m13 * m_sharedMatrix->m42 + - m_sharedMatrix->m41 * m_sharedMatrix->m12 * m_sharedMatrix->m33 - - m_sharedMatrix->m41 * m_sharedMatrix->m13 * m_sharedMatrix->m32; - - inv[14] = -m_sharedMatrix->m11 * m_sharedMatrix->m22 * m_sharedMatrix->m43 + - m_sharedMatrix->m11 * m_sharedMatrix->m23 * m_sharedMatrix->m42 + - m_sharedMatrix->m21 * m_sharedMatrix->m12 * m_sharedMatrix->m43 - - m_sharedMatrix->m21 * m_sharedMatrix->m13 * m_sharedMatrix->m42 - - m_sharedMatrix->m41 * m_sharedMatrix->m12 * m_sharedMatrix->m23 + - m_sharedMatrix->m41 * m_sharedMatrix->m13 * m_sharedMatrix->m22; - - inv[15] = m_sharedMatrix->m11 * m_sharedMatrix->m22 * m_sharedMatrix->m33 - - m_sharedMatrix->m11 * m_sharedMatrix->m23 * m_sharedMatrix->m32 - - m_sharedMatrix->m21 * m_sharedMatrix->m12 * m_sharedMatrix->m33 + - m_sharedMatrix->m21 * m_sharedMatrix->m13 * m_sharedMatrix->m32 + - m_sharedMatrix->m31 * m_sharedMatrix->m12 * m_sharedMatrix->m23 - - m_sharedMatrix->m31 * m_sharedMatrix->m13 * m_sharedMatrix->m22; - - T invDet = F(1.0) / det; - for (unsigned int i = 0; i < 16; ++i) - inv[i] *= invDet; - - Set(inv); - if (succeeded) - *succeeded = true; - } - else - { - NazaraError("Matrix has no inverse"); - if (succeeded) - *succeeded = false; - } + bool result = GetInverse(this); + if (succeeded) + *succeeded = result; return *this; } @@ -363,15 +434,6 @@ template NzMatrix4& NzMatrix4::InverseAffine(bool* succeeded) { #if NAZARA_MATH_SAFE - if (!IsDefined()) - { - NazaraError("Matrix not defined"); - if (succeeded) - *succeeded = false; - - return *this; - } - if (!IsAffine()) { NazaraError("Matrix not affine"); @@ -382,83 +444,9 @@ NzMatrix4& NzMatrix4::InverseAffine(bool* succeeded) } #endif - T det = GetDeterminant(); - if (!NzNumberEquals(det, F(0.0))) - { - // http://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix - T inv[16]; - inv[0] = m_sharedMatrix->m22 * m_sharedMatrix->m33 - - m_sharedMatrix->m32 * m_sharedMatrix->m23; - - inv[1] = -m_sharedMatrix->m12 * m_sharedMatrix->m33 + - m_sharedMatrix->m32 * m_sharedMatrix->m13; - - inv[2] = m_sharedMatrix->m12 * m_sharedMatrix->m23 - - m_sharedMatrix->m22 * m_sharedMatrix->m13; - - inv[3] = F(0.0); - - inv[4] = -m_sharedMatrix->m21 * m_sharedMatrix->m33 + - m_sharedMatrix->m31 * m_sharedMatrix->m23; - - inv[5] = m_sharedMatrix->m11 * m_sharedMatrix->m33 - - m_sharedMatrix->m31 * m_sharedMatrix->m13; - - inv[6] = -m_sharedMatrix->m11 * m_sharedMatrix->m23 + - m_sharedMatrix->m21 * m_sharedMatrix->m13; - - inv[7] = F(0.0); - - inv[8] = m_sharedMatrix->m21 * m_sharedMatrix->m32 - - m_sharedMatrix->m31 * m_sharedMatrix->m22; - - inv[9] = -m_sharedMatrix->m11 * m_sharedMatrix->m32 + - m_sharedMatrix->m31 * m_sharedMatrix->m12; - - inv[10] = m_sharedMatrix->m11 * m_sharedMatrix->m22 - - m_sharedMatrix->m21 * m_sharedMatrix->m12; - - inv[11] = F(0.0); - - inv[12] = -m_sharedMatrix->m21 * m_sharedMatrix->m32 * m_sharedMatrix->m43 + - m_sharedMatrix->m21 * m_sharedMatrix->m33 * m_sharedMatrix->m42 + - m_sharedMatrix->m31 * m_sharedMatrix->m22 * m_sharedMatrix->m43 - - m_sharedMatrix->m31 * m_sharedMatrix->m23 * m_sharedMatrix->m42 - - m_sharedMatrix->m41 * m_sharedMatrix->m22 * m_sharedMatrix->m33 + - m_sharedMatrix->m41 * m_sharedMatrix->m23 * m_sharedMatrix->m32; - - inv[13] = m_sharedMatrix->m11 * m_sharedMatrix->m32 * m_sharedMatrix->m43 - - m_sharedMatrix->m11 * m_sharedMatrix->m33 * m_sharedMatrix->m42 - - m_sharedMatrix->m31 * m_sharedMatrix->m12 * m_sharedMatrix->m43 + - m_sharedMatrix->m31 * m_sharedMatrix->m13 * m_sharedMatrix->m42 + - m_sharedMatrix->m41 * m_sharedMatrix->m12 * m_sharedMatrix->m33 - - m_sharedMatrix->m41 * m_sharedMatrix->m13 * m_sharedMatrix->m32; - - inv[14] = -m_sharedMatrix->m11 * m_sharedMatrix->m22 * m_sharedMatrix->m43 + - m_sharedMatrix->m11 * m_sharedMatrix->m23 * m_sharedMatrix->m42 + - m_sharedMatrix->m21 * m_sharedMatrix->m12 * m_sharedMatrix->m43 - - m_sharedMatrix->m21 * m_sharedMatrix->m13 * m_sharedMatrix->m42 - - m_sharedMatrix->m41 * m_sharedMatrix->m12 * m_sharedMatrix->m23 + - m_sharedMatrix->m41 * m_sharedMatrix->m13 * m_sharedMatrix->m22; - - inv[15] = F(0.0); - - T invDet = F(1.0) / det; - for (unsigned int i = 0; i < 16; ++i) - inv[i] *= invDet; - - inv[15] = F(1.0); - - Set(inv); - if (succeeded) - *succeeded = true; - } - else - { - NazaraError("Matrix has no inverse"); - if (succeeded) - *succeeded = false; - } + bool result = GetInverseAffine(this); + if (succeeded) + *succeeded = result; return *this; } @@ -466,24 +454,10 @@ NzMatrix4& NzMatrix4::InverseAffine(bool* succeeded) template bool NzMatrix4::IsAffine() const { - #if NAZARA_MATH_SAFE - if (!IsDefined()) - { - NazaraError("Matrix not defined"); - return false; - } - #endif - - return NzNumberEquals(m_sharedMatrix->m14, F(0.0)) && - NzNumberEquals(m_sharedMatrix->m24, F(0.0)) && - NzNumberEquals(m_sharedMatrix->m34, F(0.0)) && - NzNumberEquals(m_sharedMatrix->m44, F(1.0)); -} - -template -bool NzMatrix4::IsDefined() const -{ - return m_sharedMatrix != nullptr; + return NzNumberEquals(m14, F(0.0)) && + NzNumberEquals(m24, F(0.0)) && + NzNumberEquals(m34, F(0.0)) && + NzNumberEquals(m44, F(1.0)); } template @@ -548,38 +522,16 @@ NzMatrix4& NzMatrix4::MakePerspective(T angle, T ratio, T zNear, T zFar) template NzMatrix4& NzMatrix4::MakeRotation(const NzQuaternion& rotation) { - // http://www.flipcode.com/documents/matrfaq.html#Q54 -/* - | 2 2 | - | 1 - 2Y - 2Z 2XY + 2ZW 2XZ - 2YW | - | | - | 2 2 | - M = | 2XY - 2ZW 1 - 2X - 2Z 2YZ + 2XW | - | | - | 2 2 | - | 2XZ + 2YW 2YZ - 2XW 1 - 2X - 2Y | - | | -*/ - ///FIXME: À corriger (Rotation quaternion != rotation matricielle) - Set(F(1.0) - F(2.0)*rotation.y*rotation.y - F(2.0)*rotation.z*rotation.z, - F(2.0)*rotation.x*rotation.y + F(2.0)*rotation.z*rotation.w, - F(2.0)*rotation.x*rotation.z - F(2.0)*rotation.y*rotation.w, - F(0.0), + SetRotation(rotation); - F(2.0)*rotation.x*rotation.y - F(2.0)*rotation.z*rotation.w, - F(1.0) - F(2.0)*rotation.x*rotation.x - F(2.0)*rotation.z*rotation.z, - F(2.0)*rotation.y*rotation.z + F(2.0)*rotation.x*rotation.w, - F(0.0), - - F(2.0)*rotation.x*rotation.z + F(2.0)*rotation.y*rotation.w, - F(2.0)*rotation.y*rotation.z - F(2.0)*rotation.x*rotation.w, - F(1.0) - F(2.0)*rotation.x*rotation.x - F(2.0)*rotation.y*rotation.y, - F(0.0), - - F(0.0), - F(0.0), - F(0.0), - F(1.0)); + // On complète la matrice + m14 = F(0.0); + m24 = F(0.0); + m34 = F(0.0); + m41 = F(0.0); + m42 = F(0.0); + m43 = F(0.0); + m44 = F(1.0); return *this; } @@ -614,10 +566,10 @@ NzMatrix4& NzMatrix4::MakeTransform(const NzVector3& translation, const SetTranslation(translation); // On complète la matrice (les transformations sont affines) - m_sharedMatrix->m14 = F(0.0); - m_sharedMatrix->m24 = F(0.0); - m_sharedMatrix->m34 = F(0.0); - m_sharedMatrix->m44 = F(1.0); + m14 = F(0.0); + m24 = F(0.0); + m34 = F(0.0); + m44 = F(1.0); // Ensuite on fait une mise à l'échelle des valeurs déjà présentes ApplyScale(scale); @@ -642,25 +594,22 @@ NzMatrix4& NzMatrix4::Set(T r11, T r12, T r13, T r14, T r31, T r32, T r33, T r34, T r41, T r42, T r43, T r44) { - ReleaseMatrix(); - - m_sharedMatrix = new SharedMatrix; - m_sharedMatrix->m11 = r11; - m_sharedMatrix->m12 = r12; - m_sharedMatrix->m13 = r13; - m_sharedMatrix->m14 = r14; - m_sharedMatrix->m21 = r21; - m_sharedMatrix->m22 = r22; - m_sharedMatrix->m23 = r23; - m_sharedMatrix->m24 = r24; - m_sharedMatrix->m31 = r31; - m_sharedMatrix->m32 = r32; - m_sharedMatrix->m33 = r33; - m_sharedMatrix->m34 = r34; - m_sharedMatrix->m41 = r41; - m_sharedMatrix->m42 = r42; - m_sharedMatrix->m43 = r43; - m_sharedMatrix->m44 = r44; + m11 = r11; + m12 = r12; + m13 = r13; + m14 = r14; + m21 = r21; + m22 = r22; + m23 = r23; + m24 = r24; + m31 = r31; + m32 = r32; + m33 = r33; + m34 = r34; + m41 = r41; + m42 = r42; + m43 = r43; + m44 = r44; return *this; } @@ -668,11 +617,8 @@ NzMatrix4& NzMatrix4::Set(T r11, T r12, T r13, T r14, template NzMatrix4& NzMatrix4::Set(const T matrix[16]) { - ReleaseMatrix(); - - m_sharedMatrix = new SharedMatrix; // Ici nous sommes certains de la continuité des éléments en mémoire - std::memcpy(&m_sharedMatrix->m11, matrix, 16*sizeof(T)); + std::memcpy(&m11, matrix, 16*sizeof(T)); return *this; } @@ -680,23 +626,9 @@ NzMatrix4& NzMatrix4::Set(const T matrix[16]) template NzMatrix4& NzMatrix4::Set(const NzMatrix4& matrix) { - ReleaseMatrix(); - - m_sharedMatrix = matrix.m_sharedMatrix; - if (m_sharedMatrix) - { - NazaraMutexLock(m_sharedMatrix->mutex); - m_sharedMatrix->refCount++; - NazaraMutexUnlock(m_sharedMatrix->mutex); - } - - return *this; -} - -template -NzMatrix4& NzMatrix4::Set(NzMatrix4&& matrix) -{ - std::swap(m_sharedMatrix, matrix.m_sharedMatrix); + NazaraError("Check 1"); + std::memcpy(&m11, &matrix.m11, 16*sizeof(T)); + NazaraError("Check 2"); return *this; } @@ -705,10 +637,10 @@ template template NzMatrix4& NzMatrix4::Set(const NzMatrix4& matrix) { - Set(F(matrix.m_sharedMatrix->m11), F(matrix.m_sharedMatrix->m12), F(matrix.m_sharedMatrix->m13), F(matrix.m_sharedMatrix->m14), - F(matrix.m_sharedMatrix->m21), F(matrix.m_sharedMatrix->m22), F(matrix.m_sharedMatrix->m23), F(matrix.m_sharedMatrix->m24), - F(matrix.m_sharedMatrix->m31), F(matrix.m_sharedMatrix->m32), F(matrix.m_sharedMatrix->m33), F(matrix.m_sharedMatrix->m34), - F(matrix.m_sharedMatrix->m41), F(matrix.m_sharedMatrix->m42), F(matrix.m_sharedMatrix->m43), F(matrix.m_sharedMatrix->m44)); + Set(F(matrix.m11), F(matrix.m12), F(matrix.m13), F(matrix.m14), + F(matrix.m21), F(matrix.m22), F(matrix.m23), F(matrix.m24), + F(matrix.m31), F(matrix.m32), F(matrix.m33), F(matrix.m34), + F(matrix.m41), F(matrix.m42), F(matrix.m43), F(matrix.m44)); return *this; } @@ -716,19 +648,30 @@ NzMatrix4& NzMatrix4::Set(const NzMatrix4& matrix) template NzMatrix4& NzMatrix4::SetRotation(const NzQuaternion& rotation) { - // http://www.flipcode.com/documents/matrfaq.html#Q54 - EnsureOwnership(); + T tx = rotation.x + rotation.x; + T ty = rotation.y + rotation.y; + T tz = rotation.z + rotation.z; + T twx = tx * rotation.w; + T twy = ty * rotation.w; + T twz = tz * rotation.w; + T txx = tx * rotation.x; + T txy = ty * rotation.x; + T txz = tz * rotation.x; + T tyy = ty * rotation.y; + T tyz = tz * rotation.y; + T tzz = tz * rotation.z; - m_sharedMatrix->m11 = F(1.0) - F(2.0)*rotation.y*rotation.y - F(2.0)*rotation.z*rotation.z; - m_sharedMatrix->m22 = F(1.0) - F(2.0)*rotation.x*rotation.x - F(2.0)*rotation.z*rotation.z; - m_sharedMatrix->m33 = F(1.0) - F(2.0)*rotation.x*rotation.x - F(2.0)*rotation.y*rotation.y; + m11 = F(1.0) - (tyy + tzz); + m12 = txy + twz; + m13 = txz - twy; - m_sharedMatrix->m12 = F(2.0)*rotation.x*rotation.y - F(2.0)*rotation.z*rotation.w; - m_sharedMatrix->m13 = F(2.0)*rotation.x*rotation.z + F(2.0)*rotation.y*rotation.w; - m_sharedMatrix->m21 = F(2.0)*rotation.x*rotation.y + F(2.0)*rotation.z*rotation.w; - m_sharedMatrix->m23 = F(2.0)*rotation.y*rotation.z - F(2.0)*rotation.x*rotation.w; - m_sharedMatrix->m31 = F(2.0)*rotation.x*rotation.z - F(2.0)*rotation.y*rotation.w; - m_sharedMatrix->m32 = F(2.0)*rotation.y*rotation.z + F(2.0)*rotation.x*rotation.w; + m21 = txy - twz; + m22 = F(1.0) - (txx + tzz); + m23 = tyz + twx; + + m31 = txz + twy; + m32 = tyz - twx; + m33 = F(1.0) - (txx + tyy); return *this; } @@ -736,11 +679,9 @@ NzMatrix4& NzMatrix4::SetRotation(const NzQuaternion& rotation) template NzMatrix4& NzMatrix4::SetScale(const NzVector3& scale) { - EnsureOwnership(); - - m_sharedMatrix->m11 = scale.x; - m_sharedMatrix->m22 = scale.y; - m_sharedMatrix->m33 = scale.z; + m11 = scale.x; + m22 = scale.y; + m33 = scale.z; return *this; } @@ -748,12 +689,9 @@ NzMatrix4& NzMatrix4::SetScale(const NzVector3& scale) template NzMatrix4& NzMatrix4::SetTranslation(const NzVector3& translation) { - EnsureOwnership(); - - m_sharedMatrix->m41 = translation.x; - m_sharedMatrix->m42 = translation.y; - m_sharedMatrix->m43 = translation.z; - m_sharedMatrix->m44 = F(1.0); + m41 = translation.x; + m42 = translation.y; + m43 = translation.z; return *this; } @@ -761,91 +699,46 @@ NzMatrix4& NzMatrix4::SetTranslation(const NzVector3& translation) template NzString NzMatrix4::ToString() const { - if (!m_sharedMatrix) - return "Matrix4(undefined)"; - NzStringStream ss; - return ss << "Matrix4(" << m_sharedMatrix->m11 << ", " << m_sharedMatrix->m12 << ", " << m_sharedMatrix->m13 << ", " << m_sharedMatrix->m14 << ",\n" - << " " << m_sharedMatrix->m21 << ", " << m_sharedMatrix->m22 << ", " << m_sharedMatrix->m23 << ", " << m_sharedMatrix->m24 << ",\n" - << " " << m_sharedMatrix->m31 << ", " << m_sharedMatrix->m32 << ", " << m_sharedMatrix->m33 << ", " << m_sharedMatrix->m34 << ",\n" - << " " << m_sharedMatrix->m41 << ", " << m_sharedMatrix->m42 << ", " << m_sharedMatrix->m43 << ", " << m_sharedMatrix->m44 << ')'; + return ss << "Matrix4(" << m11 << ", " << m12 << ", " << m13 << ", " << m14 << ",\n" + << " " << m21 << ", " << m22 << ", " << m23 << ", " << m24 << ",\n" + << " " << m31 << ", " << m32 << ", " << m33 << ", " << m34 << ",\n" + << " " << m41 << ", " << m42 << ", " << m43 << ", " << m44 << ')'; } template NzVector2 NzMatrix4::Transform(const NzVector2& vector, T z, T w) const { - #if NAZARA_MATH_SAFE - if (!m_sharedMatrix) - { - NazaraError("Matrix not defined"); - return vector; - } - #endif - - return NzVector2(m_sharedMatrix->m11*vector.x + m_sharedMatrix->m12*vector.y + m_sharedMatrix->m13*z + m_sharedMatrix->m14*w, - m_sharedMatrix->m21*vector.x + m_sharedMatrix->m22*vector.y + m_sharedMatrix->m23*z + m_sharedMatrix->m24*w); + return NzVector2(m11*vector.x + m21*vector.y + m31*z + m41*w, + m12*vector.x + m22*vector.y + m32*z + m42*w); } template NzVector3 NzMatrix4::Transform(const NzVector3& vector, T w) const { - #if NAZARA_MATH_SAFE - if (!m_sharedMatrix) - { - NazaraError("Matrix not defined"); - return vector; - } - #endif - - return NzVector3(m_sharedMatrix->m11*vector.x + m_sharedMatrix->m12*vector.y + m_sharedMatrix->m13*vector.z + m_sharedMatrix->m14*w, - m_sharedMatrix->m21*vector.x + m_sharedMatrix->m22*vector.y + m_sharedMatrix->m23*vector.z + m_sharedMatrix->m24*w, - m_sharedMatrix->m31*vector.x + m_sharedMatrix->m32*vector.y + m_sharedMatrix->m33*vector.z + m_sharedMatrix->m34*w); + return NzVector3(m11*vector.x + m21*vector.y + m31*vector.z + m41*w, + m12*vector.x + m22*vector.y + m32*vector.z + m42*w, + m13*vector.x + m23*vector.y + m33*vector.z + m43*w); } template NzVector4 NzMatrix4::Transform(const NzVector4& vector) const { - #if NAZARA_MATH_SAFE - if (!m_sharedMatrix) - { - NazaraError("Matrix not defined"); - return vector; - } - #endif - - return NzVector4(m_sharedMatrix->m11*vector.x + m_sharedMatrix->m12*vector.y + m_sharedMatrix->m13*vector.z + m_sharedMatrix->m14*vector.w, - m_sharedMatrix->m21*vector.x + m_sharedMatrix->m22*vector.y + m_sharedMatrix->m23*vector.z + m_sharedMatrix->m24*vector.w, - m_sharedMatrix->m31*vector.x + m_sharedMatrix->m32*vector.y + m_sharedMatrix->m33*vector.z + m_sharedMatrix->m34*vector.w, - m_sharedMatrix->m41*vector.x + m_sharedMatrix->m42*vector.y + m_sharedMatrix->m43*vector.z + m_sharedMatrix->m44*vector.w); + return NzVector4(m11*vector.x + m21*vector.y + m31*vector.z + m41*vector.w, + m12*vector.x + m22*vector.y + m32*vector.z + m42*vector.w, + m13*vector.x + m23*vector.y + m33*vector.z + m43*vector.w, + m14*vector.x + m24*vector.y + m34*vector.z + m44*vector.w); } template NzMatrix4& NzMatrix4::Transpose() { - #if NAZARA_MATH_SAFE - if (!m_sharedMatrix) - { - NazaraError("Matrix not defined"); - return *this; - } - #endif - - EnsureOwnership(); - - std::swap(m_sharedMatrix->m12, m_sharedMatrix->m21); - std::swap(m_sharedMatrix->m13, m_sharedMatrix->m31); - std::swap(m_sharedMatrix->m14, m_sharedMatrix->m41); - std::swap(m_sharedMatrix->m23, m_sharedMatrix->m32); - std::swap(m_sharedMatrix->m24, m_sharedMatrix->m42); - std::swap(m_sharedMatrix->m34, m_sharedMatrix->m43); - - return *this; -} - -template -NzMatrix4& NzMatrix4::Undefine() -{ - ReleaseMatrix(); + std::swap(m12, m21); + std::swap(m13, m31); + std::swap(m14, m41); + std::swap(m23, m32); + std::swap(m24, m42); + std::swap(m34, m43); return *this; } @@ -859,31 +752,13 @@ NzMatrix4::operator NzString() const template NzMatrix4::operator T*() { - #if NAZARA_MATH_SAFE - if (!m_sharedMatrix) - { - NazaraError("Matrix not defined"); - return nullptr; - } - #endif - - EnsureOwnership(); - - return &m_sharedMatrix->m11; + return &m11; } template NzMatrix4::operator const T*() const { - #if NAZARA_MATH_SAFE - if (!m_sharedMatrix) - { - NazaraError("Matrix not defined"); - return nullptr; - } - #endif - - return &m_sharedMatrix->m11; + return &m11; } template @@ -893,59 +768,37 @@ T& NzMatrix4::operator()(unsigned int x, unsigned int y) if (x > 3 || y > 3) { NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Index out of range: (" << x << ", " << y << ") > (3,3)"; + ss << "Index out of range: (" << x << ", " << y << ") > (3,3)"; throw std::out_of_range(ss.ToString()); } #endif - EnsureOwnership(); - - return (&m_sharedMatrix->m11)[y*4+x]; + return (&m11)[y*4+x]; } template const T& NzMatrix4::operator()(unsigned int x, unsigned int y) const { #if NAZARA_MATH_SAFE - if (!m_sharedMatrix) - { - NazaraError("Matrix not defined"); - throw std::runtime_error("Tried to access element of Matrix not defined"); - } - if (x > 3 || y > 3) { NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Index out of range: (" << x << ", " << y << ") > (3,3)"; + ss << "Index out of range: (" << x << ", " << y << ") > (3,3)"; + NazaraError(ss); throw std::out_of_range(ss.ToString()); } #endif - return (&m_sharedMatrix->m11)[y*4+x]; -} - -template -NzMatrix4& NzMatrix4::operator=(const NzMatrix4& matrix) -{ - Set(matrix); - - return *this; -} - -template -NzMatrix4& NzMatrix4::operator=(NzMatrix4&& matrix) noexcept -{ - Set(matrix); - - return *this; + return (&m11)[y*4+x]; } template NzMatrix4 NzMatrix4::operator*(const NzMatrix4& matrix) const { - return Concatenate(matrix); + NzMatrix4 result(*this); + return result.Concatenate(matrix); } template @@ -969,32 +822,17 @@ NzVector4 NzMatrix4::operator*(const NzVector4& vector) const template NzMatrix4 NzMatrix4::operator*(T scalar) const { - #if NAZARA_MATH_SAFE - if (!m_sharedMatrix) - { - NazaraError("Matrix not defined"); - return *this; - } - #endif + NzMatrix4 mat; + for (unsigned int i = 0; i < 16; ++i) + mat[i] = (&m11)[i] * scalar; - return NzMatrix4(m_sharedMatrix->m11 * scalar, m_sharedMatrix->m12 * scalar, m_sharedMatrix->m13 * scalar, m_sharedMatrix->m14 * scalar, - m_sharedMatrix->m21 * scalar, m_sharedMatrix->m22 * scalar, m_sharedMatrix->m23 * scalar, m_sharedMatrix->m24 * scalar, - m_sharedMatrix->m31 * scalar, m_sharedMatrix->m32 * scalar, m_sharedMatrix->m33 * scalar, m_sharedMatrix->m34 * scalar, - m_sharedMatrix->m41 * scalar, m_sharedMatrix->m42 * scalar, m_sharedMatrix->m43 * scalar, m_sharedMatrix->m44 * scalar); + return mat; } template NzMatrix4& NzMatrix4::operator*=(const NzMatrix4& matrix) { - #if NAZARA_MATH_SAFE - if (!m_sharedMatrix) - { - NazaraError("Matrix not defined"); - return *this; - } - #endif - - Set(Concatenate(*this, matrix)); + Concatenate(matrix); return *this; } @@ -1002,30 +840,8 @@ NzMatrix4& NzMatrix4::operator*=(const NzMatrix4& matrix) template NzMatrix4& NzMatrix4::operator*=(T scalar) { - #if NAZARA_MATH_SAFE - if (!m_sharedMatrix) - { - NazaraError("Matrix not defined"); - return *this; - } - #endif - - m_sharedMatrix->m11 *= scalar; - m_sharedMatrix->m12 *= scalar; - m_sharedMatrix->m13 *= scalar; - m_sharedMatrix->m14 *= scalar; - m_sharedMatrix->m21 *= scalar; - m_sharedMatrix->m22 *= scalar; - m_sharedMatrix->m23 *= scalar; - m_sharedMatrix->m24 *= scalar; - m_sharedMatrix->m31 *= scalar; - m_sharedMatrix->m32 *= scalar; - m_sharedMatrix->m33 *= scalar; - m_sharedMatrix->m34 *= scalar; - m_sharedMatrix->m41 *= scalar; - m_sharedMatrix->m42 *= scalar; - m_sharedMatrix->m43 *= scalar; - m_sharedMatrix->m44 *= scalar; + for (unsigned int i = 0; i < 16; ++i) + (&m11)[i] *= scalar; return *this; } @@ -1033,14 +849,8 @@ NzMatrix4& NzMatrix4::operator*=(T scalar) template bool NzMatrix4::operator==(const NzMatrix4& mat) const { - if (!m_sharedMatrix) - return mat.m_sharedMatrix == nullptr; - - if (!mat.m_sharedMatrix) - return false; - for (unsigned int i = 0; i < 16; ++i) - if (!NzNumberEquals((&m_sharedMatrix->m11)[i], (&mat.m_sharedMatrix->m11)[i])) + if (!NzNumberEquals((&m11)[i], (&mat.m11)[i])) return false; return true; @@ -1052,101 +862,6 @@ bool NzMatrix4::operator!=(const NzMatrix4& mat) const return !operator==(mat); } -template -NzMatrix4 NzMatrix4::Concatenate(const NzMatrix4& m1, const NzMatrix4& m2) -{ - #if NAZARA_MATH_SAFE - if (!m1.IsDefined()) - { - NazaraError("First matrix not defined"); - return NzMatrix4(); - } - - if (!m2.IsDefined()) - { - NazaraError("Second matrix not defined"); - return NzMatrix4(); - } - #endif - - #if NAZARA_MATH_MATRIX4_CHECK_AFFINE - if (m1.IsAffine() && m2.IsAffine()) - return ConcatenateAffine(m1, m2); - #endif - - return NzMatrix4(m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m11 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m21 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m31 + m1.m_sharedMatrix->m14*m2.m_sharedMatrix->m41, - m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m12 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m22 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m32 + m1.m_sharedMatrix->m14*m2.m_sharedMatrix->m42, - m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m13 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m23 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m33 + m1.m_sharedMatrix->m14*m2.m_sharedMatrix->m43, - m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m14 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m24 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m34 + m1.m_sharedMatrix->m14*m2.m_sharedMatrix->m44, - - m1.m_sharedMatrix->m21*m2.m_sharedMatrix->m11 + m1.m_sharedMatrix->m22*m2.m_sharedMatrix->m21 + m1.m_sharedMatrix->m23*m2.m_sharedMatrix->m31 + m1.m_sharedMatrix->m24*m2.m_sharedMatrix->m41, - m1.m_sharedMatrix->m21*m2.m_sharedMatrix->m12 + m1.m_sharedMatrix->m22*m2.m_sharedMatrix->m22 + m1.m_sharedMatrix->m23*m2.m_sharedMatrix->m32 + m1.m_sharedMatrix->m24*m2.m_sharedMatrix->m42, - m1.m_sharedMatrix->m21*m2.m_sharedMatrix->m13 + m1.m_sharedMatrix->m22*m2.m_sharedMatrix->m23 + m1.m_sharedMatrix->m23*m2.m_sharedMatrix->m33 + m1.m_sharedMatrix->m24*m2.m_sharedMatrix->m43, - m1.m_sharedMatrix->m21*m2.m_sharedMatrix->m14 + m1.m_sharedMatrix->m22*m2.m_sharedMatrix->m24 + m1.m_sharedMatrix->m23*m2.m_sharedMatrix->m34 + m1.m_sharedMatrix->m24*m2.m_sharedMatrix->m44, - - m1.m_sharedMatrix->m31*m2.m_sharedMatrix->m11 + m1.m_sharedMatrix->m32*m2.m_sharedMatrix->m21 + m1.m_sharedMatrix->m33*m2.m_sharedMatrix->m31 + m1.m_sharedMatrix->m34*m2.m_sharedMatrix->m41, - m1.m_sharedMatrix->m31*m2.m_sharedMatrix->m12 + m1.m_sharedMatrix->m32*m2.m_sharedMatrix->m22 + m1.m_sharedMatrix->m33*m2.m_sharedMatrix->m32 + m1.m_sharedMatrix->m34*m2.m_sharedMatrix->m42, - m1.m_sharedMatrix->m31*m2.m_sharedMatrix->m13 + m1.m_sharedMatrix->m32*m2.m_sharedMatrix->m23 + m1.m_sharedMatrix->m33*m2.m_sharedMatrix->m33 + m1.m_sharedMatrix->m34*m2.m_sharedMatrix->m43, - m1.m_sharedMatrix->m31*m2.m_sharedMatrix->m14 + m1.m_sharedMatrix->m32*m2.m_sharedMatrix->m24 + m1.m_sharedMatrix->m33*m2.m_sharedMatrix->m34 + m1.m_sharedMatrix->m34*m2.m_sharedMatrix->m44, - - m1.m_sharedMatrix->m41*m2.m_sharedMatrix->m11 + m1.m_sharedMatrix->m42*m2.m_sharedMatrix->m21 + m1.m_sharedMatrix->m43*m2.m_sharedMatrix->m31 + m1.m_sharedMatrix->m44*m2.m_sharedMatrix->m41, - m1.m_sharedMatrix->m41*m2.m_sharedMatrix->m12 + m1.m_sharedMatrix->m42*m2.m_sharedMatrix->m22 + m1.m_sharedMatrix->m43*m2.m_sharedMatrix->m32 + m1.m_sharedMatrix->m44*m2.m_sharedMatrix->m42, - m1.m_sharedMatrix->m41*m2.m_sharedMatrix->m13 + m1.m_sharedMatrix->m42*m2.m_sharedMatrix->m23 + m1.m_sharedMatrix->m43*m2.m_sharedMatrix->m33 + m1.m_sharedMatrix->m44*m2.m_sharedMatrix->m43, - m1.m_sharedMatrix->m41*m2.m_sharedMatrix->m14 + m1.m_sharedMatrix->m42*m2.m_sharedMatrix->m24 + m1.m_sharedMatrix->m43*m2.m_sharedMatrix->m34 + m1.m_sharedMatrix->m44*m2.m_sharedMatrix->m44); -} - -template -NzMatrix4 NzMatrix4::ConcatenateAffine(const NzMatrix4& m1, const NzMatrix4& m2) -{ - #if NAZARA_MATH_SAFE - if (!m1.IsDefined()) - { - NazaraError("First matrix not defined"); - return NzMatrix4(); - } - - if (!m2.IsDefined()) - { - NazaraError("Second matrix not defined"); - return NzMatrix4(); - } - #endif - - #ifdef NAZARA_DEBUG - if (!m1.IsAffine()) - { - NazaraError("First matrix not affine"); - return NzMatrix4(); - } - - if (!m2.IsAffine()) - { - NazaraError("Second matrix not affine"); - return NzMatrix4(); - } - #endif - - return NzMatrix4(m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m11 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m21 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m31, - m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m12 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m22 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m32, - m1.m_sharedMatrix->m11*m2.m_sharedMatrix->m13 + m1.m_sharedMatrix->m12*m2.m_sharedMatrix->m23 + m1.m_sharedMatrix->m13*m2.m_sharedMatrix->m33, - F(0.0), - - m1.m_sharedMatrix->m21*m2.m_sharedMatrix->m11 + m1.m_sharedMatrix->m22*m2.m_sharedMatrix->m21 + m1.m_sharedMatrix->m23*m2.m_sharedMatrix->m31, - m1.m_sharedMatrix->m21*m2.m_sharedMatrix->m12 + m1.m_sharedMatrix->m22*m2.m_sharedMatrix->m22 + m1.m_sharedMatrix->m23*m2.m_sharedMatrix->m32, - m1.m_sharedMatrix->m21*m2.m_sharedMatrix->m13 + m1.m_sharedMatrix->m22*m2.m_sharedMatrix->m23 + m1.m_sharedMatrix->m23*m2.m_sharedMatrix->m33, - F(0.0), - - m1.m_sharedMatrix->m31*m2.m_sharedMatrix->m11 + m1.m_sharedMatrix->m32*m2.m_sharedMatrix->m21 + m1.m_sharedMatrix->m33*m2.m_sharedMatrix->m31, - m1.m_sharedMatrix->m31*m2.m_sharedMatrix->m12 + m1.m_sharedMatrix->m32*m2.m_sharedMatrix->m22 + m1.m_sharedMatrix->m33*m2.m_sharedMatrix->m32, - m1.m_sharedMatrix->m31*m2.m_sharedMatrix->m13 + m1.m_sharedMatrix->m32*m2.m_sharedMatrix->m23 + m1.m_sharedMatrix->m33*m2.m_sharedMatrix->m33, - F(0.0), - - m1.m_sharedMatrix->m41*m2.m_sharedMatrix->m11 + m1.m_sharedMatrix->m42*m2.m_sharedMatrix->m21 + m1.m_sharedMatrix->m43*m2.m_sharedMatrix->m31 + m2.m_sharedMatrix->m41, - m1.m_sharedMatrix->m41*m2.m_sharedMatrix->m12 + m1.m_sharedMatrix->m42*m2.m_sharedMatrix->m22 + m1.m_sharedMatrix->m43*m2.m_sharedMatrix->m32 + m2.m_sharedMatrix->m42, - m1.m_sharedMatrix->m41*m2.m_sharedMatrix->m13 + m1.m_sharedMatrix->m42*m2.m_sharedMatrix->m23 + m1.m_sharedMatrix->m43*m2.m_sharedMatrix->m33 + m2.m_sharedMatrix->m43, - F(1.0)); -} - template NzMatrix4 NzMatrix4::Identity() { @@ -1240,42 +955,6 @@ NzMatrix4 operator*(T scale, const NzMatrix4& matrix) return matrix * scale; } -template -void NzMatrix4::EnsureOwnership() -{ - if (m_sharedMatrix) - { - NazaraLock(m_sharedMatrix->mutex); - if (m_sharedMatrix->refCount > 1) - { - m_sharedMatrix->refCount--; - - SharedMatrix* sharedMatrix = new SharedMatrix; - std::memcpy(&sharedMatrix->m11, &m_sharedMatrix->m11, 16*sizeof(T)); - - m_sharedMatrix = sharedMatrix; - } - } - else - m_sharedMatrix = new SharedMatrix; -} - -template -void NzMatrix4::ReleaseMatrix() -{ - if (!m_sharedMatrix) - return; - - NazaraMutexLock(m_sharedMatrix->mutex); - bool freeSharedMatrix = (--m_sharedMatrix->refCount == 0); - NazaraMutexUnlock(m_sharedMatrix->mutex); - - if (freeSharedMatrix) - delete m_sharedMatrix; - - m_sharedMatrix = nullptr; -} - #undef F #include diff --git a/include/Nazara/Math/Quaternion.hpp b/include/Nazara/Math/Quaternion.hpp index 7e9addfc9..b492aff11 100644 --- a/include/Nazara/Math/Quaternion.hpp +++ b/include/Nazara/Math/Quaternion.hpp @@ -15,9 +15,9 @@ template class NzVector3; template class NzQuaternion { public: - NzQuaternion(); + NzQuaternion() = default; NzQuaternion(T W, T X, T Y, T Z); - NzQuaternion(T quat[4]); + NzQuaternion(const T quat[4]); NzQuaternion(T angle, const NzVector3& axis); NzQuaternion(const NzEulerAngles& angles); //NzQuaternion(const NzMatrix3& mat); @@ -25,28 +25,31 @@ template class NzQuaternion NzQuaternion(const NzQuaternion& quat) = default; ~NzQuaternion() = default; + NzQuaternion& ComputeW(); + NzQuaternion& Conjugate(); + T DotProduct(const NzQuaternion& vec) const; NzQuaternion GetConjugate() const; NzQuaternion GetInverse() const; - NzQuaternion GetNormal() const; + NzQuaternion GetNormal(T* length = nullptr) const; - void Inverse(); + NzQuaternion& Inverse(); - void MakeIdentity(); - void MakeZero(); + NzQuaternion& MakeIdentity(); + NzQuaternion& MakeZero(); T Magnitude() const; - T Normalize(); + NzQuaternion& Normalize(T* length = nullptr); - void Set(T W, T X, T Y, T Z); - void Set(T quat[4]); - void Set(T angle, const NzVector3& normalizedAxis); - void Set(const NzEulerAngles& angles); - //void Set(const NzMatrix3& mat); - void Set(const NzQuaternion& quat); - template void Set(const NzQuaternion& quat); + NzQuaternion& Set(T W, T X, T Y, T Z); + NzQuaternion& Set(const T quat[4]); + NzQuaternion& Set(T angle, const NzVector3& normalizedAxis); + NzQuaternion& Set(const NzEulerAngles& angles); + //NzQuaternion& Set(const NzMatrix3& mat); + NzQuaternion& Set(const NzQuaternion& quat); + template NzQuaternion& Set(const NzQuaternion& quat); T SquaredMagnitude() const; diff --git a/include/Nazara/Math/Quaternion.inl b/include/Nazara/Math/Quaternion.inl index ed88e5f5b..846c80d57 100644 --- a/include/Nazara/Math/Quaternion.inl +++ b/include/Nazara/Math/Quaternion.inl @@ -12,11 +12,6 @@ #define F(a) static_cast(a) -template -NzQuaternion::NzQuaternion() -{ -} - template NzQuaternion::NzQuaternion(T W, T X, T Y, T Z) { @@ -24,7 +19,7 @@ NzQuaternion::NzQuaternion(T W, T X, T Y, T Z) } template -NzQuaternion::NzQuaternion(T quat[4]) +NzQuaternion::NzQuaternion(const T quat[4]) { Set(quat); } @@ -54,6 +49,29 @@ NzQuaternion::NzQuaternion(const NzQuaternion& quat) Set(quat); } +template +NzQuaternion& NzQuaternion::ComputeW() +{ + T t = F(1.0) - SquaredMagnitude(); + + if (t < F(0.0)) + w = F(0.0); + else + w = -std::sqrt(t); + + return *this; +} + +template +NzQuaternion& NzQuaternion::Conjugate() +{ + x = -x; + y = -y; + z = -z; + + return *this; +} + template T NzQuaternion::DotProduct(const NzQuaternion& quat) const { @@ -63,7 +81,10 @@ T NzQuaternion::DotProduct(const NzQuaternion& quat) const template NzQuaternion NzQuaternion::GetConjugate() const { - return NzQuaternion(w, -x, -y, -z); + NzQuaternion quat(*this); + quat.Conjugate(); + + return quat; } template @@ -76,16 +97,16 @@ NzQuaternion NzQuaternion::GetInverse() const } template -NzQuaternion NzQuaternion::GetNormal() const +NzQuaternion NzQuaternion::GetNormal(T* length) const { NzQuaternion quat(*this); - quat.Normalize(); + quat.Normalize(length); return quat; } template -void NzQuaternion::Inverse() +NzQuaternion& NzQuaternion::Inverse() { T norm = SquaredMagnitude(); if (norm > F(0.0)) @@ -97,18 +118,20 @@ void NzQuaternion::Inverse() y *= -invNorm; z *= -invNorm; } + + return *this; } template -void NzQuaternion::MakeIdentity() +NzQuaternion& NzQuaternion::MakeIdentity() { - Set(F(1.0), F(0.0), F(0.0), F(0.0)); + return Set(F(1.0), F(0.0), F(0.0), F(0.0)); } template -void NzQuaternion::MakeZero() +NzQuaternion& NzQuaternion::MakeZero() { - Set(F(0.0), F(0.0), F(0.0), F(0.0)); + return Set(F(0.0), F(0.0), F(0.0), F(0.0)); } template @@ -118,49 +141,48 @@ T NzQuaternion::Magnitude() const } template -T NzQuaternion::Normalize() +NzQuaternion& NzQuaternion::Normalize(T* length) { - T squaredMagnitude = SquaredMagnitude(); + T norm = std::sqrt(SquaredMagnitude()); + T invNorm = F(1.0) / norm; - // Inutile de vérifier si la magnitude au carrée est négative (Elle ne peut pas l'être) - if (!NzNumberEquals(squaredMagnitude, F(1.0))) - { - T norm = std::sqrt(squaredMagnitude); - T invNorm = F(1.0) / norm; + w *= invNorm; + x *= invNorm; + y *= invNorm; + z *= invNorm; - w *= invNorm; - x *= invNorm; - y *= invNorm; - z *= invNorm; + if (length) + *length = norm; - return norm; - } - else - return F(1.0); // Le quaternion est déjà normalisé + return *this; } template -void NzQuaternion::Set(T W, T X, T Y, T Z) +NzQuaternion& NzQuaternion::Set(T W, T X, T Y, T Z) { w = W; x = X; y = Y; z = Z; + + return *this; } template -void NzQuaternion::Set(T quat[4]) +NzQuaternion& NzQuaternion::Set(const T quat[4]) { w = quat[0]; x = quat[1]; y = quat[2]; z = quat[3]; + + return *this; } template -void NzQuaternion::Set(T angle, const NzVector3& axis) +NzQuaternion& NzQuaternion::Set(T angle, const NzVector3& axis) { - angle /= F(2.0); + angle *= F(0.5); #if !NAZARA_MATH_ANGLE_RADIAN angle = NzDegreeToRadian(angle); @@ -175,32 +197,36 @@ void NzQuaternion::Set(T angle, const NzVector3& axis) y = normalizedAxis.y * sinAngle; z = normalizedAxis.z * sinAngle; - Normalize(); + return Normalize(); } template -void NzQuaternion::Set(const NzEulerAngles& angles) +NzQuaternion& NzQuaternion::Set(const NzEulerAngles& angles) { - Set(angles.ToQuaternion()); + return Set(angles.ToQuaternion()); } template template -void NzQuaternion::Set(const NzQuaternion& quat) +NzQuaternion& NzQuaternion::Set(const NzQuaternion& quat) { w = static_cast(quat.w); x = static_cast(quat.x); y = static_cast(quat.y); z = static_cast(quat.z); + + return *this; } template -void NzQuaternion::Set(const NzQuaternion& quat) +NzQuaternion& NzQuaternion::Set(const NzQuaternion& quat) { w = quat.w; x = quat.x; y = quat.y; z = quat.z; + + return *this; } template @@ -242,27 +268,31 @@ NzQuaternion::operator NzString() const template NzQuaternion& NzQuaternion::operator=(const NzQuaternion& quat) { - Set(quat); - - return *this; + return Set(quat); } template NzQuaternion NzQuaternion::operator+(const NzQuaternion& quat) const { - return NzQuaternion(w + quat.w, - x + quat.x, - y + quat.y, - z + quat.z); + NzQuaternion result; + result.w = w + quat.w; + result.x = x + quat.x; + result.y = y + quat.y; + result.z = z + quat.z; + + return result; } template NzQuaternion NzQuaternion::operator*(const NzQuaternion& quat) const { - return NzQuaternion(w*quat.w - x*quat.x - y*quat.y - z*quat.z, - w*quat.x + x*quat.w + y*quat.z - z*quat.y, - w*quat.y + y*quat.w + z*quat.x - x*quat.z, - w*quat.z + z*quat.w + x*quat.y - y*quat.x); + NzQuaternion result; + result.w = w*quat.w - x*quat.x - y*quat.y - z*quat.z; + result.x = w*quat.x + x*quat.w + y*quat.z - z*quat.y; + result.y = w*quat.y + y*quat.w + z*quat.x - x*quat.z; + result.z = w*quat.z + z*quat.w + x*quat.y - y*quat.x; + + return result; } template diff --git a/include/Nazara/Math/Rect.hpp b/include/Nazara/Math/Rect.hpp index 0d373507d..66066405d 100644 --- a/include/Nazara/Math/Rect.hpp +++ b/include/Nazara/Math/Rect.hpp @@ -14,7 +14,7 @@ template class NzRect { public: - NzRect(); + NzRect() = default; NzRect(T X, T Y, T Width, T Height); NzRect(const T rect[4]); NzRect(const NzVector2& vec1, const NzVector2& vec2); @@ -26,21 +26,23 @@ class NzRect bool Contains(const NzVector2& point) const; bool Contains(const NzRect& rect) const; - void ExtendTo(const NzVector2& point); - void ExtendTo(const NzRect& rect); + NzRect& ExtendTo(const NzVector2& point); + NzRect& ExtendTo(const NzRect& rect); NzVector2 GetCenter() const; + NzVector2 GetPosition() const; + NzVector2 GetSize() const; bool Intersect(const NzRect& rect, NzRect* intersection = nullptr) const; bool IsValid() const; - void MakeZero(); + NzRect& MakeZero(); - void Set(T X, T Y, T Width, T Height); - void Set(const T rect[4]); - void Set(const NzVector2& vec1, const NzVector2& vec2); - template void Set(const NzRect& rect); + NzRect& Set(T X, T Y, T Width, T Height); + NzRect& Set(const T rect[4]); + NzRect& Set(const NzVector2& vec1, const NzVector2& vec2); + template NzRect& Set(const NzRect& rect); NzString ToString() const; diff --git a/include/Nazara/Math/Rect.inl b/include/Nazara/Math/Rect.inl index 62f7684f4..c637a15ac 100644 --- a/include/Nazara/Math/Rect.inl +++ b/include/Nazara/Math/Rect.inl @@ -8,11 +8,6 @@ #define F(a) static_cast(a) -template -NzRect::NzRect() -{ -} - template NzRect::NzRect(T X, T Y, T Width, T Height) { @@ -59,27 +54,43 @@ bool NzRect::Contains(const NzRect& rect) const } template -void NzRect::ExtendTo(const NzVector2& point) +NzRect& NzRect::ExtendTo(const NzVector2& point) { x = std::min(x, point.x); y = std::min(y, point.y); - width = std::max(x+width, point.x)-x; - height = std::max(y+height, point.y)-y; + width = std::max(x + width, point.x) - x; + height = std::max(y + height, point.y) - y; + + return *this; } template -void NzRect::ExtendTo(const NzRect& rect) +NzRect& NzRect::ExtendTo(const NzRect& rect) { x = std::min(x, rect.x); y = std::min(y, rect.y); - width = std::max(x+width, rect.x+rect.width)-x; - height = std::max(x+height, rect.y+rect.height)-y; + width = std::max(x + width, rect.x + rect.width) - x; + height = std::max(x + height, rect.y + rect.height) - y; + + return *this; } template NzVector2 NzRect::GetCenter() const { - return NzVector2((x+width)/F(2.0), (y+height)/F(2.0)); + return NzVector2(x + width/F(2.0), y + height/F(2.0)); +} + +template +NzVector2 NzRect::GetPosition() const +{ + return NzVector2(x, y); +} + +template +NzVector2 NzRect::GetSize() const +{ + return NzVector2(width, height); } template @@ -113,49 +124,59 @@ bool NzRect::IsValid() const } template -void NzRect::MakeZero() +NzRect& NzRect::MakeZero() { x = F(0.0); y = F(0.0); width = F(0.0); height = F(0.0); + + return *this; } template -void NzRect::Set(T X, T Y, T Width, T Height) +NzRect& NzRect::Set(T X, T Y, T Width, T Height) { x = X; y = Y; width = Width; height = Height; + + return *this; } template -void NzRect::Set(const T rect[4]) +NzRect& NzRect::Set(const T rect[4]) { x = rect[0]; y = rect[1]; width = rect[2]; height = rect[3]; + + return *this; } template -void NzRect::Set(const NzVector2& vec1, const NzVector2& vec2) +NzRect& NzRect::Set(const NzVector2& vec1, const NzVector2& vec2) { x = std::min(vec1.x, vec2.x); y = std::min(vec1.y, vec2.y); width = (vec2.x > vec1.x) ? vec2.x-vec1.x : vec1.x-vec2.x; height = (vec2.y > vec1.y) ? vec2.y-vec1.y : vec1.y-vec2.y; + + return *this; } template template -void NzRect::Set(const NzRect& rect) +NzRect& NzRect::Set(const NzRect& rect) { x = F(rect.x); y = F(rect.y); width = F(rect.width); height = F(rect.height); + + return *this; } template @@ -179,8 +200,9 @@ T& NzRect::operator[](unsigned int i) if (i >= 4) { NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Index out of range (" << i << " >= 4)"; + ss << "Index out of range: (" << i << " >= 4)"; + NazaraError(ss); throw std::domain_error(ss.ToString()); } #endif @@ -195,8 +217,9 @@ T NzRect::operator[](unsigned int i) const if (i >= 4) { NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Index out of range (" << i << " >= 4)"; + ss << "Index out of range: (" << i << " >= 4)"; + NazaraError(ss); throw std::domain_error(ss.ToString()); } #endif diff --git a/include/Nazara/Math/Vector2.hpp b/include/Nazara/Math/Vector2.hpp index c60f1950f..816760fd5 100644 --- a/include/Nazara/Math/Vector2.hpp +++ b/include/Nazara/Math/Vector2.hpp @@ -9,13 +9,14 @@ #include -template class NzVector2 +template +class NzVector2 { public: - NzVector2(); + NzVector2() = default; NzVector2(T X, T Y); explicit NzVector2(T scale); - NzVector2(T vec[2]); + NzVector2(const T vec[2]); template explicit NzVector2(const NzVector2& vec); NzVector2(const NzVector2& vec) = default; ~NzVector2() = default; @@ -32,19 +33,19 @@ template class NzVector2 T Length() const; float Lengthf() const; - void MakeUnitX(); - void MakeUnitY(); - void MakeZero(); + NzVector2& MakeUnitX(); + NzVector2& MakeUnitY(); + NzVector2& MakeZero(); - void Maximize(const NzVector2& vec); - void Minimize(const NzVector2& vec); + NzVector2& Maximize(const NzVector2& vec); + NzVector2& Minimize(const NzVector2& vec); - void Normalize(); + NzVector2& Normalize(T* length = nullptr); - void Set(T X, T Y); - void Set(T scale); - void Set(T vec[2]); - template void Set(const NzVector2& vec); + NzVector2& Set(T X, T Y); + NzVector2& Set(T scale); + NzVector2& Set(const T vec[2]); + template NzVector2& Set(const NzVector2& vec); T SquaredDistance(const NzVector2& vec) const; T SquaredLength() const; diff --git a/include/Nazara/Math/Vector2.inl b/include/Nazara/Math/Vector2.inl index 7e8ebaeab..4fc18f312 100644 --- a/include/Nazara/Math/Vector2.inl +++ b/include/Nazara/Math/Vector2.inl @@ -12,11 +12,6 @@ #define F(a) static_cast(a) -template -NzVector2::NzVector2() -{ -} - template NzVector2::NzVector2(T X, T Y) { @@ -30,7 +25,7 @@ NzVector2::NzVector2(T scale) } template -NzVector2::NzVector2(T vec[2]) +NzVector2::NzVector2(const T vec[2]) { Set(vec); } @@ -100,83 +95,96 @@ float NzVector2::Lengthf() const } template -void NzVector2::MakeUnitX() +NzVector2& NzVector2::MakeUnitX() { Set(F(1.0), F(0.0)); } template -void NzVector2::MakeUnitY() +NzVector2& NzVector2::MakeUnitY() { - Set(F(0.0), F(1.0)); + return Set(F(0.0), F(1.0)); } template -void NzVector2::MakeZero() +NzVector2& NzVector2::MakeZero() { - Set(F(0.0), F(0.0)); + return Set(F(0.0), F(0.0)); } template -void NzVector2::Maximize(const NzVector2& vec) +NzVector2& NzVector2::Maximize(const NzVector2& vec) { if (vec.x > x) x = vec.x; if (vec.y > y) y = vec.y; + + return *this; } template -void NzVector2::Minimize(const NzVector2& vec) +NzVector2& NzVector2::Minimize(const NzVector2& vec) { if (vec.x < x) x = vec.x; if (vec.y < y) y = vec.y; + + return *this; } template -void NzVector2::Normalize() +NzVector2& NzVector2::Normalize(T* length) { - T squaredLength = SquaredLength(); + T norm = std::sqrt(SquaredLength()); + T invNorm = F(1.0) / length; - if (squaredLength-F(1.0) > std::numeric_limits::epsilon()) - { - T length = std::sqrt(squaredLength); + x *= invNorm; + y *= invNorm; - x /= length; - y /= length; - } + if (length) + *length = norm; + + return *this; } template -void NzVector2::Set(T X, T Y) +NzVector2& NzVector2::Set(T X, T Y) { x = X; y = Y; + + return *this; } template -void NzVector2::Set(T scale) +NzVector2& NzVector2::Set(T scale) { x = scale; y = scale; + + return *this; } template -void NzVector2::Set(T vec[2]) +NzVector2& NzVector2::Set(const T vec[2]) { std::memcpy(&x, vec, 2*sizeof(T)); + + return *this; } template template -void NzVector2::Set(const NzVector2& vec) +NzVector2& NzVector2::Set(const NzVector2& vec) { x = F(vec.x); y = F(vec.y); + + return *this; } template @@ -224,8 +232,9 @@ T& NzVector2::operator[](unsigned int i) if (i >= 2) { NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Index out of range (" << i << " >= 2)"; + ss << "Index out of range: (" << i << " >= 2)"; + NazaraError(ss); throw std::domain_error(ss.ToString()); } #endif @@ -240,8 +249,9 @@ T NzVector2::operator[](unsigned int i) const if (i >= 2) { NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Index out of range (" << i << " >= 2)"; + ss << "Index out of range: (" << i << " >= 2)"; + NazaraError(ss); throw std::domain_error(ss.ToString()); } #endif @@ -291,10 +301,10 @@ NzVector2 NzVector2::operator/(const NzVector2& vec) const #if NAZARA_MATH_SAFE if (NzNumberEquals(vec.x, F(0.0)) || NzNumberEquals(vec.y, F(0.0))) { - NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; + NzString error("Division by zero"); - throw std::domain_error(ss.ToString()); + NazaraError(error); + throw std::domain_error(error); } #endif @@ -307,10 +317,10 @@ NzVector2 NzVector2::operator/(T scale) const #if NAZARA_MATH_SAFE if (NzNumberEquals(scale, F(0.0))) { - NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; + NzString error("Division by zero"); - throw std::domain_error(ss.ToString()); + NazaraError(error); + throw std::domain_error(error); } #endif @@ -359,10 +369,10 @@ NzVector2& NzVector2::operator/=(const NzVector2& vec) #if NAZARA_MATH_SAFE if (NzNumberEquals(vec.x, F(0.0)) || NzNumberEquals(vec.y, F(0.0)) || NzNumberEquals(vec.z, F(0.0))) { - NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; + NzString error("Division by zero"); - throw std::domain_error(ss.ToString()); + NazaraError(error); + throw std::domain_error(error); } #endif @@ -378,10 +388,10 @@ NzVector2& NzVector2::operator/=(T scale) #if NAZARA_MATH_SAFE if (NzNumberEquals(scale, F(0.0))) { - NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; + NzString error("Division by zero"); - throw std::domain_error(ss.ToString()); + NazaraError(error); + throw std::domain_error(error); } #endif @@ -479,10 +489,10 @@ NzVector2 operator/(T scale, const NzVector2& vec) #if NAZARA_MATH_SAFE if (NzNumberEquals(vec.x, F(0.0)) || NzNumberEquals(vec.y, F(0.0)) || NzNumberEquals(vec.z, F(0.0))) { - NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; + NzString error("Division by zero"); - throw std::domain_error(ss.ToString()); + NazaraError(error); + throw std::domain_error(error); } #endif diff --git a/include/Nazara/Math/Vector3.hpp b/include/Nazara/Math/Vector3.hpp index 8353af6fd..d65b764b9 100644 --- a/include/Nazara/Math/Vector3.hpp +++ b/include/Nazara/Math/Vector3.hpp @@ -13,10 +13,10 @@ template class NzVector3 { public: - NzVector3(); + NzVector3() = default; NzVector3(T X, T Y, T Z); explicit NzVector3(T scale); - NzVector3(T vec[3]); + NzVector3(const T vec[3]); NzVector3(const NzVector2& vec, T Z = 0.0); template explicit NzVector3(const NzVector3& vec); NzVector3(const NzVector3& vec) = default; @@ -36,24 +36,24 @@ template class NzVector3 T Length() const; float Lengthf() const; - void MakeForward(); - void MakeLeft(); - void MakeUnitX(); - void MakeUnitY(); - void MakeUnitZ(); - void MakeUp(); - void MakeZero(); + NzVector3& MakeForward(); + NzVector3& MakeLeft(); + NzVector3& MakeUnitX(); + NzVector3& MakeUnitY(); + NzVector3& MakeUnitZ(); + NzVector3& MakeUp(); + NzVector3& MakeZero(); - void Maximize(const NzVector3& vec); - void Minimize(const NzVector3& vec); + NzVector3& Maximize(const NzVector3& vec); + NzVector3& Minimize(const NzVector3& vec); - void Normalize(); + NzVector3& Normalize(T* length = nullptr); - void Set(T X, T Y, T Z); - void Set(T scale); - void Set(T vec[3]); - void Set(const NzVector2& vec, T Z = 0.0); - template void Set(const NzVector3& vec); + NzVector3& Set(T X, T Y, T Z); + NzVector3& Set(T scale); + NzVector3& Set(const T vec[3]); + NzVector3& Set(const NzVector2& vec, T Z = 0.0); + template NzVector3& Set(const NzVector3& vec); T SquaredDistance(const NzVector3& vec) const; T SquaredLength() const; diff --git a/include/Nazara/Math/Vector3.inl b/include/Nazara/Math/Vector3.inl index 3725d5900..648ebfb1e 100644 --- a/include/Nazara/Math/Vector3.inl +++ b/include/Nazara/Math/Vector3.inl @@ -12,11 +12,6 @@ #define F(a) static_cast(a) -template -NzVector3::NzVector3() -{ -} - template NzVector3::NzVector3(T X, T Y, T Z) { @@ -30,7 +25,7 @@ NzVector3::NzVector3(T scale) } template -NzVector3::NzVector3(T vec[3]) +NzVector3::NzVector3(const T vec[3]) { Set(vec); } @@ -112,49 +107,49 @@ float NzVector3::Lengthf() const } template -void NzVector3::MakeForward() +NzVector3& NzVector3::MakeForward() { Set(F(0.0), F(0.0), F(-1.0)); } template -void NzVector3::MakeLeft() +NzVector3& NzVector3::MakeLeft() { Set(F(-1.0), F(0.0), F(0.0)); } template -void NzVector3::MakeUnitX() +NzVector3& NzVector3::MakeUnitX() { - Set(F(1.0), F(0.0), F(0.0)); + return Set(F(1.0), F(0.0), F(0.0)); } template -void NzVector3::MakeUnitY() +NzVector3& NzVector3::MakeUnitY() { - Set(F(0.0), F(1.0), F(0.0)); + return Set(F(0.0), F(1.0), F(0.0)); } template -void NzVector3::MakeUnitZ() +NzVector3& NzVector3::MakeUnitZ() { - Set(F(0.0), F(0.0), F(1.0)); + return Set(F(0.0), F(0.0), F(1.0)); } template -void NzVector3::MakeUp() +NzVector3& NzVector3::MakeUp() { - Set(F(0.0), F(1.0), F(0.0)); + return Set(F(0.0), F(1.0), F(0.0)); } template -void NzVector3::MakeZero() +NzVector3& NzVector3::MakeZero() { - Set(F(0.0), F(0.0), F(0.0)); + return Set(F(0.0), F(0.0), F(0.0)); } template -void NzVector3::Maximize(const NzVector3& vec) +NzVector3& NzVector3::Maximize(const NzVector3& vec) { if (vec.x > x) x = vec.x; @@ -164,10 +159,12 @@ void NzVector3::Maximize(const NzVector3& vec) if (vec.z > z) z = vec.z; + + return *this; } template -void NzVector3::Minimize(const NzVector3& vec) +NzVector3& NzVector3::Minimize(const NzVector3& vec) { if (vec.x < x) x = vec.x; @@ -177,60 +174,73 @@ void NzVector3::Minimize(const NzVector3& vec) if (vec.z < z) z = vec.z; + + return *this; } template -void NzVector3::Normalize() +NzVector3& NzVector3::Normalize(T* length) { - T squaredLength = SquaredLength(); + T norm = std::sqrt(SquaredLength()); + T invNorm = F(1.0) / norm; - if (!NzNumberEquals(squaredLength, F(1.0))) - { - T invLength = F(1.0) / std::sqrt(squaredLength); + x *= invNorm; + y *= invNorm; + z *= invNorm; - x *= invLength; - y *= invLength; - z *= invLength; - } + if (length) + *length = norm; + + return *this; } template -void NzVector3::Set(T X, T Y, T Z) +NzVector3& NzVector3::Set(T X, T Y, T Z) { x = X; y = Y; z = Z; + + return *this; } template -void NzVector3::Set(T scale) +NzVector3& NzVector3::Set(T scale) { x = scale; y = scale; z = scale; + + return *this; } template -void NzVector3::Set(T vec[3]) +NzVector3& NzVector3::Set(const T vec[3]) { std::memcpy(&x, vec, 3*sizeof(T)); + + return *this; } template -void NzVector3::Set(const NzVector2& vec, T Z) +NzVector3& NzVector3::Set(const NzVector2& vec, T Z) { x = vec.x; y = vec.y; z = Z; + + return *this; } template template -void NzVector3::Set(const NzVector3& vec) +NzVector3& NzVector3::Set(const NzVector3& vec) { x = F(vec.x); y = F(vec.y); z = F(vec.z); + + return *this; } template @@ -278,8 +288,9 @@ T& NzVector3::operator[](unsigned int i) if (i >= 3) { NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Index out of range (" << i << " >= 3)"; + ss << "Index out of range: (" << i << " >= 3)"; + NazaraError(ss); throw std::out_of_range(ss.ToString()); } #endif @@ -294,8 +305,9 @@ T NzVector3::operator[](unsigned int i) const if (i >= 3) { NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Index out of range (" << i << " >= 3)"; + ss << "Index out of range: (" << i << " >= 3)"; + NazaraError(ss); throw std::out_of_range(ss.ToString()); } #endif @@ -345,10 +357,10 @@ NzVector3 NzVector3::operator/(const NzVector3& vec) const #if NAZARA_MATH_SAFE if (NzNumberEquals(vec.x, F(0.0)) || NzNumberEquals(vec.y, F(0.0)) || NzNumberEquals(vec.z, F(0.0))) { - NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; + NzString error("Division by zero"); - throw std::domain_error(ss.ToString()); + NazaraError(error); + throw std::domain_error(error); } #endif @@ -361,10 +373,10 @@ NzVector3 NzVector3::operator/(T scale) const #if NAZARA_MATH_SAFE if (NzNumberEquals(scale, F(0.0))) { - NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; + NzString error("Division by zero"); - throw std::domain_error(ss.ToString()); + NazaraError(error); + throw std::domain_error(error); } #endif @@ -416,10 +428,10 @@ NzVector3& NzVector3::operator/=(const NzVector3& vec) { if (NzNumberEquals(vec.x, F(0.0)) || NzNumberEquals(vec.y, F(0.0)) || NzNumberEquals(vec.z, F(0.0))) { - NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; + NzString error("Division by zero"); - throw std::domain_error(ss.ToString()); + NazaraError(error); + throw std::domain_error(error); } x /= vec.x; @@ -434,10 +446,10 @@ NzVector3& NzVector3::operator/=(T scale) { if (NzNumberEquals(scale, F(0.0))) { - NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; + NzString error("Division by zero"); - throw std::domain_error(ss.ToString()); + NazaraError(error); + throw std::domain_error(error); } x /= scale; @@ -590,10 +602,10 @@ NzVector3 operator/(T scale, const NzVector3& vec) #if NAZARA_MATH_SAFE if (NzNumberEquals(vec.x, F(0.0)) || NzNumberEquals(vec.y, F(0.0)) || NzNumberEquals(vec.z, F(0.0))) { - NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; + NzString error("Division by zero"); - throw std::domain_error(ss.ToString()); + NazaraError(error); + throw std::domain_error(error); } #endif diff --git a/include/Nazara/Math/Vector4.hpp b/include/Nazara/Math/Vector4.hpp index 06b24b558..9daa32507 100644 --- a/include/Nazara/Math/Vector4.hpp +++ b/include/Nazara/Math/Vector4.hpp @@ -13,10 +13,10 @@ template class NzVector4 { public: - NzVector4(); + NzVector4() = default; NzVector4(T X, T Y, T Z, T W = 1.0); explicit NzVector4(T scale); - NzVector4(T vec[4]); + NzVector4(const T vec[4]); NzVector4(const NzVector3& vec, T W = 1.0); template explicit NzVector4(const NzVector4& vec); NzVector4(const NzVector4& vec) = default; @@ -26,21 +26,21 @@ template class NzVector4 T DotProduct(const NzVector4& vec) const; - void MakeUnitX(); - void MakeUnitY(); - void MakeUnitZ(); - void MakeZero(); + NzVector4& MakeUnitX(); + NzVector4& MakeUnitY(); + NzVector4& MakeUnitZ(); + NzVector4& MakeZero(); - void Maximize(const NzVector4& vec); - void Minimize(const NzVector4& vec); + NzVector4& Maximize(const NzVector4& vec); + NzVector4& Minimize(const NzVector4& vec); - void Normalize(); + NzVector4& Normalize(T* length = nullptr); - void Set(T X, T Y, T Z, T W = 1.0); - void Set(T scale); - void Set(T vec[4]); - void Set(const NzVector3& vec, T W = 1.0); - template void Set(const NzVector4& vec); + NzVector4& Set(T X, T Y, T Z, T W = 1.0); + NzVector4& Set(T scale); + NzVector4& Set(const T vec[4]); + NzVector4& Set(const NzVector3& vec, T W = 1.0); + template NzVector4& Set(const NzVector4& vec); NzString ToString() const; diff --git a/include/Nazara/Math/Vector4.inl b/include/Nazara/Math/Vector4.inl index 9d67e56ec..a4617487e 100644 --- a/include/Nazara/Math/Vector4.inl +++ b/include/Nazara/Math/Vector4.inl @@ -13,11 +13,6 @@ #define F(a) static_cast(a) -template -NzVector4::NzVector4() -{ -} - template NzVector4::NzVector4(T X, T Y, T Z, T W) { @@ -31,7 +26,7 @@ NzVector4::NzVector4(T scale) } template -NzVector4::NzVector4(T vec[4]) +NzVector4::NzVector4(const T vec[4]) { Set(vec); } @@ -74,31 +69,31 @@ T NzVector4::DotProduct(const NzVector4& vec) const } template -void NzVector4::MakeUnitX() +NzVector4& NzVector4::MakeUnitX() { - Set(F(1.0), F(0.0), F(0.0), F(1.0)); + return Set(F(1.0), F(0.0), F(0.0), F(1.0)); } template -void NzVector4::MakeUnitY() +NzVector4& NzVector4::MakeUnitY() { - Set(F(0.0), F(1.0), F(0.0), F(1.0)); + return Set(F(0.0), F(1.0), F(0.0), F(1.0)); } template -void NzVector4::MakeUnitZ() +NzVector4& NzVector4::MakeUnitZ() { - Set(F(0.0), F(0.0), F(1.0), F(1.0)); + return Set(F(0.0), F(0.0), F(1.0), F(1.0)); } template -void NzVector4::MakeZero() +NzVector4& NzVector4::MakeZero() { - Set(F(0.0), F(0.0), F(0.0), F(0.0)); + return Set(F(0.0), F(0.0), F(0.0), F(0.0)); } template -void NzVector4::Maximize(const NzVector4& vec) +NzVector4& NzVector4::Maximize(const NzVector4& vec) { if (vec.x > x) x = vec.x; @@ -111,10 +106,12 @@ void NzVector4::Maximize(const NzVector4& vec) if (vec.w > w) w = vec.w; + + return *this; } template -void NzVector4::Minimize(const NzVector4& vec) +NzVector4& NzVector4::Minimize(const NzVector4& vec) { if (vec.x < x) x = vec.x; @@ -127,60 +124,76 @@ void NzVector4::Minimize(const NzVector4& vec) if (vec.w < w) w = vec.w; + + return *this; } template -void NzVector4::Normalize() +NzVector4& NzVector4::Normalize(T* length) { - if (!NzNumberEquals(w, F(0.0))) - { - x /= w; - y /= w; - z /= w; - } + x /= w; + y /= w; + z /= w; + + w = F(1.0); + + if (length) + *length = w; + + return *this; } template -void NzVector4::Set(T X, T Y, T Z, T W) +NzVector4& NzVector4::Set(T X, T Y, T Z, T W) { w = W; x = X; y = Y; z = Z; + + return *this; } template -void NzVector4::Set(T scale) +NzVector4& NzVector4::Set(T scale) { w = scale; x = scale; y = scale; z = scale; + + return *this; } template -void NzVector4::Set(T vec[4]) +NzVector4& NzVector4::Set(const T vec[4]) { std::memcpy(&x, vec, 4*sizeof(T)); + + return *this; } template -void NzVector4::Set(const NzVector3& vec, T W) +NzVector4& NzVector4::Set(const NzVector3& vec, T W) { - w = W; x = vec.x; y = vec.y; z = vec.z; + w = W; + + return *this; } template template -void NzVector4::Set(const NzVector4& vec) +NzVector4& NzVector4::Set(const NzVector4& vec) { w = F(vec.w); x = F(vec.x); y = F(vec.y); z = F(vec.z); + + return *this; } template @@ -216,8 +229,9 @@ T& NzVector4::operator[](unsigned int i) if (i >= 4) { NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Index out of range (" << i << " >= 4)"; + ss << "Index out of range: (" << i << " >= 4)"; + NazaraError(ss); throw std::domain_error(ss.ToString()); } #endif @@ -232,8 +246,9 @@ T NzVector4::operator[](unsigned int i) const if (i >= 4) { NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Index out of range (" << i << " >= 4)"; + ss << "Index out of range: (" << i << " >= 4)"; + NazaraError(ss); throw std::domain_error(ss.ToString()); } #endif @@ -283,10 +298,10 @@ NzVector4 NzVector4::operator/(const NzVector4& vec) const #if NAZARA_MATH_SAFE if (NzNumberEquals(vec.x, F(0.0)) || NzNumberEquals(vec.y, F(0.0)) || NzNumberEquals(vec.z, F(0.0)) || NzNumberEquals(vec.w, F(0.0))) { - NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; + NzString error("Division by zero"); - throw std::domain_error(ss.ToString()); + NazaraError(error); + throw std::domain_error(error); } #endif @@ -299,10 +314,10 @@ NzVector4 NzVector4::operator/(T scale) const #if NAZARA_MATH_SAFE if (NzNumberEquals(scale, F(0.0))) { - NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; + NzString error("Division by zero"); - throw std::domain_error(ss.ToString()); + NazaraError(error); + throw std::domain_error(error); } #endif @@ -359,10 +374,10 @@ NzVector4& NzVector4::operator/=(const NzVector4& vec) #if NAZARA_MATH_SAFE if (NzNumberEquals(vec.x, F(0.0)) || NzNumberEquals(vec.y, F(0.0)) || NzNumberEquals(vec.z, F(0.0)) || NzNumberEquals(vec.w, F(0.0))) { - NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; + NzString error("Division by zero"); - throw std::domain_error(ss.ToString()); + NazaraError(error); + throw std::domain_error(error); } #endif @@ -380,10 +395,10 @@ NzVector4& NzVector4::operator/=(T scale) #if NAZARA_MATH_SAFE if (NzNumberEquals(scale, F(0.0))) { - NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; + NzString error("Division by zero"); - throw std::domain_error(ss.ToString()); + NazaraError(error); + throw std::domain_error(error); } #endif @@ -488,10 +503,10 @@ NzVector4 operator/(T scale, const NzVector4& vec) #if NAZARA_MATH_SAFE if (NzNumberEquals(vec.x, F(0.0)) || NzNumberEquals(vec.y, F(0.0)) || NzNumberEquals(vec.z, F(0.0)) || NzNumberEquals(vec.w, F(0.0))) { - NzStringStream ss; - ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; + NzString error("Division by zero"); - throw std::domain_error(ss.ToString()); + NazaraError(error); + throw std::domain_error(error); } #endif diff --git a/include/Nazara/Noise.hpp b/include/Nazara/Noise.hpp index 4be156c28..2f1c9d2ba 100644 --- a/include/Nazara/Noise.hpp +++ b/include/Nazara/Noise.hpp @@ -26,6 +26,9 @@ #pragma once +#ifndef NAZARA_GLOBAL_NOISE_HPP +#define NAZARA_GLOBAL_NOISE_HPP + #include #include #include @@ -37,3 +40,5 @@ #include #include #include + +#endif // NAZARA_GLOBAL_NOISE_HPP diff --git a/include/Nazara/Renderer.hpp b/include/Nazara/Renderer.hpp index 1b6342e47..eabb1d8a6 100644 --- a/include/Nazara/Renderer.hpp +++ b/include/Nazara/Renderer.hpp @@ -26,9 +26,13 @@ #pragma once +#ifndef NAZARA_GLOBAL_RENDERER_HPP +#define NAZARA_GLOBAL_RENDERER_HPP + #include #include #include +#include #include #include #include @@ -39,3 +43,5 @@ #include #include #include + +#endif // NAZARA_GLOBAL_RENDERER_HPP diff --git a/include/Nazara/Renderer/DebugDrawer.hpp b/include/Nazara/Renderer/DebugDrawer.hpp new file mode 100644 index 000000000..0828f4f2d --- /dev/null +++ b/include/Nazara/Renderer/DebugDrawer.hpp @@ -0,0 +1,44 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_DEBUGDRAWER_HPP +#define NAZARA_DEBUGDRAWER_HPP + +#include +#include +#include +#include + +class NzAxisAlignedBox; +class NzSkeleton; + +class NAZARA_API NzDebugDrawer +{ + public: + static void Draw(const NzAxisAlignedBox& aabb); + static void Draw(const NzCubef& cube); + static void Draw(const NzCubei& cube); + static void Draw(const NzCubeui& cube); + static void Draw(const NzSkeleton* skeleton); + + static bool Initialize(); + + static bool GetDepthTest(); + static float GetLineWidth(); + static float GetPointSize(); + static NzColor GetPrimaryColor(); + static NzColor GetSecondaryColor(); + + static void SetDepthTest(bool shouldTest); + static void SetLineWidth(float width); + static void SetPointSize(float size); + static void SetPrimaryColor(const NzColor& color); + static void SetSecondaryColor(const NzColor& color); + + static void Uninitialize(); +}; + +#endif // NAZARA_DEBUG_DRAWER_HPP diff --git a/include/Nazara/Renderer/OpenGL.hpp b/include/Nazara/Renderer/OpenGL.hpp index b346d3cc0..0a6d354ea 100644 --- a/include/Nazara/Renderer/OpenGL.hpp +++ b/include/Nazara/Renderer/OpenGL.hpp @@ -131,6 +131,8 @@ NAZARA_API extern PFNGLDRAWARRAYSPROC glDrawArrays; NAZARA_API extern PFNGLDRAWBUFFERPROC glDrawBuffer; NAZARA_API extern PFNGLDRAWBUFFERSPROC glDrawBuffers; NAZARA_API extern PFNGLDRAWELEMENTSPROC glDrawElements; +NAZARA_API extern PFNGLENABLEPROC glEnable; +NAZARA_API extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; NAZARA_API extern PFNGLENDQUERYPROC glEndQuery; NAZARA_API extern PFNGLFLUSHPROC glFlush; NAZARA_API extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer; @@ -139,8 +141,6 @@ NAZARA_API extern PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D; NAZARA_API extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; NAZARA_API extern PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D; NAZARA_API extern PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer; -NAZARA_API extern PFNGLENABLEPROC glEnable; -NAZARA_API extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; NAZARA_API extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap; NAZARA_API extern PFNGLGENBUFFERSPROC glGenBuffers; NAZARA_API extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; @@ -148,6 +148,7 @@ NAZARA_API extern PFNGLGENQUERIESPROC glGenQueries; NAZARA_API extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; NAZARA_API extern PFNGLGENTEXTURESPROC glGenTextures; NAZARA_API extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; +NAZARA_API extern PFNGLGETBOOLEANVPROC glGetBooleanv; NAZARA_API extern PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv; NAZARA_API extern PFNGLGETDEBUGMESSAGELOGPROC glGetDebugMessageLog; NAZARA_API extern PFNGLGETERRORPROC glGetError; @@ -169,6 +170,7 @@ NAZARA_API extern PFNGLGETTEXLEVELPARAMETERIVPROC glGetTexLevelParameteriv; NAZARA_API extern PFNGLGETTEXPARAMETERFVPROC glGetTexParameterfv; NAZARA_API extern PFNGLGETTEXPARAMETERIVPROC glGetTexParameteriv; NAZARA_API extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; +NAZARA_API extern PFNGLISENABLEDPROC glIsEnabled; NAZARA_API extern PFNGLLINEWIDTHPROC glLineWidth; NAZARA_API extern PFNGLLINKPROGRAMPROC glLinkProgram; NAZARA_API extern PFNGLMAPBUFFERPROC glMapBuffer; diff --git a/include/Nazara/Renderer/RenderWindow.hpp b/include/Nazara/Renderer/RenderWindow.hpp index 7df1bfb4d..ea3f5501b 100644 --- a/include/Nazara/Renderer/RenderWindow.hpp +++ b/include/Nazara/Renderer/RenderWindow.hpp @@ -29,8 +29,8 @@ class NAZARA_API NzRenderWindow : public NzRenderTarget, public NzWindow NzRenderWindow(NzWindowHandle handle, const NzContextParameters& parameters = NzContextParameters()); virtual ~NzRenderWindow(); - bool CopyToImage(NzImage* image); ///TODO: Const - bool CopyToTexture(NzTexture* texture); ///TODO: Const + bool CopyToImage(NzImage* image) const; + bool CopyToTexture(NzTexture* texture) const; bool Create(NzVideoMode mode, const NzString& title, nzUInt32 style = nzWindowStyle_Default, const NzContextParameters& parameters = NzContextParameters()); bool Create(NzWindowHandle handle, const NzContextParameters& parameters = NzContextParameters()); @@ -61,7 +61,7 @@ class NAZARA_API NzRenderWindow : public NzRenderTarget, public NzWindow NzClock m_clock; NzContextParameters m_parameters; - NzContext* m_context = nullptr; + mutable NzContext* m_context = nullptr; unsigned int m_framerateLimit = 0; }; diff --git a/include/Nazara/Renderer/Renderer.hpp b/include/Nazara/Renderer/Renderer.hpp index 10c4bfc3a..3aada5dfc 100644 --- a/include/Nazara/Renderer/Renderer.hpp +++ b/include/Nazara/Renderer/Renderer.hpp @@ -36,7 +36,7 @@ class NAZARA_API NzRenderer static void Enable(nzRendererParameter parameter, bool enable); - float GetLineWidth(); + static float GetLineWidth(); //static NzMatrix4f GetMatrix(nzMatrixCombination combination); static NzMatrix4f GetMatrix(nzMatrixType type); static unsigned int GetMaxAnisotropyLevel(); @@ -51,6 +51,7 @@ class NAZARA_API NzRenderer static bool Initialize(); + static bool IsEnabled(nzRendererParameter parameter); static bool IsInitialized(); static void SetBlendFunc(nzBlendFunc src, nzBlendFunc dest); @@ -73,7 +74,6 @@ class NAZARA_API NzRenderer static void SetStencilZFailOperation(nzStencilOperation zfailOperation); static bool SetTarget(NzRenderTarget* target); static bool SetVertexBuffer(const NzVertexBuffer* vertexBuffer); - static bool SetVertexDeclaration(const NzVertexDeclaration* vertexDeclaration); static void SetViewport(const NzRectui& viewport); static void Uninitialize(); diff --git a/include/Nazara/Utility.hpp b/include/Nazara/Utility.hpp index c1ee264ef..e9bc08118 100644 --- a/include/Nazara/Utility.hpp +++ b/include/Nazara/Utility.hpp @@ -26,6 +26,9 @@ #pragma once +#ifndef NAZARA_GLOBAL_UTILITY_HPP +#define NAZARA_GLOBAL_UTILITY_HPP + #include #include #include @@ -37,16 +40,25 @@ #include #include #include +#include #include #include #include #include +#include #include +#include +#include +#include #include #include #include +#include #include #include +#include #include #include #include + +#endif // NAZARA_GLOBAL_UTILITY_HPP diff --git a/include/Nazara/Utility/Animation.hpp b/include/Nazara/Utility/Animation.hpp index f39931ec9..81f63a0bb 100644 --- a/include/Nazara/Utility/Animation.hpp +++ b/include/Nazara/Utility/Animation.hpp @@ -12,8 +12,9 @@ #include #include #include +#include -struct NzAnimationParams +struct NAZARA_API NzAnimationParams { unsigned int endFrame = static_cast(-1); unsigned int startFrame = 0; @@ -21,15 +22,8 @@ struct NzAnimationParams bool IsValid() const; }; -struct NzSequence -{ - NzString name; - unsigned int firstFrame; - unsigned int lastFrame; - unsigned int framePerSecond; -}; - class NzAnimation; +class NzSkeleton; using NzAnimationLoader = NzResourceLoader; @@ -44,8 +38,10 @@ class NAZARA_API NzAnimation : public NzResource ~NzAnimation(); bool AddSequence(const NzSequence& sequence); + void AnimateSkeleton(NzSkeleton* targetSkeleton, unsigned int frameA, unsigned int frameB, float interpolation) const; - bool Create(nzAnimationType type, unsigned int frameCount); + bool CreateKeyframe(unsigned int frameCount); + bool CreateSkeletal(unsigned int frameCount, unsigned int jointCount); void Destroy(); unsigned int GetFrameCount() const; @@ -55,6 +51,8 @@ class NAZARA_API NzAnimation : public NzResource const NzSequence* GetSequence(unsigned int index) const; unsigned int GetSequenceCount() const; int GetSequenceIndex(const NzString& sequenceName) const; + NzSequenceJoint* GetSequenceJoints(unsigned int frameIndex = 0); + const NzSequenceJoint* GetSequenceJoints(unsigned int frameIndex = 0) const; nzAnimationType GetType() const; bool HasSequence(const NzString& sequenceName) const; diff --git a/include/Nazara/Utility/AxisAlignedBox.hpp b/include/Nazara/Utility/AxisAlignedBox.hpp index c52573a29..7d1d0dfef 100644 --- a/include/Nazara/Utility/AxisAlignedBox.hpp +++ b/include/Nazara/Utility/AxisAlignedBox.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -20,10 +21,13 @@ class NAZARA_API NzAxisAlignedBox NzAxisAlignedBox(nzExtend extend); bool Contains(const NzAxisAlignedBox& box); + bool Contains(const NzVector3f& vector); void ExtendTo(const NzAxisAlignedBox& box); void ExtendTo(const NzVector3f& vector); + NzVector3f GetCorner(nzCorner corner) const; + NzCubef GetCube() const; nzExtend GetExtend() const; NzVector3f GetMaximum() const; NzVector3f GetMinimum() const; @@ -38,6 +42,8 @@ class NAZARA_API NzAxisAlignedBox NzString ToString() const; + void Transform(const NzMatrix4f& matrix); + operator NzString() const; static NzAxisAlignedBox Lerp(const NzAxisAlignedBox& from, const NzAxisAlignedBox& to, float interpolation); diff --git a/include/Nazara/Utility/Config.hpp b/include/Nazara/Utility/Config.hpp index 2f9e23ffc..a44a52f6a 100644 --- a/include/Nazara/Utility/Config.hpp +++ b/include/Nazara/Utility/Config.hpp @@ -38,8 +38,11 @@ // Active les tests de sécurité basés sur le code (Conseillé pour le développement) #define NAZARA_UTILITY_SAFE 1 +// Lors du parsage d'une ressource, déclenche un avertissement si une erreur non-critique est repérée dans une ressource (Plus lent) +#define NAZARA_UTILITY_STRICT_RESOURCE_PARSING 1 + // Fait tourner chaque fenêtre dans un thread séparé si le système le supporte -#define NAZARA_UTILITY_THREADED_WINDOW 0 ///FIXME: Buggé depuis GCC 4.7 +#define NAZARA_UTILITY_THREADED_WINDOW 0 ///FIXME: Buggé depuis GCC 4.7 avec certains ordinateurs // Protège les classes des accès concurrentiels #define NAZARA_UTILITY_THREADSAFE 1 diff --git a/include/Nazara/Utility/Enums.hpp b/include/Nazara/Utility/Enums.hpp index 39dd17751..d74d34d4b 100644 --- a/include/Nazara/Utility/Enums.hpp +++ b/include/Nazara/Utility/Enums.hpp @@ -51,6 +51,28 @@ enum nzBufferUsage nzBufferUsage_Max = nzBufferUsage_Static }; +enum nzCoordSys +{ + nzCoordSys_Global, + nzCoordSys_Local, + + nzCoordSys_Max = nzCoordSys_Local +}; + +enum nzCorner +{ + nzCorner_FarLeftBottom, + nzCorner_FarLeftTop, + nzCorner_FarRightBottom, + nzCorner_FarRightTop, + nzCorner_NearLeftBottom, + nzCorner_NearLeftTop, + nzCorner_NearRightBottom, + nzCorner_NearRightTop, + + nzCorner_Max = nzCorner_FarRightTop +}; + enum nzCubemapFace { // Cette énumération est prévue pour remplacer l'argument "z" des méthodes de NzImage contenant un cubemap diff --git a/include/Nazara/Utility/Image.hpp b/include/Nazara/Utility/Image.hpp index 5c7411496..25c9a83d7 100644 --- a/include/Nazara/Utility/Image.hpp +++ b/include/Nazara/Utility/Image.hpp @@ -26,7 +26,7 @@ ///TODO: Filtres -struct NzImageParams +struct NAZARA_API NzImageParams { nzPixelFormat loadFormat = nzPixelFormat_Undefined; nzUInt8 levelCount = 0; diff --git a/include/Nazara/Utility/Joint.hpp b/include/Nazara/Utility/Joint.hpp new file mode 100644 index 000000000..7a2e19813 --- /dev/null +++ b/include/Nazara/Utility/Joint.hpp @@ -0,0 +1,38 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_JOINT_HPP +#define NAZARA_JOINT_HPP + +#include +#include +#include +#include + +class NzSkeleton; + +class NAZARA_API NzJoint : public NzNode +{ + public: + NzJoint(NzSkeleton* skeleton); + NzJoint(const NzJoint& joint); + ~NzJoint() = default; + + NzMatrix4f GetInverseBindMatrix() const; + NzString GetName() const; + NzSkeleton* GetSkeleton(); + const NzSkeleton* GetSkeleton() const; + + void SetInverseBindMatrix(const NzMatrix4f& matrix); + void SetName(const NzString& name); + + private: + NzMatrix4f m_inverseBindMatrix; + NzString m_name; + NzSkeleton* m_skeleton; +}; + +#endif // NAZARA_JOINT_HPP diff --git a/include/Nazara/Utility/KeyframeMesh.hpp b/include/Nazara/Utility/KeyframeMesh.hpp index 47988cf1d..e2574cba4 100644 --- a/include/Nazara/Utility/KeyframeMesh.hpp +++ b/include/Nazara/Utility/KeyframeMesh.hpp @@ -8,15 +8,48 @@ #define NAZARA_KEYFRAMEMESH_HPP #include +#include #include -class NzMesh; +struct NzKeyframeMeshImpl; -class NAZARA_API NzKeyframeMesh : public NzSubMesh +class NAZARA_API NzKeyframeMesh final : public NzSubMesh { + friend NzMesh; + public: NzKeyframeMesh(const NzMesh* parent); virtual ~NzKeyframeMesh(); + + bool Create(NzVertexBuffer* vertexBuffer, unsigned int frameCount, bool lock = true); + void Destroy(); + + void Finish(); + + const NzAxisAlignedBox& GetAABB() const override; + nzAnimationType GetAnimationType() const override; + unsigned int GetFrameCount() const; + const NzIndexBuffer* GetIndexBuffer() const override; + bool GetVertex(NzMeshVertex* dest, unsigned int frameIndex, unsigned int vertexIndex, bool queryUV = true) const; + const NzVertexBuffer* GetVertexBuffer() const override; + + void Interpolate(unsigned int frameA, unsigned int frameB, float interpolation); + + bool IsAnimated() const override; + bool IsValid(); + + bool Lock(nzBufferAccess access) const; + + void SetAABB(unsigned int frameIndex, const NzAxisAlignedBox& aabb); + void SetIndexBuffer(const NzIndexBuffer* indexBuffer); + bool SetVertex(const NzMeshVertex& source, unsigned int frameIndex, unsigned int vertexIndex, bool setUV = true); + + void Unlock() const; + + private: + void InterpolateImpl(unsigned int frameA, unsigned int frameB, float interpolation); + + NzKeyframeMeshImpl* m_impl = nullptr; }; #endif // NAZARA_KEYFRAMEMESH_HPP diff --git a/include/Nazara/Utility/Mesh.hpp b/include/Nazara/Utility/Mesh.hpp index 6f101fd38..c6cd4545b 100644 --- a/include/Nazara/Utility/Mesh.hpp +++ b/include/Nazara/Utility/Mesh.hpp @@ -15,22 +15,27 @@ #include #include #include +#include #include +#include class NzVertexDeclaration; -struct NzMeshParams +struct NAZARA_API NzMeshParams { + NzMeshParams(); // Vérifie que le storage indiqué un peu plus bas est supporté + NzAnimationParams animation; - //const NzVertexDeclaration* declaration = nullptr; nzBufferStorage storage = nzBufferStorage_Hardware; - bool loadAnimations = true; + bool animated = true; bool IsValid() const; }; class NzMesh; +typedef NzVertexStruct_XYZ_Normal_UV_Tangent NzMeshVertex; + using NzMeshLoader = NzResourceLoader; struct NzMeshImpl; @@ -43,21 +48,26 @@ class NAZARA_API NzMesh : public NzResource, NzResourceListener NzMesh() = default; ~NzMesh(); - bool AddSkin(const NzString& skin, bool setDefault = false); + bool AddMaterial(const NzString& matPath, unsigned int* matIndex = nullptr); bool AddSubMesh(NzSubMesh* subMesh); bool AddSubMesh(const NzString& identifier, NzSubMesh* subMesh); void Animate(unsigned int frameA, unsigned int frameB, float interpolation); - bool Create(nzAnimationType type); + bool CreateKeyframe(); + bool CreateSkeletal(unsigned int jointCount); + bool CreateStatic(); void Destroy(); const NzAxisAlignedBox& GetAABB() const; const NzAnimation* GetAnimation() const; nzAnimationType GetAnimationType() const; unsigned int GetFrameCount() const; - NzString GetSkin(unsigned int index = 0) const; - unsigned int GetSkinCount() const; + unsigned int GetJointCount() const; + NzString GetMaterial(unsigned int index) const; + unsigned int GetMaterialCount() const; + NzSkeleton* GetSkeleton(); + const NzSkeleton* GetSkeleton() const; NzSubMesh* GetSubMesh(const NzString& identifier); NzSubMesh* GetSubMesh(unsigned int index); const NzSubMesh* GetSubMesh(const NzString& identifier) const; @@ -67,7 +77,7 @@ class NAZARA_API NzMesh : public NzResource, NzResourceListener unsigned int GetVertexCount() const; bool HasAnimation() const; - bool HasSkin(unsigned int index = 0) const; + bool HasMaterial(unsigned int index) const; bool HasSubMesh(const NzString& identifier) const; bool HasSubMesh(unsigned int index = 0) const; @@ -80,11 +90,14 @@ class NAZARA_API NzMesh : public NzResource, NzResourceListener bool LoadFromMemory(const void* data, std::size_t size, const NzMeshParams& params = NzMeshParams()); bool LoadFromStream(NzInputStream& stream, const NzMeshParams& params = NzMeshParams()); - void RemoveSkin(unsigned int index = 0); + void RemoveMaterial(unsigned int index); void RemoveSubMesh(const NzString& identifier); - void RemoveSubMesh(unsigned int index = 0); + void RemoveSubMesh(unsigned int index); bool SetAnimation(const NzAnimation* animation); + void Skin(const NzSkeleton* skeleton); + + static const NzVertexDeclaration* GetDeclaration(); private: void OnResourceCreated(const NzResource* resource, int index) override; diff --git a/include/Nazara/Utility/Node.hpp b/include/Nazara/Utility/Node.hpp new file mode 100644 index 000000000..15733f5f1 --- /dev/null +++ b/include/Nazara/Utility/Node.hpp @@ -0,0 +1,85 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_NODE_HPP +#define NAZARA_NODE_HPP + +#include +#include +#include +#include +#include +#include + +class NAZARA_API NzNode +{ + public: + NzNode(); + NzNode(const NzNode& node); + virtual ~NzNode(); + + NzQuaternionf GetDerivedRotation() const; + NzVector3f GetDerivedScale() const; + NzVector3f GetDerivedTranslation() const; + bool GetInheritRotation() const; + bool GetInheritScale() const; + bool GetInheritTranslation() const; + const NzNode* GetParent() const; + NzQuaternionf GetRotation() const; + NzVector3f GetScale() const; + NzVector3f GetTranslation() const; + NzMatrix4f GetTransformMatrix() const; + + NzNode& Interpolate(const NzNode& nodeA, const NzNode& nodeB, float interpolation); + + NzNode& Rotate(const NzQuaternionf& rotation, nzCoordSys coordSys = nzCoordSys_Local); + + NzNode& Scale(const NzVector3f& scale); + NzNode& Scale(float scale); + NzNode& Scale(float scaleX, float scaleY, float scaleZ); + + NzNode& Translate(const NzVector3f& movement, nzCoordSys coordSys = nzCoordSys_Local); + NzNode& Translate(float movementX, float movementY, float movementZ, nzCoordSys coordSys = nzCoordSys_Local); + + void SetInheritRotation(bool inheritRotation); + void SetInheritScale(bool inheritScale); + void SetInheritTranslation(bool inheritTranslation); + void SetParent(const NzNode* node = nullptr); + void SetParent(const NzNode& node); + void SetRotation(const NzQuaternionf& quat, nzCoordSys coordSys = nzCoordSys_Local); + void SetScale(const NzVector3f& scale, nzCoordSys coordSys = nzCoordSys_Local); + void SetScale(float scale, nzCoordSys coordSys = nzCoordSys_Local); + void SetScale(float scaleX, float scaleY, float scaleZ, nzCoordSys coordSys = nzCoordSys_Local); + void SetTranslation(const NzVector3f& translation, nzCoordSys coordSys = nzCoordSys_Local); + void SetTranslation(float translationX, float translationXY, float translationZ, nzCoordSys coordSys = nzCoordSys_Local); + + NzNode& operator=(const NzNode& node); + + protected: + void AddChild(NzNode* node) const; + void Invalidate(); + void RemoveChild(NzNode* node) const; + void UpdateDerived() const; + virtual void UpdateMatrix() const; + + mutable std::set m_childs; + mutable NzMatrix4f m_transformMatrix; + mutable NzQuaternionf m_derivedRotation; + NzQuaternionf m_rotation; + NzString m_name; + mutable NzVector3f m_derivedTranslation; + mutable NzVector3f m_derivedScale; + NzVector3f m_scale; + NzVector3f m_translation; + const NzNode* m_parent; + mutable bool m_derivedUpdated; + bool m_inheritRotation; + bool m_inheritScale; + bool m_inheritTranslation; + mutable bool m_matrixUpdated; +}; + +#endif // NAZARA_NODE_HPP diff --git a/include/Nazara/Utility/Sequence.hpp b/include/Nazara/Utility/Sequence.hpp new file mode 100644 index 000000000..bf1ca7376 --- /dev/null +++ b/include/Nazara/Utility/Sequence.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SEQUENCE_HPP +#define NAZARA_SEQUENCE_HPP + +#include +#include +#include + +struct NzSequence +{ + NzString name; + unsigned int firstFrame; + unsigned int frameCount; + unsigned int frameRate; +}; + +struct NzSequenceJoint +{ + NzQuaternionf rotation; + NzVector3f scale; + NzVector3f translation; +}; + +#endif // NAZARA_SEQUENCE_HPP diff --git a/include/Nazara/Utility/SkeletalMesh.hpp b/include/Nazara/Utility/SkeletalMesh.hpp new file mode 100644 index 000000000..523e25032 --- /dev/null +++ b/include/Nazara/Utility/SkeletalMesh.hpp @@ -0,0 +1,62 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SKELETALMESH_HPP +#define NAZARA_SKELETALMESH_HPP + +#include +#include +#include + +class NzSkeleton; + +struct NzVertexWeight +{ + std::vector weights; +}; + +struct NzWeight +{ + float weight; + unsigned int jointIndex; +}; + +struct NzSkeletalMeshImpl; + +class NAZARA_API NzSkeletalMesh final : public NzSubMesh +{ + public: + NzSkeletalMesh(const NzMesh* parent); + virtual ~NzSkeletalMesh(); + + bool Create(NzVertexBuffer* vertexBuffer, unsigned int weightCount); + void Destroy(); + + const NzAxisAlignedBox& GetAABB() const; + nzAnimationType GetAnimationType() const final; + void* GetBindPoseBuffer(); + const void* GetBindPoseBuffer() const; + const NzIndexBuffer* GetIndexBuffer() const override; + const NzVertexBuffer* GetVertexBuffer() const override; + NzVertexWeight* GetVertexWeight(unsigned int vertexIndex = 0); + const NzVertexWeight* GetVertexWeight(unsigned int vertexIndex = 0) const; + NzWeight* GetWeight(unsigned int weightIndex = 0); + const NzWeight* GetWeight(unsigned int weightIndex = 0) const; + unsigned int GetWeightCount() const; + + bool IsAnimated() const final; + bool IsValid() const; + + void Skin(); + void Skin(const NzSkeleton* skeleton); + + void SetIndexBuffer(const NzIndexBuffer* indexBuffer); + + private: + NzSkeletalMeshImpl* m_impl = nullptr; +}; + +#endif // NAZARA_SKELETALMESH_HPP diff --git a/include/Nazara/Utility/Skeleton.hpp b/include/Nazara/Utility/Skeleton.hpp new file mode 100644 index 000000000..fe9e82840 --- /dev/null +++ b/include/Nazara/Utility/Skeleton.hpp @@ -0,0 +1,53 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SKELETON_HPP +#define NAZARA_SKELETON_HPP + +#include +#include +#include +#include + +struct NzSkeletonImpl; + +class NAZARA_API NzSkeleton +{ + friend NzJoint; + + public: + NzSkeleton() = default; + NzSkeleton(const NzSkeleton& skeleton); + ~NzSkeleton(); + + bool Create(unsigned int jointCount); + void Destroy(); + + const NzAxisAlignedBox& GetAABB() const; + NzJoint* GetJoint(const NzString& jointName); + NzJoint* GetJoint(unsigned int index); + const NzJoint* GetJoint(const NzString& jointName) const; + const NzJoint* GetJoint(unsigned int index) const; + NzJoint* GetJoints(); + const NzJoint* GetJoints() const; + unsigned int GetJointCount() const; + int GetJointIndex(const NzString& jointName) const; + + void Interpolate(const NzSkeleton& skeletonA, const NzSkeleton& skeletonB, float interpolation); + void Interpolate(const NzSkeleton& skeletonA, const NzSkeleton& skeletonB, float interpolation, unsigned int* indices, unsigned int indiceCount); + + bool IsValid() const; + + NzSkeleton& operator=(const NzSkeleton& skeleton); + + private: + void InvalidateJointMap(); + void UpdateJointMap() const; + + NzSkeletonImpl* m_impl = nullptr; +}; + +#endif // NAZARA_SKELETON_HPP diff --git a/include/Nazara/Utility/StaticMesh.hpp b/include/Nazara/Utility/StaticMesh.hpp index d20c0626b..b6a5e8dd7 100644 --- a/include/Nazara/Utility/StaticMesh.hpp +++ b/include/Nazara/Utility/StaticMesh.hpp @@ -15,37 +15,30 @@ class NAZARA_API NzStaticMesh final : public NzSubMesh, NzResourceListener { public: NzStaticMesh(const NzMesh* parent); - NzStaticMesh(const NzMesh* parent, const NzVertexDeclaration* vertexDeclaration, NzVertexBuffer* vertexBuffer, NzIndexBuffer* indexBuffer = nullptr); virtual ~NzStaticMesh(); - bool Create(const NzVertexDeclaration* vertexDeclaration, NzVertexBuffer* vertexBuffer, NzIndexBuffer* indexBuffer = nullptr); + bool Create(NzVertexBuffer* vertexBuffer); void Destroy(); bool GenerateAABB(); - const NzAxisAlignedBox& GetAABB() const; - nzAnimationType GetAnimationType() const; - unsigned int GetFrameCount() const; - const NzIndexBuffer* GetIndexBuffer() const; - nzPrimitiveType GetPrimitiveType() const; - const NzVertexBuffer* GetVertexBuffer() const; - const NzVertexDeclaration* GetVertexDeclaration() const; + const NzAxisAlignedBox& GetAABB() const override; + nzAnimationType GetAnimationType() const final; + const NzIndexBuffer* GetIndexBuffer() const override; + const NzVertexBuffer* GetVertexBuffer() const override; - bool IsAnimated() const; + bool IsAnimated() const final; bool IsValid() const; void SetAABB(const NzAxisAlignedBox& aabb); - void SetPrimitiveType(nzPrimitiveType primitiveType); + void SetIndexBuffer(const NzIndexBuffer* indexBuffer); private: - void AnimateImpl(unsigned int frameA, unsigned int frameB, float interpolation); void OnResourceReleased(const NzResource* resource, int index) override; - nzPrimitiveType m_primitiveType = nzPrimitiveType_TriangleList; NzAxisAlignedBox m_aabb; - NzIndexBuffer* m_indexBuffer = nullptr; + const NzIndexBuffer* m_indexBuffer = nullptr; NzVertexBuffer* m_vertexBuffer = nullptr; - const NzVertexDeclaration* m_vertexDeclaration = nullptr; }; #endif // NAZARA_STATICMESH_HPP diff --git a/include/Nazara/Utility/SubMesh.hpp b/include/Nazara/Utility/SubMesh.hpp index f1acc4687..31655c9b5 100644 --- a/include/Nazara/Utility/SubMesh.hpp +++ b/include/Nazara/Utility/SubMesh.hpp @@ -19,26 +19,30 @@ class NzMesh; class NAZARA_API NzSubMesh : public NzResource { - friend class NzMesh; + friend NzMesh; public: NzSubMesh(const NzMesh* parent); virtual ~NzSubMesh(); - void Animate(unsigned int frameA, unsigned int frameB, float interpolation); - virtual const NzAxisAlignedBox& GetAABB() const = 0; + virtual nzAnimationType GetAnimationType() const = 0; virtual const NzIndexBuffer* GetIndexBuffer() const = 0; const NzMesh* GetParent() const; - virtual nzPrimitiveType GetPrimitiveType() const = 0; + nzPrimitiveType GetPrimitiveType() const; + unsigned int GetSkinIndex() const; virtual const NzVertexBuffer* GetVertexBuffer() const = 0; - virtual const NzVertexDeclaration* GetVertexDeclaration() const = 0; - unsigned int GetVertexCount() const; + virtual unsigned int GetVertexCount() const; + + virtual bool IsAnimated() const = 0; + + void SetMaterialIndex(unsigned int matIndex); + void SetPrimitiveType(nzPrimitiveType primitiveType); protected: - virtual void AnimateImpl(unsigned int frameA, unsigned int frameB, float interpolation) = 0; - + nzPrimitiveType m_primitiveType = nzPrimitiveType_TriangleList; const NzMesh* m_parent; + unsigned int m_matIndex; }; #endif // NAZARA_SUBMESH_HPP diff --git a/include/Nazara/Utility/VertexBuffer.hpp b/include/Nazara/Utility/VertexBuffer.hpp index 600152f7d..8da31649a 100644 --- a/include/Nazara/Utility/VertexBuffer.hpp +++ b/include/Nazara/Utility/VertexBuffer.hpp @@ -10,12 +10,13 @@ #include #include #include +#include class NAZARA_API NzVertexBuffer : public NzResource { public: - NzVertexBuffer(NzBuffer* buffer, unsigned int startVertex, unsigned int vertexCount); - NzVertexBuffer(unsigned int length, nzUInt8 typeSize, nzBufferStorage storage = nzBufferStorage_Software, nzBufferUsage usage = nzBufferUsage_Static); + NzVertexBuffer(const NzVertexDeclaration* vertexDeclaration, NzBuffer* buffer, unsigned int startVertex, unsigned int vertexCount); + NzVertexBuffer(const NzVertexDeclaration* vertexDeclaration, unsigned int length, nzBufferStorage storage = nzBufferStorage_Software, nzBufferUsage usage = nzBufferUsage_Static); NzVertexBuffer(const NzVertexBuffer& vertexBuffer); ~NzVertexBuffer(); @@ -27,6 +28,7 @@ class NAZARA_API NzVertexBuffer : public NzResource unsigned int GetStartVertex() const; nzUInt8 GetTypeSize() const; unsigned int GetVertexCount() const; + const NzVertexDeclaration* GetVertexDeclaration() const; bool IsHardware() const; @@ -38,6 +40,7 @@ class NAZARA_API NzVertexBuffer : public NzResource private: NzBuffer* m_buffer; + const NzVertexDeclaration* m_vertexDeclaration; bool m_ownsBuffer; unsigned int m_startVertex; unsigned int m_vertexCount; diff --git a/include/Nazara/Utility/VertexStruct.hpp b/include/Nazara/Utility/VertexStruct.hpp new file mode 100644 index 000000000..a57c70601 --- /dev/null +++ b/include/Nazara/Utility/VertexStruct.hpp @@ -0,0 +1,113 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_VERTEXSTRUCT_HPP +#define NAZARA_VERTEXSTRUCT_HPP + +#include +#include + +struct NzVertexStruct_XY +{ + NzVector2f position; +}; + +struct NzVertexStruct_XY_Color : public NzVertexStruct_XY +{ + NzVector3f color; +}; + +///////////////////////////////////////// + +struct NzVertexStruct_XYZ +{ + NzVector3f position; +}; + +struct NzVertexStruct_XYZ_Color : public NzVertexStruct_XYZ +{ + NzVector3f color; +}; + +struct NzVertexStruct_XYZ_Normal : public NzVertexStruct_XYZ +{ + NzVector3f normal; +}; + +struct NzVertexStruct_XYZ_Normal_Color : public NzVertexStruct_XYZ_Normal +{ + NzVector3f color; +}; + +///////////////////////////////////////// + +struct NzVertexStruct_XYZ_UV : public NzVertexStruct_XYZ +{ + NzVector2f uv; +}; + +struct NzVertexStruct_XYZ_UV_Color : public NzVertexStruct_XYZ_UV +{ + NzVector3f color; +}; + +struct NzVertexStruct_XYZ_Normal_UV : public NzVertexStruct_XYZ_Normal +{ + NzVector2f uv; +}; + +struct NzVertexStruct_XYZ_Normal_UV_Color : public NzVertexStruct_XYZ_Normal_UV +{ + NzVector3f color; +}; + +struct NzVertexStruct_XYZ_Normal_UV_Tangent : public NzVertexStruct_XYZ_Normal_UV +{ + NzVector3f tangent; +}; + +struct NzVertexStruct_XYZ_Normal_UV_Tangent_Color : public NzVertexStruct_XYZ_Normal_UV_Tangent +{ + NzVector3f color; +}; + +///////////////////////////////////////// + +struct NzVertexStruct_XYZ_UV_UV2 : public NzVertexStruct_XYZ_UV +{ + NzVector2f uv2; +}; + +struct NzVertexStruct_XYZ_UV_UV2_Color : public NzVertexStruct_XYZ_UV_UV2 +{ + NzVector3f color; +}; + +///////////////////////////////////////// + +struct NzVertexStruct_XYZ_Normal_UV_UV2 : public NzVertexStruct_XYZ_Normal_UV +{ + NzVector2f uv2; +}; + +struct NzVertexStruct_XYZ_Normal_UV_UV2_Color : public NzVertexStruct_XYZ_Normal_UV_UV2 +{ + NzVector3f color; +}; + +struct NzVertexStruct_XYZ_Normal_UV_UV2_Tangent : public NzVertexStruct_XYZ_Normal_UV_UV2 +{ + NzVector3f tangent; +}; + +///////////////////////////////////////// + +struct NzVertexStruct_XYZ_Normal_UV_UV2_Tangent_Color : public NzVertexStruct_XYZ_Normal_UV_UV2_Tangent +{ + NzVector3f color; +}; + +#endif // NAZARA_VERTEXSTRUCT_HPP diff --git a/src/Nazara/Core/File.cpp b/src/Nazara/Core/File.cpp index f4aaec911..06e5cace5 100644 --- a/src/Nazara/Core/File.cpp +++ b/src/Nazara/Core/File.cpp @@ -158,18 +158,11 @@ nzUInt64 NzFile::GetCursorPos() const return m_impl->GetCursorPos(); } -NzString NzFile::GetDirectoryPath() const +NzString NzFile::GetDirectory() const { NazaraLock(m_mutex) - return m_filePath.SubstrTo(NAZARA_DIRECTORY_SEPARATOR, -1, true); -} - -NzString NzFile::GetFilePath() const -{ - NazaraLock(m_mutex) - - return m_filePath; + return m_filePath.SubstrTo(NAZARA_DIRECTORY_SEPARATOR, -1, true, true); } NzString NzFile::GetFileName() const @@ -193,6 +186,13 @@ time_t NzFile::GetLastWriteTime() const return GetLastWriteTime(m_filePath); } +NzString NzFile::GetPath() const +{ + NazaraLock(m_mutex) + + return m_filePath; +} + nzUInt64 NzFile::GetSize() const { NazaraLock(m_mutex) @@ -602,6 +602,11 @@ time_t NzFile::GetCreationTime(const NzString& filePath) return NzFileImpl::GetCreationTime(NormalizePath(filePath)); } +NzString NzFile::GetDirectory(const NzString& filePath) +{ + return filePath.SubstrTo(NAZARA_DIRECTORY_SEPARATOR, -1, true, true); +} + time_t NzFile::GetLastAccessTime(const NzString& filePath) { if (filePath.IsEmpty()) @@ -642,29 +647,25 @@ nzUInt64 NzFile::GetSize(const NzString& filePath) return NzFileImpl::GetSize(NormalizePath(filePath)); } -bool NzFile::IsAbsolute(const NzString& path) +bool NzFile::IsAbsolute(const NzString& filePath) { - NzString wpath(path); - wpath.Trim(); - - if (wpath.IsEmpty()) + NzString path(filePath.Trimmed()); + if (path.IsEmpty()) return false; - #if NAZARA_CORE_NORMALIZE_DIRECTORY_SEPARATORS - wpath = NormalizeSeparators(wpath); - #endif + path = NormalizeSeparators(path); #ifdef NAZARA_PLATFORM_WINDOWS - if (path.Match("?:*")) + if (path.Match("?:*")) // Ex: C:\Hello return true; - else if (path.Match("\\\\*")) + else if (path.Match("\\\\*")) // Ex: \\Laptop return true; - else if (wpath.StartsWith('\\')) // Spécial : '\' fait référence au disque racine + else if (path.StartsWith('\\')) // Spécial : '\' fait référence au disque racine return true; else return false; #elif defined(NAZARA_PLATEFORM_LINUX) - return wpath.StartsWith('/'); + return path.StartsWith('/'); #else #error OS case not implemented #endif @@ -672,12 +673,7 @@ bool NzFile::IsAbsolute(const NzString& path) NzString NzFile::NormalizePath(const NzString& filePath) { - NzString path(filePath); - path.Trim(); - - #if NAZARA_CORE_NORMALIZE_DIRECTORY_SEPARATORS - path = NormalizeSeparators(path); - #endif + NzString path = NormalizeSeparators(filePath.Trimmed()); if (!IsAbsolute(path)) path = NzDirectory::GetCurrent() + NAZARA_DIRECTORY_SEPARATOR + path; diff --git a/src/Nazara/Core/InputStream.cpp b/src/Nazara/Core/InputStream.cpp index 7049a080e..0ce5c916c 100644 --- a/src/Nazara/Core/InputStream.cpp +++ b/src/Nazara/Core/InputStream.cpp @@ -8,7 +8,7 @@ NzInputStream::~NzInputStream() = default; -NzString NzInputStream::GetLine(unsigned int lineSize) +NzString NzInputStream::ReadLine(unsigned int lineSize) { NzString line; if (lineSize == 0) // Taille maximale indéterminée diff --git a/src/Nazara/Core/Log.cpp b/src/Nazara/Core/Log.cpp index 0d36dcb0d..97a8d1ac4 100644 --- a/src/Nazara/Core/Log.cpp +++ b/src/Nazara/Core/Log.cpp @@ -79,7 +79,7 @@ NzString NzLog::GetFile() const NazaraLock(m_mutex) if (m_file) - return m_file->GetFilePath(); + return m_file->GetPath(); else return NzString(); } diff --git a/src/Nazara/Core/Resource.cpp b/src/Nazara/Core/Resource.cpp index 9bbc29b81..1cea4eb37 100644 --- a/src/Nazara/Core/Resource.cpp +++ b/src/Nazara/Core/Resource.cpp @@ -23,9 +23,13 @@ m_resourceReferenceCount(0) NzResource::~NzResource() { EnsureResourceListenerUpdate(); + for (const NzResourceEntry& entry : m_resourceListenersCache) + entry.listener->OnResourceReleased(this, entry.index); - for (auto it = m_resourceListenersCache.begin(); it != m_resourceListenersCache.end(); ++it) - (*it).listener->OnResourceReleased(this, (*it).index); + #if NAZARA_CORE_SAFE + if (m_resourceReferenceCount > 0) + NazaraWarning("Resource destroyed while still referenced " + NzString::Number(m_resourceReferenceCount) + " time(s)"); + #endif } void NzResource::AddResourceListener(NzResourceListener* listener, int index) const @@ -57,14 +61,31 @@ bool NzResource::IsPersistent() const void NzResource::RemoveResourceListener(NzResourceListener* listener) const { - NazaraLock(m_mutex) + NazaraMutexLock(m_mutex); if (m_resourceListeners.erase(listener) != 0) m_resourceListenerUpdated = false; else - NazaraError(NzString::Pointer(listener) + " is not listening to " + NzString::Pointer(this)); + NazaraError(NzString::Pointer(listener) + " is not a listener of " + NzString::Pointer(this)); - RemoveResourceReference(); + // RemoveResourceReference() + #if NAZARA_CORE_SAFE + if (m_resourceReferenceCount == 0) + { + NazaraError("Impossible to remove reference (Ref. counter is already 0)"); + return; + } + #endif + + if (--m_resourceReferenceCount == 0 && !m_resourcePersistent) + { + NazaraMutexUnlock(m_mutex); + delete this; + } + else + { + NazaraMutexUnlock(m_mutex); + } } void NzResource::RemoveResourceReference() const @@ -112,9 +133,8 @@ void NzResource::NotifyCreated() NazaraLock(m_mutex) EnsureResourceListenerUpdate(); - - for (auto it = m_resourceListenersCache.begin(); it != m_resourceListenersCache.end(); ++it) - (*it).listener->OnResourceCreated(this, (*it).index); + for (const NzResourceEntry& entry : m_resourceListenersCache) + entry.listener->OnResourceCreated(this, entry.index); } void NzResource::NotifyDestroy() @@ -122,9 +142,8 @@ void NzResource::NotifyDestroy() NazaraLock(m_mutex) EnsureResourceListenerUpdate(); - - for (auto it = m_resourceListenersCache.begin(); it != m_resourceListenersCache.end(); ++it) - (*it).listener->OnResourceDestroy(this, (*it).index); + for (const NzResourceEntry& entry : m_resourceListenersCache) + entry.listener->OnResourceDestroy(this, entry.index); } void NzResource::EnsureResourceListenerUpdate() const diff --git a/src/Nazara/Core/Stream.cpp b/src/Nazara/Core/Stream.cpp index 37cb56e2f..254e1a865 100644 --- a/src/Nazara/Core/Stream.cpp +++ b/src/Nazara/Core/Stream.cpp @@ -7,6 +7,16 @@ NzStream::~NzStream() = default; +NzString NzStream::GetDirectory() const +{ + return NzString(); +} + +NzString NzStream::GetPath() const +{ + return NzString(); +} + unsigned int NzStream::GetStreamOptions() const { return m_streamOptions; diff --git a/src/Nazara/Core/String.cpp b/src/Nazara/Core/String.cpp index 7e5e26cc4..a7ffa95f4 100644 --- a/src/Nazara/Core/String.cpp +++ b/src/Nazara/Core/String.cpp @@ -3369,7 +3369,7 @@ NzString NzString::Simplified(nzUInt32 flags) const while (++ptr != limit); } - if (!inword) + if (!inword && p != str) p--; *p = '\0'; @@ -4040,7 +4040,7 @@ NzString NzString::Trimmed(char character, nzUInt32 flags) const { for (; endPos > 0; --endPos) { - if (nzToLower(m_sharedString->string[startPos]) != ch) + if (nzToLower(m_sharedString->string[endPos]) != ch) break; } } @@ -4060,7 +4060,7 @@ NzString NzString::Trimmed(char character, nzUInt32 flags) const { for (; endPos > 0; --endPos) { - if (m_sharedString->string[startPos] != character) + if (m_sharedString->string[endPos] != character) break; } } diff --git a/src/Nazara/Core/Win32/SemaphoreImpl.cpp b/src/Nazara/Core/Win32/SemaphoreImpl.cpp index 30af1edb4..f6baf07c9 100644 --- a/src/Nazara/Core/Win32/SemaphoreImpl.cpp +++ b/src/Nazara/Core/Win32/SemaphoreImpl.cpp @@ -11,10 +11,8 @@ NzSemaphoreImpl::NzSemaphoreImpl(unsigned int count) { m_semaphore = CreateSemaphore(nullptr, count, std::numeric_limits::max(), nullptr); - #if NAZARA_CORE_SAFE ///FIXME: Ne peut échouer qu'à cause de mauvais paramètres ? if (!m_semaphore) NazaraError("Failed to create semaphore: " + NzGetLastSystemError()); - #endif } NzSemaphoreImpl::~NzSemaphoreImpl() diff --git a/src/Nazara/Renderer/DebugDrawer.cpp b/src/Nazara/Renderer/DebugDrawer.cpp new file mode 100644 index 000000000..bb7822cb2 --- /dev/null +++ b/src/Nazara/Renderer/DebugDrawer.cpp @@ -0,0 +1,411 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +///TODO: Améliorer + +namespace +{ + static NzColor primaryColor = NzColor::Red; + static NzColor secondaryColor = NzColor::Green; + static NzShader* shader = nullptr; + static NzVertexBuffer* vertexBuffer = nullptr; + static NzVertexDeclaration* vertexDeclaration = nullptr; + static bool depthTest = true; + static bool initialized = false; + static float lineWidth = 2.f; + static float pointSize = 3.f; + static int colorLocation = -1; +} + +void NzDebugDrawer::Draw(const NzAxisAlignedBox& aabb) +{ + if (!aabb.IsFinite()) + return; + + Draw(aabb.GetCube()); +} + +void NzDebugDrawer::Draw(const NzCubei& cube) +{ + Draw(NzCubef(cube)); +} + +void NzDebugDrawer::Draw(const NzCubef& cube) +{ + if (!initialized) + { + NazaraError("Debug drawer is not initialized"); + return; + } + + NzVertexStruct_XYZ* vertex = reinterpret_cast(vertexBuffer->Map(nzBufferAccess_DiscardAndWrite, 0, 24)); + if (!vertex) + { + NazaraError("Failed to map buffer"); + return; + } + + NzVector3f max, min; + max = cube.GetPosition() + cube.GetSize(); + min = cube.GetPosition(); + + vertex->position.Set(min.x, min.y, min.z); + vertex++; + vertex->position.Set(max.x, min.y, min.z); + vertex++; + + vertex->position.Set(min.x, min.y, min.z); + vertex++; + vertex->position.Set(min.x, max.y, min.z); + vertex++; + + vertex->position.Set(min.x, min.y, min.z); + vertex++; + vertex->position.Set(min.x, min.y, max.z); + vertex++; + + vertex->position.Set(max.x, max.y, max.z); + vertex++; + vertex->position.Set(min.x, max.y, max.z); + vertex++; + + vertex->position.Set(max.x, max.y, max.z); + vertex++; + vertex->position.Set(max.x, min.y, max.z); + vertex++; + + vertex->position.Set(max.x, max.y, max.z); + vertex++; + vertex->position.Set(max.x, max.y, min.z); + vertex++; + + vertex->position.Set(min.x, min.y, max.z); + vertex++; + vertex->position.Set(max.x, min.y, max.z); + vertex++; + + vertex->position.Set(min.x, min.y, max.z); + vertex++; + vertex->position.Set(min.x, max.y, max.z); + vertex++; + + vertex->position.Set(min.x, max.y, min.z); + vertex++; + vertex->position.Set(max.x, max.y, min.z); + vertex++; + + vertex->position.Set(min.x, max.y, min.z); + vertex++; + vertex->position.Set(min.x, max.y, max.z); + vertex++; + + vertex->position.Set(max.x, min.y, min.z); + vertex++; + vertex->position.Set(max.x, max.y, min.z); + vertex++; + + vertex->position.Set(max.x, min.y, min.z); + vertex++; + vertex->position.Set(max.x, min.y, max.z); + vertex++; + + if (!vertexBuffer->Unmap()) + NazaraWarning("Failed to unmap buffer"); + + NzShader* oldShader = NzRenderer::GetShader(); + + if (!NzRenderer::SetShader(shader)) + { + NazaraError("Failed to set debug shader"); + return; + } + + bool depthTestActive = NzRenderer::IsEnabled(nzRendererParameter_DepthTest); + if (depthTestActive != depthTest) + NzRenderer::Enable(nzRendererParameter_DepthTest, depthTest); + + NzRenderer::SetVertexBuffer(vertexBuffer); + + shader->SendColor(colorLocation, primaryColor); + + NzRenderer::DrawPrimitives(nzPrimitiveType_LineList, 0, 24); + + if (depthTestActive != depthTest) + NzRenderer::Enable(nzRendererParameter_DepthTest, depthTestActive); + + if (!NzRenderer::SetShader(oldShader)) + NazaraWarning("Failed to reset shader"); +} + +void NzDebugDrawer::Draw(const NzCubeui& cube) +{ + Draw(NzCubef(cube)); +} + +void NzDebugDrawer::Draw(const NzSkeleton* skeleton) +{ + if (!initialized) + { + NazaraError("Debug drawer is not initialized"); + return; + } + + unsigned int jointCount = skeleton->GetJointCount(); + if (vertexBuffer->GetVertexCount() < jointCount*2) + { + NazaraError("Debug buffer not length enougth to draw object"); + return; + } + + NzVertexStruct_XYZ* vertex = reinterpret_cast(vertexBuffer->Map(nzBufferAccess_DiscardAndWrite, 0, jointCount*2)); + if (!vertex) + { + NazaraError("Failed to map buffer"); + return; + } + + unsigned int vertexCount = 0; + for (unsigned int i = 0; i < jointCount; ++i) + { + const NzNode* joint = skeleton->GetJoint(i); + const NzNode* parent = joint->GetParent(); + if (parent) + { + vertex->position = joint->GetDerivedTranslation(); + vertex++; + + vertex->position = parent->GetDerivedTranslation(); + vertex++; + + vertexCount += 2; + } + } + + if (!vertexBuffer->Unmap()) + NazaraWarning("Failed to unmap buffer"); + + if (vertexCount > 0) + { + NzShader* oldShader = NzRenderer::GetShader(); + + if (!NzRenderer::SetShader(shader)) + { + NazaraError("Failed to set debug shader"); + return; + } + + bool depthTestActive = NzRenderer::IsEnabled(nzRendererParameter_DepthTest); + if (depthTestActive != depthTest) + NzRenderer::Enable(nzRendererParameter_DepthTest, depthTest); + + NzRenderer::SetVertexBuffer(vertexBuffer); + + shader->SendColor(colorLocation, primaryColor); + NzRenderer::DrawPrimitives(nzPrimitiveType_LineList, 0, vertexCount); + + float oldPointSize = NzRenderer::GetPointSize(); + NzRenderer::SetPointSize(pointSize); + + shader->SendColor(colorLocation, secondaryColor); + NzRenderer::DrawPrimitives(nzPrimitiveType_PointList, 0, vertexCount); + + NzRenderer::SetPointSize(oldPointSize); + + if (depthTestActive != depthTest) + NzRenderer::Enable(nzRendererParameter_DepthTest, depthTestActive); + + if (!NzRenderer::SetShader(oldShader)) + NazaraWarning("Failed to reset shader"); + } +} + +bool NzDebugDrawer::Initialize() +{ + if (!initialized) + { + // Shader + { + const char* fragmentSource110 = + "#version 110\n" + "uniform vec3 color;\n" + "void main()\n" + "{\n" + " gl_FragColor = vec4(color, 1.0);\n" + "}\n"; + + const char* fragmentSource140 = + "#version 140\n" + "uniform vec3 color;\n" + "out vec4 RenderTarget0;\n" + "void main()\n" + "{\n" + " RenderTarget0 = vec4(color, 1.0);\n" + "}\n"; + + const char* vertexSource110 = + "#version 110\n" + "attribute vec3 Position;\n" + "uniform mat4 WorldViewProjMatrix;\n" + "void main()\n" + "{\n" + " gl_Position = WorldViewProjMatrix * vec4(Position, 1.0);\n" + "}\n"; + + const char* vertexSource140 = + "#version 140\n" + "in vec3 Position;\n" + "uniform mat4 WorldViewProjMatrix;\n" + "void main()\n" + "{\n" + " gl_Position = WorldViewProjMatrix * vec4(Position, 1.0);\n" + "}\n"; + + bool useGLSL140 = (NzOpenGL::GetVersion() >= 310); + + shader = new NzShader(nzShaderLanguage_GLSL); + if (!shader->Load(nzShaderType_Fragment, (useGLSL140) ? fragmentSource140 : fragmentSource110)) + { + NazaraError("Failed to load fragment shader"); + Uninitialize(); + + return false; + } + + if (!shader->Load(nzShaderType_Vertex, (useGLSL140) ? vertexSource140 : vertexSource110)) + { + NazaraError("Failed to load vertex shader"); + Uninitialize(); + + return false; + } + + if (!shader->Compile()) + { + NazaraError("Failed to compile shader"); + Uninitialize(); + + return false; + } + + colorLocation = shader->GetUniformLocation("color"); + } + + // VertexDeclaration + { + NzVertexElement element; + element.offset = 0; + element.type = nzElementType_Float3; + element.usage = nzElementUsage_Position; + + vertexDeclaration = new NzVertexDeclaration; + if (!vertexDeclaration->Create(&element, 1)) + { + NazaraError("Failed to create declaration"); + Uninitialize(); + + return false; + } + } + + // VertexBuffer (Nécessite la déclaration) + { + vertexBuffer = new NzVertexBuffer(vertexDeclaration, 256, nzBufferStorage_Hardware, nzBufferUsage_Dynamic); + if (!vertexBuffer->GetBuffer()->IsValid()) + { + NazaraError("Failed to create buffer"); + Uninitialize(); + + return false; + } + } + + initialized = true; + } + + return true; +} + +bool NzDebugDrawer::GetDepthTest() +{ + return depthTest; +} + +float NzDebugDrawer::GetLineWidth() +{ + return lineWidth; +} + +float NzDebugDrawer::GetPointSize() +{ + return pointSize; +} + +NzColor NzDebugDrawer::GetPrimaryColor() +{ + return primaryColor; +} + +NzColor NzDebugDrawer::GetSecondaryColor() +{ + return secondaryColor; +} + +void NzDebugDrawer::SetDepthTest(bool shouldTest) +{ + depthTest = shouldTest; +} + +void NzDebugDrawer::SetLineWidth(float width) +{ + lineWidth = width; +} + +void NzDebugDrawer::SetPointSize(float size) +{ + pointSize = size; +} + +void NzDebugDrawer::SetPrimaryColor(const NzColor& color) +{ + primaryColor = color; +} + +void NzDebugDrawer::SetSecondaryColor(const NzColor& color) +{ + secondaryColor = color; +} + +void NzDebugDrawer::Uninitialize() +{ + if (shader) + { + delete shader; + shader = nullptr; + } + + if (vertexBuffer) + { + delete vertexBuffer; + vertexBuffer = nullptr; + } + + if (vertexDeclaration) + { + delete vertexDeclaration; + vertexDeclaration = nullptr; + } + + initialized = false; +} diff --git a/src/Nazara/Renderer/GLSLShader.cpp b/src/Nazara/Renderer/GLSLShader.cpp index 34608c57a..79fd60388 100644 --- a/src/Nazara/Renderer/GLSLShader.cpp +++ b/src/Nazara/Renderer/GLSLShader.cpp @@ -23,12 +23,6 @@ m_parent(parent) { } -NzGLSLShader::~NzGLSLShader() -{ - for (auto it = m_textures.begin(); it != m_textures.end(); ++it) - it->second.texture->RemoveResourceListener(this); -} - bool NzGLSLShader::Bind() { #if NAZARA_RENDERER_SAFE @@ -165,11 +159,13 @@ void NzGLSLShader::Destroy() NzContext::EnsureContext(); for (auto it = m_textures.begin(); it != m_textures.end(); ++it) - it->second.texture->RemoveResourceReference(); + it->second.texture->RemoveResourceListener(this); for (GLuint shader : m_shaders) + { if (shader) glDeleteShader(shader); + } if (m_program) glDeleteProgram(m_program); @@ -730,4 +726,6 @@ void NzGLSLShader::OnResourceReleased(const NzResource* resource, int index) { if (m_textures.erase(index) == 0) NazaraInternalError("Texture " + NzString::Pointer(resource) + " not found"); + + resource->RemoveResourceListener(this); } diff --git a/src/Nazara/Renderer/GLSLShader.hpp b/src/Nazara/Renderer/GLSLShader.hpp index 551bc43b7..d816f82f8 100644 --- a/src/Nazara/Renderer/GLSLShader.hpp +++ b/src/Nazara/Renderer/GLSLShader.hpp @@ -20,7 +20,7 @@ class NzGLSLShader : public NzShaderImpl, NzResourceListener { public: NzGLSLShader(NzShader* parent); - ~NzGLSLShader(); + ~NzGLSLShader() = default; bool Bind(); bool BindTextures(); diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index c7486d946..740607d5e 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -253,13 +253,14 @@ namespace NzOpenGL glDrawBuffer = reinterpret_cast(LoadEntry("glDrawBuffer")); glDrawBuffers = reinterpret_cast(LoadEntry("glDrawBuffers")); glDrawElements = reinterpret_cast(LoadEntry("glDrawElements")); - glFlush = reinterpret_cast(LoadEntry("glFlush")); glEnable = reinterpret_cast(LoadEntry("glEnable")); glEnableVertexAttribArray = reinterpret_cast(LoadEntry("glEnableVertexAttribArray")); glEndQuery = reinterpret_cast(LoadEntry("glEndQuery")); + glFlush = reinterpret_cast(LoadEntry("glFlush")); glGenBuffers = reinterpret_cast(LoadEntry("glGenBuffers")); glGenQueries = reinterpret_cast(LoadEntry("glGenQueries")); glGenTextures = reinterpret_cast(LoadEntry("glGenTextures")); + glGetBooleanv = reinterpret_cast(LoadEntry("glGetBooleanv")); glGetBufferParameteriv = reinterpret_cast(LoadEntry("glGetBufferParameteriv")); glGetError = reinterpret_cast(LoadEntry("glGetError")); glGetFloatv = reinterpret_cast(LoadEntry("glGetFloatv")); @@ -278,6 +279,7 @@ namespace NzOpenGL glGetTexParameterfv = reinterpret_cast(LoadEntry("glGetTexParameterfv")); glGetTexParameteriv = reinterpret_cast(LoadEntry("glGetTexParameteriv")); glGetUniformLocation = reinterpret_cast(LoadEntry("glGetUniformLocation")); + glIsEnabled = reinterpret_cast(LoadEntry("glIsEnabled")); glLineWidth = reinterpret_cast(LoadEntry("glLineWidth")); glLinkProgram = reinterpret_cast(LoadEntry("glLinkProgram")); glMapBuffer = reinterpret_cast(LoadEntry("glMapBuffer")); @@ -919,6 +921,8 @@ PFNGLDRAWARRAYSPROC glDrawArrays = nullptr; PFNGLDRAWBUFFERPROC glDrawBuffer = nullptr; PFNGLDRAWBUFFERSPROC glDrawBuffers = nullptr; PFNGLDRAWELEMENTSPROC glDrawElements = nullptr; +PFNGLENABLEPROC glEnable = nullptr; +PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr; PFNGLENDQUERYPROC glEndQuery = nullptr; PFNGLFLUSHPROC glFlush = nullptr; PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = nullptr; @@ -927,8 +931,6 @@ PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D = nullptr; PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = nullptr; PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D = nullptr; PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer = nullptr; -PFNGLENABLEPROC glEnable = nullptr; -PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr; PFNGLGENERATEMIPMAPPROC glGenerateMipmap = nullptr; PFNGLGENBUFFERSPROC glGenBuffers = nullptr; PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = nullptr; @@ -936,6 +938,7 @@ PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = nullptr; PFNGLGENQUERIESPROC glGenQueries = nullptr; PFNGLGENTEXTURESPROC glGenTextures = nullptr; PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr; +PFNGLGETBOOLEANVPROC glGetBooleanv = nullptr; PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv = nullptr; PFNGLGETDEBUGMESSAGELOGPROC glGetDebugMessageLog = nullptr; PFNGLGETERRORPROC glGetError = nullptr; @@ -957,6 +960,7 @@ PFNGLGETTEXLEVELPARAMETERIVPROC glGetTexLevelParameteriv = nullptr; PFNGLGETTEXPARAMETERFVPROC glGetTexParameterfv = nullptr; PFNGLGETTEXPARAMETERIVPROC glGetTexParameteriv = nullptr; PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr; +PFNGLISENABLEDPROC glIsEnabled = nullptr; PFNGLLINEWIDTHPROC glLineWidth = nullptr; PFNGLLINKPROGRAMPROC glLinkProgram = nullptr; PFNGLMAPBUFFERPROC glMapBuffer = nullptr; diff --git a/src/Nazara/Renderer/RenderTexture.cpp b/src/Nazara/Renderer/RenderTexture.cpp index e7b962166..bbf2b5421 100644 --- a/src/Nazara/Renderer/RenderTexture.cpp +++ b/src/Nazara/Renderer/RenderTexture.cpp @@ -725,4 +725,6 @@ void NzRenderTexture::OnResourceDestroy(const NzResource* resource, int index) m_impl->checked = false; m_impl->drawBuffersUpdated = false; } + + resource->RemoveResourceListener(this); } diff --git a/src/Nazara/Renderer/RenderWindow.cpp b/src/Nazara/Renderer/RenderWindow.cpp index 255981c0c..10d09353c 100644 --- a/src/Nazara/Renderer/RenderWindow.cpp +++ b/src/Nazara/Renderer/RenderWindow.cpp @@ -43,7 +43,7 @@ NzRenderWindow::~NzRenderWindow() OnWindowDestroy(); } -bool NzRenderWindow::CopyToImage(NzImage* image) +bool NzRenderWindow::CopyToImage(NzImage* image) const { #if NAZARA_RENDERER_SAFE if (!m_context) @@ -59,10 +59,14 @@ bool NzRenderWindow::CopyToImage(NzImage* image) } #endif - if (!m_context->SetActive(true)) + NzContext* currentContext = NzContext::GetCurrent(); + if (m_context != currentContext) { - NazaraError("Failed to activate context"); - return false; + if (!m_context->SetActive(true)) + { + NazaraError("Failed to activate context"); + return false; + } } NzVector2ui size = GetSize(); @@ -78,10 +82,21 @@ bool NzRenderWindow::CopyToImage(NzImage* image) image->FlipVertically(); + if (m_context != currentContext) + { + if (currentContext) + { + if (!currentContext->SetActive(true)) + NazaraWarning("Failed to reset current context"); + } + else + m_context->SetActive(false); + } + return true; } -bool NzRenderWindow::CopyToTexture(NzTexture* texture) +bool NzRenderWindow::CopyToTexture(NzTexture* texture) const { #if NAZARA_RENDERER_SAFE if (!m_context) @@ -97,10 +112,14 @@ bool NzRenderWindow::CopyToTexture(NzTexture* texture) } #endif - if (!m_context->SetActive(true)) + NzContext* currentContext = NzContext::GetCurrent(); + if (m_context != currentContext) { - NazaraError("Failed to activate context"); - return false; + if (!m_context->SetActive(true)) + { + NazaraError("Failed to activate context"); + return false; + } } NzVector2ui size = GetSize(); @@ -113,6 +132,17 @@ bool NzRenderWindow::CopyToTexture(NzTexture* texture) glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, size.x, size.y); + if (m_context != currentContext) + { + if (currentContext) + { + if (!currentContext->SetActive(true)) + NazaraWarning("Failed to reset current context"); + } + else + m_context->SetActive(false); + } + texture->Unlock(); return true; diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index 1a14cfb57..61278b532 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -102,6 +103,12 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int f NazaraError("No active context"); return; } + + if (primitive > nzPrimitiveType_Max) + { + NazaraError("Primitive type out of enum"); + return; + } #endif #if NAZARA_RENDERER_SAFE @@ -156,6 +163,12 @@ void NzRenderer::DrawPrimitives(nzPrimitiveType primitive, unsigned int firstVer NazaraError("No active context"); return; } + + if (primitive > nzPrimitiveType_Max) + { + NazaraError("Primitive type out of enum"); + return; + } #endif if (!EnsureStateUpdate()) @@ -175,6 +188,12 @@ void NzRenderer::Enable(nzRendererParameter parameter, bool enable) NazaraError("No active context"); return; } + + if (parameter > nzRendererParameter_Max) + { + NazaraError("Renderer parameter out of enum"); + return; + } #endif switch (parameter) @@ -199,6 +218,14 @@ void NzRenderer::Enable(nzRendererParameter parameter, bool enable) float NzRenderer::GetLineWidth() { + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return 0.f; + } + #endif + float lineWidth; glGetFloatv(GL_LINE_WIDTH, &lineWidth); @@ -240,6 +267,14 @@ NzMatrix4f NzRenderer::GetMatrix(nzMatrixCombination combination) */ NzMatrix4f NzRenderer::GetMatrix(nzMatrixType type) { + #ifdef NAZARA_DEBUG + if (type > nzMatrixType_Max) + { + NazaraError("Matrix type out of enum"); + return NzMatrix4f(); + } + #endif + return s_matrix[type]; } @@ -260,6 +295,14 @@ unsigned int NzRenderer::GetMaxTextureUnits() float NzRenderer::GetPointSize() { + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return 0.f; + } + #endif + float pointSize; glGetFloatv(GL_POINT_SIZE, &pointSize); @@ -294,6 +337,14 @@ NzRectui NzRenderer::GetViewport() bool NzRenderer::HasCapability(nzRendererCap capability) { + #ifdef NAZARA_DEBUG + if (capability > nzRendererCap_Max) + { + NazaraError("Renderer capability out of enum"); + return false; + } + #endif + return s_capabilities[capability]; } @@ -393,11 +444,55 @@ bool NzRenderer::Initialize() NzBuffer::SetBufferFunction(nzBufferStorage_Hardware, HardwareBufferFunction); + #ifdef NAZARA_DEBUG + if (!NzDebugDrawer::Initialize()) + NazaraWarning("Failed to initialize debug drawer"); + #endif + NazaraNotice("Initialized: Renderer module"); return true; } +bool NzRenderer::IsEnabled(nzRendererParameter parameter) +{ + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return false; + } + + if (parameter > nzRendererParameter_Max) + { + NazaraError("Renderer parameter out of enum"); + return false; + } + #endif + + switch (parameter) + { + case nzRendererParameter_ColorWrite: + { + GLboolean enabled; + glGetBooleanv(GL_COLOR_WRITEMASK, &enabled); + + return enabled; + } + + case nzRendererParameter_DepthWrite: + { + GLboolean enabled; + glGetBooleanv(GL_DEPTH_WRITEMASK, &enabled); + + return enabled; + } + + default: + return glIsEnabled(NzOpenGL::RendererParameter[parameter]); + } +} + bool NzRenderer::IsInitialized() { return s_moduleReferenceCouter != 0; @@ -515,6 +610,14 @@ bool NzRenderer::SetIndexBuffer(const NzIndexBuffer* indexBuffer) void NzRenderer::SetLineWidth(float width) { + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + #if NAZARA_RENDERER_SAFE if (width <= 0.f) { @@ -528,6 +631,14 @@ void NzRenderer::SetLineWidth(float width) void NzRenderer::SetMatrix(nzMatrixType type, const NzMatrix4f& matrix) { + #ifdef NAZARA_DEBUG + if (type > nzMatrixType_Max) + { + NazaraError("Matrix type out of enum"); + return; + } + #endif + s_matrix[type] = matrix; // Invalidation des combinaisons @@ -545,6 +656,14 @@ void NzRenderer::SetMatrix(nzMatrixType type, const NzMatrix4f& matrix) void NzRenderer::SetPointSize(float size) { + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + #if NAZARA_RENDERER_SAFE if (size <= 0.f) { @@ -593,7 +712,7 @@ bool NzRenderer::SetShader(NzShader* shader) s_matrixLocation[nzMatrixCombination_WorldView] = shader->GetUniformLocation("WorldViewMatrix"); s_matrixLocation[nzMatrixCombination_WorldViewProj] = shader->GetUniformLocation("WorldViewProjMatrix"); - ///FIXME: Peut VRAIMENT être optimisé + ///FIXME: Peut être optimisé for (unsigned int i = 0; i < totalMatrixCount; ++i) s_matrixUpdated[i] = false; } @@ -605,6 +724,14 @@ bool NzRenderer::SetShader(NzShader* shader) void NzRenderer::SetStencilCompareFunction(nzRendererComparison compareFunc) { + #ifdef NAZARA_DEBUG + if (compareFunc > nzRendererComparison_Max) + { + NazaraError("Renderer comparison out of enum"); + return; + } + #endif + if (compareFunc != s_stencilCompare) { s_stencilCompare = compareFunc; @@ -614,6 +741,14 @@ void NzRenderer::SetStencilCompareFunction(nzRendererComparison compareFunc) void NzRenderer::SetStencilFailOperation(nzStencilOperation failOperation) { + #ifdef NAZARA_DEBUG + if (failOperation > nzStencilOperation_Max) + { + NazaraError("Stencil fail operation out of enum"); + return; + } + #endif + if (failOperation != s_stencilFail) { s_stencilFail = failOperation; @@ -632,6 +767,14 @@ void NzRenderer::SetStencilMask(nzUInt32 mask) void NzRenderer::SetStencilPassOperation(nzStencilOperation passOperation) { + #ifdef NAZARA_DEBUG + if (passOperation > nzStencilOperation_Max) + { + NazaraError("Stencil pass operation out of enum"); + return; + } + #endif + if (passOperation != s_stencilPass) { s_stencilPass = passOperation; @@ -650,6 +793,14 @@ void NzRenderer::SetStencilReferenceValue(unsigned int refValue) void NzRenderer::SetStencilZFailOperation(nzStencilOperation zfailOperation) { + #ifdef NAZARA_DEBUG + if (zfailOperation > nzStencilOperation_Max) + { + NazaraError("Stencil zfail operation out of enum"); + return; + } + #endif + if (zfailOperation != s_stencilZFail) { s_stencilZFail = zfailOperation; @@ -705,17 +856,11 @@ bool NzRenderer::SetVertexBuffer(const NzVertexBuffer* vertexBuffer) if (s_vertexBuffer != vertexBuffer) { s_vertexBuffer = vertexBuffer; - s_vaoUpdated = false; - } - return true; -} + const NzVertexDeclaration* vertexDeclaration = s_vertexBuffer->GetVertexDeclaration(); + if (s_vertexDeclaration != vertexDeclaration) + s_vertexDeclaration = vertexDeclaration; -bool NzRenderer::SetVertexDeclaration(const NzVertexDeclaration* vertexDeclaration) -{ - if (s_vertexDeclaration != vertexDeclaration) - { - s_vertexDeclaration = vertexDeclaration; s_vaoUpdated = false; } @@ -758,6 +903,10 @@ void NzRenderer::Uninitialize() if (--s_moduleReferenceCouter != 0) return; // Encore utilisé + #ifdef NAZARA_DEBUG + NzDebugDrawer::Uninitialize(); + #endif + // Libération du module NzContext::EnsureContext(); @@ -812,7 +961,8 @@ bool NzRenderer::EnsureStateUpdate() // Cas spéciaux car il faut recalculer la matrice if (!s_matrixUpdated[nzMatrixCombination_ViewProj]) { - s_matrix[nzMatrixCombination_ViewProj] = s_matrix[nzMatrixType_View] * s_matrix[nzMatrixType_Projection]; + s_matrix[nzMatrixCombination_ViewProj] = s_matrix[nzMatrixType_View]; + s_matrix[nzMatrixCombination_ViewProj].Concatenate(s_matrix[nzMatrixType_Projection]); shaderImpl->SendMatrix(s_matrixLocation[nzMatrixCombination_ViewProj], s_matrix[nzMatrixCombination_ViewProj]); s_matrixUpdated[nzMatrixCombination_ViewProj] = true; @@ -820,7 +970,8 @@ bool NzRenderer::EnsureStateUpdate() if (!s_matrixUpdated[nzMatrixCombination_WorldView]) { - s_matrix[nzMatrixCombination_WorldView] = NzMatrix4f::ConcatenateAffine(s_matrix[nzMatrixType_World], s_matrix[nzMatrixType_View]); + s_matrix[nzMatrixCombination_WorldView] = s_matrix[nzMatrixType_World]; + s_matrix[nzMatrixCombination_WorldView].ConcatenateAffine(s_matrix[nzMatrixType_View]); shaderImpl->SendMatrix(s_matrixLocation[nzMatrixCombination_WorldView], s_matrix[nzMatrixCombination_WorldView]); s_matrixUpdated[nzMatrixCombination_WorldView] = true; @@ -828,7 +979,8 @@ bool NzRenderer::EnsureStateUpdate() if (!s_matrixUpdated[nzMatrixCombination_WorldViewProj]) { - s_matrix[nzMatrixCombination_WorldViewProj] = s_matrix[nzMatrixCombination_WorldView] * s_matrix[nzMatrixType_Projection]; + s_matrix[nzMatrixCombination_WorldViewProj] = s_matrix[nzMatrixCombination_WorldView]; + s_matrix[nzMatrixCombination_WorldViewProj].Concatenate(s_matrix[nzMatrixType_Projection]); shaderImpl->SendMatrix(s_matrixLocation[nzMatrixCombination_WorldViewProj], s_matrix[nzMatrixCombination_WorldViewProj]); s_matrixUpdated[nzMatrixCombination_WorldViewProj] = true; diff --git a/src/Nazara/Renderer/Texture.cpp b/src/Nazara/Renderer/Texture.cpp index 786faa070..ba3210e1e 100644 --- a/src/Nazara/Renderer/Texture.cpp +++ b/src/Nazara/Renderer/Texture.cpp @@ -1382,7 +1382,6 @@ bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRe glTexSubImage2D(NzOpenGL::CubemapFace[face], level, rect.x, height-rect.height-rect.y, rect.width, rect.height, format.dataFormat, format.dataType, mirrored); UnlockTexture(m_impl); - return true; } @@ -1480,7 +1479,8 @@ bool NzTexture::IsFormatSupported(nzPixelFormat format) case nzPixelFormat_Stencil16: return false; - // Dépréciés depuis OpenGL 3 (FIXME: Il doit bien exister des remplaçants ..) + // Dépréciés depuis OpenGL 3 + ///FIXME: Il doit bien exister des remplaçants .. case nzPixelFormat_L8: case nzPixelFormat_LA8: return false; diff --git a/src/Nazara/Utility/Animation.cpp b/src/Nazara/Utility/Animation.cpp index d38a38e23..cf38fa09d 100644 --- a/src/Nazara/Utility/Animation.cpp +++ b/src/Nazara/Utility/Animation.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -13,15 +14,17 @@ struct NzAnimationImpl { std::map sequenceMap; std::vector sequences; + std::vector sequenceJoints; // Uniquement pour les animations squelettiques nzAnimationType type; unsigned int frameCount; + unsigned int jointCount; // Uniquement pour les animations squelettiques }; bool NzAnimationParams::IsValid() const { if (startFrame > endFrame) { - NazaraError("Start frame must be lower than end frame"); + NazaraError("Start frame index must be smaller than end frame index"); return false; } @@ -41,9 +44,34 @@ bool NzAnimation::AddSequence(const NzSequence& sequence) NazaraError("Animation not created"); return false; } + + if (sequence.frameCount == 0) + { + NazaraError("Sequence frame count must be over 0"); + return false; + } #endif - unsigned int index = m_impl->sequences.size(); + if (m_impl->type == nzAnimationType_Skeletal) + { + unsigned int endFrame = sequence.firstFrame + sequence.frameCount - 1; + if (endFrame >= m_impl->frameCount) + { + m_impl->frameCount = endFrame+1; + m_impl->sequenceJoints.resize(m_impl->frameCount*m_impl->jointCount); + } + } + #if NAZARA_UTILITY_SAFE + else + { + unsigned int endFrame = sequence.firstFrame + sequence.frameCount - 1; + if (endFrame >= m_impl->frameCount) + { + NazaraError("Sequence end frame is over animation end frame"); + return false; + } + } + #endif if (!sequence.name.IsEmpty()) { @@ -56,7 +84,7 @@ bool NzAnimation::AddSequence(const NzSequence& sequence) } #endif - m_impl->sequenceMap[sequence.name] = index; + m_impl->sequenceMap[sequence.name] = m_impl->sequences.size(); } m_impl->sequences.push_back(sequence); @@ -64,17 +92,72 @@ bool NzAnimation::AddSequence(const NzSequence& sequence) return true; } -bool NzAnimation::Create(nzAnimationType type, unsigned int frameCount) +void NzAnimation::AnimateSkeleton(NzSkeleton* targetSkeleton, unsigned int frameA, unsigned int frameB, float interpolation) const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Animation not created"); + return; + } + + if (m_impl->type != nzAnimationType_Skeletal) + { + NazaraError("Animation is not skeletal"); + return; + } + + if (!targetSkeleton || !targetSkeleton->IsValid()) + { + NazaraError("Target skeleton is invalid"); + return; + } + + if (targetSkeleton->GetJointCount() != m_impl->jointCount) + { + NazaraError("Target skeleton joint count must match animation joint count"); + return; + } + + if (frameA >= m_impl->frameCount) + { + NazaraError("Frame A is out of range (" + NzString::Number(frameA) + " >= " + NzString::Number(m_impl->frameCount) + ')'); + return; + } + + if (frameB >= m_impl->frameCount) + { + NazaraError("Frame B is out of range (" + NzString::Number(frameB) + " >= " + NzString::Number(m_impl->frameCount) + ')'); + return; + } + #endif + + #ifdef NAZARA_DEBUG + if (interpolation < 0.f || interpolation > 1.f) + { + NazaraError("Interpolation must be in range [0..1] (Got " + NzString::Number(interpolation) + ')'); + return; + } + #endif + + for (unsigned int i = 0; i < m_impl->jointCount; ++i) + { + NzJoint* joint = targetSkeleton->GetJoint(i); + + NzSequenceJoint& sequenceJointA = m_impl->sequenceJoints[frameA*m_impl->jointCount + i]; + NzSequenceJoint& sequenceJointB = m_impl->sequenceJoints[frameB*m_impl->jointCount + i]; + + joint->SetRotation(NzQuaternionf::Slerp(sequenceJointA.rotation, sequenceJointB.rotation, interpolation)); + joint->SetScale(NzVector3f::Lerp(sequenceJointA.scale, sequenceJointB.scale, interpolation)); + joint->SetTranslation(NzVector3f::Lerp(sequenceJointA.translation, sequenceJointB.translation, interpolation)); + } +} + +bool NzAnimation::CreateKeyframe(unsigned int frameCount) { Destroy(); #if NAZARA_UTILITY_SAFE - if (type == nzAnimationType_Static) - { - NazaraError("Invalid type"); - return false; - } - if (frameCount == 0) { NazaraError("Frame count must be over zero"); @@ -84,7 +167,29 @@ bool NzAnimation::Create(nzAnimationType type, unsigned int frameCount) m_impl = new NzAnimationImpl; m_impl->frameCount = frameCount; - m_impl->type = type; + m_impl->type = nzAnimationType_Keyframe; + + NotifyCreated(); + return true; +} + +bool NzAnimation::CreateSkeletal(unsigned int frameCount, unsigned int jointCount) +{ + Destroy(); + + #if NAZARA_UTILITY_SAFE + if (frameCount == 0) + { + NazaraError("Frame count must be over zero"); + return false; + } + #endif + + m_impl = new NzAnimationImpl; + m_impl->frameCount = frameCount; + m_impl->jointCount = jointCount; + m_impl->sequenceJoints.resize(frameCount*jointCount); + m_impl->type = nzAnimationType_Skeletal; NotifyCreated(); return true; @@ -122,18 +227,19 @@ NzSequence* NzAnimation::GetSequence(const NzString& sequenceName) NazaraError("Animation not created"); return nullptr; } + #endif auto it = m_impl->sequenceMap.find(sequenceName); + + #if NAZARA_UTILITY_SAFE if (it == m_impl->sequenceMap.end()) { NazaraError("Sequence not found"); return nullptr; } + #endif return &m_impl->sequences[it->second]; - #else - return &m_impl->sequences[m_impl->sequenceMap[sequenceName]]; - #endif } NzSequence* NzAnimation::GetSequence(unsigned int index) @@ -163,18 +269,19 @@ const NzSequence* NzAnimation::GetSequence(const NzString& sequenceName) const NazaraError("Animation not created"); return nullptr; } + #endif auto it = m_impl->sequenceMap.find(sequenceName); + + #if NAZARA_UTILITY_SAFE if (it == m_impl->sequenceMap.end()) { NazaraError("Sequence not found"); return nullptr; } + #endif return &m_impl->sequences[it->second]; - #else - return &m_impl->sequences[m_impl->sequenceMap[sequenceName]]; - #endif } const NzSequence* NzAnimation::GetSequence(unsigned int index) const @@ -217,18 +324,57 @@ int NzAnimation::GetSequenceIndex(const NzString& sequenceName) const NazaraError("Animation not created"); return -1; } + #endif auto it = m_impl->sequenceMap.find(sequenceName); + + #if NAZARA_UTILITY_SAFE if (it == m_impl->sequenceMap.end()) { NazaraError("Sequence not found"); return -1; } + #endif return it->second; - #else - return m_impl->sequenceMap[sequenceName]; +} + +NzSequenceJoint* NzAnimation::GetSequenceJoints(unsigned int frameIndex) +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Animation not created"); + return nullptr; + } + + if (m_impl->type != nzAnimationType_Skeletal) + { + NazaraError("Animation is not skeletal"); + return nullptr; + } #endif + + return &m_impl->sequenceJoints[frameIndex*m_impl->jointCount]; +} + +const NzSequenceJoint* NzAnimation::GetSequenceJoints(unsigned int frameIndex) const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Animation not created"); + return nullptr; + } + + if (m_impl->type != nzAnimationType_Skeletal) + { + NazaraError("Animation is not skeletal"); + return nullptr; + } + #endif + + return &m_impl->sequenceJoints[frameIndex*m_impl->jointCount]; } nzAnimationType NzAnimation::GetType() const diff --git a/src/Nazara/Utility/AxisAlignedBox.cpp b/src/Nazara/Utility/AxisAlignedBox.cpp index a481fb703..339e178e5 100644 --- a/src/Nazara/Utility/AxisAlignedBox.cpp +++ b/src/Nazara/Utility/AxisAlignedBox.cpp @@ -38,6 +38,24 @@ bool NzAxisAlignedBox::Contains(const NzAxisAlignedBox& box) return m_cube.Contains(box.m_cube); } +bool NzAxisAlignedBox::Contains(const NzVector3f& vector) +{ + switch (m_extend) + { + case nzExtend_Finite: + return m_cube.Contains(vector); + + case nzExtend_Infinite: + return true; + + case nzExtend_Null: + return false; + } + + NazaraError("Extend type not handled (0x" + NzString::Number(m_extend, 16) + ')'); + return false; +} + void NzAxisAlignedBox::ExtendTo(const NzAxisAlignedBox& box) { switch (m_extend) @@ -81,17 +99,50 @@ void NzAxisAlignedBox::ExtendTo(const NzVector3f& vector) break; case nzExtend_Null: - // Nous étendons l'AABB en la construisant de l'origine jusqu'au vecteur - m_cube.x = 0.f; - m_cube.y = 0.f; - m_cube.z = 0.f; - m_cube.width = std::fabs(vector.x); - m_cube.height = std::fabs(vector.y); - m_cube.depth = std::fabs(vector.z); + m_extend = nzExtend_Finite; + m_cube.Set(vector, vector); break; } } +NzVector3f NzAxisAlignedBox::GetCorner(nzCorner corner) const +{ + switch (corner) + { + case nzCorner_FarLeftBottom: + return NzVector3f(m_cube.x, m_cube.y, m_cube.z); + + case nzCorner_FarLeftTop: + return NzVector3f(m_cube.x, m_cube.y+m_cube.height, m_cube.z); + + case nzCorner_FarRightBottom: + return NzVector3f(m_cube.x+m_cube.width, m_cube.y, m_cube.z); + + case nzCorner_FarRightTop: + return NzVector3f(m_cube.x+m_cube.width, m_cube.y+m_cube.height, m_cube.z); + + case nzCorner_NearLeftBottom: + return NzVector3f(m_cube.x, m_cube.y, m_cube.z+m_cube.depth); + + case nzCorner_NearLeftTop: + return NzVector3f(m_cube.x, m_cube.y+m_cube.height, m_cube.z+m_cube.depth); + + case nzCorner_NearRightBottom: + return NzVector3f(m_cube.x+m_cube.width, m_cube.y, m_cube.z+m_cube.depth); + + case nzCorner_NearRightTop: + return NzVector3f(m_cube.x+m_cube.width, m_cube.y+m_cube.height, m_cube.z+m_cube.depth); + } + + NazaraError("Corner not handled (0x" + NzString::Number(corner, 16) + ')'); + return NzVector3f(); +} + +NzCubef NzAxisAlignedBox::GetCube() const +{ + return m_cube; +} + nzExtend NzAxisAlignedBox::GetExtend() const { return m_extend; @@ -99,12 +150,12 @@ nzExtend NzAxisAlignedBox::GetExtend() const NzVector3f NzAxisAlignedBox::GetMaximum() const { - return NzVector3f(m_cube.x+m_cube.width, m_cube.y+m_cube.height, m_cube.z+m_cube.depth); + return m_cube.GetPosition() + m_cube.GetSize(); } NzVector3f NzAxisAlignedBox::GetMinimum() const { - return NzVector3f(m_cube.x, m_cube.y, m_cube.z); + return m_cube.GetPosition(); } bool NzAxisAlignedBox::IsFinite() const @@ -155,6 +206,22 @@ NzString NzAxisAlignedBox::ToString() const return "NzAxisAlignedBox(ERROR)"; } +void NzAxisAlignedBox::Transform(const NzMatrix4f& matrix) +{ + if (m_extend != nzExtend_Finite) + return; + + NzVector3f center = matrix.Transform(m_cube.GetCenter(), 0.f); // 0.f pour annuler la translation + NzVector3f halfSize = m_cube.GetSize() * 0.5f; + + 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, + std::fabs(matrix(0,2))*halfSize.x + std::fabs(matrix(1,2))*halfSize.y + std::fabs(matrix(2,2))*halfSize.z); + + + m_cube.Set(center - halfSize, center + halfSize); +} + NzAxisAlignedBox::operator NzString() const { return ToString(); diff --git a/src/Nazara/Utility/Buffer.cpp b/src/Nazara/Utility/Buffer.cpp index 728d4be45..0a73f9619 100644 --- a/src/Nazara/Utility/Buffer.cpp +++ b/src/Nazara/Utility/Buffer.cpp @@ -88,26 +88,23 @@ bool NzBuffer::Create(unsigned int length, nzUInt8 typeSize, nzBufferStorage sto { Destroy(); - // On tente d'abord de faire un buffer hardware, si supporté - if (s_bufferFunctions[storage]) - { - NzBufferImpl* impl = s_bufferFunctions[storage](this, m_type); - if (!impl->Create(length*typeSize, usage)) - { - NazaraError("Failed to create buffer"); - delete impl; - - return false; - } - - m_impl = impl; - } - else + // Notre buffer est-il supporté ? + if (!s_bufferFunctions[storage]) { NazaraError("Buffer storage not supported"); return false; } + NzBufferImpl* impl = s_bufferFunctions[storage](this, m_type); + if (!impl->Create(length*typeSize, usage)) + { + NazaraError("Failed to create buffer"); + delete impl; + + return false; + } + + m_impl = impl; m_length = length; m_typeSize = typeSize; m_storage = storage; diff --git a/src/Nazara/Utility/Cursor.cpp b/src/Nazara/Utility/Cursor.cpp index 3f8e17873..c1bf020e7 100644 --- a/src/Nazara/Utility/Cursor.cpp +++ b/src/Nazara/Utility/Cursor.cpp @@ -34,6 +34,7 @@ bool NzCursor::Create(const NzImage& cursor, int hotSpotX, int hotSpotY) NazaraError("Failed to create cursor implementation"); delete m_impl; m_impl = nullptr; + return false; } @@ -50,6 +51,7 @@ void NzCursor::Destroy() if (m_impl) { m_impl->Destroy(); + delete m_impl; m_impl = nullptr; } diff --git a/src/Nazara/Utility/Icon.cpp b/src/Nazara/Utility/Icon.cpp index f16506467..e0e160d91 100644 --- a/src/Nazara/Utility/Icon.cpp +++ b/src/Nazara/Utility/Icon.cpp @@ -34,6 +34,7 @@ bool NzIcon::Create(const NzImage& icon) NazaraError("Failed to create icon implementation"); delete m_impl; m_impl = nullptr; + return false; } @@ -45,6 +46,7 @@ void NzIcon::Destroy() if (m_impl) { m_impl->Destroy(); + delete m_impl; m_impl = nullptr; } diff --git a/src/Nazara/Utility/Joint.cpp b/src/Nazara/Utility/Joint.cpp new file mode 100644 index 000000000..d3354db0e --- /dev/null +++ b/src/Nazara/Utility/Joint.cpp @@ -0,0 +1,52 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +NzJoint::NzJoint(NzSkeleton* skeleton) : +m_skeleton(skeleton) +{ +} + +NzJoint::NzJoint(const NzJoint& joint) : +NzNode(joint), +m_inverseBindMatrix(joint.m_inverseBindMatrix), +m_name(joint.m_name), +m_skeleton(joint.m_skeleton) +{ +} + +NzMatrix4f NzJoint::GetInverseBindMatrix() const +{ + return m_inverseBindMatrix; +} + +NzString NzJoint::GetName() const +{ + return m_name; +} + +NzSkeleton* NzJoint::GetSkeleton() +{ + return m_skeleton; +} + +const NzSkeleton* NzJoint::GetSkeleton() const +{ + return m_skeleton; +} + +void NzJoint::SetInverseBindMatrix(const NzMatrix4f& matrix) +{ + m_inverseBindMatrix = matrix; +} + +void NzJoint::SetName(const NzString& name) +{ + m_name = name; + + m_skeleton->InvalidateJointMap(); +} diff --git a/src/Nazara/Utility/KeyframeMesh.cpp b/src/Nazara/Utility/KeyframeMesh.cpp index fa9ee4e04..b3459261a 100644 --- a/src/Nazara/Utility/KeyframeMesh.cpp +++ b/src/Nazara/Utility/KeyframeMesh.cpp @@ -3,11 +3,456 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include +#include +#include #include +struct NzKeyframeMeshImpl +{ + nzBufferAccess lockAccess; + NzAxisAlignedBox* aabb; + NzMeshVertex* lockBuffer; + NzVector3f* normals; + NzVector3f* positions; + NzVector3f* tangents; + const NzIndexBuffer* indexBuffer = nullptr; + NzVertexBuffer* vertexBuffer; + unsigned int frameCount; + unsigned int lockLevel = 0; +}; + NzKeyframeMesh::NzKeyframeMesh(const NzMesh* parent) : NzSubMesh(parent) { } -NzKeyframeMesh::~NzKeyframeMesh() = default; +NzKeyframeMesh::~NzKeyframeMesh() +{ + Destroy(); +} + +bool NzKeyframeMesh::Create(NzVertexBuffer* vertexBuffer, unsigned int frameCount, bool lock) +{ + Destroy(); + + #if NAZARA_UTILITY_SAFE + if (!vertexBuffer) + { + NazaraError("Invalid vertex buffer"); + return false; + } + + if (vertexBuffer->GetTypeSize() < sizeof(NzMeshVertex)) + { + NazaraError("Vertex buffer type size must be greater or equal than size of mesh vertex"); + return false; + } + + if (frameCount == 0) + { + NazaraError("Frame count must be over 0"); + return false; + } + #endif + + vertexBuffer->AddResourceReference(); + + m_impl = new NzKeyframeMeshImpl; + m_impl->aabb = new NzAxisAlignedBox[frameCount+1]; // La première case représente l'AABB interpolée + m_impl->frameCount = frameCount; + m_impl->vertexBuffer = vertexBuffer; + + unsigned int vertexCount = vertexBuffer->GetVertexCount(); + + m_impl->positions = new NzVector3f[frameCount*vertexCount]; + m_impl->normals = new NzVector3f[frameCount*vertexCount]; + m_impl->tangents = new NzVector3f[frameCount*vertexCount]; + + if (lock && !Lock(nzBufferAccess_DiscardAndWrite)) + { + NazaraError("Failed to lock buffer"); + Destroy(); + + return false; + } + + NotifyCreated(); + return true; +} + +void NzKeyframeMesh::Destroy() +{ + if (m_impl) + { + NotifyDestroy(); + + if (m_impl->indexBuffer) + m_impl->indexBuffer->RemoveResourceReference(); + + m_impl->vertexBuffer->RemoveResourceReference(); + + delete[] m_impl->aabb; + delete[] m_impl->normals; + delete[] m_impl->positions; + delete[] m_impl->tangents; + + delete m_impl; + m_impl = nullptr; + } +} + +void NzKeyframeMesh::Finish() +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Keyframe mesh not created"); + return; + } + #endif + + InterpolateImpl(0, 0, 0.f); +} + +const NzAxisAlignedBox& NzKeyframeMesh::GetAABB() const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Keyframe mesh not created"); + return NzAxisAlignedBox::Null; + } + #endif + + return m_impl->aabb[0]; +} + +nzAnimationType NzKeyframeMesh::GetAnimationType() const +{ + return nzAnimationType_Keyframe; +} + +unsigned int NzKeyframeMesh::GetFrameCount() const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Keyframe mesh not created"); + return 0; + } + #endif + + return m_impl->frameCount; +} + +const NzIndexBuffer* NzKeyframeMesh::GetIndexBuffer() const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Keyframe mesh not created"); + return nullptr; + } + #endif + + return m_impl->indexBuffer; +} + +bool NzKeyframeMesh::GetVertex(NzMeshVertex* dest, unsigned int frameIndex, unsigned int vertexIndex, bool queryUV) const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Keyframe mesh not created"); + return false; + } + + if (frameIndex >= m_impl->frameCount) + { + NazaraError("Frame index out of bounds (" + NzString::Number(frameIndex) + " >= " + NzString::Number(m_impl->frameCount) + ')'); + return false; + } + #endif + + unsigned int vertexCount = m_impl->vertexBuffer->GetVertexCount(); + + #if NAZARA_UTILITY_SAFE + if (vertexIndex >= vertexCount) + { + NazaraError("Vertex index out of bounds (" + NzString::Number(vertexIndex) + " >= " + NzString::Number(vertexCount) + ')'); + return false; + } + #endif + + unsigned int index = frameIndex*vertexCount + vertexIndex; + + dest->normal = m_impl->normals[index]; + dest->position = m_impl->positions[index]; + dest->tangent = m_impl->tangents[index]; + + if (queryUV) + { + if (!Lock(nzBufferAccess_ReadOnly)) + { + NazaraError("Failed to query UV"); + return false; + } + + NzMeshVertex& vertex = m_impl->lockBuffer[vertexIndex]; + dest->uv = vertex.uv; + + Unlock(); + } + + return true; +} + +const NzVertexBuffer* NzKeyframeMesh::GetVertexBuffer() const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Keyframe mesh not created"); + return nullptr; + } + #endif + + return m_impl->vertexBuffer; +} + +void NzKeyframeMesh::Interpolate(unsigned int frameA, unsigned int frameB, float interpolation) +{ + #if NAZARA_UTILITY_SAFE + if (!m_parent->HasAnimation()) + { + NazaraError("Parent mesh has no animation"); + return; + } + + unsigned int frameCount = m_parent->GetFrameCount(); + if (frameA >= frameCount) + { + NazaraError("Frame A is out of range (" + NzString::Number(frameA) + " >= " + NzString::Number(frameCount) + ')'); + return; + } + + if (frameB >= frameCount) + { + NazaraError("Frame B is out of range (" + NzString::Number(frameB) + " >= " + NzString::Number(frameCount) + ')'); + return; + } + #endif + + #ifdef NAZARA_DEBUG + if (interpolation < 0.f || interpolation > 1.f) + { + NazaraError("Interpolation must be in range [0..1] (Got " + NzString::Number(interpolation) + ')'); + return; + } + #endif + + InterpolateImpl(frameA, frameB, interpolation); + + m_parent->InvalidateAABB(); +} + +bool NzKeyframeMesh::IsAnimated() const +{ + return true; +} + +bool NzKeyframeMesh::IsValid() +{ + return m_impl != nullptr; +} + +bool NzKeyframeMesh::Lock(nzBufferAccess access) const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Keyframe mesh not created"); + return false; + } + #endif + + if (m_impl->lockLevel == 0) + { + m_impl->lockBuffer = reinterpret_cast(m_impl->vertexBuffer->Map(access)); + if (!m_impl->lockBuffer) + { + NazaraError("Failed to lock vertex buffer"); + m_impl->lockLevel = 0; + + return false; + } + + m_impl->lockAccess = access; + } + else + { + ///FIXME: Vérifier cette condition + if (m_impl->lockAccess != access && + (m_impl->lockAccess != nzBufferAccess_ReadWrite || access != nzBufferAccess_WriteOnly) && + (m_impl->lockAccess != nzBufferAccess_ReadWrite || access != nzBufferAccess_ReadOnly) && + (m_impl->lockAccess != nzBufferAccess_DiscardAndWrite || access != nzBufferAccess_WriteOnly)) + { + NazaraError("Vertex buffer already locked by an incompatible lock access"); + return false; + } + } + + m_impl->lockLevel++; + + return true; +} + +void NzKeyframeMesh::SetAABB(unsigned int frameIndex, const NzAxisAlignedBox& aabb) +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Keyframe mesh not created"); + return; + } + + if (frameIndex >= m_impl->frameCount) + { + NazaraError("Frame index out of bounds (" + NzString::Number(frameIndex) + " >= " + NzString::Number(m_impl->frameCount) + ')'); + return; + } + #endif + + m_impl->aabb[frameIndex+1] = aabb; +} + +void NzKeyframeMesh::SetIndexBuffer(const NzIndexBuffer* indexBuffer) +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Keyframe mesh not created"); + return; + } + #endif + + if (m_impl->indexBuffer) + m_impl->indexBuffer->RemoveResourceReference(); + + if (indexBuffer) + indexBuffer->AddResourceReference(); + + m_impl->indexBuffer = indexBuffer; +} + +bool NzKeyframeMesh::SetVertex(const NzMeshVertex& source, unsigned int frameIndex, unsigned int vertexIndex, bool setUV) +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Keyframe mesh not created"); + return false; + } + + if (frameIndex >= m_impl->frameCount) + { + NazaraError("Frame index out of bounds (" + NzString::Number(frameIndex) + " >= " + NzString::Number(m_impl->frameCount) + ')'); + return false; + } + #endif + + unsigned int vertexCount = m_impl->vertexBuffer->GetVertexCount(); + + #if NAZARA_UTILITY_SAFE + if (vertexIndex >= vertexCount) + { + NazaraError("Vertex index out of bounds (" + NzString::Number(vertexIndex) + " >= " + NzString::Number(vertexCount) + ')'); + return false; + } + #endif + + unsigned int index = frameIndex*vertexCount + vertexIndex; + + m_impl->normals[index] = source.normal; + m_impl->positions[index] = source.position; + m_impl->tangents[index] = source.tangent; + + if (setUV) + { + if (!Lock(nzBufferAccess_WriteOnly)) + { + NazaraError("Failed to write UV"); + return false; + } + + NzMeshVertex& vertex = m_impl->lockBuffer[vertexIndex]; + vertex.uv = source.uv; + + Unlock(); + } + + return true; +} + +void NzKeyframeMesh::Unlock() const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Keyframe mesh not created"); + return; + } + + if (m_impl->lockLevel == 0) + { + NazaraWarning("Unlock called on non-locked texture"); + return; + } + #endif + + if (--m_impl->lockLevel == 0) + { + if (!m_impl->vertexBuffer->Unmap()) + NazaraWarning("Failed to unmap vertex buffer, expect mesh corruption"); + } +} + +void NzKeyframeMesh::InterpolateImpl(unsigned int frameA, unsigned int frameB, float interpolation) +{ + #ifdef NAZARA_DEBUG + if (!m_impl) + { + NazaraError("Keyframe mesh not created"); + return; + } + #endif + + // Interpolation de l'AABB + m_impl->aabb[0] = NzAxisAlignedBox::Lerp(m_impl->aabb[frameA+1], m_impl->aabb[frameB+1], interpolation); + + if (!Lock(nzBufferAccess_WriteOnly)) + { + NazaraError("Failed to lock vertex buffer"); + return; + } + + unsigned int vertexCount = m_impl->vertexBuffer->GetVertexCount(); + + // Adaptation des indices + frameA *= vertexCount; + frameB *= vertexCount; + + NzMeshVertex* vertex = m_impl->lockBuffer; + for (unsigned int i = 0; i < vertexCount; ++i) + { + vertex->normal = NzVector3f::Lerp(m_impl->positions[frameA+i], m_impl->positions[frameB+i], interpolation); + vertex->position = NzVector3f::Lerp(m_impl->positions[frameA+i], m_impl->positions[frameB+i], interpolation); + vertex->tangent = NzVector3f::Lerp(m_impl->positions[frameA+i], m_impl->positions[frameB+i], interpolation); + + vertex++; + } + + Unlock(); +} diff --git a/src/Nazara/Utility/Loaders/MD2/Constants.hpp b/src/Nazara/Utility/Loaders/MD2/Constants.hpp index 9e9d9062b..354c55874 100644 --- a/src/Nazara/Utility/Loaders/MD2/Constants.hpp +++ b/src/Nazara/Utility/Loaders/MD2/Constants.hpp @@ -7,7 +7,6 @@ #include #include -#include struct md2_header { @@ -51,14 +50,6 @@ struct md2_triangle nzUInt16 texCoords[3]; }; -struct md2_frame -{ - NzVector3f scale; - NzVector3f translate; - char name[16]; - std::vector vertices; -}; - extern const nzUInt32 md2Ident; extern const NzVector3f md2Normals[162]; diff --git a/src/Nazara/Utility/Loaders/MD2/Loader.cpp b/src/Nazara/Utility/Loaders/MD2/Loader.cpp index dbe93fc39..a6f246d39 100644 --- a/src/Nazara/Utility/Loaders/MD2/Loader.cpp +++ b/src/Nazara/Utility/Loaders/MD2/Loader.cpp @@ -7,16 +7,18 @@ #include #include #include +#include +#include #include #include -#include #include #include +#include #include namespace { - bool NzLoader_MD2_Check(NzInputStream& stream, const NzMeshParams& parameters) + bool Check(NzInputStream& stream, const NzMeshParams& parameters) { NazaraUnused(parameters); @@ -24,7 +26,7 @@ namespace if (stream.Read(&magic[0], 2*sizeof(nzUInt32)) != 2*sizeof(nzUInt32)) return false; - #if defined(NAZARA_BIG_ENDIAN) + #ifdef NAZARA_BIG_ENDIAN NzByteSwap(&magic[0], sizeof(nzUInt32)); NzByteSwap(&magic[1], sizeof(nzUInt32)); #endif @@ -32,7 +34,7 @@ namespace return magic[0] == md2Ident && magic[1] == 8; } - bool NzLoader_MD2_Load(NzMesh* mesh, NzInputStream& stream, const NzMeshParams& parameters) + bool Load(NzMesh* mesh, NzInputStream& stream, const NzMeshParams& parameters) { md2_header header; if (stream.Read(&header, sizeof(md2_header)) != sizeof(md2_header)) @@ -41,7 +43,7 @@ namespace return false; } - #if defined(NAZARA_BIG_ENDIAN) + #ifdef NAZARA_BIG_ENDIAN NzByteSwap(&header.skinwidth, sizeof(nzUInt32)); NzByteSwap(&header.skinheight, sizeof(nzUInt32)); NzByteSwap(&header.framesize, sizeof(nzUInt32)); @@ -67,16 +69,16 @@ namespace /// Création du mesh // Animé ou statique, c'est la question - bool animated; unsigned int startFrame = NzClamp(parameters.animation.startFrame, 0U, static_cast(header.num_frames-1)); unsigned int endFrame = NzClamp(parameters.animation.endFrame, 0U, static_cast(header.num_frames-1)); - if (parameters.loadAnimations && startFrame != endFrame) - animated = true; + bool animated = (parameters.animated && startFrame != endFrame); + if (animated) + mesh->CreateKeyframe(); else - animated = false; + mesh->CreateStatic(); - if (!mesh->Create((animated) ? nzAnimationType_Keyframe : nzAnimationType_Static)) // Ne devrait jamais échouer + if (!mesh->IsValid()) // Ne devrait jamais échouer { NazaraInternalError("Failed to create mesh"); return false; @@ -87,11 +89,12 @@ namespace { stream.SetCursorPos(header.offset_skins); { + NzString baseDir = stream.GetDirectory(); char skin[68]; for (unsigned int i = 0; i < header.num_skins; ++i) { stream.Read(skin, 68*sizeof(char)); - mesh->AddSkin(skin); + mesh->AddMaterial(baseDir + skin); } } } @@ -100,16 +103,13 @@ namespace if (animated) { NzAnimation* animation = new NzAnimation; - if (animation->Create(nzAnimationType_Keyframe, endFrame-startFrame+1)) + if (animation->CreateKeyframe(endFrame-startFrame+1)) { // Décodage des séquences - NzString frameName; + ///TODO: Optimiser le calcul + char last[16]; - NzSequence sequence; - sequence.framePerSecond = 10; // Par défaut pour les animations MD2 - - char name[16], last[16]; - stream.SetCursorPos(header.offset_frames + startFrame*header.framesize + offsetof(md2_frame, name)); + stream.SetCursorPos(header.offset_frames + startFrame*header.framesize + 2*sizeof(NzVector3f)); stream.Read(last, 16*sizeof(char)); int pos = std::strlen(last)-1; @@ -122,10 +122,16 @@ namespace } last[pos+1] = '\0'; - unsigned int numFrames = 0; + NzSequence sequence; + sequence.firstFrame = startFrame; + sequence.frameCount = 0; + sequence.frameRate = 10; // Par défaut pour les animations MD2 + sequence.name = last; + + char name[16]; for (unsigned int i = startFrame; i <= endFrame; ++i) { - stream.SetCursorPos(header.offset_frames + i*header.framesize + offsetof(md2_frame, name)); + stream.SetCursorPos(header.offset_frames + i*header.framesize + 2*sizeof(NzVector3f)); stream.Read(name, 16*sizeof(char)); pos = std::strlen(name)-1; @@ -140,24 +146,20 @@ namespace if (std::strcmp(name, last) != 0) // Si les deux frames n'ont pas le même nom { - // Alors on enregistre la séquence - sequence.firstFrame = i-numFrames; - sequence.lastFrame = i-1; - sequence.name = last; - animation->AddSequence(sequence); - std::strcpy(last, name); - numFrames = 0; + // Alors on enregistre la séquence actuelle + animation->AddSequence(sequence); + + // Et on initialise la séquence suivante + sequence.firstFrame = i; + sequence.frameCount = 0; + sequence.name = last; } - numFrames++; + sequence.frameCount++; } - // On ajoute la dernière frame (Qui n'a pas été traitée par la boucle) - sequence.firstFrame = endFrame-numFrames; - sequence.lastFrame = endFrame; - sequence.name = last; animation->AddSequence(sequence); mesh->SetAnimation(animation); @@ -169,15 +171,118 @@ namespace /// Chargement des submesh // Actuellement le loader ne charge qu'un submesh - // TODO: Utiliser les commandes OpenGL pour accélérer le rendu - NzMD2Mesh* subMesh = new NzMD2Mesh(mesh); - if (!subMesh->Create(header, stream, parameters)) + // TODO: Utiliser les commandes OpenGL pour créer des indices et accélérer le rendu + unsigned int frameCount = endFrame - startFrame + 1; + unsigned int vertexCount = header.num_tris * 3; + + std::unique_ptr vertexBuffer(new NzVertexBuffer(NzMesh::GetDeclaration(), vertexCount, parameters.storage, nzBufferUsage_Dynamic)); + std::unique_ptr subMesh(new NzKeyframeMesh(mesh)); + if (!subMesh->Create(vertexBuffer.get(), frameCount)) { - NazaraError("Failed to create MD2 mesh"); + NazaraError("Failed to create SubMesh"); return false; } - mesh->AddSubMesh(subMesh); + vertexBuffer->SetPersistent(false); + vertexBuffer.release(); + + /// Lecture des triangles + std::vector triangles(header.num_tris); + + stream.SetCursorPos(header.offset_tris); + stream.Read(&triangles[0], header.num_tris*sizeof(md2_triangle)); + + #ifdef NAZARA_BIG_ENDIAN + for (unsigned int i = 0; i < header.num_tris; ++i) + { + NzByteSwap(&triangles[i].vertices[0], sizeof(nzUInt16)); + NzByteSwap(&triangles[i].texCoords[0], sizeof(nzUInt16)); + + NzByteSwap(&triangles[i].vertices[1], sizeof(nzUInt16)); + NzByteSwap(&triangles[i].texCoords[1], sizeof(nzUInt16)); + + NzByteSwap(&triangles[i].vertices[2], sizeof(nzUInt16)); + NzByteSwap(&triangles[i].texCoords[2], sizeof(nzUInt16)); + } + #endif + + /// Lecture des coordonnées de texture + std::vector texCoords(header.num_st); + + // Lecture des coordonnées de texture + stream.SetCursorPos(header.offset_st); + stream.Read(&texCoords[0], header.num_st*sizeof(md2_texCoord)); + + #ifdef NAZARA_BIG_ENDIAN + for (unsigned int i = 0; i < header.num_st; ++i) + { + NzByteSwap(&texCoords[i].u, sizeof(nzInt16)); + NzByteSwap(&texCoords[i].v, sizeof(nzInt16)); + } + #endif + + /// Chargement des frames + stream.SetCursorPos(header.offset_frames + header.framesize*startFrame); + + // Pour que le modèle soit correctement aligné, on génère un quaternion que nous appliquerons à chacune des vertices + NzQuaternionf rotationQuat = NzEulerAnglesf(-90.f, 90.f, 0.f); + + md2_vertex* vertices = new md2_vertex[header.num_vertices]; + for (unsigned int f = 0; f < frameCount; ++f) + { + NzVector3f scale, translate; + + stream.Read(scale, sizeof(NzVector3f)); + stream.Read(translate, sizeof(NzVector3f)); + stream.Read(nullptr, 16*sizeof(char)); + stream.Read(vertices, header.num_vertices*sizeof(md2_vertex)); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&scale.x, sizeof(float)); + NzByteSwap(&scale.y, sizeof(float)); + NzByteSwap(&scale.z, sizeof(float)); + + NzByteSwap(&translate.x, sizeof(float)); + NzByteSwap(&translate.y, sizeof(float)); + NzByteSwap(&translate.z, sizeof(float)); + #endif + + NzAxisAlignedBox aabb; + for (unsigned int t = 0; t < header.num_tris; ++t) + { + for (unsigned int v = 0; v < 3; ++v) + { + const md2_vertex& vert = vertices[triangles[t].vertices[v]]; + NzVector3f position = rotationQuat * NzVector3f(vert.x * scale.x + translate.x, vert.y * scale.y + translate.y, vert.z * scale.z + translate.z); + + // On fait en sorte d'étendre l'AABB pour qu'il contienne ce sommet + aabb.ExtendTo(position); + + // Et on finit par copier les éléments dans le buffer + NzMeshVertex vertex; + vertex.normal = md2Normals[vert.n]; + vertex.position = position; + + // On ne définit les coordonnées de texture que pour la première frame + bool firstFrame = (f == 0); + if (firstFrame) + { + const md2_texCoord& texC = texCoords[triangles[t].texCoords[v]]; + vertex.uv.Set(texC.u / static_cast(header.skinwidth), 1.f - texC.v / static_cast(header.skinheight)); + } + + subMesh->SetVertex(vertex, f, vertexCount - (t*3 + v) - 1, firstFrame); + } + } + + subMesh->SetAABB(f, aabb); + } + delete[] vertices; + + subMesh->Unlock(); + + subMesh->SetMaterialIndex(0); + mesh->AddSubMesh(subMesh.release()); return true; } @@ -185,14 +290,10 @@ namespace void NzLoaders_MD2_Register() { - NzMD2Mesh::Initialize(); - - NzMeshLoader::RegisterLoader("md2", NzLoader_MD2_Check, NzLoader_MD2_Load); + NzMeshLoader::RegisterLoader("md2", Check, Load); } void NzLoaders_MD2_Unregister() { - NzMeshLoader::UnregisterLoader("md2", NzLoader_MD2_Check, NzLoader_MD2_Load); - - NzMD2Mesh::Uninitialize(); + NzMeshLoader::UnregisterLoader("md2", Check, Load); } diff --git a/src/Nazara/Utility/Loaders/MD2/Mesh.cpp b/src/Nazara/Utility/Loaders/MD2/Mesh.cpp deleted file mode 100644 index 2e74b4bea..000000000 --- a/src/Nazara/Utility/Loaders/MD2/Mesh.cpp +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright (C) 2012 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include -#include -#include -#include - -NzMD2Mesh::NzMD2Mesh(const NzMesh* parent) : -NzKeyframeMesh(parent), -m_frames(nullptr), -m_indexBuffer(nullptr), -m_vertexBuffer(nullptr) -{ -} - -NzMD2Mesh::~NzMD2Mesh() -{ - Destroy(); -} - -bool NzMD2Mesh::Create(const md2_header& header, NzInputStream& stream, const NzMeshParams& parameters) -{ - Destroy(); - - unsigned int startFrame = NzClamp(parameters.animation.startFrame, 0U, static_cast(header.num_frames-1)); - unsigned int endFrame = NzClamp(parameters.animation.endFrame, 0U, static_cast(header.num_frames-1)); - - m_frameCount = endFrame - startFrame + 1; - m_vertexCount = header.num_tris * 3; - - /// Chargement des vertices - std::vector texCoords(header.num_st); - std::vector triangles(header.num_tris); - - // Lecture des coordonnées de texture - stream.SetCursorPos(header.offset_st); - stream.Read(&texCoords[0], header.num_st*sizeof(md2_texCoord)); - - #if defined(NAZARA_BIG_ENDIAN) - for (unsigned int i = 0; i < header.num_st; ++i) - { - NzByteSwap(&texCoords[i].u, sizeof(nzInt16)); - NzByteSwap(&texCoords[i].v, sizeof(nzInt16)); - } - #endif - - stream.SetCursorPos(header.offset_tris); - stream.Read(&triangles[0], header.num_tris*sizeof(md2_triangle)); - - #if defined(NAZARA_BIG_ENDIAN) - for (unsigned int i = 0; i < header.num_tris; ++i) - { - NzByteSwap(&triangles[i].vertices[0], sizeof(nzUInt16)); - NzByteSwap(&texCoords[i].texCoords[0], sizeof(nzUInt16)); - - NzByteSwap(&triangles[i].vertices[1], sizeof(nzUInt16)); - NzByteSwap(&texCoords[i].texCoords[1], sizeof(nzUInt16)); - - NzByteSwap(&triangles[i].vertices[2], sizeof(nzUInt16)); - NzByteSwap(&texCoords[i].texCoords[2], sizeof(nzUInt16)); - } - #endif - - stream.SetCursorPos(header.offset_frames + header.framesize*startFrame); - - md2_frame frame; - frame.vertices.resize(header.num_vertices); - - // Pour que le modèle soit correctement aligné, on génère un quaternion que nous appliquerons à chacune des vertices - NzQuaternionf rotationQuat = NzEulerAnglesf(-90.f, 90.f, 0.f); - //NzMatrix4f rotationMatrix = NzMatrix4f::Rotate(NzEulerAnglesf(-90.f, -90.f, 0.f)); - - unsigned int stride = s_declaration.GetStride(nzElementStream_VertexData); - - m_frames = new Frame[m_frameCount]; - for (unsigned int i = 0; i < m_frameCount; ++i) - { - stream.Read(&frame.scale, sizeof(NzVector3f)); - stream.Read(&frame.translate, sizeof(NzVector3f)); - stream.Read(&frame.name, 16*sizeof(char)); - stream.Read(&frame.vertices[0], header.num_vertices*sizeof(md2_vertex)); - - #if defined(NAZARA_BIG_ENDIAN) - NzByteSwap(&frame.scale.x, sizeof(float)); - NzByteSwap(&frame.scale.y, sizeof(float)); - NzByteSwap(&frame.scale.z, sizeof(float)); - - NzByteSwap(&frame.translate.x, sizeof(float)); - NzByteSwap(&frame.translate.y, sizeof(float)); - NzByteSwap(&frame.translate.z, sizeof(float)); - #endif - - m_frames[i].normal = new nzUInt8[m_vertexCount]; // Nous stockons l'indice MD2 de la normale plutôt que la normale (gain d'espace) - m_frames[i].vertices = new NzVector3f[m_vertexCount]; - - NzVector3f max, min; - for (unsigned int t = 0; t < header.num_tris; ++t) - { - for (unsigned int v = 0; v < 3; ++v) - { - const md2_vertex& vert = frame.vertices[triangles[t].vertices[v]]; - - NzVector3f vertex = rotationQuat * NzVector3f(vert.x * frame.scale.x + frame.translate.x, vert.y * frame.scale.y + frame.translate.y, vert.z * frame.scale.z + frame.translate.z); - - // On fait en sorte d'avoir deux vertices de délimitation, définissant un rectangle dans l'espace - max.Maximize(vertex); - min.Minimize(vertex); - - // Le MD2 ne définit pas ses vertices dans le bon ordre, il nous faut donc les ajouter dans l'ordre inverse - unsigned int index = m_vertexCount - (t*3 + v) - 1; - m_frames[i].normal[index] = vert.n; - m_frames[i].vertices[index] = vertex; - } - } - - m_frames[i].aabb.SetExtends(min, max); - } - - m_indexBuffer = nullptr; // Pas d'indexbuffer pour l'instant - m_vertexBuffer = new NzVertexBuffer(m_vertexCount, (3+3+2)*sizeof(float), parameters.storage, nzBufferUsage_Dynamic); - - nzUInt8* ptr = reinterpret_cast(m_vertexBuffer->Map(nzBufferAccess_WriteOnly)); - if (!ptr) - { - NazaraError("Failed to map vertex buffer"); - Destroy(); - - return false; - } - - // On avance jusqu'aux dernières coordonnées de texture et on les définit dans l'ordre inverse - ptr += s_declaration.GetElement(nzElementStream_VertexData, nzElementUsage_TexCoord)->offset + stride * (m_vertexCount-1); - for (unsigned int t = 0; t < header.num_tris; ++t) - { - for (unsigned int v = 0; v < 3; ++v) - { - const md2_texCoord& texC = texCoords[triangles[t].texCoords[v]]; - - NzVector2f* coords = reinterpret_cast(ptr); - coords->x = texC.u / static_cast(header.skinwidth); - coords->y = 1.f - texC.v / static_cast(header.skinheight); - - ptr -= stride; - } - } - - if (!m_vertexBuffer->Unmap()) - { - NazaraError("Failed to unmap buffer"); - Destroy(); - - return false; - } - - m_vertexBuffer->AddResourceReference(); - m_vertexBuffer->SetPersistent(false); - - AnimateImpl(0, 0, 0.f); - - return true; -} - -void NzMD2Mesh::Destroy() -{ - if (m_frames) - { - for (unsigned int i = 0; i < m_frameCount; ++i) - { - delete[] m_frames[i].normal; - delete[] m_frames[i].vertices; - } - - delete[] m_frames; - m_frames = nullptr; - } - - if (m_indexBuffer) - { - m_indexBuffer->RemoveResourceReference(); - m_indexBuffer = nullptr; - } - - if (m_vertexBuffer) - { - m_vertexBuffer->RemoveResourceReference(); - m_vertexBuffer = nullptr; - } -} - -const NzAxisAlignedBox& NzMD2Mesh::GetAABB() const -{ - return m_aabb; -} - -nzAnimationType NzMD2Mesh::GetAnimationType() const -{ - if (m_frameCount > 1) - return nzAnimationType_Keyframe; - else - return nzAnimationType_Static; -} - -unsigned int NzMD2Mesh::GetFrameCount() const -{ - return m_frameCount; -} - -const NzIndexBuffer* NzMD2Mesh::GetIndexBuffer() const -{ - return nullptr; - //return m_indexBuffer; -} - -nzPrimitiveType NzMD2Mesh::GetPrimitiveType() const -{ - return nzPrimitiveType_TriangleList; -} - -const NzVertexBuffer* NzMD2Mesh::GetVertexBuffer() const -{ - return m_vertexBuffer; -} - -const NzVertexDeclaration* NzMD2Mesh::GetVertexDeclaration() const -{ - return &s_declaration; -} - -void NzMD2Mesh::Initialize() -{ - NzVertexElement elements[3]; - elements[0].offset = 0; - elements[0].type = nzElementType_Float3; - elements[0].usage = nzElementUsage_Position; - - elements[1].offset = 3*sizeof(float); - elements[1].type = nzElementType_Float3; - elements[1].usage = nzElementUsage_Normal; - - elements[2].offset = 3*sizeof(float) + 3*sizeof(float); - elements[2].type = nzElementType_Float2; - elements[2].usage = nzElementUsage_TexCoord; - - s_declaration.Create(elements, 3); -} - -void NzMD2Mesh::Uninitialize() -{ - s_declaration.Destroy(); -} - -void NzMD2Mesh::AnimateImpl(unsigned int frameA, unsigned int frameB, float interpolation) -{ - nzUInt8* ptr = reinterpret_cast(m_vertexBuffer->Map(nzBufferAccess_WriteOnly)); - if (!ptr) - { - NazaraError("Failed to map vertex buffer"); - return; - } - - unsigned int stride = s_declaration.GetStride(nzElementStream_VertexData); - unsigned int positionOffset = s_declaration.GetElement(nzElementStream_VertexData, nzElementUsage_Position)->offset; - unsigned int normalOffset = s_declaration.GetElement(nzElementStream_VertexData, nzElementUsage_Normal)->offset; - - Frame* fA = &m_frames[frameA]; - Frame* fB = &m_frames[frameB]; - for (unsigned int i = 0; i < m_vertexCount; ++i) - { - NzVector3f* position = reinterpret_cast(ptr + positionOffset); - NzVector3f* normal = reinterpret_cast(ptr + normalOffset); - - *position = fA->vertices[i] + interpolation * (fB->vertices[i] - fA->vertices[i]); - *normal = md2Normals[fA->normal[i]] + interpolation * (md2Normals[fB->normal[i]] - md2Normals[fA->normal[i]]); - - ptr += stride; - } - - if (!m_vertexBuffer->Unmap()) - NazaraWarning("Failed to unmap vertex buffer, expect mesh corruption"); - - // Interpolation de l'AABB - NzVector3f max1 = fA->aabb.GetMaximum(); - NzVector3f min1 = fA->aabb.GetMinimum(); - m_aabb.SetExtends(min1 + interpolation * (fB->aabb.GetMinimum() - min1), max1 + interpolation * (fB->aabb.GetMaximum() - max1)); -} - -NzVertexDeclaration NzMD2Mesh::s_declaration; diff --git a/src/Nazara/Utility/Loaders/MD2/Mesh.hpp b/src/Nazara/Utility/Loaders/MD2/Mesh.hpp deleted file mode 100644 index 7135cd106..000000000 --- a/src/Nazara/Utility/Loaders/MD2/Mesh.hpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2012 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_LOADERS_MD2_MESH_HPP -#define NAZARA_LOADERS_MD2_MESH_HPP - -#include -#include -#include -#include -#include - -class NzIndexBuffer; -class NzInputStream; -class NzVertexBuffer; -struct NzMeshParams; - -class NAZARA_API NzMD2Mesh : public NzKeyframeMesh -{ - public: - NzMD2Mesh(const NzMesh* parent); - ~NzMD2Mesh(); - - bool Create(const md2_header& header, NzInputStream& stream, const NzMeshParams& parameters); - void Destroy(); - - const NzAxisAlignedBox& GetAABB() const; - nzAnimationType GetAnimationType() const; - unsigned int GetFrameCount() const; - const NzIndexBuffer* GetIndexBuffer() const; - nzPrimitiveType GetPrimitiveType() const; - const NzVertexBuffer* GetVertexBuffer() const; - const NzVertexDeclaration* GetVertexDeclaration() const; - - bool IsAnimated() const; - - static void Initialize(); - static void Uninitialize(); - - private: - void AnimateImpl(unsigned int frameA, unsigned int frameB, float interpolation); - - struct Frame - { - NzAxisAlignedBox aabb; - nzUInt8* normal; - NzVector3f* tangents; - NzVector3f* vertices; - char name[16]; - }; - - NzAxisAlignedBox m_aabb; - Frame* m_frames; - NzIndexBuffer* m_indexBuffer; - NzVertexBuffer* m_vertexBuffer; - unsigned int m_frameCount; - unsigned int m_vertexCount; - - static NzVertexDeclaration s_declaration; -}; - -#endif // NAZARA_LOADERS_MD2_MESH_HPP diff --git a/src/Nazara/Utility/Loaders/MD5Anim.hpp b/src/Nazara/Utility/Loaders/MD5Anim.hpp new file mode 100644 index 000000000..e9d3530fb --- /dev/null +++ b/src/Nazara/Utility/Loaders/MD5Anim.hpp @@ -0,0 +1,15 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LOADERS_MD5ANIM_HPP +#define NAZARA_LOADERS_MD5ANIM_HPP + +#include + +void NzLoaders_MD5Anim_Register(); +void NzLoaders_MD5Anim_Unregister(); + +#endif // NAZARA_LOADERS_MD5ANIM_HPP diff --git a/src/Nazara/Utility/Loaders/MD5Anim/Loader.cpp b/src/Nazara/Utility/Loaders/MD5Anim/Loader.cpp new file mode 100644 index 000000000..58d9dba49 --- /dev/null +++ b/src/Nazara/Utility/Loaders/MD5Anim/Loader.cpp @@ -0,0 +1,32 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace +{ + bool Check(NzInputStream& stream, const NzAnimationParams& parameters) + { + NzMD5AnimParser parser(stream, parameters); + return parser.Check(); + } + + bool Load(NzAnimation* animation, NzInputStream& stream, const NzAnimationParams& parameters) + { + NzMD5AnimParser parser(stream, parameters); + return parser.Parse(animation); + } +} + +void NzLoaders_MD5Anim_Register() +{ + NzAnimationLoader::RegisterLoader("md5anim", Check, Load); +} + +void NzLoaders_MD5Anim_Unregister() +{ + NzAnimationLoader::UnregisterLoader("md5anim", Check, Load); +} diff --git a/src/Nazara/Utility/Loaders/MD5Anim/Parser.cpp b/src/Nazara/Utility/Loaders/MD5Anim/Parser.cpp new file mode 100644 index 000000000..76ec2f956 --- /dev/null +++ b/src/Nazara/Utility/Loaders/MD5Anim/Parser.cpp @@ -0,0 +1,529 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +NzMD5AnimParser::NzMD5AnimParser(NzInputStream& stream, const NzAnimationParams& parameters) : +m_stream(stream), +m_parameters(parameters), +m_keepLastLine(false), +m_frameIndex(0), +m_frameRate(0), +m_lineCount(0), +m_streamFlags(stream.GetStreamOptions()) +{ + if ((m_streamFlags & nzStreamOption_Text) == 0) + m_stream.SetStreamOptions(m_streamFlags | nzStreamOption_Text); +} + +NzMD5AnimParser::~NzMD5AnimParser() +{ + if ((m_streamFlags & nzStreamOption_Text) == 0) + m_stream.SetStreamOptions(m_streamFlags); +} + +bool NzMD5AnimParser::Check() +{ + if (!Advance(false)) + return false; + + unsigned int version; + if (std::sscanf(&m_currentLine[0], " MD5Version %u", &version) != 1) + return false; + + return version == 10; +} + +bool NzMD5AnimParser::Parse(NzAnimation* animation) +{ + while (Advance(false)) + { + switch (m_currentLine[0]) + { + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + case 'M': // MD5Version + if (m_currentLine.GetWord(0) != "MD5Version") + UnrecognizedLine(); + break; + #endif + + case 'b': // baseframe/bounds + if (m_currentLine.StartsWith("baseframe {")) + { + if (!ParseBaseframe()) + { + Error("Failed to parse baseframe"); + return false; + } + } + else if (m_currentLine.StartsWith("bounds {")) + { + if (!ParseBounds()) + { + Error("Failed to parse bounds"); + return false; + } + } + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + else + UnrecognizedLine(); + #endif + break; + + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + case 'c': // commandline + if (m_currentLine.GetWord(0) != "commandline") + UnrecognizedLine(); + break; + #endif + + case 'f': + { + unsigned int index; + if (std::sscanf(&m_currentLine[0], "frame %u {", &index) == 1) + { + if (m_frameIndex != index) + { + Error("Unexpected frame index (expected " + NzString::Number(m_frameIndex) + ", got " + NzString::Number(index) + ')'); + return false; + } + + if (!ParseFrame()) + { + Error("Failed to parse frame"); + return false; + } + + m_frameIndex++; + } + else if (std::sscanf(&m_currentLine[0], "frameRate %u", &m_frameRate) != 1) + { + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + UnrecognizedLine(); + #endif + } + break; + } + + case 'h': // hierarchy + if (m_currentLine.StartsWith("hierarchy {")) + { + if (!ParseHierarchy()) + { + Error("Failed to parse hierarchy"); + return false; + } + } + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + else + UnrecognizedLine(); + #endif + break; + + case 'n': // num[Frames/Joints] + { + unsigned int count; + if (std::sscanf(&m_currentLine[0], "numAnimatedComponents %u", &count) == 1) + { + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + if (!m_animatedComponents.empty()) + Warning("Animated components count is already defined"); + #endif + + m_animatedComponents.resize(count); + } + else if (std::sscanf(&m_currentLine[0], "numFrames %u", &count) == 1) + { + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + if (!m_frames.empty()) + Warning("Frame count is already defined"); + #endif + + m_frames.resize(count); + } + else if (std::sscanf(&m_currentLine[0], "numJoints %u", &count) == 1) + { + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + if (!m_joints.empty()) + Warning("Joint count is already defined"); + #endif + + m_joints.resize(count); + } + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + else + UnrecognizedLine(); + #endif + break; + } + + default: + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + UnrecognizedLine(); + #endif + break; + } + } + + unsigned int frameCount = m_frames.size(); + if (frameCount == 0) + { + NazaraError("Frame count is invalid or missing"); + return false; + } + + unsigned int jointCount = m_joints.size(); + if (jointCount == 0) + { + NazaraError("Joint count is invalid or missing"); + return false; + } + + if (m_frameIndex != frameCount) + { + NazaraError("Missing frame infos: [" + NzString::Number(m_frameIndex) + ',' + NzString::Number(frameCount) + ']'); + return false; + } + + if (m_frameRate == 0) + { + NazaraWarning("Framerate is either invalid or missing, assuming a default value of 24"); + m_frameRate = 24; + } + + // À ce stade, nous sommes censés avoir assez d'informations pour créer l'animation + if (!animation->CreateSkeletal(frameCount, jointCount)) + { + NazaraError("Failed to create animation"); + return false; + } + + NzSequence sequence; + sequence.firstFrame = 0; + sequence.frameCount = m_frames.size(); + sequence.frameRate = m_frameRate; + sequence.name = m_stream.GetPath().SubstrFrom(NAZARA_DIRECTORY_SEPARATOR, -1, true); + if (!animation->AddSequence(sequence)) + NazaraWarning("Failed to add sequence"); + + NzSequenceJoint* sequenceJoints = animation->GetSequenceJoints(); + + // Pour que le squelette soit correctement aligné, il faut appliquer un quaternion "de correction" aux joints à la base du squelette + NzQuaternionf rotationQuat = NzEulerAnglesf(-90.f, 90.f, 0.f); + for (unsigned int i = 0; i < jointCount; ++i) + { + int parent = m_joints[i].parent; + for (unsigned int j = 0; j < frameCount; ++j) + { + NzSequenceJoint& sequenceJoint = sequenceJoints[j*jointCount + i]; + + if (parent >= 0) + sequenceJoint.rotation = m_frames[j].joints[i].orient; + else + sequenceJoint.rotation = rotationQuat * m_frames[j].joints[i].orient; + + sequenceJoint.scale = NzVector3f(1.f, 1.f, 1.f); + + if (parent >= 0) + sequenceJoint.translation = m_frames[j].joints[i].pos; + else + sequenceJoint.translation = rotationQuat * m_frames[j].joints[i].pos; + } + } + + return true; +} + +bool NzMD5AnimParser::Advance(bool required) +{ + if (!m_keepLastLine) + { + do + { + if (m_stream.EndOfStream()) + { + if (required) + Error("Incomplete MD5 file"); + + return false; + } + + m_lineCount++; + + m_currentLine = m_stream.ReadLine(); + m_currentLine = m_currentLine.SubstrTo("//"); // On ignore les commentaires + m_currentLine.Simplify(); // Pour un traitement plus simple + } + while (m_currentLine.IsEmpty()); + } + else + m_keepLastLine = false; + + return true; +} + +void NzMD5AnimParser::Error(const NzString& message) +{ + NazaraError(message + " at line #" + NzString::Number(m_lineCount)); +} + +bool NzMD5AnimParser::ParseBaseframe() +{ + unsigned int jointCount = m_joints.size(); + if (jointCount == 0) + { + Error("Joint count is invalid or missing"); + return false; + } + + for (unsigned int i = 0; i < jointCount; ++i) + { + 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, + &m_joints[i].bindOrient.x, &m_joints[i].bindOrient.y, &m_joints[i].bindOrient.z) != 6) + { + UnrecognizedLine(true); + return false; + } + } + + if (!Advance()) + return false; + + if (m_currentLine != '}') + { + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + Warning("Bounds braces closing not found"); + #endif + + // On tente de survivre à l'erreur + m_keepLastLine = true; + } + + return true; +} + +bool NzMD5AnimParser::ParseBounds() +{ + unsigned int frameCount = m_frames.size(); + if (frameCount == 0) + { + Error("Frame count is invalid or missing"); + return false; + } + + for (unsigned int i = 0; i < frameCount; ++i) + { + if (!Advance()) + return false; + + NzVector3f 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) + { + UnrecognizedLine(true); + return false; + } + + m_frames[i].aabb.SetExtends(min, max); + } + + if (!Advance()) + return false; + + if (m_currentLine != '}') + { + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + Warning("Bounds braces closing not found"); + #endif + + // On tente de survivre à l'erreur + m_keepLastLine = true; + } + + return true; +} + +bool NzMD5AnimParser::ParseFrame() +{ + unsigned int animatedComponentsCount = m_animatedComponents.size(); + if (animatedComponentsCount == 0) + { + Error("Animated components count is missing or invalid"); + return false; + } + + unsigned int jointCount = m_joints.size(); + if (jointCount == 0) + { + Error("Joint count is invalid or missing"); + return false; + } + + NzString line; + + unsigned int count = 0; + do + { + if (!Advance()) + return false; + + unsigned int index = 0; + unsigned int size = m_currentLine.GetSize(); + do + { + float f; + int read; + if (std::sscanf(&m_currentLine[index], "%f%n", &f, &read) != 1) + { + UnrecognizedLine(true); + return false; + } + + index += read; + + m_animatedComponents[count] = f; + + count++; + } + while (index < size); + } + while (count < animatedComponentsCount); + + m_frames[m_frameIndex].joints.resize(jointCount); + + for (unsigned int i = 0; i < jointCount; ++i) + { + NzQuaternionf jointOrient = m_joints[i].bindOrient; + NzVector3f jointPos = m_joints[i].bindPos; + unsigned int j = 0; + + if (m_joints[i].flags & 1) // Px + jointPos.x = m_animatedComponents[m_joints[i].index + j++]; + + if (m_joints[i].flags & 2) // Py + jointPos.y = m_animatedComponents[m_joints[i].index + j++]; + + if (m_joints[i].flags & 4) // Pz + jointPos.z = m_animatedComponents[m_joints[i].index + j++]; + + if (m_joints[i].flags & 8) // Qx + jointOrient.x = m_animatedComponents[m_joints[i].index + j++]; + + if (m_joints[i].flags & 16) // Qy + jointOrient.y = m_animatedComponents[m_joints[i].index + j++]; + + if (m_joints[i].flags & 32) // Qz + jointOrient.z = m_animatedComponents[m_joints[i].index + j++]; + + jointOrient.ComputeW(); + + m_frames[m_frameIndex].joints[i].orient = jointOrient; + m_frames[m_frameIndex].joints[i].pos = jointPos; + } + + if (!Advance(false)) + return true; + + if (m_currentLine != '}') + { + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + Warning("Hierarchy braces closing not found"); + #endif + + // On tente de survivre à l'erreur + m_keepLastLine = true; + } + + return true; +} + +bool NzMD5AnimParser::ParseHierarchy() +{ + unsigned int jointCount = m_joints.size(); + if (jointCount == 0) + { + Error("Joint count is invalid or missing"); + return false; + } + + for (unsigned int i = 0; i < jointCount; ++i) + { + if (!Advance()) + return false; + + unsigned int pos = m_currentLine.Find(' '); + if (pos == NzString::npos) + { + UnrecognizedLine(true); + return false; + } + + if (pos >= 64) + { + NazaraError("Joint name is too long (>= 64 characters)"); + return false; + } + + char name[64]; + if (std::sscanf(&m_currentLine[0], "%s %d %u %u", &name[0], &m_joints[i].parent, &m_joints[i].flags, &m_joints[i].index) != 4) + { + UnrecognizedLine(true); + return false; + } + + m_joints[i].name = name; + m_joints[i].name.Trim('"'); + + int parent = m_joints[i].parent; + if (parent >= 0) + { + if (static_cast(parent) >= jointCount) + { + Error("Joint's parent is out of bounds (" + NzString::Number(parent) + " >= " + NzString::Number(jointCount) + ')'); + return false; + } + } + } + + if (!Advance()) + return false; + + if (m_currentLine != '}') + { + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + Warning("Hierarchy braces closing not found"); + #endif + + // On tente de survivre à l'erreur + m_keepLastLine = true; + } + + return true; +} + +void NzMD5AnimParser::Warning(const NzString& message) +{ + NazaraWarning(message + " at line #" + NzString::Number(m_lineCount)); +} + +void NzMD5AnimParser::UnrecognizedLine(bool error) +{ + NzString message = "Unrecognized \"" + m_currentLine + '"'; + + if (error) + Error(message); + else + Warning(message); +} diff --git a/src/Nazara/Utility/Loaders/MD5Anim/Parser.hpp b/src/Nazara/Utility/Loaders/MD5Anim/Parser.hpp new file mode 100644 index 000000000..797ef9114 --- /dev/null +++ b/src/Nazara/Utility/Loaders/MD5Anim/Parser.hpp @@ -0,0 +1,72 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LOADERS_MD5ANIM_PARSER_HPP +#define NAZARA_LOADERS_MD5ANIM_PARSER_HPP + +#include +#include +#include +#include +#include +#include +#include + +class NzMD5AnimParser +{ + public: + NzMD5AnimParser(NzInputStream& stream, const NzAnimationParams& parameters); + ~NzMD5AnimParser(); + + bool Check(); + bool Parse(NzAnimation* animation); + + private: + struct Frame + { + struct Joint + { + NzQuaternionf orient; + NzVector3f pos; + }; + + std::vector joints; + NzAxisAlignedBox aabb; + }; + + struct Joint + { + NzQuaternionf bindOrient; + NzString name; + NzVector3f bindPos; + int parent; + unsigned int flags; + unsigned int index; + }; + + bool Advance(bool required = true); + void Error(const NzString& message); + bool ParseBaseframe(); + bool ParseBounds(); + bool ParseFrame(); + bool ParseHierarchy(); + void Warning(const NzString& message); + void UnrecognizedLine(bool error = false); + + std::vector m_animatedComponents; + std::vector m_frames; + std::vector m_joints; + NzInputStream& m_stream; + NzString m_currentLine; + const NzAnimationParams& m_parameters; + bool m_keepLastLine; + unsigned int m_frameIndex; + unsigned int m_frameRate; + unsigned int m_lineCount; + unsigned int m_streamFlags; +}; + +#endif // NAZARA_LOADERS_MD5ANIM_PARSER_HPP diff --git a/src/Nazara/Utility/Loaders/MD5Mesh.hpp b/src/Nazara/Utility/Loaders/MD5Mesh.hpp new file mode 100644 index 000000000..46edaaa38 --- /dev/null +++ b/src/Nazara/Utility/Loaders/MD5Mesh.hpp @@ -0,0 +1,15 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LOADERS_MD5MESH_HPP +#define NAZARA_LOADERS_MD5MESH_HPP + +#include + +void NzLoaders_MD5Mesh_Register(); +void NzLoaders_MD5Mesh_Unregister(); + +#endif // NAZARA_LOADERS_MD5MESH_HPP diff --git a/src/Nazara/Utility/Loaders/MD5Mesh/Loader.cpp b/src/Nazara/Utility/Loaders/MD5Mesh/Loader.cpp new file mode 100644 index 000000000..c4f84c578 --- /dev/null +++ b/src/Nazara/Utility/Loaders/MD5Mesh/Loader.cpp @@ -0,0 +1,32 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace +{ + bool Check(NzInputStream& stream, const NzMeshParams& parameters) + { + NzMD5MeshParser parser(stream, parameters); + return parser.Check(); + } + + bool Load(NzMesh* mesh, NzInputStream& stream, const NzMeshParams& parameters) + { + NzMD5MeshParser parser(stream, parameters); + return parser.Parse(mesh); + } +} + +void NzLoaders_MD5Mesh_Register() +{ + NzMeshLoader::RegisterLoader("md5mesh", Check, Load); +} + +void NzLoaders_MD5Mesh_Unregister() +{ + NzMeshLoader::UnregisterLoader("md5mesh", Check, Load); +} diff --git a/src/Nazara/Utility/Loaders/MD5Mesh/Parser.cpp b/src/Nazara/Utility/Loaders/MD5Mesh/Parser.cpp new file mode 100644 index 000000000..e6c8e3f41 --- /dev/null +++ b/src/Nazara/Utility/Loaders/MD5Mesh/Parser.cpp @@ -0,0 +1,756 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +NzMD5MeshParser::NzMD5MeshParser(NzInputStream& stream, const NzMeshParams& parameters) : +m_stream(stream), +m_parameters(parameters), +m_keepLastLine(false), +m_lineCount(0), +m_meshIndex(0), +m_streamFlags(stream.GetStreamOptions()) +{ + if ((m_streamFlags & nzStreamOption_Text) == 0) + m_stream.SetStreamOptions(m_streamFlags | nzStreamOption_Text); +} + +NzMD5MeshParser::~NzMD5MeshParser() +{ + if ((m_streamFlags & nzStreamOption_Text) == 0) + m_stream.SetStreamOptions(m_streamFlags); +} + +bool NzMD5MeshParser::Check() +{ + if (!Advance(false)) + return false; + + unsigned int version; + if (std::sscanf(&m_currentLine[0], "MD5Version %u", &version) != 1) + return false; + + return version == 10; +} + +bool NzMD5MeshParser::Parse(NzMesh* mesh) +{ + while (Advance(false)) + { + switch (m_currentLine[0]) + { + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + case 'M': // MD5Version + if (m_currentLine.GetWord(0) != "MD5Version") + UnrecognizedLine(); + break; + + case 'c': // commandline + if (m_currentLine.GetWord(0) != "commandline") + UnrecognizedLine(); + break; + #endif + + case 'j': // joints + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + if (!m_currentLine.StartsWith("joints {")) + { + UnrecognizedLine(); + break; + } + #endif + + if (!ParseJoints()) + { + Error("Failed to parse joints"); + return false; + } + break; + + case 'm': // mesh + { + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + if (m_currentLine != "mesh {") + { + UnrecognizedLine(); + break; + } + #endif + + if (m_meshIndex >= m_meshes.size()) + { + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + Warning("More meshes than registred"); + #endif + + m_meshes.push_back(Mesh()); + } + + if (!ParseMesh()) + { + NazaraError("Failed to parse mesh"); + return false; + } + + m_meshIndex++; + break; + } + + case 'n': // num[Frames/Joints] + { + unsigned int count; + if (std::sscanf(&m_currentLine[0], "numJoints %u", &count) == 1) + { + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + if (!m_joints.empty()) + Warning("Joint count is already defined"); + #endif + + m_joints.resize(count); + } + else if (std::sscanf(&m_currentLine[0], "numMeshes %u", &count) == 1) + { + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + if (!m_meshes.empty()) + Warning("Mesh count is already defined"); + #endif + + m_meshes.resize(count); + } + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + else + UnrecognizedLine(); + #endif + break; + } + + default: + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + UnrecognizedLine(); + #endif + break; + } + } + + // Pour que le squelette soit correctement aligné, il faut appliquer un quaternion "de correction" aux joints à la base du squelette + NzQuaternionf rotationQuat = NzEulerAnglesf(-90.f, 180.f, 0.f); + NzString baseDir = m_stream.GetDirectory(); + + if (m_parameters.animated) + { + if (!mesh->CreateSkeletal(m_joints.size())) // Ne devrait jamais échouer + { + NazaraInternalError("Failed to create mesh"); + return false; + } + + NzSkeleton* skeleton = mesh->GetSkeleton(); + for (unsigned int i = 0; i < m_joints.size(); ++i) + { + NzJoint* joint = skeleton->GetJoint(i); + + int parent = m_joints[i].parent; + if (parent >= 0) + joint->SetParent(skeleton->GetJoint(parent)); + + joint->SetName(m_joints[i].name); + + NzMatrix4f bindMatrix; + bindMatrix.MakeRotation((parent >= 0) ? m_joints[i].bindOrient : rotationQuat * m_joints[i].bindOrient); + bindMatrix.SetTranslation(m_joints[i].bindPos); // Plus rapide que de multiplier par une matrice de translation + + joint->SetInverseBindMatrix(bindMatrix.InverseAffine()); + } + + for (const Mesh& md5Mesh : m_meshes) + { + void* ptr; + unsigned int indexCount = md5Mesh.triangles.size()*3; + unsigned int vertexCount = md5Mesh.vertices.size(); + unsigned int weightCount = md5Mesh.weights.size(); + + // Index buffer + nzUInt8 indexSize; + if (vertexCount > std::numeric_limits::max()) + indexSize = 4; + else if (vertexCount > std::numeric_limits::max()) + indexSize = 2; + else + indexSize = 1; + + std::unique_ptr indexBuffer(new NzIndexBuffer(indexCount, indexSize, m_parameters.storage)); + if (!indexBuffer->GetBuffer()->IsValid()) + { + NazaraError("Failed to create index buffer"); + continue; + } + + ptr = indexBuffer->Map(nzBufferAccess_WriteOnly); + if (!ptr) + { + NazaraError("Failed to map index buffer"); + continue; + } + + switch (indexSize) + { + case 1: + { + nzUInt8* index = reinterpret_cast(ptr); + + for (const Mesh::Triangle& triangle : md5Mesh.triangles) + { + // On les respécifie dans le bon ordre + *index++ = triangle.x; + *index++ = triangle.z; + *index++ = triangle.y; + } + break; + } + + case 2: + { + nzUInt16* index = reinterpret_cast(ptr); + + for (const Mesh::Triangle& triangle : md5Mesh.triangles) + { + // On les respécifie dans le bon ordre + *index++ = triangle.x; + *index++ = triangle.z; + *index++ = triangle.y; + } + break; + } + + case 4: + { + nzUInt32* index = reinterpret_cast(ptr); + + for (const Mesh::Triangle& triangle : md5Mesh.triangles) + { + // On les respécifie dans le bon ordre + *index++ = triangle.x; + *index++ = triangle.z; + *index++ = triangle.y; + } + break; + } + } + + if (!indexBuffer->Unmap()) + NazaraWarning("Failed to unmap index buffer"); + + std::unique_ptr vertexBuffer(new NzVertexBuffer(NzMesh::GetDeclaration(), vertexCount, m_parameters.storage, nzBufferUsage_Dynamic)); + + std::unique_ptr subMesh(new NzSkeletalMesh(mesh)); + if (!subMesh->Create(vertexBuffer.get(), weightCount)) + { + NazaraError("Failed to create skeletal mesh"); + continue; + } + + subMesh->SetIndexBuffer(indexBuffer.get()); + indexBuffer->SetPersistent(false); + indexBuffer.release(); + + vertexBuffer->SetPersistent(false); + vertexBuffer.release(); + + NzWeight* weights = subMesh->GetWeight(); + for (unsigned int i = 0; i < weightCount; ++i) + { + weights->jointIndex = md5Mesh.weights[i].joint; + weights->weight = md5Mesh.weights[i].bias; + weights++; + } + + NzMeshVertex* bindPosVertex = reinterpret_cast(subMesh->GetBindPoseBuffer()); + NzVertexWeight* vertexWeight = subMesh->GetVertexWeight(); + for (const Mesh::Vertex& vertex : md5Mesh.vertices) + { + // Skinning MD5 (Formule d'Id Tech) + NzVector3f finalPos(NzVector3f::Zero()); + + vertexWeight->weights.resize(vertex.weightCount); + for (unsigned int j = 0; j < vertex.weightCount; ++j) + { + const Mesh::Weight& weight = md5Mesh.weights[vertex.startWeight + j]; + const Joint& joint = m_joints[weight.joint]; + + finalPos += (joint.bindPos + joint.bindOrient*weight.pos) * weight.bias; + vertexWeight->weights[j] = vertex.startWeight + j; + } + + bindPosVertex->position = finalPos; + bindPosVertex->uv.Set(vertex.uv.x, 1.f-vertex.uv.y); + bindPosVertex++; + vertexWeight++; + } + + // Material + if (!md5Mesh.shader.IsEmpty()) + { + unsigned int skinIndex; + if (mesh->AddMaterial(baseDir + md5Mesh.shader, &skinIndex)) + subMesh->SetMaterialIndex(skinIndex); + else + NazaraWarning("Failed to add mesh shader"); + } + + if (!mesh->AddSubMesh(subMesh.get())) + { + NazaraError("Failed to add submesh"); + continue; + } + + subMesh.release(); + + // Animation + // Il est peut-être éventuellement possible que la probabilité que l'animation ait le même nom soit non-nulle. + NzString animationPath = m_stream.GetPath(); + if (!animationPath.IsEmpty()) + { + animationPath.Replace(".md5mesh", ".md5anim", -8, NzString::CaseInsensitive); + if (NzFile::Exists(animationPath)) + { + std::unique_ptr animation(new NzAnimation); + if (animation->LoadFromFile(animationPath) && mesh->SetAnimation(animation.get())) + animation.release(); + else + NazaraWarning("Failed to load mesh's animation"); + } + } + } + } + else + { + if (!mesh->CreateStatic()) // Ne devrait jamais échouer + { + NazaraInternalError("Failed to create mesh"); + return false; + } + + for (const Mesh& md5Mesh : m_meshes) + { + void* ptr; + unsigned int indexCount = md5Mesh.triangles.size()*3; + unsigned int vertexCount = md5Mesh.vertices.size(); + + // Index buffer + nzUInt8 indexSize; + if (vertexCount > std::numeric_limits::max()) + indexSize = 4; + else if (vertexCount > std::numeric_limits::max()) + indexSize = 2; + else + indexSize = 1; + + std::unique_ptr indexBuffer(new NzIndexBuffer(indexCount, indexSize, m_parameters.storage)); + if (!indexBuffer->GetBuffer()->IsValid()) + { + NazaraError("Failed to create index buffer"); + continue; + } + + ptr = indexBuffer->Map(nzBufferAccess_WriteOnly); + if (!ptr) + { + NazaraError("Failed to map index buffer"); + continue; + } + + switch (indexSize) + { + case 1: + { + nzUInt8* index = reinterpret_cast(ptr); + + for (const Mesh::Triangle& triangle : md5Mesh.triangles) + { + // On les respécifie dans le bon ordre + *index++ = triangle.x; + *index++ = triangle.z; + *index++ = triangle.y; + } + break; + } + + case 2: + { + nzUInt16* index = reinterpret_cast(ptr); + + for (const Mesh::Triangle& triangle : md5Mesh.triangles) + { + // On les respécifie dans le bon ordre + *index++ = triangle.x; + *index++ = triangle.z; + *index++ = triangle.y; + } + break; + } + + case 4: + { + nzUInt32* index = reinterpret_cast(ptr); + + for (const Mesh::Triangle& triangle : md5Mesh.triangles) + { + // On les respécifie dans le bon ordre + *index++ = triangle.x; + *index++ = triangle.z; + *index++ = triangle.y; + } + break; + } + } + + if (!indexBuffer->Unmap()) + NazaraWarning("Failed to unmap index buffer"); + + // Vertex buffer + std::unique_ptr vertexBuffer(new NzVertexBuffer(NzMesh::GetDeclaration(), vertexCount, m_parameters.storage, nzBufferUsage_Dynamic)); + if (!vertexBuffer->GetBuffer()->IsValid()) + { + NazaraError("Failed to create vertex buffer"); + continue; + } + + ptr = vertexBuffer->Map(nzBufferAccess_WriteOnly); + if (!ptr) + { + NazaraError("Failed to map vertex buffer"); + continue; + } + + NzAxisAlignedBox aabb; + NzMeshVertex* vertex = reinterpret_cast(ptr); + for (const Mesh::Vertex& md5Vertex : md5Mesh.vertices) + { + // Skinning MD5 (Formule d'Id Tech) + NzVector3f finalPos(NzVector3f::Zero()); + for (unsigned int j = 0; j < md5Vertex.weightCount; ++j) + { + const Mesh::Weight& weight = md5Mesh.weights[md5Vertex.startWeight + j]; + const Joint& joint = m_joints[weight.joint]; + + finalPos += (joint.bindPos + joint.bindOrient*weight.pos) * weight.bias; + } + + // On retourne le modèle dans le bon sens + finalPos = rotationQuat * finalPos; + aabb.ExtendTo(finalPos); + + vertex->position = finalPos; + vertex->uv.Set(md5Vertex.uv.x, 1.f - md5Vertex.uv.y); + vertex++; + } + + if (!vertexBuffer->Unmap()) + NazaraWarning("Failed to unmap vertex buffer"); + + // Submesh + std::unique_ptr subMesh(new NzStaticMesh(mesh)); + if (!subMesh->Create(vertexBuffer.get())) + { + NazaraError("Failed to create static submesh"); + continue; + } + + vertexBuffer->SetPersistent(false); + vertexBuffer.release(); + + subMesh->SetAABB(aabb); + subMesh->SetIndexBuffer(indexBuffer.get()); + + indexBuffer->SetPersistent(false); + indexBuffer.release(); + + // Material + if (!md5Mesh.shader.IsEmpty()) + { + unsigned int skinIndex; + if (mesh->AddMaterial(baseDir + md5Mesh.shader, &skinIndex)) + subMesh->SetMaterialIndex(skinIndex); + else + NazaraWarning("Failed to add mesh shader"); + } + + if (!mesh->AddSubMesh(subMesh.get())) + { + NazaraError("Failed to add submesh"); + continue; + } + + subMesh.release(); + } + } + + return true; +} + +bool NzMD5MeshParser::Advance(bool required) +{ + if (!m_keepLastLine) + { + do + { + if (m_stream.EndOfStream()) + { + if (required) + Error("Incomplete MD5 file"); + + return false; + } + + m_lineCount++; + + m_currentLine = m_stream.ReadLine(); + m_currentLine = m_currentLine.SubstrTo("//"); // On ignore les commentaires + m_currentLine.Simplify(); // Pour un traitement plus simple + } + while (m_currentLine.IsEmpty()); + } + else + m_keepLastLine = false; + + return true; +} + +void NzMD5MeshParser::Error(const NzString& message) +{ + NazaraError(message + " at line #" + NzString::Number(m_lineCount)); +} + +bool NzMD5MeshParser::ParseJoints() +{ + unsigned int jointCount = m_joints.size(); + if (jointCount == 0) + { + Error("Joint count is invalid or missing"); + return false; + } + + for (unsigned int i = 0; i < jointCount; ++i) + { + if (!Advance()) + return false; + + unsigned int pos = m_currentLine.Find(' '); + if (pos == NzString::npos) + { + UnrecognizedLine(true); + return false; + } + + if (pos >= 64) + { + NazaraError("Joint name is too long (>= 64 characters)"); + return false; + } + + char name[64]; + if (std::sscanf(&m_currentLine[0], "%s %d ( %f %f %f ) ( %f %f %f )", &name[0], &m_joints[i].parent, + &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) != 8) + { + UnrecognizedLine(true); + return false; + } + + m_joints[i].name = name; + m_joints[i].name.Trim('"'); + + int parent = m_joints[i].parent; + if (parent >= 0) + { + if (static_cast(parent) >= jointCount) + { + Error("Joint's parent is out of bounds (" + NzString::Number(parent) + " >= " + NzString::Number(jointCount) + ')'); + return false; + } + } + + m_joints[i].bindOrient.ComputeW(); // On calcule la composante W + } + + if (!Advance()) + return false; + + if (m_currentLine != '}') + { + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + Warning("Hierarchy braces closing not found"); + #endif + + // On tente de survivre à l'erreur + m_keepLastLine = true; + } + + return true; +} + +bool NzMD5MeshParser::ParseMesh() +{ + bool finished = false; + while (!finished && Advance(false)) + { + switch (m_currentLine[0]) + { + case '}': + finished = true; + break; + + case 's': // shader + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + if (!m_currentLine.StartsWith("shader ")) + { + UnrecognizedLine(); + break; + } + #endif + + m_meshes[m_meshIndex].shader = m_currentLine.Substr(7); + m_meshes[m_meshIndex].shader.Trim('"'); + break; + + case 'n': // num[tris/verts] + { + unsigned int count; + if (std::sscanf(&m_currentLine[0], "numtris %u", &count) == 1) + { + m_meshes[m_meshIndex].triangles.resize(count); + for (unsigned int i = 0; i < count; ++i) + { + if (!Advance()) + return false; + + Mesh::Triangle& triangle = m_meshes[m_meshIndex].triangles[i]; + unsigned int index; + if (std::sscanf(&m_currentLine[0], "tri %u %u %u %u", &index, &triangle.x, &triangle.y, &triangle.z) != 4) + { + UnrecognizedLine(true); + return false; + } + + if (index != i) + { + Error("Unexpected triangle index (expected " + NzString::Number(i) + ", got " + NzString::Number(index) + ')'); + return false; + } + } + } + else if (std::sscanf(&m_currentLine[0], "numverts %u", &count) == 1) + { + m_meshes[m_meshIndex].vertices.resize(count); + for (unsigned int i = 0; i < count; ++i) + { + if (!Advance()) + return false; + + Mesh::Vertex& vertex = m_meshes[m_meshIndex].vertices[i]; + unsigned int index; + if (std::sscanf(&m_currentLine[0], "vert %u ( %f %f ) %u %u", &index, &vertex.uv.x, &vertex.uv.y, &vertex.startWeight, &vertex.weightCount) != 5) + { + UnrecognizedLine(true); + return false; + } + + if (index != i) + { + Error("Unexpected vertex index (expected " + NzString::Number(i) + ", got " + NzString::Number(index) + ')'); + return false; + } + } + } + else if (std::sscanf(&m_currentLine[0], "numweights %u", &count) == 1) + { + m_meshes[m_meshIndex].weights.resize(count); + for (unsigned int i = 0; i < count; ++i) + { + if (!Advance()) + return false; + + Mesh::Weight& weight = m_meshes[m_meshIndex].weights[i]; + unsigned int index; + if (std::sscanf(&m_currentLine[0], "weight %u %u %f ( %f %f %f )", &index, &weight.joint, &weight.bias, + &weight.pos.x, &weight.pos.y, &weight.pos.z) != 6) + { + UnrecognizedLine(true); + return false; + } + + if (index != i) + { + Error("Unexpected weight index (expected " + NzString::Number(i) + ", got " + NzString::Number(index) + ')'); + return false; + } + } + } + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + else + UnrecognizedLine(); + #endif + break; + } + + default: + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + UnrecognizedLine(); + #endif + break; + } + } + + if (m_meshes[m_meshIndex].triangles.size() == 0) + { + NazaraError("Mesh has no triangles"); + return false; + } + + if (m_meshes[m_meshIndex].vertices.size() == 0) + { + NazaraError("Mesh has no vertices"); + return false; + } + + if (m_meshes[m_meshIndex].weights.size() == 0) + { + NazaraError("Mesh has no weights"); + return false; + } + + #if NAZARA_UTILITY_STRICT_RESOURCE_PARSING + if (!finished) + Warning("Mesh braces closing not found"); + #endif + + return true; +} + +void NzMD5MeshParser::Warning(const NzString& message) +{ + NazaraWarning(message + " at line #" + NzString::Number(m_lineCount)); +} + +void NzMD5MeshParser::UnrecognizedLine(bool error) +{ + NzString message = "Unrecognized \"" + m_currentLine + '"'; + + if (error) + Error(message); + else + Warning(message); +} diff --git a/src/Nazara/Utility/Loaders/MD5Mesh/Parser.hpp b/src/Nazara/Utility/Loaders/MD5Mesh/Parser.hpp new file mode 100644 index 000000000..213944bd0 --- /dev/null +++ b/src/Nazara/Utility/Loaders/MD5Mesh/Parser.hpp @@ -0,0 +1,78 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LOADERS_MD5MESH_PARSER_HPP +#define NAZARA_LOADERS_MD5MESH_PARSER_HPP + +#include +#include +#include +#include +#include +#include +#include + +class NzMD5MeshParser +{ + public: + NzMD5MeshParser(NzInputStream& stream, const NzMeshParams& parameters); + ~NzMD5MeshParser(); + + bool Check(); + bool Parse(NzMesh* mesh); + + private: + struct Joint + { + NzQuaternionf bindOrient; + NzString name; + NzVector3f bindPos; + int parent; + }; + + struct Mesh + { + typedef NzVector3ui Triangle; + + struct Vertex + { + NzVector2f uv; + unsigned int startWeight; + unsigned int weightCount; + }; + + struct Weight + { + NzVector3f pos; + float bias; + unsigned int joint; + }; + + std::vector triangles; + std::vector vertices; + std::vector weights; + NzString shader; + }; + + bool Advance(bool required = true); + void Error(const NzString& message); + bool ParseJoints(); + bool ParseMesh(); + void Warning(const NzString& message); + void UnrecognizedLine(bool error = false); + + std::vector m_joints; + std::vector m_meshes; + NzInputStream& m_stream; + NzString m_currentLine; + const NzMeshParams& m_parameters; + bool m_keepLastLine; + unsigned int m_lineCount; + unsigned int m_meshIndex; + unsigned int m_streamFlags; +}; + +#endif // NAZARA_LOADERS_MD5MESH_PARSER_HPP diff --git a/src/Nazara/Utility/Loaders/PCX/Loader.cpp b/src/Nazara/Utility/Loaders/PCX/Loader.cpp index ec453b566..ee9a20cbc 100644 --- a/src/Nazara/Utility/Loaders/PCX/Loader.cpp +++ b/src/Nazara/Utility/Loaders/PCX/Loader.cpp @@ -37,6 +37,8 @@ namespace nzUInt8 padding[54]; }; + //static_assert(sizeof(pcx_header) == 1024, "PCX header must be 1024 bytes sized"); + bool Check(NzInputStream& stream, const NzImageParams& parameters) { NazaraUnused(parameters); diff --git a/src/Nazara/Utility/Mesh.cpp b/src/Nazara/Utility/Mesh.cpp index adcf25d71..50746f107 100644 --- a/src/Nazara/Utility/Mesh.cpp +++ b/src/Nazara/Utility/Mesh.cpp @@ -6,12 +6,21 @@ #include #include #include +#include +#include +#include #include #include #include #include #include +NzMeshParams::NzMeshParams() +{ + if (!NzBuffer::IsSupported(storage)) + storage = nzBufferStorage_Software; +} + bool NzMeshParams::IsValid() const { if (!animation.IsValid()) @@ -31,12 +40,14 @@ bool NzMeshParams::IsValid() const struct NzMeshImpl { - std::deque skins; std::map subMeshMap; + std::vector materials; std::vector subMeshes; nzAnimationType animationType; NzAxisAlignedBox aabb; + NzSkeleton skeleton; // Uniquement pour les animations squelettiques const NzAnimation* animation = nullptr; + unsigned int jointCount; // Uniquement pour les animations squelettiques }; NzMesh::~NzMesh() @@ -44,7 +55,7 @@ NzMesh::~NzMesh() Destroy(); } -bool NzMesh::AddSkin(const NzString& skin, bool setDefault) +bool NzMesh::AddMaterial(const NzString& matPath, unsigned int* matIndex) { #if NAZARA_UTILITY_SAFE if (!m_impl) @@ -53,17 +64,32 @@ bool NzMesh::AddSkin(const NzString& skin, bool setDefault) return false; } - if (skin.IsEmpty()) + if (matPath.IsEmpty()) { - NazaraError("Skin is empty"); + NazaraError("Material path is empty"); return false; } #endif - if (setDefault) - m_impl->skins.push_front(skin); - else - m_impl->skins.push_back(skin); + NzString path = NzFile::NormalizeSeparators(matPath); + + for (unsigned int i = 0; i < m_impl->materials.size(); ++i) + { + if (m_impl->materials[i] == path) // Ce skin est-il déjà présent ? + { + if (matIndex) + *matIndex = i; + + return true; + } + } + + // Sinon on l'ajoute + + if (matIndex) + *matIndex = m_impl->materials.size(); + + m_impl->materials.push_back(matPath); return true; } @@ -82,6 +108,12 @@ bool NzMesh::AddSubMesh(NzSubMesh* subMesh) NazaraError("Invalid submesh"); return false; } + + if (subMesh->GetAnimationType() != m_impl->animationType) + { + NazaraError("Submesh's animation type must match mesh animation type"); + return false; + } #endif subMesh->AddResourceListener(this, m_impl->subMeshes.size()); @@ -119,6 +151,12 @@ bool NzMesh::AddSubMesh(const NzString& identifier, NzSubMesh* subMesh) NazaraError("Invalid submesh"); return false; } + + if (m_impl->animationType != subMesh->GetAnimationType()) + { + NazaraError("Submesh's animation type must match mesh animation type"); + return false; + } #endif int index = m_impl->subMeshes.size(); @@ -159,7 +197,9 @@ void NzMesh::Animate(unsigned int frameA, unsigned int frameB, float interpolati NazaraError("Frame B is out of range (" + NzString::Number(frameB) + " >= " + NzString::Number(frameCount) + ')'); return; } + #endif + #ifdef NAZARA_DEBUG if (interpolation < 0.f || interpolation > 1.f) { NazaraError("Interpolation must be in range [0..1] (Got " + NzString::Number(interpolation) + ')'); @@ -167,18 +207,70 @@ void NzMesh::Animate(unsigned int frameA, unsigned int frameB, float interpolati } #endif - for (NzSubMesh* subMesh : m_impl->subMeshes) - subMesh->AnimateImpl(frameA, frameB, interpolation); + switch (m_impl->animationType) + { + case nzAnimationType_Keyframe: + for (NzSubMesh* subMesh : m_impl->subMeshes) + { + NzKeyframeMesh* keyframeMesh = static_cast(subMesh); + keyframeMesh->Interpolate(frameA, frameB, interpolation); + } + break; + + case nzAnimationType_Skeletal: + m_impl->animation->AnimateSkeleton(&m_impl->skeleton, frameA, frameB, interpolation); + for (NzSubMesh* subMesh : m_impl->subMeshes) + { + NzSkeletalMesh* skeletalMesh = static_cast(subMesh); + skeletalMesh->Skin(&m_impl->skeleton); + } + break; + + case nzAnimationType_Static: + // Le safe mode est censé nous protéger de cet appel + NazaraInternalError("Static mesh has no animation, please enable safe mode"); + break; + } m_impl->aabb.SetNull(); // On invalide l'AABB } -bool NzMesh::Create(nzAnimationType type) +bool NzMesh::CreateKeyframe() { Destroy(); m_impl = new NzMeshImpl; - m_impl->animationType = type; + m_impl->animationType = nzAnimationType_Keyframe; + + NotifyCreated(); + return true; +} + +bool NzMesh::CreateSkeletal(unsigned int jointCount) +{ + Destroy(); + + m_impl = new NzMeshImpl; + m_impl->animationType = nzAnimationType_Skeletal; + m_impl->jointCount = jointCount; + if (!m_impl->skeleton.Create(jointCount)) + { + NazaraError("Failed to create skeleton"); + + delete m_impl; + return false; + } + + NotifyCreated(); + return true; +} + +bool NzMesh::CreateStatic() +{ + Destroy(); + + m_impl = new NzMeshImpl; + m_impl->animationType = nzAnimationType_Static; NotifyCreated(); return true; @@ -265,7 +357,26 @@ unsigned int NzMesh::GetFrameCount() const return m_impl->animation->GetFrameCount(); } -NzString NzMesh::GetSkin(unsigned int index) const +unsigned int NzMesh::GetJointCount() const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Mesh not created"); + return 0; + } + + if (m_impl->animationType != nzAnimationType_Skeletal) + { + NazaraError("Mesh's animation type is not skeletal"); + return 0; + } + #endif + + return m_impl->jointCount; +} + +NzString NzMesh::GetMaterial(unsigned int index) const { #if NAZARA_UTILITY_SAFE if (!m_impl) @@ -274,17 +385,17 @@ NzString NzMesh::GetSkin(unsigned int index) const return NzString(); } - if (index >= m_impl->skins.size()) + if (index >= m_impl->materials.size()) { - NazaraError("Skin index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->skins.size()) + ')'); + NazaraError("Material index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->materials.size()) + ')'); return NzString(); } #endif - return m_impl->skins[index]; + return m_impl->materials[index]; } -unsigned int NzMesh::GetSkinCount() const +unsigned int NzMesh::GetMaterialCount() const { #if NAZARA_UTILITY_SAFE if (!m_impl) @@ -294,7 +405,45 @@ unsigned int NzMesh::GetSkinCount() const } #endif - return m_impl->skins.size(); + return m_impl->materials.size(); +} + +NzSkeleton* NzMesh::GetSkeleton() +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Animation not created"); + return nullptr; + } + + if (m_impl->animationType != nzAnimationType_Skeletal) + { + NazaraError("Mesh's animation type is not skeletal"); + return nullptr; + } + #endif + + return &m_impl->skeleton; +} + +const NzSkeleton* NzMesh::GetSkeleton() const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Animation not created"); + return nullptr; + } + + if (m_impl->animationType != nzAnimationType_Skeletal) + { + NazaraError("Mesh's animation type is not skeletal"); + return nullptr; + } + #endif + + return &m_impl->skeleton; } NzSubMesh* NzMesh::GetSubMesh(const NzString& identifier) @@ -305,18 +454,19 @@ NzSubMesh* NzMesh::GetSubMesh(const NzString& identifier) NazaraError("Mesh not created"); return nullptr; } + #endif auto it = m_impl->subMeshMap.find(identifier); + + #if NAZARA_UTILITY_SAFE if (it == m_impl->subMeshMap.end()) { NazaraError("SubMesh not found"); return nullptr; } + #endif return m_impl->subMeshes[it->second]; - #else - return m_impl->subMeshes[m_impl->subMeshMap[identifier]]; - #endif } NzSubMesh* NzMesh::GetSubMesh(unsigned int index) @@ -346,18 +496,19 @@ const NzSubMesh* NzMesh::GetSubMesh(const NzString& identifier) const NazaraError("Mesh not created"); return nullptr; } + #endif auto it = m_impl->subMeshMap.find(identifier); + + #if NAZARA_UTILITY_SAFE if (it == m_impl->subMeshMap.end()) { NazaraError("SubMesh not found"); return nullptr; } + #endif return m_impl->subMeshes[it->second]; - #else - return m_impl->subMeshes[m_impl->subMeshMap[identifier]]; - #endif } const NzSubMesh* NzMesh::GetSubMesh(unsigned int index) const @@ -400,18 +551,19 @@ int NzMesh::GetSubMeshIndex(const NzString& identifier) const NazaraError("Mesh not created"); return -1; } + #endif auto it = m_impl->subMeshMap.find(identifier); + + #if NAZARA_UTILITY_SAFE if (it == m_impl->subMeshMap.end()) { NazaraError("SubMesh not found"); return -1; } + #endif return it->second; - #else - return m_impl->subMeshMap[identifier]; - #endif } unsigned int NzMesh::GetVertexCount() const @@ -457,7 +609,7 @@ bool NzMesh::HasAnimation() const return m_impl->animation != nullptr; } -bool NzMesh::HasSkin(unsigned int index) const +bool NzMesh::HasMaterial(unsigned int index) const { #if NAZARA_UTILITY_SAFE if (!m_impl) @@ -467,7 +619,7 @@ bool NzMesh::HasSkin(unsigned int index) const } #endif - return m_impl->skins.size() > index; + return index < m_impl->materials.size(); } bool NzMesh::HasSubMesh(const NzString& identifier) const @@ -529,7 +681,7 @@ bool NzMesh::LoadFromStream(NzInputStream& stream, const NzMeshParams& params) return NzMeshLoader::LoadFromStream(this, stream, params); } -void NzMesh::RemoveSkin(unsigned int index) +void NzMesh::RemoveMaterial(unsigned int index) { #if NAZARA_UTILITY_SAFE if (!m_impl) @@ -538,18 +690,18 @@ void NzMesh::RemoveSkin(unsigned int index) return; } - if (m_impl->skins.size() <= index) + if (index >= m_impl->materials.size()) { - NazaraError("Skin index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->skins.size()) + ')'); + NazaraError("Material index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->materials.size()) + ')'); return; } #endif // On accède à l'itérateur correspondant à l'entrée #index - auto it = m_impl->skins.begin(); + auto it = m_impl->materials.begin(); std::advance(it, index); - m_impl->skins.erase(it); + m_impl->materials.erase(it); } void NzMesh::RemoveSubMesh(const NzString& identifier) @@ -639,6 +791,8 @@ bool NzMesh::SetAnimation(const NzAnimation* animation) if (animation->GetType() != m_impl->animationType) { NazaraError("Animation's type must match mesh animation type"); + m_impl->animation = nullptr; + return false; } #endif @@ -651,6 +805,59 @@ bool NzMesh::SetAnimation(const NzAnimation* animation) return true; } +void NzMesh::Skin(const NzSkeleton* skeleton) +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Mesh not created"); + return; + } + + if (m_impl->animationType != nzAnimationType_Skeletal) + { + NazaraError("Mesh's animation type is not skeletal"); + return; + } + #endif + + for (NzSubMesh* subMesh : m_impl->subMeshes) + { + NzSkeletalMesh* skeletalMesh = static_cast(subMesh); + skeletalMesh->Skin(skeleton); + } +} + +const NzVertexDeclaration* NzMesh::GetDeclaration() +{ + static NzVertexDeclaration declaration; + + if (!declaration.IsValid()) + { + // Déclaration correspondant à NzVertexStruct_XYZ_Normal_UV_Tangent + NzVertexElement elements[4]; + elements[0].offset = 0; + elements[0].type = nzElementType_Float3; + elements[0].usage = nzElementUsage_Position; + + elements[1].offset = 3*sizeof(float); + elements[1].type = nzElementType_Float3; + elements[1].usage = nzElementUsage_Normal; + + elements[2].offset = 3*sizeof(float) + 3*sizeof(float); + elements[2].type = nzElementType_Float2; + elements[2].usage = nzElementUsage_TexCoord; + + elements[3].offset = 3*sizeof(float) + 3*sizeof(float) + 2*sizeof(float); + elements[3].type = nzElementType_Float3; + elements[3].usage = nzElementUsage_Tangent; + + declaration.Create(elements, 4); + } + + return &declaration; +} + void NzMesh::OnResourceCreated(const NzResource* resource, int index) { NazaraUnused(index); diff --git a/src/Nazara/Utility/Node.cpp b/src/Nazara/Utility/Node.cpp new file mode 100644 index 000000000..4d045f81d --- /dev/null +++ b/src/Nazara/Utility/Node.cpp @@ -0,0 +1,429 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +NzNode::NzNode() : +m_rotation(NzQuaternionf::Identity()), +m_scale(NzVector3f(1.f, 1.f, 1.f)), +m_translation(NzVector3f::Zero()), +m_parent(nullptr), +m_derivedUpdated(false), +m_inheritRotation(true), +m_inheritScale(true), +m_inheritTranslation(true), +m_matrixUpdated(false) +{ +} + +NzNode::NzNode(const NzNode& node) : +m_rotation(node.m_rotation), +m_scale(node.m_scale), +m_translation(node.m_translation), +m_parent(node.m_parent), +m_derivedUpdated(false), +m_inheritRotation(node.m_inheritRotation), +m_inheritScale(node.m_inheritScale), +m_inheritTranslation(node.m_inheritTranslation), +m_matrixUpdated(false) +{ + if (m_parent) + m_parent->AddChild(this); +} + +NzNode::~NzNode() +{ + for (NzNode* child : m_childs) + child->m_parent = nullptr; + + if (m_parent) + m_parent->RemoveChild(this); +} + +NzQuaternionf NzNode::GetDerivedRotation() const +{ + if (!m_derivedUpdated) + UpdateDerived(); + + return m_derivedRotation; +} + +NzVector3f NzNode::GetDerivedScale() const +{ + if (!m_derivedUpdated) + UpdateDerived(); + + return m_derivedScale; +} + +NzVector3f NzNode::GetDerivedTranslation() const +{ + if (!m_derivedUpdated) + UpdateDerived(); + + return m_derivedTranslation; +} + +bool NzNode::GetInheritRotation() const +{ + return m_inheritRotation; +} + +bool NzNode::GetInheritScale() const +{ + return m_inheritScale; +} + +bool NzNode::GetInheritTranslation() const +{ + return m_inheritTranslation; +} + +const NzNode* NzNode::GetParent() const +{ + return m_parent; +} + +NzQuaternionf NzNode::GetRotation() const +{ + return m_rotation; +} + +NzVector3f NzNode::GetScale() const +{ + return m_scale; +} + +NzVector3f NzNode::GetTranslation() const +{ + return m_translation; +} + +NzMatrix4f NzNode::GetTransformMatrix() const +{ + if (!m_matrixUpdated) + UpdateMatrix(); + + return m_transformMatrix; +} + +NzNode& NzNode::Interpolate(const NzNode& nodeA, const NzNode& nodeB, float interpolation) +{ + m_rotation = NzQuaternionf::Slerp(nodeA.m_rotation, nodeB.m_rotation, interpolation); + m_scale = NzVector3f::Lerp(nodeA.m_scale, nodeB.m_scale, interpolation); + m_translation = NzVector3f::Lerp(nodeA.m_translation, nodeB.m_translation, interpolation); + + Invalidate(); + return *this; +} + +NzNode& NzNode::Rotate(const NzQuaternionf& rotation, nzCoordSys coordSys) +{ + // Évitons toute mauvaise surprise .. + NzQuaternionf q(rotation); + q.Normalize(); + + switch (coordSys) + { + case nzCoordSys_Global: + { + if (!m_derivedUpdated) + UpdateDerived(); + + m_rotation *= m_derivedRotation.GetInverse() * q * m_derivedRotation; + break; + } + + case nzCoordSys_Local: + m_rotation *= q; + break; + } + + m_rotation.Normalize(); + + Invalidate(); + return *this; +} + +NzNode& NzNode::Scale(const NzVector3f& scale) +{ + m_scale *= scale; + + Invalidate(); + return *this; +} + +NzNode& NzNode::Scale(float scale) +{ + m_scale *= scale; + + Invalidate(); + return *this; +} + +NzNode& NzNode::Scale(float scaleX, float scaleY, float scaleZ) +{ + m_scale.x *= scaleX; + m_scale.y *= scaleY; + m_scale.z *= scaleZ; + + Invalidate(); + return *this; +} + +NzNode& NzNode::Translate(const NzVector3f& movement, nzCoordSys coordSys) +{ + switch (coordSys) + { + case nzCoordSys_Global: + { + if (m_parent) + m_translation += (m_parent->GetDerivedRotation().GetInverse() * movement) / m_parent->GetDerivedScale(); // Compensation + else + m_translation += movement; // Rien n'affecte le node + + break; + } + + case nzCoordSys_Local: + m_translation += m_scale * (m_rotation * movement); + break; + } + + Invalidate(); + return *this; +} + +NzNode& NzNode::Translate(float moveX, float moveY, float moveZ, nzCoordSys coordSys) +{ + return Translate(NzVector3f(moveX, moveY, moveZ), coordSys); +} + +void NzNode::SetInheritRotation(bool inheritRotation) +{ + ///DOC: Un appel redondant est sans effet + if (m_inheritRotation != inheritRotation) + { + m_inheritRotation = inheritRotation; + + Invalidate(); + } +} + +void NzNode::SetInheritScale(bool inheritScale) +{ + ///DOC: Un appel redondant est sans effet + if (m_inheritScale != inheritScale) + { + m_inheritScale = inheritScale; + + Invalidate(); + } +} + +void NzNode::SetInheritTranslation(bool inheritTranslation) +{ + if (m_inheritTranslation != inheritTranslation) + { + m_inheritTranslation = inheritTranslation; + + Invalidate(); + } +} + +void NzNode::SetParent(const NzNode* node) +{ + if (m_parent == node) + return; + + if (m_parent) + m_parent->RemoveChild(this); + + m_parent = node; + if (m_parent) + m_parent->AddChild(this); + + Invalidate(); +} + +void NzNode::SetParent(const NzNode& node) +{ + SetParent(&node); +} + +void NzNode::SetRotation(const NzQuaternionf& rotation, nzCoordSys coordSys) +{ + // Évitons toute mauvaise surprise .. + NzQuaternionf q(rotation); + q.Normalize(); + + switch (coordSys) + { + case nzCoordSys_Global: + { + if (m_parent) + { + m_rotation = q * m_parent->GetDerivedRotation().GetInverse(); ///FIXME: Vérifier si le résultat est correct + m_rotation.Normalize(); + } + else + m_rotation = q; + + break; + } + + case nzCoordSys_Local: + m_rotation = q; + break; + } + + Invalidate(); +} + +void NzNode::SetScale(const NzVector3f& scale, nzCoordSys coordSys) +{ + switch (coordSys) + { + case nzCoordSys_Global: + { + if (m_parent) + m_scale = scale / m_parent->GetDerivedScale(); + else + m_scale = scale; + break; + } + + case nzCoordSys_Local: + m_scale = scale; + break; + } + + Invalidate(); +} + +void NzNode::SetScale(float scale, nzCoordSys coordSys) +{ + SetScale(NzVector3f(scale), coordSys); +} + +void NzNode::SetScale(float scaleX, float scaleY, float scaleZ, nzCoordSys coordSys) +{ + SetScale(NzVector3f(scaleX, scaleY, scaleZ), coordSys); +} + +void NzNode::SetTranslation(const NzVector3f& translation, nzCoordSys coordSys) +{ + switch (coordSys) + { + case nzCoordSys_Global: + { + if (m_parent) + m_translation = translation - m_parent->GetDerivedTranslation(); + else + m_translation = translation; + break; + } + + case nzCoordSys_Local: + m_translation = translation; + break; + } +} + +void NzNode::SetTranslation(float translationX, float translationY, float translationZ, nzCoordSys coordSys) +{ + SetTranslation(NzVector3f(translationX, translationY, translationZ), coordSys); +} + +NzNode& NzNode::operator=(const NzNode& node) +{ + SetParent(node.m_parent); + + m_inheritRotation = node.m_inheritRotation; + m_inheritScale = node.m_inheritScale; + m_inheritTranslation = node.m_inheritTranslation; + m_rotation = node.m_rotation; + m_scale = node.m_scale; + m_translation = node.m_translation; + + Invalidate(); + + return *this; +} + +void NzNode::AddChild(NzNode* node) const +{ + auto pair = m_childs.insert(node); + + if (pair.second) + node->Invalidate(); + #ifdef NAZARA_DEBUG + else + NazaraWarning("Child already in set"); + #endif +} + +void NzNode::Invalidate() +{ + m_derivedUpdated = false; + m_matrixUpdated = false; + + for (NzNode* node : m_childs) + node->Invalidate(); +} + +void NzNode::RemoveChild(NzNode* node) const +{ + #ifdef NAZARA_DEBUG + if (m_childs.erase(node) == 0) + NazaraWarning("Child not found in set"); + #else + m_childs.erase(node); + #endif +} + +void NzNode::UpdateDerived() const +{ + if (m_parent) + { + if (!m_parent->m_derivedUpdated) + m_parent->UpdateDerived(); + + if (m_inheritRotation) + { + m_derivedRotation = m_parent->m_derivedRotation * m_rotation; + m_derivedRotation.Normalize(); + } + else + m_derivedRotation = m_rotation; + + m_derivedScale = m_scale; + if (m_inheritScale) + m_derivedScale *= m_parent->m_derivedScale; + + if (m_inheritTranslation) + m_derivedTranslation = m_parent->m_derivedRotation*(m_parent->m_derivedScale * m_translation) + m_parent->m_derivedTranslation; + else + m_derivedTranslation = m_translation; + } + else + { + m_derivedRotation = m_rotation; + m_derivedScale = m_scale; + m_derivedTranslation = m_translation; + } + + m_derivedUpdated = true; +} + +void NzNode::UpdateMatrix() const +{ + if (!m_derivedUpdated) + UpdateDerived(); + + m_transformMatrix.MakeTransform(m_derivedTranslation, m_derivedScale, m_derivedRotation); + + m_matrixUpdated = true; +} diff --git a/src/Nazara/Utility/PixelFormat.cpp b/src/Nazara/Utility/PixelFormat.cpp index 7c812f030..f3ba68909 100644 --- a/src/Nazara/Utility/PixelFormat.cpp +++ b/src/Nazara/Utility/PixelFormat.cpp @@ -1104,6 +1104,9 @@ namespace bool NzPixelFormat::Initialize() { + // Réinitialisation + std::memset(s_convertFunctions, 0, (nzPixelFormat_Max+1)*(nzPixelFormat_Max+1)*sizeof(NzPixelFormat::ConvertFunction)); + /**********************************BGR8***********************************/ RegisterConverter(); RegisterConverter(); @@ -1320,5 +1323,5 @@ void NzPixelFormat::Uninitialize() s_flipFunctions[i].clear(); } -NzPixelFormat::ConvertFunction NzPixelFormat::s_convertFunctions[nzPixelFormat_Max+1][nzPixelFormat_Max+1] = {{nullptr}}; ///FIXME: Fonctionne correctement ? +NzPixelFormat::ConvertFunction NzPixelFormat::s_convertFunctions[nzPixelFormat_Max+1][nzPixelFormat_Max+1]; std::map NzPixelFormat::s_flipFunctions[nzPixelFlipping_Max+1]; diff --git a/src/Nazara/Utility/SkeletalMesh.cpp b/src/Nazara/Utility/SkeletalMesh.cpp new file mode 100644 index 000000000..a04c56c01 --- /dev/null +++ b/src/Nazara/Utility/SkeletalMesh.cpp @@ -0,0 +1,311 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include + +struct NzSkeletalMeshImpl +{ + std::vector vertexWeights; + std::vector weights; + NzAxisAlignedBox aabb; + nzUInt8* bindPoseBuffer; + const NzIndexBuffer* indexBuffer = nullptr; + NzVertexBuffer* vertexBuffer; +}; + +NzSkeletalMesh::NzSkeletalMesh(const NzMesh* parent) : +NzSubMesh(parent) +{ +} + +NzSkeletalMesh::~NzSkeletalMesh() +{ + Destroy(); +} + +bool NzSkeletalMesh::Create(NzVertexBuffer* vertexBuffer, unsigned int weightCount) +{ + Destroy(); + + #if NAZARA_UTILITY_SAFE + if (!vertexBuffer) + { + NazaraError("Invalid vertex buffer"); + return false; + } + + if (weightCount == 0) + { + NazaraError("Weight count must be over 0"); + return false; + } + #endif + + vertexBuffer->AddResourceReference(); + + unsigned int vertexCount = vertexBuffer->GetVertexCount(); + + m_impl = new NzSkeletalMeshImpl; + m_impl->bindPoseBuffer = new nzUInt8[vertexCount*vertexBuffer->GetTypeSize()]; + m_impl->vertexBuffer = vertexBuffer; + m_impl->vertexWeights.resize(vertexCount); + m_impl->weights.resize(weightCount); + + return true; +} + +void NzSkeletalMesh::Destroy() +{ + if (m_impl) + { + if (m_impl->indexBuffer) + m_impl->indexBuffer->RemoveResourceReference(); + + if (m_impl->vertexBuffer) + m_impl->vertexBuffer->RemoveResourceReference(); + + delete[] m_impl->bindPoseBuffer; + delete m_impl; + m_impl = nullptr; + } +} + +const NzAxisAlignedBox& NzSkeletalMesh::GetAABB() const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeletal mesh not created"); + return NzAxisAlignedBox::Null; + } + #endif + + return m_parent->GetSkeleton()->GetAABB(); +} + +nzAnimationType NzSkeletalMesh::GetAnimationType() const +{ + return nzAnimationType_Skeletal; +} + +void* NzSkeletalMesh::GetBindPoseBuffer() +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeletal mesh not created"); + return nullptr; + } + #endif + + return m_impl->bindPoseBuffer; +} + +const void* NzSkeletalMesh::GetBindPoseBuffer() const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeletal mesh not created"); + return nullptr; + } + #endif + + return m_impl->bindPoseBuffer; +} + +const NzIndexBuffer* NzSkeletalMesh::GetIndexBuffer() const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeletal mesh not created"); + return nullptr; + } + #endif + + return m_impl->indexBuffer; +} + +const NzVertexBuffer* NzSkeletalMesh::GetVertexBuffer() const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeletal mesh not created"); + return nullptr; + } + #endif + + return m_impl->vertexBuffer; +} + +NzVertexWeight* NzSkeletalMesh::GetVertexWeight(unsigned int vertexIndex) +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeletal mesh not created"); + return nullptr; + } + #endif + + return &m_impl->vertexWeights[vertexIndex]; +} + +const NzVertexWeight* NzSkeletalMesh::GetVertexWeight(unsigned int vertexIndex) const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeletal mesh not created"); + return nullptr; + } + #endif + + return &m_impl->vertexWeights[vertexIndex]; +} + +NzWeight* NzSkeletalMesh::GetWeight(unsigned int weightIndex) +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeletal mesh not created"); + return nullptr; + } + #endif + + return &m_impl->weights[weightIndex]; +} + +const NzWeight* NzSkeletalMesh::GetWeight(unsigned int weightIndex) const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeletal mesh not created"); + return nullptr; + } + #endif + + return &m_impl->weights[weightIndex]; +} + +unsigned int NzSkeletalMesh::GetWeightCount() const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeletal mesh not created"); + return 0; + } + #endif + + return m_impl->weights.size(); +} + +bool NzSkeletalMesh::IsAnimated() const +{ + return true; +} + +bool NzSkeletalMesh::IsValid() const +{ + return m_impl != nullptr; +} + +void NzSkeletalMesh::Skin() +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeletal mesh not created"); + return; + } + #endif + + Skin(m_parent->GetSkeleton()); +} + +void NzSkeletalMesh::Skin(const NzSkeleton* skeleton) +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeletal mesh not created"); + return; + } + #endif + + void* outputBuffer = m_impl->vertexBuffer->Map(nzBufferAccess_DiscardAndWrite); + if (!outputBuffer) + { + NazaraError("Failed to map vertex buffer"); + return; + } + + NzVertexStruct_XYZ_Normal_UV_Tangent* inputVertex = reinterpret_cast(m_impl->bindPoseBuffer); + NzVertexStruct_XYZ_Normal_UV_Tangent* outputVertex = reinterpret_cast(outputBuffer); + + NzClock c; + + const NzJoint* joints = skeleton->GetJoints(); + unsigned int vertexCount = m_impl->vertexBuffer->GetVertexCount(); + for (unsigned int i = 0; i < vertexCount; ++i) + { + NzVector3f finalPosition(NzVector3f::Zero()); + NzVector3f finalNormal(NzVector3f::Zero()); + NzVector3f finalTangent(NzVector3f::Zero()); + + unsigned int weightCount = m_impl->vertexWeights[i].weights.size(); + for (unsigned int j = 0; j < weightCount; ++j) + { + const NzWeight& weight = m_impl->weights[m_impl->vertexWeights[i].weights[j]]; + + NzMatrix4f mat(joints[weight.jointIndex].GetInverseBindMatrix()); + mat.ConcatenateAffine(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++; + } + + nzUInt64 t = c.GetMicroseconds(); + + NazaraError("Skinning took a total of " + NzString::Number(t) + "us\n\n"); + + if (!m_impl->vertexBuffer->Unmap()) + NazaraWarning("Failed to unmap vertex buffer"); +} + +void NzSkeletalMesh::SetIndexBuffer(const NzIndexBuffer* indexBuffer) +{ + if (m_impl->indexBuffer) + m_impl->indexBuffer->RemoveResourceReference(); + + if (indexBuffer) + indexBuffer->AddResourceReference(); + + m_impl->indexBuffer = indexBuffer; +} diff --git a/src/Nazara/Utility/Skeleton.cpp b/src/Nazara/Utility/Skeleton.cpp new file mode 100644 index 000000000..fbe457032 --- /dev/null +++ b/src/Nazara/Utility/Skeleton.cpp @@ -0,0 +1,384 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +struct NzSkeletonImpl +{ + std::map jointMap; + std::vector joints; + NzAxisAlignedBox aabb; + bool jointMapUpdated = false; +}; + +NzSkeleton::NzSkeleton(const NzSkeleton& skeleton) +{ + if (skeleton.m_impl) + { + m_impl = new NzSkeletonImpl; + m_impl->jointMap = skeleton.m_impl->jointMap; + m_impl->jointMapUpdated = skeleton.m_impl->jointMapUpdated; + m_impl->joints = skeleton.m_impl->joints; + } + else + m_impl = nullptr; +} + +NzSkeleton::~NzSkeleton() +{ + Destroy(); +} + +bool NzSkeleton::Create(unsigned int jointCount) +{ + #if NAZARA_UTILITY_SAFE + if (jointCount == 0) + { + NazaraError("Joint count must be over 0"); + return false; + } + #endif + + m_impl = new NzSkeletonImpl; + m_impl->joints.resize(jointCount, NzJoint(this)); + + return true; +} + +void NzSkeleton::Destroy() +{ + if (m_impl) + { + delete m_impl; + m_impl = nullptr; + } +} + +const NzAxisAlignedBox& NzSkeleton::GetAABB() const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeleton not created"); + return NzAxisAlignedBox::Null; + } + #endif + + if (m_impl->aabb.IsNull()) + { + for (unsigned int i = 0; i < m_impl->joints.size(); ++i) + m_impl->aabb.ExtendTo(m_impl->joints[i].GetDerivedTranslation()); + } + + return m_impl->aabb; +} + +NzJoint* NzSkeleton::GetJoint(const NzString& jointName) +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeleton not created"); + return nullptr; + } + #endif + + if (!m_impl->jointMapUpdated) + UpdateJointMap(); + + auto it = m_impl->jointMap.find(jointName); + + #if NAZARA_UTILITY_SAFE + if (it == m_impl->jointMap.end()) + { + NazaraError("Joint not found"); + return nullptr; + } + #endif + + // Invalidation de l'AABB + m_impl->aabb.SetNull(); + + return &m_impl->joints[it->second]; +} + +NzJoint* NzSkeleton::GetJoint(unsigned int index) +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeleton not created"); + return nullptr; + } + + if (index >= m_impl->joints.size()) + { + NazaraError("Joint index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->joints.size()) + ')'); + return nullptr; + } + #endif + + // Invalidation de l'AABB + m_impl->aabb.SetNull(); + + return &m_impl->joints[index]; +} + +const NzJoint* NzSkeleton::GetJoint(const NzString& jointName) const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeleton not created"); + return nullptr; + } + #endif + + if (!m_impl->jointMapUpdated) + UpdateJointMap(); + + auto it = m_impl->jointMap.find(jointName); + + #if NAZARA_UTILITY_SAFE + if (it == m_impl->jointMap.end()) + { + NazaraError("Joint not found"); + return nullptr; + } + #endif + + return &m_impl->joints[it->second]; +} + +const NzJoint* NzSkeleton::GetJoint(unsigned int index) const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeleton not created"); + return nullptr; + } + + if (index >= m_impl->joints.size()) + { + NazaraError("Joint index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->joints.size()) + ')'); + return nullptr; + } + #endif + + return &m_impl->joints[index]; +} + +NzJoint* NzSkeleton::GetJoints() +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeleton not created"); + return nullptr; + } + #endif + + return &m_impl->joints[0]; +} + +const NzJoint* NzSkeleton::GetJoints() const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeleton not created"); + return nullptr; + } + #endif + + return &m_impl->joints[0]; +} + +unsigned int NzSkeleton::GetJointCount() const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeleton not created"); + return 0; + } + #endif + + return m_impl->joints.size(); +} + +int NzSkeleton::GetJointIndex(const NzString& jointName) const +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeleton not created"); + return -1; + } + #endif + + if (!m_impl->jointMapUpdated) + UpdateJointMap(); + + auto it = m_impl->jointMap.find(jointName); + + #if NAZARA_UTILITY_SAFE + if (it == m_impl->jointMap.end()) + { + NazaraError("Joint not found"); + return -1; + } + #endif + + return it->second; +} + +void NzSkeleton::Interpolate(const NzSkeleton& skeletonA, const NzSkeleton& skeletonB, float interpolation) +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeleton not created"); + return; + } + + if (!skeletonA.IsValid()) + { + NazaraError("Skeleton A is invalid"); + return; + } + + if (!skeletonB.IsValid()) + { + NazaraError("Skeleton B is invalid"); + return; + } + + if (skeletonA.GetJointCount() != skeletonB.GetJointCount() || m_impl->joints.size() != skeletonA.GetJointCount()) + { + NazaraError("Skeletons must have the same joint count"); + return; + } + #endif + + NzJoint* jointsA = &skeletonA.m_impl->joints[0]; + NzJoint* jointsB = &skeletonB.m_impl->joints[0]; + for (unsigned int i = 0; i < m_impl->joints.size(); ++i) + m_impl->joints[i].Interpolate(jointsA[i], jointsB[i], interpolation); +} + +void NzSkeleton::Interpolate(const NzSkeleton& skeletonA, const NzSkeleton& skeletonB, float interpolation, unsigned int* indices, unsigned int indiceCount) +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Skeleton not created"); + return; + } + + if (!skeletonA.IsValid()) + { + NazaraError("Skeleton A is invalid"); + return; + } + + if (!skeletonB.IsValid()) + { + NazaraError("Skeleton B is invalid"); + return; + } + + if (skeletonA.GetJointCount() != skeletonB.GetJointCount() || m_impl->joints.size() != skeletonA.GetJointCount()) + { + NazaraError("Skeletons must have the same joint count"); + return; + } + #endif + + NzJoint* jointsA = &skeletonA.m_impl->joints[0]; + NzJoint* jointsB = &skeletonB.m_impl->joints[0]; + for (unsigned int i = 0; i < indiceCount; ++i) + { + unsigned int index = indices[i]; + + #if NAZARA_UTILITY_SAFE + if (index >= m_impl->joints.size()) + { + NazaraError("Index #" + NzString::Number(i) + " out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->joints.size()) + ')'); + return; + } + #endif + + m_impl->joints[index].Interpolate(jointsA[index], jointsB[index], interpolation); + } +} + +bool NzSkeleton::IsValid() const +{ + return m_impl != nullptr; +} + +NzSkeleton& NzSkeleton::operator=(const NzSkeleton& skeleton) +{ + Destroy(); + + if (skeleton.m_impl) + { + m_impl = new NzSkeletonImpl; + m_impl->jointMap = skeleton.m_impl->jointMap; + m_impl->jointMapUpdated = skeleton.m_impl->jointMapUpdated; + m_impl->joints = skeleton.m_impl->joints; + } + + return *this; +} + +void NzSkeleton::InvalidateJointMap() +{ + #ifdef NAZARA_DEBUG + if (!m_impl) + { + NazaraError("Invalid skeleton"); + return; + } + #endif + + m_impl->jointMapUpdated = false; +} + +void NzSkeleton::UpdateJointMap() const +{ + #ifdef NAZARA_DEBUG + if (!m_impl) + { + NazaraError("Invalid skeleton"); + return; + } + #endif + + m_impl->jointMap.clear(); + for (unsigned int i = 0; i < m_impl->joints.size(); ++i) + { + NzString name = m_impl->joints[i].GetName(); + if (!name.IsEmpty()) + { + #if NAZARA_UTILITY_SAFE + auto it = m_impl->jointMap.find(name); + if (it != m_impl->jointMap.end()) + { + NazaraWarning("Joint name \"" + name + "\" is already present in joint map for joint #" + NzString::Number(it->second)); + continue; + } + #endif + + m_impl->jointMap[name] = i; + } + } + + m_impl->jointMapUpdated = true; +} diff --git a/src/Nazara/Utility/StaticMesh.cpp b/src/Nazara/Utility/StaticMesh.cpp index d3d470dd7..bde9bc596 100644 --- a/src/Nazara/Utility/StaticMesh.cpp +++ b/src/Nazara/Utility/StaticMesh.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -12,36 +13,16 @@ NzSubMesh(parent) { } -NzStaticMesh::NzStaticMesh(const NzMesh* parent, const NzVertexDeclaration* vertexDeclaration, NzVertexBuffer* vertexBuffer, NzIndexBuffer* indexBuffer) : -NzSubMesh(parent) -{ - #ifdef NAZARA_DEBUG - if (!Create(vertexDeclaration, vertexBuffer, indexBuffer)) - { - NazaraError("Failed to create mesh"); - throw std::runtime_error("Constructor failed"); - } - #else - Create(vertexDeclaration, vertexBuffer, indexBuffer); - #endif -} - NzStaticMesh::~NzStaticMesh() { Destroy(); } -bool NzStaticMesh::Create(const NzVertexDeclaration* vertexDeclaration, NzVertexBuffer* vertexBuffer, NzIndexBuffer* indexBuffer) +bool NzStaticMesh::Create(NzVertexBuffer* vertexBuffer) { Destroy(); #if NAZARA_UTILITY_SAFE - if (!vertexDeclaration) - { - NazaraError("Invalid vertex declaration"); - return false; - } - if (!vertexBuffer) { NazaraError("Invalid vertex buffer"); @@ -49,17 +30,9 @@ bool NzStaticMesh::Create(const NzVertexDeclaration* vertexDeclaration, NzVertex } #endif - if (indexBuffer) - indexBuffer->AddResourceListener(this); - - m_indexBuffer = indexBuffer; - m_vertexBuffer = vertexBuffer; m_vertexBuffer->AddResourceListener(this); - m_vertexDeclaration = vertexDeclaration; - m_vertexDeclaration->AddResourceListener(this); - return true; } @@ -78,12 +51,6 @@ void NzStaticMesh::Destroy() m_vertexBuffer->RemoveResourceListener(this); m_vertexBuffer = nullptr; } - - if (m_vertexDeclaration) - { - m_vertexDeclaration->RemoveResourceListener(this); - m_vertexDeclaration = nullptr; - } } bool NzStaticMesh::GenerateAABB() @@ -91,31 +58,24 @@ bool NzStaticMesh::GenerateAABB() if (!m_aabb.IsNull()) return true; - const NzVertexElement* position = m_vertexDeclaration->GetElement(nzElementStream_VertexData, nzElementUsage_Position); - if (position && position->type == nzElementType_Float3) // Si nous avons des positions du type Vec3 + // On lock le buffer pour itérer sur toutes les positions et composer notre AABB + NzMeshVertex* vertex = reinterpret_cast(m_vertexBuffer->Map(nzBufferAccess_ReadOnly)); + if (!vertex) { - // On lock le buffer pour itérer sur toutes les positions et composer notre AABB - nzUInt8* buffer = reinterpret_cast(m_vertexBuffer->Map(nzBufferAccess_ReadOnly)); - if (!buffer) - { - NazaraWarning("Failed to lock vertex buffer"); - return false; - } - - buffer += position->offset; - unsigned int stride = m_vertexDeclaration->GetStride(nzElementStream_VertexData); - unsigned int vertexCount = m_vertexBuffer->GetVertexCount(); - for (unsigned int i = 0; i < vertexCount; ++i) - { - m_aabb.ExtendTo(*reinterpret_cast(buffer)); - - buffer += stride; - } - - if (!m_vertexBuffer->Unmap()) - NazaraWarning("Failed to unmap vertex buffer"); + NazaraWarning("Failed to lock vertex buffer"); + return false; } + unsigned int vertexCount = m_vertexBuffer->GetVertexCount(); + for (unsigned int i = 0; i < vertexCount; ++i) + { + m_aabb.ExtendTo(vertex->position); + vertex++; + } + + if (!m_vertexBuffer->Unmap()) + NazaraWarning("Failed to unmap vertex buffer"); + return true; } @@ -129,31 +89,16 @@ nzAnimationType NzStaticMesh::GetAnimationType() const return nzAnimationType_Static; } -unsigned int NzStaticMesh::GetFrameCount() const -{ - return 1; -} - const NzIndexBuffer* NzStaticMesh::GetIndexBuffer() const { return m_indexBuffer; } -nzPrimitiveType NzStaticMesh::GetPrimitiveType() const -{ - return m_primitiveType; -} - const NzVertexBuffer* NzStaticMesh::GetVertexBuffer() const { return m_vertexBuffer; } -const NzVertexDeclaration* NzStaticMesh::GetVertexDeclaration() const -{ - return m_vertexDeclaration; -} - bool NzStaticMesh::IsAnimated() const { return false; @@ -161,7 +106,7 @@ bool NzStaticMesh::IsAnimated() const bool NzStaticMesh::IsValid() const { - return m_vertexBuffer != nullptr && m_vertexDeclaration != nullptr; + return m_vertexBuffer != nullptr; } void NzStaticMesh::SetAABB(const NzAxisAlignedBox& aabb) @@ -169,19 +114,15 @@ void NzStaticMesh::SetAABB(const NzAxisAlignedBox& aabb) m_aabb = aabb; } -void NzStaticMesh::SetPrimitiveType(nzPrimitiveType primitiveType) +void NzStaticMesh::SetIndexBuffer(const NzIndexBuffer* indexBuffer) { - m_primitiveType = primitiveType; -} + if (m_indexBuffer) + m_indexBuffer->RemoveResourceReference(); -void NzStaticMesh::AnimateImpl(unsigned int frameA, unsigned int frameB, float interpolation) -{ - NazaraUnused(frameA); - NazaraUnused(frameB); - NazaraUnused(interpolation); + if (indexBuffer) + indexBuffer->AddResourceReference(); - // Le safe mode est censé nous protéger de cet appel - NazaraError("Static mesh have no animation, please enable safe mode"); + m_indexBuffer = indexBuffer; } void NzStaticMesh::OnResourceReleased(const NzResource* resource, int index) @@ -192,8 +133,8 @@ void NzStaticMesh::OnResourceReleased(const NzResource* resource, int index) m_indexBuffer = nullptr; else if (resource == m_vertexBuffer) m_vertexBuffer = nullptr; - else if (resource == m_vertexDeclaration) - m_vertexDeclaration = nullptr; else NazaraInternalError("Not listening to " + NzString::Pointer(resource)); + + resource->RemoveResourceListener(this); } diff --git a/src/Nazara/Utility/SubMesh.cpp b/src/Nazara/Utility/SubMesh.cpp index 1d04b038f..febca402e 100644 --- a/src/Nazara/Utility/SubMesh.cpp +++ b/src/Nazara/Utility/SubMesh.cpp @@ -12,61 +12,39 @@ NzSubMesh::NzSubMesh(const NzMesh* parent) : NzResource(false), // Un SubMesh n'est pas persistant par défaut -m_parent(parent) +m_parent(parent), +m_matIndex(0) { - #ifdef NAZARA_DEBUG - if (!m_parent) - { - NazaraError("Parent mesh must be valid"); - throw std::invalid_argument("Parent mesh must be valid"); - } - #endif } NzSubMesh::~NzSubMesh() = default; -void NzSubMesh::Animate(unsigned int frameA, unsigned int frameB, float interpolation) -{ - #if NAZARA_UTILITY_SAFE - if (!m_parent->HasAnimation()) - { - NazaraError("Parent mesh has no animation"); - return; - } - - unsigned int frameCount = m_parent->GetFrameCount(); - if (frameA >= frameCount) - { - NazaraError("Frame A is out of range (" + NzString::Number(frameA) + " >= " + NzString::Number(frameCount) + ')'); - return; - } - - if (frameB >= frameCount) - { - NazaraError("Frame B is out of range (" + NzString::Number(frameB) + " >= " + NzString::Number(frameCount) + ')'); - return; - } - #endif - - #ifdef NAZARA_DEBUG - if (interpolation < 0.f || interpolation > 1.f) - { - NazaraError("Interpolation must be in range [0..1] (Got " + NzString::Number(interpolation) + ')'); - return; - } - #endif - - AnimateImpl(frameA, frameB, interpolation); - - m_parent->InvalidateAABB(); -} - const NzMesh* NzSubMesh::GetParent() const { return m_parent; } +nzPrimitiveType NzSubMesh::GetPrimitiveType() const +{ + return m_primitiveType; +} + +unsigned int NzSubMesh::GetSkinIndex() const +{ + return m_matIndex; +} + unsigned int NzSubMesh::GetVertexCount() const { return GetVertexBuffer()->GetVertexCount(); } + +void NzSubMesh::SetPrimitiveType(nzPrimitiveType primitiveType) +{ + m_primitiveType = primitiveType; +} + +void NzSubMesh::SetMaterialIndex(unsigned int matIndex) +{ + m_matIndex = matIndex; +} diff --git a/src/Nazara/Utility/Utility.cpp b/src/Nazara/Utility/Utility.cpp index 095161214..23d66bb32 100644 --- a/src/Nazara/Utility/Utility.cpp +++ b/src/Nazara/Utility/Utility.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -48,17 +50,22 @@ bool NzUtility::Initialize() return false; } - /// Loaders spécialisés - // Mesh - NzLoaders_MD2_Register(); // Loader de fichiers .MD2 (v8) + // On enregistre les loaders pour les extensions + // Il s'agit ici d'une liste LIFO, le dernier loader enregistré possède la priorité - // Image - NzLoaders_PCX_Register(); // Loader de fichiers .PCX (1, 4, 8, 24) - - /// Loaders génériques (En dernier pour donner la priorité aux loaders spécialisés) + /// Loaders génériques // Image NzLoaders_STB_Register(); // Loader générique (STB) + /// Loaders spécialisés + // Mesh + NzLoaders_MD2_Register(); // Loader de fichiers .md2 (v8) + NzLoaders_MD5Anim_Register(); // Loader de fichiers .md5anim (v10) + NzLoaders_MD5Mesh_Register(); // Loader de fichiers .md5mesh (v10) + + // Image + NzLoaders_PCX_Register(); // Loader de fichiers .pcx (1, 4, 8, 24 bits) + NazaraNotice("Initialized: Utility module"); return true; @@ -76,6 +83,7 @@ void NzUtility::Uninitialize() // Libération du module NzLoaders_MD2_Unregister(); + NzLoaders_MD5Mesh_Unregister(); NzLoaders_PCX_Unregister(); NzLoaders_STB_Unregister(); diff --git a/src/Nazara/Utility/VertexBuffer.cpp b/src/Nazara/Utility/VertexBuffer.cpp index f8f4c2512..754a7a1c8 100644 --- a/src/Nazara/Utility/VertexBuffer.cpp +++ b/src/Nazara/Utility/VertexBuffer.cpp @@ -9,35 +9,54 @@ ///FIXME: Gérer efficacement les erreurs de création du buffer -NzVertexBuffer::NzVertexBuffer(NzBuffer* buffer, unsigned int startVertex, unsigned int vertexCount) : +NzVertexBuffer::NzVertexBuffer(const NzVertexDeclaration* vertexDeclaration, NzBuffer* buffer, unsigned int startVertex, unsigned int vertexCount) : m_buffer(buffer), +m_vertexDeclaration(vertexDeclaration), m_ownsBuffer(false), m_startVertex(startVertex), m_vertexCount(vertexCount) { #ifdef NAZARA_DEBUG - if (!m_buffer) + if (!m_buffer || !m_buffer->IsValid()) { - NazaraError("Buffer is null"); + NazaraError("Buffer is invalid"); throw std::invalid_argument("Buffer must be valid"); } + + if (!m_vertexDeclaration || !m_vertexDeclaration->IsValid()) + { + NazaraError("Vertex declaration is invalid"); + throw std::invalid_argument("Invalid vertex declaration"); + } #endif m_buffer->AddResourceReference(); + m_vertexDeclaration->AddResourceReference(); } -NzVertexBuffer::NzVertexBuffer(unsigned int length, nzUInt8 typeSize, nzBufferStorage storage, nzBufferUsage usage) : +NzVertexBuffer::NzVertexBuffer(const NzVertexDeclaration* vertexDeclaration, unsigned int length, nzBufferStorage storage, nzBufferUsage usage) : +m_vertexDeclaration(vertexDeclaration), m_ownsBuffer(true), m_startVertex(0), m_vertexCount(length) { - m_buffer = new NzBuffer(nzBufferType_Vertex, length, typeSize, storage, usage); + #ifdef NAZARA_DEBUG + if (!m_vertexDeclaration || !m_vertexDeclaration->IsValid()) + { + NazaraError("Vertex declaration is invalid"); + throw std::invalid_argument("Invalid vertex declaration"); + } + #endif + + m_buffer = new NzBuffer(nzBufferType_Vertex, length, vertexDeclaration->GetStride(nzElementStream_VertexData), storage, usage); m_buffer->AddResourceReference(); m_buffer->SetPersistent(false); + m_vertexDeclaration->AddResourceReference(); } NzVertexBuffer::NzVertexBuffer(const NzVertexBuffer& vertexBuffer) : NzResource(true), +m_vertexDeclaration(vertexBuffer.m_vertexDeclaration), m_ownsBuffer(vertexBuffer.m_ownsBuffer), m_startVertex(vertexBuffer.m_startVertex), m_vertexCount(vertexBuffer.m_vertexCount) @@ -56,11 +75,14 @@ m_vertexCount(vertexBuffer.m_vertexCount) m_buffer = vertexBuffer.m_buffer; m_buffer->AddResourceReference(); } + + m_vertexDeclaration->AddResourceReference(); } NzVertexBuffer::~NzVertexBuffer() { m_buffer->RemoveResourceReference(); + m_vertexDeclaration->RemoveResourceReference(); } bool NzVertexBuffer::Fill(const void* data, unsigned int offset, unsigned int length) @@ -106,6 +128,11 @@ unsigned int NzVertexBuffer::GetVertexCount() const return m_vertexCount; } +const NzVertexDeclaration* NzVertexBuffer::GetVertexDeclaration() const +{ + return m_vertexDeclaration; +} + bool NzVertexBuffer::IsHardware() const { return m_buffer->IsHardware(); diff --git a/src/Nazara/Utility/VertexDeclaration.cpp b/src/Nazara/Utility/VertexDeclaration.cpp index 019a48fed..e7028f574 100644 --- a/src/Nazara/Utility/VertexDeclaration.cpp +++ b/src/Nazara/Utility/VertexDeclaration.cpp @@ -244,37 +244,20 @@ const NzVertexElement* NzVertexDeclaration::GetElement(nzElementStream stream, n #endif int elementPos = m_sharedImpl->elementPos[stream][usage]; - #if NAZARA_UTILITY_SAFE if (elementPos == -1) - { - NazaraError("Element not found"); return nullptr; - } - #endif if (usageIndex == 0) // Si l'usage index vaut zéro, alors nous sommes certains d'être sur le bon élément (Majorité des cas) return &m_sharedImpl->elements[elementPos]; else { elementPos += usageIndex; - - #if NAZARA_UTILITY_SAFE if (static_cast(elementPos) >= m_sharedImpl->elements.size()) - { - NazaraError("Element not found"); return nullptr; - } - #endif NzVertexElement& element = m_sharedImpl->elements[elementPos]; - - #if NAZARA_UTILITY_SAFE if (element.stream != stream || element.usage != usage || element.usageIndex != usageIndex) - { - NazaraError("Element not found"); return nullptr; - } - #endif return &element; }