diff --git a/build/scripts/module/3d.lua b/build/scripts/module/3d.lua new file mode 100644 index 000000000..cb508f8d5 --- /dev/null +++ b/build/scripts/module/3d.lua @@ -0,0 +1,41 @@ +if (not _OPTIONS["united"]) then + project "Nazara3D" +end + +files +{ + "../include/Nazara/3D/**.hpp", + "../include/Nazara/3D/**.inl", + "../src/Nazara/3D/**.hpp", + "../src/Nazara/3D/**.cpp" +} + +if (os.is("windows")) then + excludes { "../src/Nazara/3D/Posix/*.hpp", "../src/Nazara/3D/Posix/*.cpp" } +else + excludes { "../src/Nazara/3D/Win32/*.hpp", "../src/Nazara/3D/Win32/*.cpp" } +end + +if (_OPTIONS["united"]) then + excludes "../src/Nazara/3D/Debug/Leaks.cpp" +else + configuration "DebugStatic" + links "NazaraCore-s-d" + links "NazaraUtility-s-d" + links "NazaraRenderer-s-d" + + configuration "ReleaseStatic" + links "NazaraCore-s" + links "NazaraUtility-s" + links "NazaraRenderer-s" + + configuration "DebugDLL" + links "NazaraCore-d" + links "NazaraUtility-d" + links "NazaraRenderer-d" + + configuration "ReleaseDLL" + links "NazaraCore" + links "NazaraUtility" + links "NazaraRenderer" +end \ No newline at end of file diff --git a/examples/AnimatedMesh/build.lua b/examples/AnimatedMesh/build.lua index ec434dd22..18ee3ebd4 100644 --- a/examples/AnimatedMesh/build.lua +++ b/examples/AnimatedMesh/build.lua @@ -16,21 +16,25 @@ if (_OPTIONS["united"]) then links "NazaraEngine" else configuration "DebugStatic" + links "Nazara3D-s-d" links "NazaraRenderer-s-d" links "NazaraUtility-s-d" links "NazaraCore-s-d" configuration "ReleaseStatic" + links "Nazara3D-s" links "NazaraRenderer-s" links "NazaraUtility-s" links "NazaraCore-s" configuration "DebugDLL" + links "Nazara3D-d" links "NazaraRenderer-d" links "NazaraUtility-d" links "NazaraCore-d" configuration "ReleaseDLL" + links "Nazara3D" links "NazaraRenderer" links "NazaraUtility" links "NazaraCore" diff --git a/include/Nazara/3D/3D.hpp b/include/Nazara/3D/3D.hpp new file mode 100644 index 000000000..f1fff1471 --- /dev/null +++ b/include/Nazara/3D/3D.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - 3D Module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_3D_HPP +#define NAZARA_3D_HPP + +#include +#include + +class Nz3D +{ + public: + Nz3D() = delete; + ~Nz3D() = delete; + + static bool Initialize(); + + static bool IsInitialized(); + + static void Uninitialize(); + + private: + static unsigned int s_moduleReferenceCounter; +}; + +#endif // NAZARA_3D_HPP diff --git a/include/Nazara/3D/Config.hpp b/include/Nazara/3D/Config.hpp new file mode 100644 index 000000000..0fd581bc0 --- /dev/null +++ b/include/Nazara/3D/Config.hpp @@ -0,0 +1,38 @@ +/* + Nazara Engine - 3D module + + 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 + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#pragma once + +#ifndef NAZARA_CONFIG_3D_HPP +#define NAZARA_CONFIG_3D_HPP + +/// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci + +// Utilise un tracker pour repérer les éventuels leaks (Ralentit l'exécution) +#define NAZARA_3D_MEMORYLEAKTRACKER 0 + +// Active les tests de sécurité basés sur le code (Conseillé pour le développement) +#define NAZARA_3D_SAFE 1 + +#endif // NAZARA_CONFIG_3D_HPP diff --git a/include/Nazara/3D/Debug.hpp b/include/Nazara/3D/Debug.hpp new file mode 100644 index 000000000..f2e12bcbf --- /dev/null +++ b/include/Nazara/3D/Debug.hpp @@ -0,0 +1,11 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - 3D Module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#if NAZARA_3D_MEMORYLEAKTRACKER || defined(NAZARA_DEBUG) + #include + + #define delete NzMemoryManager::NextFree(__FILE__, __LINE__), delete + #define new new(__FILE__, __LINE__) +#endif diff --git a/include/Nazara/3D/DebugOff.hpp b/include/Nazara/3D/DebugOff.hpp new file mode 100644 index 000000000..d2a6b98b0 --- /dev/null +++ b/include/Nazara/3D/DebugOff.hpp @@ -0,0 +1,8 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - 3D Module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#if NAZARA_3D_MEMORYLEAKTRACKER || defined(NAZARA_DEBUG) + #undef delete + #undef new +#endif diff --git a/include/Nazara/Core/Resource.hpp b/include/Nazara/Core/Resource.hpp index 0da8c78c3..f5da1ce10 100644 --- a/include/Nazara/Core/Resource.hpp +++ b/include/Nazara/Core/Resource.hpp @@ -50,7 +50,7 @@ class NAZARA_API NzResource void RemoveResourceListener(NzResourceListener* listener) const; void RemoveResourceReference() const; - void SetPersistent(bool persistent = true); + void SetPersistent(bool persistent = true, bool checkReferenceCount = true); protected: void NotifyCreated(); diff --git a/include/Nazara/Core/ResourceLoader.inl b/include/Nazara/Core/ResourceLoader.inl index 7ee0363fa..659d3dd24 100644 --- a/include/Nazara/Core/ResourceLoader.inl +++ b/include/Nazara/Core/ResourceLoader.inl @@ -31,7 +31,7 @@ bool NzResourceLoader::LoadFromFile(Type* resource, const NzSt NzFile file(path, NzFile::ReadOnly); if (!file.IsOpen()) { - NazaraError("Failed to open file"); + NazaraError("Failed to open \"" + path + '"'); return false; } @@ -42,6 +42,8 @@ bool NzResourceLoader::LoadFromFile(Type* resource, const NzSt int cmp = NzString::Compare(loaderExt, ext); if (cmp == 0) { + file.SetCursorPos(0); + if (!std::get<1>(*loader)(file, parameters)) continue; @@ -52,8 +54,6 @@ bool NzResourceLoader::LoadFromFile(Type* resource, const NzSt return true; NazaraWarning("Loader failed"); - - file.SetCursorPos(0); } else if (cmp < 0) // S'il est encore possible que l'extension se situe après continue; @@ -95,11 +95,13 @@ bool NzResourceLoader::LoadFromStream(Type* resource, NzInputS nzUInt64 streamPos = stream.GetCursorPos(); for (auto loader = Type::s_loaders.begin(); loader != Type::s_loaders.end(); ++loader) { + stream.SetCursorPos(streamPos); + // Le loader supporte-t-il les données ? if (!std::get<1>(*loader)(stream, parameters)) continue; - // On repositionne le stream au début + // On repositionne le stream à son ancienne position stream.SetCursorPos(streamPos); // Chargement de la ressource @@ -107,7 +109,6 @@ bool NzResourceLoader::LoadFromStream(Type* resource, NzInputS return true; NazaraWarning("Loader failed"); - stream.SetCursorPos(streamPos); // On repositionne au début } NazaraError("Failed to load file: no loader"); diff --git a/include/Nazara/Math/Matrix4.inl b/include/Nazara/Math/Matrix4.inl index 135d7584c..ccc2e228f 100644 --- a/include/Nazara/Math/Matrix4.inl +++ b/include/Nazara/Math/Matrix4.inl @@ -590,9 +590,9 @@ NzMatrix4& NzMatrix4::MakeZero() template NzMatrix4& 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) { m11 = r11; m12 = r12; @@ -626,9 +626,7 @@ NzMatrix4& NzMatrix4::Set(const T matrix[16]) template NzMatrix4& NzMatrix4::Set(const NzMatrix4& matrix) { - NazaraError("Check 1"); std::memcpy(&m11, &matrix.m11, 16*sizeof(T)); - NazaraError("Check 2"); return *this; } diff --git a/include/Nazara/Renderer/Material.hpp b/include/Nazara/Renderer/Material.hpp new file mode 100644 index 000000000..4f0f8e9ad --- /dev/null +++ b/include/Nazara/Renderer/Material.hpp @@ -0,0 +1,95 @@ +// 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_MATERIAL_HPP +#define NAZARA_MATERIAL_HPP + +#include +#include +#include +#include +#include + +struct NAZARA_API NzMaterialParams +{ + bool loadDiffuseMap = true; + bool loadSpecularMap = true; + + bool IsValid() const; +}; + +class NzMaterial; + +using NzMaterialLoader = NzResourceLoader; + +class NAZARA_API NzMaterial : public NzResource +{ + friend NzMaterialLoader; + + public: + NzMaterial(); + ~NzMaterial(); + + void EnableAlphaBlending(bool alphaBlending); + void EnableZTest(bool zTest); + void EnableZWrite(bool zWrite); + + NzColor GetAmbientColor() const; + NzColor GetDiffuseColor() const; + const NzTexture* GetDiffuseMap() const; + nzBlendFunc GetDstAlpha() const; + nzFaceCulling GetFaceCulling() const; + nzFaceFilling GetFaceFilling() const; + float GetShininess() const; + NzColor GetSpecularColor() const; + const NzTexture* GetSpecularMap() const; + nzBlendFunc GetSrcAlpha() const; + nzRendererComparison GetZTestCompare() const; + + bool IsAlphaBlendingEnabled() const; + bool IsZTestEnabled() const; + bool IsZWriteEnabled() const; + + bool LoadFromFile(const NzString& filePath, const NzMaterialParams& params = NzMaterialParams()); + bool LoadFromMemory(const void* data, std::size_t size, const NzMaterialParams& params = NzMaterialParams()); + bool LoadFromStream(NzInputStream& stream, const NzMaterialParams& params = NzMaterialParams()); + + void Reset(); + + void SetAmbientColor(const NzColor& ambient); + void SetDiffuseColor(const NzColor& diffuse); + void SetDiffuseMap(const NzTexture* map); + void SetDstAlpha(nzBlendFunc func); + void SetFaceCulling(nzFaceCulling culling); + void SetFaceFilling(nzFaceFilling filling); + void SetShininess(float shininess); + void SetSpecularColor(const NzColor& specular); + void SetSpecularMap(const NzTexture* map); + void SetSrcAlpha(nzBlendFunc func); + void SetZTestCompare(nzRendererComparison compareFunc); + + static const NzMaterial* GetDefault(); + + private: + nzBlendFunc m_dstAlpha; + nzBlendFunc m_srcAlpha; + nzFaceCulling m_faceCulling; + nzFaceFilling m_faceFilling; + nzRendererComparison m_zTestCompareFunc; + NzColor m_ambientColor; + NzColor m_diffuseColor; + NzColor m_specularColor; + const NzTexture* m_diffuseMap; + const NzTexture* m_specularMap; + bool m_alphaBlendingEnabled; + bool m_zTestEnabled; + bool m_zWriteEnabled; + float m_shininess; + + static NzMaterialLoader::LoaderList s_loaders; +}; + +#endif // NAZARA_MATERIAL_HPP diff --git a/include/Nazara/Utility/KeyframeMesh.hpp b/include/Nazara/Utility/KeyframeMesh.hpp index 6c47a3421..0ece85e77 100644 --- a/include/Nazara/Utility/KeyframeMesh.hpp +++ b/include/Nazara/Utility/KeyframeMesh.hpp @@ -33,7 +33,7 @@ class NAZARA_API NzKeyframeMesh final : public NzSubMesh 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) const; + void Interpolate(const NzAnimation* animation, unsigned int frameA, unsigned int frameB, float interpolation) const; bool IsAnimated() const override; bool IsValid(); diff --git a/include/Nazara/Utility/Mesh.hpp b/include/Nazara/Utility/Mesh.hpp index 7134ff1a6..4de0d937a 100644 --- a/include/Nazara/Utility/Mesh.hpp +++ b/include/Nazara/Utility/Mesh.hpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -23,13 +22,13 @@ struct NAZARA_API NzMeshParams { NzMeshParams(); // Vérifie que le storage indiqué un peu plus bas est supporté - NzAnimationParams animation; nzBufferStorage storage = nzBufferStorage_Hardware; bool animated = true; bool IsValid() const; }; +class NzAnimation; class NzMesh; typedef NzVertexStruct_XYZ_Normal_UV_Tangent NzMeshVertex; @@ -46,11 +45,10 @@ class NAZARA_API NzMesh : public NzResource, NzResourceListener NzMesh() = default; ~NzMesh(); - 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) const; + void Animate(const NzAnimation* animation, unsigned int frameA, unsigned int frameB, float interpolation) const; bool CreateKeyframe(); bool CreateSkeletal(unsigned int jointCount); @@ -58,9 +56,8 @@ class NAZARA_API NzMesh : public NzResource, NzResourceListener void Destroy(); const NzAxisAlignedBox& GetAABB() const; - const NzAnimation* GetAnimation() const; + NzString GetAnimation() const; nzAnimationType GetAnimationType() const; - unsigned int GetFrameCount() const; unsigned int GetJointCount() const; NzString GetMaterial(unsigned int index) const; unsigned int GetMaterialCount() const; @@ -74,8 +71,6 @@ class NAZARA_API NzMesh : public NzResource, NzResourceListener int GetSubMeshIndex(const NzString& identifier) const; unsigned int GetVertexCount() const; - bool HasAnimation() const; - bool HasMaterial(unsigned int index) const; bool HasSubMesh(const NzString& identifier) const; bool HasSubMesh(unsigned int index = 0) const; @@ -88,18 +83,18 @@ 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 RemoveMaterial(unsigned int index); void RemoveSubMesh(const NzString& identifier); void RemoveSubMesh(unsigned int index); - bool SetAnimation(const NzAnimation* animation); + void SetAnimation(const NzString& animationPath); + void SetMaterial(unsigned int matIndex, const NzString& materialPath); + void SetMaterialCount(unsigned int matCount); void Skin(const NzSkeleton* skeleton) const; static const NzVertexDeclaration* GetDeclaration(); private: - void OnResourceCreated(const NzResource* resource, int index) override; void OnResourceReleased(const NzResource* resource, int index) override; NzMeshImpl* m_impl = nullptr; diff --git a/include/Nazara/Utility/Node.hpp b/include/Nazara/Utility/Node.hpp index 15733f5f1..b47c89dee 100644 --- a/include/Nazara/Utility/Node.hpp +++ b/include/Nazara/Utility/Node.hpp @@ -31,7 +31,7 @@ class NAZARA_API NzNode NzQuaternionf GetRotation() const; NzVector3f GetScale() const; NzVector3f GetTranslation() const; - NzMatrix4f GetTransformMatrix() const; + const NzMatrix4f& GetTransformMatrix() const; NzNode& Interpolate(const NzNode& nodeA, const NzNode& nodeB, float interpolation); diff --git a/include/Nazara/Utility/SubMesh.hpp b/include/Nazara/Utility/SubMesh.hpp index 31655c9b5..3d4ff7d61 100644 --- a/include/Nazara/Utility/SubMesh.hpp +++ b/include/Nazara/Utility/SubMesh.hpp @@ -28,9 +28,9 @@ class NAZARA_API NzSubMesh : public NzResource virtual const NzAxisAlignedBox& GetAABB() const = 0; virtual nzAnimationType GetAnimationType() const = 0; virtual const NzIndexBuffer* GetIndexBuffer() const = 0; + unsigned int GetMaterialIndex() const; const NzMesh* GetParent() const; nzPrimitiveType GetPrimitiveType() const; - unsigned int GetSkinIndex() const; virtual const NzVertexBuffer* GetVertexBuffer() const = 0; virtual unsigned int GetVertexCount() const; diff --git a/src/Nazara/3D/3D.cpp b/src/Nazara/3D/3D.cpp new file mode 100644 index 000000000..1901032e1 --- /dev/null +++ b/src/Nazara/3D/3D.cpp @@ -0,0 +1,49 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - 3D Module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include + +bool Nz3D::Initialize() +{ + if (s_moduleReferenceCounter++ != 0) + return true; // Déjà initialisé + + // Initialisation des dépendances + if (!NzRenderer::Initialize()) + { + NazaraError("Failed to initialize renderer module"); + return false; + } + + // Initialisation du module + + NazaraNotice("Initialized: 3D module"); + + return true; +} + +bool Nz3D::IsInitialized() +{ + return s_moduleReferenceCounter != 0; +} + +void Nz3D::Uninitialize() +{ + if (--s_moduleReferenceCounter != 0) + return; // Encore utilisé + + // Libération du module + + NazaraNotice("Uninitialized: 3D module"); + + // Libération des dépendances + NzRenderer::Uninitialize(); +} + +unsigned int Nz3D::s_moduleReferenceCounter = 0; diff --git a/src/Nazara/Core/Error.cpp b/src/Nazara/Core/Error.cpp index 302b12e88..53e1ae9d4 100644 --- a/src/Nazara/Core/Error.cpp +++ b/src/Nazara/Core/Error.cpp @@ -20,7 +20,7 @@ void NzError(nzErrorType type, const NzString& error, unsigned int line, const c #if NAZARA_CORE_EXIT_ON_ASSERT_FAILURE if (type == nzErrorType_AssertFailed) - exit(EXIT_FAILURE); + std::exit(EXIT_FAILURE); #endif } @@ -56,7 +56,7 @@ NzString NzGetLastSystemError(unsigned int code) return error; #elif defined(NAZARA_PLATFORM_POSIX) - return strerror(code); + return std::strerror(code); #else #error GetLastSystemError is not implemented on this platform diff --git a/src/Nazara/Core/Resource.cpp b/src/Nazara/Core/Resource.cpp index 1cea4eb37..e29501272 100644 --- a/src/Nazara/Core/Resource.cpp +++ b/src/Nazara/Core/Resource.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include NzResource::NzResource(bool persistent) : @@ -111,13 +113,13 @@ void NzResource::RemoveResourceReference() const } } -void NzResource::SetPersistent(bool persistent) +void NzResource::SetPersistent(bool persistent, bool checkReferenceCount) { NazaraMutexLock(m_mutex); m_resourcePersistent = persistent; - if (!persistent && m_resourceReferenceCount == 0) + if (checkReferenceCount && !persistent && m_resourceReferenceCount == 0) { NazaraMutexUnlock(m_mutex); delete this; diff --git a/src/Nazara/Renderer/Loaders/Texture.hpp b/src/Nazara/Renderer/Loaders/Texture.hpp new file mode 100644 index 000000000..c70b28305 --- /dev/null +++ b/src/Nazara/Renderer/Loaders/Texture.hpp @@ -0,0 +1,15 @@ +// 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_LOADERS_TEXTURE_HPP +#define NAZARA_LOADERS_TEXTURE_HPP + +#include + +void NzLoaders_Texture_Register(); +void NzLoaders_Texture_Unregister(); + +#endif // NAZARA_LOADERS_TEXTURE_HPP diff --git a/src/Nazara/Renderer/Loaders/Texture/Loader.cpp b/src/Nazara/Renderer/Loaders/Texture/Loader.cpp new file mode 100644 index 000000000..902609f87 --- /dev/null +++ b/src/Nazara/Renderer/Loaders/Texture/Loader.cpp @@ -0,0 +1,48 @@ +// 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 + +namespace +{ + bool Check(NzInputStream& stream, const NzMaterialParams& parameters) + { + NazaraUnused(stream); + NazaraUnused(parameters); + + return true; ///FIXME: Pas bon + } + + bool Load(NzMaterial* material, NzInputStream& stream, const NzMaterialParams& parameters) + { + NazaraUnused(parameters); + + NzTexture* texture = new NzTexture; + if (!texture->LoadFromStream(stream)) + { + NazaraError("Failed to load diffuse map"); + return false; + } + + material->Reset(); + material->SetDiffuseMap(texture); + texture->SetPersistent(false); + + return true; + } +} + +void NzLoaders_Texture_Register() +{ + ///FIXME: Pas bon + NzMaterialLoader::RegisterLoader("bmp,gif,hdr,jpg,jpeg,pic,png,psd,tga", Check, Load); +} + +void NzLoaders_Texture_Unregister() +{ + NzMaterialLoader::UnregisterLoader("bmp,gif,hdr,jpg,jpeg,pic,png,psd,tga", Check, Load); +} diff --git a/src/Nazara/Renderer/Material.cpp b/src/Nazara/Renderer/Material.cpp new file mode 100644 index 000000000..5676d6534 --- /dev/null +++ b/src/Nazara/Renderer/Material.cpp @@ -0,0 +1,238 @@ +// 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 + +bool NzMaterialParams::IsValid() const +{ + return true; +} + +NzMaterial::NzMaterial() : +m_diffuseMap(nullptr), +m_specularMap(nullptr) +{ + Reset(); +} + +NzMaterial::~NzMaterial() +{ + if (m_diffuseMap) + m_diffuseMap->RemoveResourceReference(); + + if (m_specularMap) + m_specularMap->RemoveResourceReference(); +} + +void NzMaterial::EnableAlphaBlending(bool alphaBlending) +{ + m_alphaBlendingEnabled = alphaBlending; +} + +void NzMaterial::EnableZTest(bool zTest) +{ + m_zTestEnabled = zTest; +} + +void NzMaterial::EnableZWrite(bool zWrite) +{ + m_zWriteEnabled = zWrite; +} + +NzColor NzMaterial::GetAmbientColor() const +{ + return m_ambientColor; +} + +NzColor NzMaterial::GetDiffuseColor() const +{ + return m_diffuseColor; +} + +const NzTexture* NzMaterial::GetDiffuseMap() const +{ + return m_diffuseMap; +} + +nzBlendFunc NzMaterial::GetDstAlpha() const +{ + return m_dstAlpha; +} + +nzFaceCulling NzMaterial::GetFaceCulling() const +{ + return m_faceCulling; +} + +nzFaceFilling NzMaterial::GetFaceFilling() const +{ + return m_faceFilling; +} + +float NzMaterial::GetShininess() const +{ + return m_shininess; +} + +NzColor NzMaterial::GetSpecularColor() const +{ + return m_specularColor; +} + +const NzTexture* NzMaterial::GetSpecularMap() const +{ + return m_specularMap; +} + +nzBlendFunc NzMaterial::GetSrcAlpha() const +{ + return m_srcAlpha; +} + +nzRendererComparison NzMaterial::GetZTestCompare() const +{ + return m_zTestCompareFunc; +} + +bool NzMaterial::IsAlphaBlendingEnabled() const +{ + return m_alphaBlendingEnabled; +} + +bool NzMaterial::IsZTestEnabled() const +{ + return m_zTestEnabled; +} + +bool NzMaterial::IsZWriteEnabled() const +{ + return m_zWriteEnabled; +} + +bool NzMaterial::LoadFromFile(const NzString& filePath, const NzMaterialParams& params) +{ + return NzMaterialLoader::LoadFromFile(this, filePath, params); +} + +bool NzMaterial::LoadFromMemory(const void* data, std::size_t size, const NzMaterialParams& params) +{ + return NzMaterialLoader::LoadFromMemory(this, data, size, params); +} + +bool NzMaterial::LoadFromStream(NzInputStream& stream, const NzMaterialParams& params) +{ + return NzMaterialLoader::LoadFromStream(this, stream, params); +} + +void NzMaterial::Reset() +{ + if (m_diffuseMap) + { + m_diffuseMap->RemoveResourceReference(); + m_diffuseMap = nullptr; + } + + if (m_specularMap) + { + m_specularMap->RemoveResourceReference(); + m_specularMap = nullptr; + } + + m_alphaBlendingEnabled = false; + m_ambientColor = NzColor::Black; + m_diffuseColor = NzColor::White; + m_dstAlpha = nzBlendFunc_Zero; + m_faceCulling = nzFaceCulling_Back; + m_faceFilling = nzFaceFilling_Fill; + m_shininess = 0; + m_specularColor = NzColor::White; + m_srcAlpha = nzBlendFunc_One; + m_zTestCompareFunc = nzRendererComparison_LessOrEqual; + m_zTestEnabled = true; + m_zWriteEnabled = true; +} + +void NzMaterial::SetAmbientColor(const NzColor& ambient) +{ + m_ambientColor = ambient; +} + +void NzMaterial::SetDiffuseColor(const NzColor& diffuse) +{ + m_diffuseColor = diffuse; +} + +void NzMaterial::SetDiffuseMap(const NzTexture* map) +{ + if (m_diffuseMap) + m_diffuseMap->RemoveResourceReference(); + + m_diffuseMap = map; + if (m_diffuseMap) + m_diffuseMap->AddResourceReference(); +} + +void NzMaterial::SetDstAlpha(nzBlendFunc func) +{ + m_dstAlpha = func; +} + +void NzMaterial::SetFaceCulling(nzFaceCulling culling) +{ + m_faceCulling = culling; +} + +void NzMaterial::SetFaceFilling(nzFaceFilling filling) +{ + m_faceFilling = filling; +} + +void NzMaterial::SetShininess(float shininess) +{ + m_shininess = shininess; +} + +void NzMaterial::SetSpecularColor(const NzColor& specular) +{ + m_specularColor = specular; +} + +void NzMaterial::SetSpecularMap(const NzTexture* map) +{ + if (m_specularMap) + m_specularMap->RemoveResourceReference(); + + m_specularMap = map; + if (m_specularMap) + m_specularMap->AddResourceReference(); +} + +void NzMaterial::SetSrcAlpha(nzBlendFunc func) +{ + m_srcAlpha = func; +} + +void NzMaterial::SetZTestCompare(nzRendererComparison compareFunc) +{ + m_zTestEnabled = compareFunc; +} + +const NzMaterial* NzMaterial::GetDefault() +{ + static NzMaterial defaultMaterial; + static bool initialized = false; + + if (!initialized) + { + defaultMaterial.SetFaceCulling(nzFaceCulling_FrontAndBack); + defaultMaterial.SetFaceFilling(nzFaceFilling_Line); + defaultMaterial.SetDiffuseColor(NzColor::White); + + initialized = true; + } + + return &defaultMaterial; +} + +NzMaterialLoader::LoaderList NzMaterial::s_loaders; diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index 055e9fb63..3b3e07f26 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -449,6 +450,9 @@ bool NzRenderer::Initialize() NazaraWarning("Failed to initialize debug drawer"); #endif + // Loaders + NzLoaders_Texture_Register(); + NazaraNotice("Initialized: Renderer module"); return true; @@ -903,6 +907,9 @@ void NzRenderer::Uninitialize() if (--s_moduleReferenceCounter != 0) return; // Encore utilisé + // Loaders + NzLoaders_Texture_Unregister(); + #ifdef NAZARA_DEBUG NzDebugDrawer::Uninitialize(); #endif @@ -1065,11 +1072,11 @@ bool NzRenderer::EnsureStateUpdate() glEnableVertexAttribArray(NzOpenGL::AttributeIndex[i]); glVertexAttribPointer(NzOpenGL::AttributeIndex[i], - NzVertexDeclaration::GetElementCount(element->type), - NzOpenGL::ElementType[element->type], - (element->type == nzElementType_Color) ? GL_TRUE : GL_FALSE, - stride, - &buffer[element->offset]); + NzVertexDeclaration::GetElementCount(element->type), + NzOpenGL::ElementType[element->type], + (element->type == nzElementType_Color) ? GL_TRUE : GL_FALSE, + stride, + &buffer[element->offset]); } else glDisableVertexAttribArray(NzOpenGL::AttributeIndex[i]); diff --git a/src/Nazara/Utility/KeyframeMesh.cpp b/src/Nazara/Utility/KeyframeMesh.cpp index fbd08fcb6..69c2aa9de 100644 --- a/src/Nazara/Utility/KeyframeMesh.cpp +++ b/src/Nazara/Utility/KeyframeMesh.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -222,16 +223,22 @@ const NzVertexBuffer* NzKeyframeMesh::GetVertexBuffer() const return m_impl->vertexBuffer; } -void NzKeyframeMesh::Interpolate(unsigned int frameA, unsigned int frameB, float interpolation) const +void NzKeyframeMesh::Interpolate(const NzAnimation* animation, unsigned int frameA, unsigned int frameB, float interpolation) const { #if NAZARA_UTILITY_SAFE - if (!m_parent->HasAnimation()) + if (!animation || !animation->IsValid()) { - NazaraError("Parent mesh has no animation"); + NazaraError("Animation must be valid"); return; } - unsigned int frameCount = m_parent->GetFrameCount(); + if (animation->GetType() != nzAnimationType_Keyframe) + { + NazaraError("Animation must be of keyframe type"); + return; + } + + unsigned int frameCount = animation->GetFrameCount(); if (frameA >= frameCount) { NazaraError("Frame A is out of range (" + NzString::Number(frameA) + " >= " + NzString::Number(frameCount) + ')'); diff --git a/src/Nazara/Utility/Loaders/MD2/Loader.cpp b/src/Nazara/Utility/Loaders/MD2/Loader.cpp index a6f246d39..c4cc78ce8 100644 --- a/src/Nazara/Utility/Loaders/MD2/Loader.cpp +++ b/src/Nazara/Utility/Loaders/MD2/Loader.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -18,7 +19,8 @@ namespace { - bool Check(NzInputStream& stream, const NzMeshParams& parameters) + /// Loader de mesh + bool CheckMesh(NzInputStream& stream, const NzMeshParams& parameters) { NazaraUnused(parameters); @@ -34,7 +36,7 @@ namespace return magic[0] == md2Ident && magic[1] == 8; } - bool Load(NzMesh* mesh, NzInputStream& stream, const NzMeshParams& parameters) + bool LoadMesh(NzMesh* mesh, NzInputStream& stream, const NzMeshParams& parameters) { md2_header header; if (stream.Read(&header, sizeof(md2_header)) != sizeof(md2_header)) @@ -69,11 +71,8 @@ namespace /// Création du mesh // Animé ou statique, c'est la question - 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)); - - bool animated = (parameters.animated && startFrame != endFrame); - if (animated) + ///FIXME: Le loader ne traite pas correctement le cas d'un mesh statique + if (parameters.animated) mesh->CreateKeyframe(); else mesh->CreateStatic(); @@ -84,9 +83,12 @@ namespace return false; } + mesh->SetAnimation(stream.GetPath()); // Même fichier + /// Chargement des skins if (header.num_skins > 0) { + mesh->SetMaterialCount(header.num_skins); stream.SetCursorPos(header.offset_skins); { NzString baseDir = stream.GetDirectory(); @@ -94,90 +96,19 @@ namespace for (unsigned int i = 0; i < header.num_skins; ++i) { stream.Read(skin, 68*sizeof(char)); - mesh->AddMaterial(baseDir + skin); + mesh->SetMaterial(i, baseDir + skin); } } } - /// Chargement des animations - if (animated) - { - NzAnimation* animation = new NzAnimation; - if (animation->CreateKeyframe(endFrame-startFrame+1)) - { - // Décodage des séquences - ///TODO: Optimiser le calcul - char last[16]; - - stream.SetCursorPos(header.offset_frames + startFrame*header.framesize + 2*sizeof(NzVector3f)); - stream.Read(last, 16*sizeof(char)); - - int pos = std::strlen(last)-1; - for (unsigned int j = 0; j < 2; ++j) - { - if (!std::isdigit(last[pos])) - break; - - pos--; - } - last[pos+1] = '\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 + 2*sizeof(NzVector3f)); - stream.Read(name, 16*sizeof(char)); - - pos = std::strlen(name)-1; - for (unsigned int j = 0; j < 2; ++j) - { - if (!std::isdigit(name[pos])) - break; - - pos--; - } - name[pos+1] = '\0'; - - if (std::strcmp(name, last) != 0) // Si les deux frames n'ont pas le même nom - { - std::strcpy(last, name); - - // 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; - } - - sequence.frameCount++; - } - // On ajoute la dernière frame (Qui n'a pas été traitée par la boucle) - animation->AddSequence(sequence); - - mesh->SetAnimation(animation); - animation->SetPersistent(false); - } - else - NazaraInternalError("Failed to create animaton"); - } - /// Chargement des submesh // Actuellement le loader ne charge qu'un submesh // 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)) + if (!subMesh->Create(vertexBuffer.get(), header.num_frames)) { NazaraError("Failed to create SubMesh"); return false; @@ -222,13 +153,13 @@ namespace #endif /// Chargement des frames - stream.SetCursorPos(header.offset_frames + header.framesize*startFrame); + stream.SetCursorPos(header.offset_frames); // 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) + for (unsigned int f = 0; f < header.num_frames; ++f) { NzVector3f scale, translate; @@ -286,14 +217,125 @@ namespace return true; } + + /// Loader d'animations + bool CheckAnim(NzInputStream& stream, const NzAnimationParams& parameters) + { + NazaraUnused(parameters); + + nzUInt32 magic[2]; + if (stream.Read(&magic[0], 2*sizeof(nzUInt32)) != 2*sizeof(nzUInt32)) + return false; + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&magic[0], sizeof(nzUInt32)); + NzByteSwap(&magic[1], sizeof(nzUInt32)); + #endif + + return magic[0] == md2Ident && magic[1] == 8; + } + + bool LoadAnim(NzAnimation* animation, NzInputStream& stream, const NzAnimationParams& parameters) + { + md2_header header; + if (stream.Read(&header, sizeof(md2_header)) != sizeof(md2_header)) + { + NazaraError("Failed to read header"); + return false; + } + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&header.framesize, sizeof(nzUInt32)); + NzByteSwap(&header.num_frames, sizeof(nzUInt32)); + NzByteSwap(&header.offset_frames, sizeof(nzUInt32)); + NzByteSwap(&header.offset_end, sizeof(nzUInt32)); + #endif + + if (stream.GetSize() < header.offset_end) + { + NazaraError("Incomplete MD2 file"); + return false; + } + + unsigned int startFrame = std::min(parameters.startFrame, static_cast(header.num_frames-1)); + unsigned int endFrame = std::min(parameters.endFrame, static_cast(header.num_frames-1)); + + unsigned int frameCount = endFrame - startFrame + 1; + if (!animation->CreateKeyframe(frameCount)) + { + NazaraInternalError("Failed to create animaton"); + return false; + } + + // Décodage des séquences + ///TODO: Optimiser le calcul + char last[16]; + + stream.SetCursorPos(header.offset_frames + startFrame*header.framesize + 2*sizeof(NzVector3f)); + stream.Read(last, 16*sizeof(char)); + + int pos = std::strlen(last)-1; + for (unsigned int j = 0; j < 2; ++j) + { + if (!std::isdigit(last[pos])) + break; + + pos--; + } + last[pos+1] = '\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 + 2*sizeof(NzVector3f)); + stream.Read(name, 16*sizeof(char)); + + pos = std::strlen(name)-1; + for (unsigned int j = 0; j < 2; ++j) + { + if (!std::isdigit(name[pos])) + break; + + pos--; + } + name[pos+1] = '\0'; + + if (std::strcmp(name, last) != 0) // Si les deux frames n'ont pas le même nom + { + std::strcpy(last, name); + + // 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; + } + + sequence.frameCount++; + } + // On ajoute la dernière frame (Qui n'a pas été traitée par la boucle) + animation->AddSequence(sequence); + + return true; + } } void NzLoaders_MD2_Register() { - NzMeshLoader::RegisterLoader("md2", Check, Load); + NzAnimationLoader::RegisterLoader("md2", CheckAnim, LoadAnim); + NzMeshLoader::RegisterLoader("md2", CheckMesh, LoadMesh); } void NzLoaders_MD2_Unregister() { - NzMeshLoader::UnregisterLoader("md2", Check, Load); + NzAnimationLoader::UnregisterLoader("md2", CheckAnim, LoadAnim); + NzMeshLoader::UnregisterLoader("md2", CheckMesh, LoadMesh); } diff --git a/src/Nazara/Utility/Loaders/MD5Mesh/Parser.cpp b/src/Nazara/Utility/Loaders/MD5Mesh/Parser.cpp index e6c8e3f41..fe3bcb68f 100644 --- a/src/Nazara/Utility/Loaders/MD5Mesh/Parser.cpp +++ b/src/Nazara/Utility/Loaders/MD5Mesh/Parser.cpp @@ -175,8 +175,11 @@ bool NzMD5MeshParser::Parse(NzMesh* mesh) joint->SetInverseBindMatrix(bindMatrix.InverseAffine()); } - for (const Mesh& md5Mesh : m_meshes) + mesh->SetMaterialCount(m_meshes.size()); + for (unsigned int i = 0; i < m_meshes.size(); ++i) { + const Mesh& md5Mesh = m_meshes[i]; + void* ptr; unsigned int indexCount = md5Mesh.triangles.size()*3; unsigned int vertexCount = md5Mesh.vertices.size(); @@ -270,10 +273,10 @@ bool NzMD5MeshParser::Parse(NzMesh* mesh) vertexBuffer.release(); NzWeight* weights = subMesh->GetWeight(); - for (unsigned int i = 0; i < weightCount; ++i) + for (unsigned int j = 0; j < weightCount; ++j) { - weights->jointIndex = md5Mesh.weights[i].joint; - weights->weight = md5Mesh.weights[i].bias; + weights->jointIndex = md5Mesh.weights[j].joint; + weights->weight = md5Mesh.weights[j].bias; weights++; } @@ -301,14 +304,8 @@ bool NzMD5MeshParser::Parse(NzMesh* mesh) } // 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"); - } + mesh->SetMaterial(i, baseDir + md5Mesh.shader); + subMesh->SetMaterialIndex(i); if (!mesh->AddSubMesh(subMesh.get())) { @@ -320,18 +317,12 @@ bool NzMD5MeshParser::Parse(NzMesh* mesh) // 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()) + NzString path = m_stream.GetPath(); + if (!path.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"); - } + path.Replace(".md5mesh", ".md5anim", -8, NzString::CaseInsensitive); + if (NzFile::Exists(path)) + mesh->SetAnimation(path); } } } @@ -343,8 +334,9 @@ bool NzMD5MeshParser::Parse(NzMesh* mesh) return false; } - for (const Mesh& md5Mesh : m_meshes) + for (unsigned int i = 0; i < m_meshes.size(); ++i) { + const Mesh& md5Mesh = m_meshes[i]; void* ptr; unsigned int indexCount = md5Mesh.triangles.size()*3; unsigned int vertexCount = md5Mesh.vertices.size(); @@ -479,14 +471,8 @@ bool NzMD5MeshParser::Parse(NzMesh* mesh) 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"); - } + mesh->SetMaterial(i, baseDir + md5Mesh.shader); + subMesh->SetMaterialIndex(i); if (!mesh->AddSubMesh(subMesh.get())) { diff --git a/src/Nazara/Utility/Mesh.cpp b/src/Nazara/Utility/Mesh.cpp index daa0ac94d..81861ce04 100644 --- a/src/Nazara/Utility/Mesh.cpp +++ b/src/Nazara/Utility/Mesh.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -23,12 +24,6 @@ NzMeshParams::NzMeshParams() bool NzMeshParams::IsValid() const { - if (!animation.IsValid()) - { - NazaraError("Invalid animation parameters"); - return false; - } - if (!NzBuffer::IsSupported(storage)) { NazaraError("Storage not supported"); @@ -46,7 +41,7 @@ struct NzMeshImpl nzAnimationType animationType; NzAxisAlignedBox aabb; NzSkeleton skeleton; // Uniquement pour les animations squelettiques - const NzAnimation* animation = nullptr; + NzString animationPath; unsigned int jointCount; // Uniquement pour les animations squelettiques }; @@ -55,45 +50,6 @@ NzMesh::~NzMesh() Destroy(); } -bool NzMesh::AddMaterial(const NzString& matPath, unsigned int* matIndex) -{ - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Mesh not created"); - return false; - } - - if (matPath.IsEmpty()) - { - NazaraError("Material path is empty"); - return false; - } - #endif - - 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; -} - bool NzMesh::AddSubMesh(NzSubMesh* subMesh) { #if NAZARA_UTILITY_SAFE @@ -111,7 +67,7 @@ bool NzMesh::AddSubMesh(NzSubMesh* subMesh) if (subMesh->GetAnimationType() != m_impl->animationType) { - NazaraError("Submesh's animation type must match mesh animation type"); + NazaraError("Submesh animation type must match mesh animation type"); return false; } #endif @@ -154,7 +110,7 @@ bool NzMesh::AddSubMesh(const NzString& identifier, NzSubMesh* subMesh) if (m_impl->animationType != subMesh->GetAnimationType()) { - NazaraError("Submesh's animation type must match mesh animation type"); + NazaraError("Submesh animation type must match mesh animation type"); return false; } #endif @@ -170,7 +126,7 @@ bool NzMesh::AddSubMesh(const NzString& identifier, NzSubMesh* subMesh) return true; } -void NzMesh::Animate(unsigned int frameA, unsigned int frameB, float interpolation) const +void NzMesh::Animate(const NzAnimation* animation, unsigned int frameA, unsigned int frameB, float interpolation) const { #if NAZARA_UTILITY_SAFE if (!m_impl) @@ -179,13 +135,19 @@ void NzMesh::Animate(unsigned int frameA, unsigned int frameB, float interpolati return; } - if (!m_impl->animation) + if (!animation || !animation->IsValid()) { - NazaraError("Mesh has no animation"); + NazaraError("Animation must be valid"); return; } - unsigned int frameCount = m_impl->animation->GetFrameCount(); + if (animation->GetType() != m_impl->animationType) + { + NazaraError("Animation type must match mesh animation type"); + return; + } + + unsigned int frameCount = animation->GetFrameCount(); if (frameA >= frameCount) { NazaraError("Frame A is out of range (" + NzString::Number(frameA) + " >= " + NzString::Number(frameCount) + ')'); @@ -213,12 +175,12 @@ void NzMesh::Animate(unsigned int frameA, unsigned int frameB, float interpolati for (NzSubMesh* subMesh : m_impl->subMeshes) { NzKeyframeMesh* keyframeMesh = static_cast(subMesh); - keyframeMesh->Interpolate(frameA, frameB, interpolation); + keyframeMesh->InterpolateImpl(frameA, frameB, interpolation); } break; case nzAnimationType_Skeletal: - m_impl->animation->AnimateSkeleton(&m_impl->skeleton, frameA, frameB, interpolation); + animation->AnimateSkeleton(&m_impl->skeleton, frameA, frameB, interpolation); for (NzSubMesh* subMesh : m_impl->subMeshes) { NzSkeletalMesh* skeletalMesh = static_cast(subMesh); @@ -282,9 +244,6 @@ void NzMesh::Destroy() { NotifyDestroy(); - if (m_impl->animation) - m_impl->animation->RemoveResourceListener(this); - for (NzSubMesh* subMesh : m_impl->subMeshes) subMesh->RemoveResourceListener(this); @@ -312,17 +271,17 @@ const NzAxisAlignedBox& NzMesh::GetAABB() const return m_impl->aabb; } -const NzAnimation* NzMesh::GetAnimation() const +NzString NzMesh::GetAnimation() const { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Mesh not created"); - return nullptr; + return nzAnimationType_Static; } #endif - return m_impl->animation; + return m_impl->animationPath; } nzAnimationType NzMesh::GetAnimationType() const @@ -338,25 +297,6 @@ nzAnimationType NzMesh::GetAnimationType() const return m_impl->animationType; } -unsigned int NzMesh::GetFrameCount() const -{ - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Mesh not created"); - return 0; - } - - if (!m_impl->animation) - { - NazaraError("Mesh has no animation"); - return 0; - } - #endif - - return m_impl->animation->GetFrameCount(); -} - unsigned int NzMesh::GetJointCount() const { #if NAZARA_UTILITY_SAFE @@ -596,32 +536,6 @@ void NzMesh::InvalidateAABB() const m_impl->aabb.SetNull(); } -bool NzMesh::HasAnimation() const -{ - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Mesh not created"); - return false; - } - #endif - - return m_impl->animation != nullptr; -} - -bool NzMesh::HasMaterial(unsigned int index) const -{ - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Mesh not created"); - return false; - } - #endif - - return index < m_impl->materials.size(); -} - bool NzMesh::HasSubMesh(const NzString& identifier) const { #if NAZARA_UTILITY_SAFE @@ -681,29 +595,6 @@ bool NzMesh::LoadFromStream(NzInputStream& stream, const NzMeshParams& params) return NzMeshLoader::LoadFromStream(this, stream, params); } -void NzMesh::RemoveMaterial(unsigned int index) -{ - #if NAZARA_UTILITY_SAFE - if (!m_impl) - { - NazaraError("Mesh not created"); - return; - } - - if (index >= m_impl->materials.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->materials.begin(); - std::advance(it, index); - - m_impl->materials.erase(it); -} - void NzMesh::RemoveSubMesh(const NzString& identifier) { #if NAZARA_UTILITY_SAFE @@ -763,46 +654,58 @@ void NzMesh::RemoveSubMesh(unsigned int index) m_impl->aabb.SetNull(); // On invalide l'AABB } -bool NzMesh::SetAnimation(const NzAnimation* animation) +void NzMesh::SetAnimation(const NzString& animationPath) { #if NAZARA_UTILITY_SAFE if (!m_impl) { NazaraError("Mesh not created"); - return false; - } - - if (m_impl->animationType == nzAnimationType_Static) - { - NazaraError("Static meshes cannot have animation"); - return false; + return; } #endif - if (animation == m_impl->animation) - return true; + m_impl->animationPath = animationPath; +} - if (m_impl->animation) - m_impl->animation->RemoveResourceListener(this); - - if (animation) +void NzMesh::SetMaterial(unsigned int matIndex, const NzString& materialPath) +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) { - #if NAZARA_UTILITY_SAFE - if (animation->GetType() != m_impl->animationType) - { - NazaraError("Animation's type must match mesh animation type"); - m_impl->animation = nullptr; - - return false; - } - #endif - - animation->AddResourceListener(this); + NazaraError("Mesh not created"); + return; } - m_impl->animation = animation; + if (matIndex >= m_impl->materials.size()) + { + NazaraError("Material index out of range (" + NzString::Number(matIndex) + " >= " + NzString::Number(m_impl->materials.size())); + return; + } + #endif - return true; + m_impl->materials[matIndex] = materialPath; +} + +void NzMesh::SetMaterialCount(unsigned int matCount) +{ + #if NAZARA_UTILITY_SAFE + if (!m_impl) + { + NazaraError("Mesh not created"); + return; + } + #endif + + m_impl->materials.resize(matCount); + + #ifdef NAZARA_DEBUG + for (NzSubMesh* subMesh : m_impl->subMeshes) + { + unsigned int matIndex = subMesh->GetMaterialIndex(); + if (matIndex >= matCount) + NazaraWarning("SubMesh " + NzString::Pointer(subMesh) + " material index is over mesh new material count (" + NzString::Number(matIndex) + " >= " + NzString::Number(matCount)); + } + #endif } void NzMesh::Skin(const NzSkeleton* skeleton) const @@ -858,30 +761,11 @@ const NzVertexDeclaration* NzMesh::GetDeclaration() return &declaration; } -void NzMesh::OnResourceCreated(const NzResource* resource, int index) -{ - NazaraUnused(index); - - if (resource == m_impl->animation) - { - #if NAZARA_UTILITY_SAFE - if (m_impl->animation->GetType() != m_impl->animationType) - { - NazaraError("Animation's type must match mesh animation type"); - - m_impl->animation->RemoveResourceListener(this); - m_impl->animation = nullptr; - } - #endif - } -} - void NzMesh::OnResourceReleased(const NzResource* resource, int index) { - if (resource == m_impl->animation) - SetAnimation(nullptr); - else - RemoveSubMesh(index); + NazaraUnused(resource); + + RemoveSubMesh(index); } NzMeshLoader::LoaderList NzMesh::s_loaders; diff --git a/src/Nazara/Utility/Node.cpp b/src/Nazara/Utility/Node.cpp index 4d045f81d..03c00ccfc 100644 --- a/src/Nazara/Utility/Node.cpp +++ b/src/Nazara/Utility/Node.cpp @@ -101,7 +101,7 @@ NzVector3f NzNode::GetTranslation() const return m_translation; } -NzMatrix4f NzNode::GetTransformMatrix() const +const NzMatrix4f& NzNode::GetTransformMatrix() const { if (!m_matrixUpdated) UpdateMatrix(); diff --git a/src/Nazara/Utility/SubMesh.cpp b/src/Nazara/Utility/SubMesh.cpp index febca402e..1a91fbac8 100644 --- a/src/Nazara/Utility/SubMesh.cpp +++ b/src/Nazara/Utility/SubMesh.cpp @@ -29,7 +29,7 @@ nzPrimitiveType NzSubMesh::GetPrimitiveType() const return m_primitiveType; } -unsigned int NzSubMesh::GetSkinIndex() const +unsigned int NzSubMesh::GetMaterialIndex() const { return m_matIndex; }