diff --git a/examples/AnimatedMesh/main.cpp b/examples/AnimatedMesh/main.cpp index 01e405b2b..b129902e1 100644 --- a/examples/AnimatedMesh/main.cpp +++ b/examples/AnimatedMesh/main.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -357,6 +358,18 @@ int main() drawHellknight = !drawHellknight; break; + case NzKeyboard::F5: + { + NzTextureSampler::SetDefaultFilterMode(nzSamplerFilter_Trilinear); + break; + } + + case NzKeyboard::F6: + { + NzTextureSampler::SetDefaultFilterMode(nzSamplerFilter_Nearest); + break; + } + /*case NzKeyboard::F5: { NzString animationName; @@ -574,9 +587,6 @@ bool CreateCheckerMaterial(NzMaterial* material) return false; } - texture->SetAnisotropyLevel(NzRenderer::GetMaxAnisotropyLevel()); // Un filtrage anisotropique pour la texture - texture->SetWrapMode(nzTextureWrap_Repeat); // Si les coordonnées de texture dépassent 1.f, la texture sera répétée - material->SetDiffuseMap(texture); texture->SetPersistent(false); diff --git a/include/Nazara/Renderer/Enums.hpp b/include/Nazara/Renderer/Enums.hpp index d56819da4..cbfaa36a9 100644 --- a/include/Nazara/Renderer/Enums.hpp +++ b/include/Nazara/Renderer/Enums.hpp @@ -117,6 +117,32 @@ enum nzRendererParameter nzRendererParameter_Max = nzRendererParameter_Stencil }; +enum nzSamplerFilter +{ + nzSamplerFilter_Unknown = -1, + + nzSamplerFilter_Bilinear, + nzSamplerFilter_Nearest, + nzSamplerFilter_Trilinear, + + nzSamplerFilter_Default, + + nzSamplerFilter_Max = nzSamplerFilter_Default +}; + +enum nzSamplerWrap +{ + nzSamplerWrap_Unknown = -1, + + nzSamplerWrap_Clamp, + nzSamplerWrap_MirroredRepeat, + nzSamplerWrap_Repeat, + + nzSamplerWrap_Default, + + nzSamplerWrap_Max = nzSamplerWrap_Repeat +}; + enum nzShaderLanguage { nzShaderLanguage_Unknown = -1, @@ -150,27 +176,4 @@ enum nzStencilOperation nzStencilOperation_Max = nzStencilOperation_Zero }; -enum nzTextureFilter -{ - nzTextureFilter_Unknown = -1, - - nzTextureFilter_Bilinear, - nzTextureFilter_Nearest, - nzTextureFilter_Trilinear, - - nzTextureFilter_Default, - - nzTextureFilter_Max = nzTextureFilter_Default -}; - -enum nzTextureWrap -{ - nzTextureWrap_Unknown = -1, - - nzTextureWrap_Clamp, - nzTextureWrap_Repeat, - - nzTextureWrap_Max = nzTextureWrap_Repeat -}; - #endif // NAZARA_ENUMS_RENDERER_HPP diff --git a/include/Nazara/Renderer/Material.hpp b/include/Nazara/Renderer/Material.hpp index 4f5fc939a..0b6484790 100644 --- a/include/Nazara/Renderer/Material.hpp +++ b/include/Nazara/Renderer/Material.hpp @@ -43,11 +43,12 @@ class NAZARA_API NzMaterial : public NzResource nzBlendFunc GetDstBlend() const; nzFaceCulling GetFaceCulling() const; nzFaceFilling GetFaceFilling() const; + nzSamplerFilter GetSamplerFilter() const; + nzSamplerWrap GetSamplerWrap() const; float GetShininess() const; NzColor GetSpecularColor() const; const NzTexture* GetSpecularMap() const; nzBlendFunc GetSrcBlend() const; - nzTextureFilter GetTextureFilter() const; nzRendererComparison GetZTestCompare() const; bool IsAlphaBlendingEnabled() const; @@ -66,12 +67,12 @@ class NAZARA_API NzMaterial : public NzResource void SetDstBlend(nzBlendFunc func); void SetFaceCulling(nzFaceCulling culling); void SetFaceFilling(nzFaceFilling filling); + void SetSamplerFilter(nzSamplerFilter filter); + void SetSamplerWrap(nzSamplerWrap wrapMode); void SetShininess(float shininess); void SetSpecularColor(const NzColor& specular); void SetSpecularMap(const NzTexture* map); void SetSrcBlend(nzBlendFunc func); - void SetTextureFilter(nzTextureFilter filter); - void SetTextureWrap(nzTextureWrap wrapMode); void SetZTestCompare(nzRendererComparison compareFunc); static const NzMaterial* GetDefault(); @@ -82,8 +83,8 @@ class NAZARA_API NzMaterial : public NzResource nzFaceCulling m_faceCulling; nzFaceFilling m_faceFilling; nzRendererComparison m_zTestCompareFunc; - nzTextureFilter m_textureFilter; - nzTextureWrap m_textureWrap; + nzSamplerFilter m_samplerFilter; + nzSamplerWrap m_samplerWrap; NzColor m_ambientColor; NzColor m_diffuseColor; NzColor m_specularColor; diff --git a/include/Nazara/Renderer/OpenGL.hpp b/include/Nazara/Renderer/OpenGL.hpp index 6172a5168..81f260e3f 100644 --- a/include/Nazara/Renderer/OpenGL.hpp +++ b/include/Nazara/Renderer/OpenGL.hpp @@ -86,12 +86,12 @@ class NAZARA_API NzOpenGL static GLenum PrimitiveType[nzPrimitiveType_Max+1]; static GLenum RendererComparison[nzRendererComparison_Max+1]; static GLenum RendererParameter[nzRendererParameter_Max+1]; + static GLenum SamplerWrapMode[nzSamplerWrap_Max+1]; static GLenum ShaderType[nzShaderType_Max+1]; static GLenum StencilOperation[nzStencilOperation_Max+1]; static GLenum TextureTarget[nzImageType_Max+1]; static GLenum TextureTargetBinding[nzImageType_Max+1]; static GLenum TextureTargetProxy[nzImageType_Max+1]; - static GLenum TextureWrapMode[nzTextureWrap_Max+1]; }; NAZARA_API extern PFNGLACTIVETEXTUREPROC glActiveTexture; diff --git a/include/Nazara/Renderer/Renderer.hpp b/include/Nazara/Renderer/Renderer.hpp index 5d08b3935..6b525f05c 100644 --- a/include/Nazara/Renderer/Renderer.hpp +++ b/include/Nazara/Renderer/Renderer.hpp @@ -12,8 +12,8 @@ #include #include #include +#include #include -#include class NzColor; class NzContext; @@ -42,7 +42,7 @@ class NAZARA_API NzRenderer static float GetLineWidth(); //static NzMatrix4f GetMatrix(nzMatrixCombination combination); static NzMatrix4f GetMatrix(nzMatrixType type); - static unsigned int GetMaxAnisotropyLevel(); + static nzUInt8 GetMaxAnisotropyLevel(); static unsigned int GetMaxRenderTargets(); static unsigned int GetMaxTextureUnits(); static float GetPointSize(); @@ -77,6 +77,8 @@ class NAZARA_API NzRenderer static void SetStencilReferenceValue(unsigned int refValue); static void SetStencilZFailOperation(nzStencilOperation zfailOperation); static bool SetTarget(NzRenderTarget* target); + static void SetTexture(unsigned int unit, const NzTexture* texture); + static void SetTextureSampling(unsigned int unit, const NzTextureSampler& sampler); static bool SetVertexBuffer(const NzVertexBuffer* vertexBuffer); static void SetViewport(const NzRectui& viewport); diff --git a/include/Nazara/Renderer/Texture.hpp b/include/Nazara/Renderer/Texture.hpp index 8cb44acf4..3ea82ba54 100644 --- a/include/Nazara/Renderer/Texture.hpp +++ b/include/Nazara/Renderer/Texture.hpp @@ -33,15 +33,13 @@ class NAZARA_API NzTexture : public NzResource, NzNonCopyable bool EnableMipmapping(bool enable); - unsigned int GetAnisotropyLevel() const; nzUInt8 GetBytesPerPixel() const; unsigned int GetDepth() const; - nzTextureFilter GetFilterMode() const; + nzSamplerFilter GetFilterMode() const; nzPixelFormat GetFormat() const; unsigned int GetHeight() const; nzImageType GetType() const; unsigned int GetWidth() const; - nzTextureWrap GetWrapMode() const; bool HasMipmaps() const; @@ -50,17 +48,14 @@ class NAZARA_API NzTexture : public NzResource, NzNonCopyable bool IsTarget() const; bool IsValid() const; - bool LoadFromFile(const NzString& filePath, const NzImageParams& params = NzImageParams()); - bool LoadFromImage(const NzImage& image); - bool LoadFromMemory(const void* data, std::size_t size, const NzImageParams& params = NzImageParams()); - bool LoadFromStream(NzInputStream& stream, const NzImageParams& params = NzImageParams()); + bool LoadFromFile(const NzString& filePath, const NzImageParams& params = NzImageParams(), bool generateMipmaps = true); + bool LoadFromImage(const NzImage& image, bool generateMipmaps = true); + bool LoadFromMemory(const void* data, std::size_t size, const NzImageParams& params = NzImageParams(), bool generateMipmaps = true); + bool LoadFromStream(NzInputStream& stream, const NzImageParams& params = NzImageParams(), bool generateMipmaps = true); bool Lock(); - bool SetAnisotropyLevel(unsigned int anistropyLevel); - bool SetFilterMode(nzTextureFilter filter); bool SetMipmapRange(nzUInt8 minLevel, nzUInt8 maxLevel); - bool SetWrapMode(nzTextureWrap wrap); bool Update(const NzImage& image, nzUInt8 level = 0); bool Update(const NzImage& image, const NzRectui& rect, unsigned int z = 0, nzUInt8 level = 0); @@ -76,8 +71,8 @@ class NAZARA_API NzTexture : public NzResource, NzNonCopyable void Unlock(); // Fonctions OpenGL + bool Bind() const; unsigned int GetOpenGLID() const; - bool Prepare() const; static unsigned int GetValidSize(unsigned int size); static bool IsFormatSupported(nzPixelFormat format); diff --git a/include/Nazara/Renderer/TextureSampler.hpp b/include/Nazara/Renderer/TextureSampler.hpp new file mode 100644 index 000000000..c5aa422c7 --- /dev/null +++ b/include/Nazara/Renderer/TextureSampler.hpp @@ -0,0 +1,60 @@ +// 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_TEXTURESAMPLER_HPP +#define NAZARA_TEXTURESAMPLER_HPP + +#include +#include + +class NzTexture; + +class NAZARA_API NzTextureSampler +{ + friend class NzRenderer; + + public: + NzTextureSampler(); + NzTextureSampler(const NzTextureSampler& sampler) = default; + + nzUInt8 GetAnisotropicLevel() const; + nzSamplerFilter GetFilterMode() const; + nzSamplerWrap GetWrapMode() const; + + void SetAnisotropyLevel(nzUInt8 anisotropyLevel); + void SetFilterMode(nzSamplerFilter filterMode); + void SetWrapMode(nzSamplerWrap wrapMode); + + NzTextureSampler& operator=(const NzTextureSampler& sampler) = default; + + static nzUInt8 GetDefaultAnisotropicLevel(); + static nzSamplerFilter GetDefaultFilterMode(); + static nzSamplerWrap GetDefaultWrapMode(); + + static void SetDefaultAnisotropyLevel(nzUInt8 anisotropyLevel); + static void SetDefaultFilterMode(nzSamplerFilter filterMode); + static void SetDefaultWrapMode(nzSamplerWrap wrapMode); + + private: + void Apply(const NzTexture* texture); + void Bind(unsigned int unit); + bool UseMipmaps(bool mipmaps); + + static bool Initialize(); + static void Uninitialize(); + + nzSamplerFilter m_filterMode; + nzSamplerWrap m_wrapMode; + nzUInt8 m_anisotropicLevel; + bool m_mipmaps; + mutable unsigned int m_samplerId; + + static nzSamplerFilter s_defaultFilterMode; + static nzSamplerWrap s_defaultWrapMode; + static nzUInt8 s_defaultAnisotropyLevel; +}; + +#endif // NAZARA_TEXTURESAMPLER_HPP diff --git a/src/Nazara/Renderer/GLSLShader.cpp b/src/Nazara/Renderer/GLSLShader.cpp index 27d5d29cf..bb71f3dfa 100644 --- a/src/Nazara/Renderer/GLSLShader.cpp +++ b/src/Nazara/Renderer/GLSLShader.cpp @@ -51,14 +51,8 @@ bool NzGLSLShader::BindTextures() for (auto it = m_textures.begin(); it != m_textures.end(); ++it) { TextureSlot& slot = it->second; - if (slot.enabled && !slot.updated) - { - glActiveTexture(GL_TEXTURE0 + slot.unit); - if (!slot.texture->Prepare()) - NazaraWarning("Failed to prepare texture"); - - slot.updated = true; - } + if (slot.enabled) + NzRenderer::SetTexture(slot.unit, slot.texture); } return true; diff --git a/src/Nazara/Renderer/Material.cpp b/src/Nazara/Renderer/Material.cpp index 41d4b8da5..8fef7efaf 100644 --- a/src/Nazara/Renderer/Material.cpp +++ b/src/Nazara/Renderer/Material.cpp @@ -145,11 +145,11 @@ void NzMaterial::Reset() m_dstBlend = nzBlendFunc_Zero; m_faceCulling = nzFaceCulling_Back; m_faceFilling = nzFaceFilling_Fill; + m_samplerFilter = nzSamplerFilter_Default; + m_samplerWrap = nzSamplerWrap_Repeat; m_shininess = 0; m_specularColor = NzColor::White; m_srcBlend = nzBlendFunc_One; - m_textureFilter = nzTextureFilter_Default; - m_textureWrap = nzTextureWrap_Repeat; m_zTestCompareFunc = nzRendererComparison_LessOrEqual; m_zTestEnabled = true; m_zWriteEnabled = true; diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index 43be759f7..73d660900 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -879,6 +879,13 @@ GLenum NzOpenGL::RendererParameter[nzRendererParameter_Max+1] = GL_STENCIL_TEST // nzRendererParameter_Stencil }; +GLenum NzOpenGL::SamplerWrapMode[nzSamplerWrap_Max+1] = +{ + GL_CLAMP_TO_EDGE, // nzTextureWrap_Clamp + GL_MIRRORED_REPEAT, // nzSamplerWrap_MirroredRepeat + GL_REPEAT // nzTextureWrap_Repeat +}; + GLenum NzOpenGL::ShaderType[nzShaderType_Max+1] = { GL_FRAGMENT_SHADER, // nzShaderType_Fragment @@ -928,12 +935,6 @@ GLenum NzOpenGL::TextureTargetProxy[nzImageType_Max+1] = GL_PROXY_TEXTURE_CUBE_MAP // nzImageType_Cubemap }; -GLenum NzOpenGL::TextureWrapMode[nzTextureWrap_Max+1] = -{ - GL_CLAMP_TO_EDGE, // nzTextureWrap_Clamp - GL_REPEAT // nzTextureWrap_Repeat -}; - PFNGLACTIVETEXTUREPROC glActiveTexture = nullptr; PFNGLATTACHSHADERPROC glAttachShader = nullptr; PFNGLBEGINQUERYPROC glBeginQuery = nullptr; diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index 630b86975..8fda92817 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -21,8 +21,10 @@ #include #include #include +#include #include #include +#include #include namespace @@ -37,6 +39,15 @@ namespace nzMatrixCombination_Max = nzMatrixCombination_WorldViewProj }; + struct TextureUnit + { + NzTextureSampler sampler; + const NzTexture* texture = nullptr; + bool samplerUpdated = false; + bool textureUpdated = true; + bool updated = true; + }; + NzBufferImpl* HardwareBufferFunction(NzBuffer* parent, nzBufferType type) { return new NzHardwareBuffer(parent, type); @@ -47,6 +58,7 @@ namespace using VAO_Key = std::tuple; std::map s_vaos; + std::vector s_textureUnits; NzMatrix4f s_matrix[totalMatrixCount]; int s_matrixLocation[totalMatrixCount]; bool s_matrixUpdated[totalMatrixCount]; @@ -59,6 +71,7 @@ namespace nzStencilOperation s_stencilFail; nzStencilOperation s_stencilPass; nzStencilOperation s_stencilZFail; + nzUInt8 s_maxAnisotropyLevel; nzUInt32 s_stencilMask; const NzIndexBuffer* s_indexBuffer; NzRenderTarget* s_target; @@ -69,7 +82,6 @@ namespace bool s_capabilities[nzRendererCap_Max+1]; bool s_stencilFuncUpdated; bool s_stencilOpUpdated; - unsigned int s_maxAnisotropyLevel; unsigned int s_maxRenderTarget; unsigned int s_maxTextureUnit; unsigned int s_stencilReference; @@ -327,7 +339,7 @@ NzMatrix4f NzRenderer::GetMatrix(nzMatrixType type) return s_matrix[type]; } -unsigned int NzRenderer::GetMaxAnisotropyLevel() +nzUInt8 NzRenderer::GetMaxAnisotropyLevel() { return s_maxAnisotropyLevel; } @@ -425,25 +437,6 @@ bool NzRenderer::Initialize(bool initializeDebugDrawer) s_matrixUpdated[i] = false; } - s_dstBlend = nzBlendFunc_Zero; - s_faceCulling = nzFaceCulling_Back; - s_faceFilling = nzFaceFilling_Fill; - s_indexBuffer = nullptr; - s_shader = nullptr; - s_srcBlend = nzBlendFunc_One; - s_stencilCompare = nzRendererComparison_Always; - s_stencilFail = nzStencilOperation_Keep; - s_stencilFuncUpdated = true; - s_stencilMask = 0xFFFFFFFF; - s_stencilOpUpdated = true; - s_stencilPass = nzStencilOperation_Keep; - s_stencilReference = 0; - s_stencilZFail = nzStencilOperation_Keep; - s_target = nullptr; - s_vaoUpdated = false; - s_vertexBuffer = nullptr; - s_vertexDeclaration = nullptr; - // Récupération des capacités d'OpenGL s_capabilities[nzRendererCap_AnisotropicFilter] = NzOpenGL::IsSupported(nzOpenGLExtension_AnisotropicFilter); s_capabilities[nzRendererCap_FP64] = NzOpenGL::IsSupported(nzOpenGLExtension_FP64); @@ -460,10 +453,10 @@ bool NzRenderer::Initialize(bool initializeDebugDrawer) if (s_capabilities[nzRendererCap_AnisotropicFilter]) { - GLint maxAnisotropy; - glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy); + GLfloat maxAnisotropy; + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy); - s_maxAnisotropyLevel = static_cast(maxAnisotropy); + s_maxAnisotropyLevel = static_cast(maxAnisotropy); } else s_maxAnisotropyLevel = 1; @@ -495,11 +488,33 @@ bool NzRenderer::Initialize(bool initializeDebugDrawer) else s_maxTextureUnit = 1; + s_dstBlend = nzBlendFunc_Zero; + s_faceCulling = nzFaceCulling_Back; + s_faceFilling = nzFaceFilling_Fill; + s_indexBuffer = nullptr; + s_shader = nullptr; + s_srcBlend = nzBlendFunc_One; + s_stencilCompare = nzRendererComparison_Always; + s_stencilFail = nzStencilOperation_Keep; + s_stencilFuncUpdated = true; + s_stencilMask = 0xFFFFFFFF; + s_stencilOpUpdated = true; + s_stencilPass = nzStencilOperation_Keep; + s_stencilReference = 0; + s_stencilZFail = nzStencilOperation_Keep; + s_target = nullptr; + s_textureUnits.resize(s_maxTextureUnit); + s_vaoUpdated = false; + s_vertexBuffer = nullptr; + s_vertexDeclaration = nullptr; + NzBuffer::SetBufferFunction(nzBufferStorage_Hardware, HardwareBufferFunction); if (initializeDebugDrawer && !NzDebugDrawer::Initialize()) NazaraWarning("Failed to initialize debug drawer"); // Non-critique + NzTextureSampler::Initialize(); + // Loaders NzLoaders_Texture_Register(); @@ -927,6 +942,47 @@ bool NzRenderer::SetTarget(NzRenderTarget* target) return true; } +void NzRenderer::SetTexture(unsigned int unit, const NzTexture* texture) +{ + #if NAZARA_RENDERER_SAFE + if (unit >= s_textureUnits.size()) + { + NazaraError("Texture unit out of range (" + NzString::Number(unit) + " >= " + NzString::Number(s_textureUnits.size()) + ')'); + return; + } + #endif + + if (!texture) // Pas besoin de mettre à jour s'il n'y a pas de texture + return; + + if (s_textureUnits[unit].texture != texture) + { + s_textureUnits[unit].texture = texture; + s_textureUnits[unit].textureUpdated = false; + + if (s_textureUnits[unit].sampler.UseMipmaps(texture->HasMipmaps())) + s_textureUnits[unit].samplerUpdated = false; + + s_textureUnits[unit].updated = false; + } +} + +void NzRenderer::SetTextureSampling(unsigned int unit, const NzTextureSampler& sampler) +{ + #if NAZARA_RENDERER_SAFE + if (unit >= s_textureUnits.size()) + { + NazaraError("Texture unit out of range (" + NzString::Number(unit) + " >= " + NzString::Number(s_textureUnits.size()) + ')'); + return; + } + #endif + + s_textureUnits[unit].sampler = sampler; + s_textureUnits[unit].sampler.UseMipmaps(s_textureUnits[unit].texture->HasMipmaps()); + s_textureUnits[unit].samplerUpdated = false; + s_textureUnits[unit].updated = false; +} + bool NzRenderer::SetVertexBuffer(const NzVertexBuffer* vertexBuffer) { #if NAZARA_RENDERER_SAFE @@ -996,10 +1052,13 @@ void NzRenderer::Uninitialize() // Libération du module s_moduleReferenceCounter = 0; + s_textureUnits.clear(); + // Loaders NzLoaders_Texture_Unregister(); NzDebugDrawer::Uninitialize(); + NzTextureSampler::Uninitialize(); NzContext::EnsureContext(); @@ -1038,9 +1097,56 @@ bool NzRenderer::EnsureStateUpdate() // Il est plus rapide d'opérer sur l'implémentation du shader directement NzShaderImpl* shaderImpl = s_shader->m_impl; + shaderImpl->BindTextures(); - if (!shaderImpl->BindTextures()) - NazaraWarning("Failed to bind textures"); + static const bool useSamplerObjects = NzOpenGL::IsSupported(nzOpenGLExtension_SamplerObjects); + + if (useSamplerObjects) + { + for (unsigned int i = 0; i < s_textureUnits.size(); ++i) + { + TextureUnit& unit = s_textureUnits[i]; + + if (!unit.updated) + { + if (!unit.textureUpdated) + { + glActiveTexture(GL_TEXTURE0 + i); + unit.texture->Bind(); + + unit.textureUpdated = true; + } + + if (!unit.samplerUpdated) + { + unit.sampler.Bind(i); + unit.samplerUpdated = true; + } + + unit.updated = true; + } + } + } + else + { + for (unsigned int i = 0; i < s_textureUnits.size(); ++i) + { + TextureUnit& unit = s_textureUnits[i]; + + if (!unit.updated) + { + glActiveTexture(GL_TEXTURE0 + i); + + unit.texture->Bind(); + unit.textureUpdated = true; + + unit.sampler.Apply(unit.texture); + unit.samplerUpdated = true; + + unit.updated = true; + } + } + } for (unsigned int i = 0; i <= nzMatrixType_Max; ++i) { diff --git a/src/Nazara/Renderer/Texture.cpp b/src/Nazara/Renderer/Texture.cpp index 85eabe9ab..177ef8c55 100644 --- a/src/Nazara/Renderer/Texture.cpp +++ b/src/Nazara/Renderer/Texture.cpp @@ -347,11 +347,6 @@ bool NzTexture::Create(nzImageType type, nzPixelFormat format, unsigned int widt m_impl = impl; - // Paramètres par défaut - SetFilterMode(nzTextureFilter_Nearest); - SetMipmapRange(0, m_impl->levelCount); - SetWrapMode(nzTextureWrap_Repeat); - if (m_impl->levelCount > 1U) EnableMipmapping(true); @@ -445,15 +440,15 @@ bool NzTexture::EnableMipmapping(bool enable) } #endif - if (m_impl->levelCount == 1) - return true; - if (!IsMipmappingSupported()) { NazaraError("Mipmapping not supported"); return false; } + if (m_impl->levelCount == 1) // Transformation d'une texture sans mipmaps vers une texture avec mipmaps + m_impl->levelCount = NzImage::GetMaxLevel(m_impl->width, m_impl->height, m_impl->depth); + if (!m_impl->mipmapping && enable) m_impl->mipmapsUpdated = false; @@ -462,29 +457,6 @@ bool NzTexture::EnableMipmapping(bool enable) return true; } -unsigned int NzTexture::GetAnisotropyLevel() const -{ - #if NAZARA_RENDERER_SAFE - if (!m_impl) - { - NazaraError("Texture must be valid"); - return 0; - } - #endif - - if (!NzOpenGL::IsSupported(nzOpenGLExtension_AnisotropicFilter)) - return 1; - - LockTexture(m_impl); - - GLint anisotropyLevel; - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropyLevel); - - UnlockTexture(m_impl); - - return anisotropyLevel; -} - nzUInt8 NzTexture::GetBytesPerPixel() const { #if NAZARA_RENDERER_SAFE @@ -511,43 +483,6 @@ unsigned int NzTexture::GetDepth() const return m_impl->depth; } -nzTextureFilter NzTexture::GetFilterMode() const -{ - #if NAZARA_RENDERER_SAFE - if (!m_impl) - { - NazaraError("Texture must be valid"); - return nzTextureFilter_Unknown; - } - #endif - - LockTexture(m_impl); - - GLint value; - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &value); - - UnlockTexture(m_impl); - - GLenum filterMode = static_cast(value); - switch (filterMode) - { - case GL_LINEAR: - case GL_LINEAR_MIPMAP_NEAREST: - return nzTextureFilter_Bilinear; - - case GL_NEAREST: - case GL_NEAREST_MIPMAP_NEAREST: - return nzTextureFilter_Nearest; - - case GL_LINEAR_MIPMAP_LINEAR: - return nzTextureFilter_Trilinear; - - default: - NazaraInternalError("OpenGL filter mode not handled (0x" + NzString::Number(filterMode, 16) + ')'); - return nzTextureFilter_Unknown; - } -} - nzPixelFormat NzTexture::GetFormat() const { #if NAZARA_RENDERER_SAFE @@ -600,38 +535,6 @@ unsigned int NzTexture::GetWidth() const return m_impl->width; } -nzTextureWrap NzTexture::GetWrapMode() const -{ - #if NAZARA_RENDERER_SAFE - if (!m_impl) - { - NazaraError("Texture must be valid"); - return nzTextureWrap_Unknown; - } - #endif - - LockTexture(m_impl); - - GLint value; - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &value); - - UnlockTexture(m_impl); - - GLenum wrapMode = static_cast(value); - switch (wrapMode) - { - case GL_CLAMP_TO_EDGE: - return nzTextureWrap_Clamp; - - case GL_REPEAT: - return nzTextureWrap_Repeat; - - default: - NazaraInternalError("OpenGL wrap mode not handled (0x" + NzString::Number(wrapMode, 16) + ')'); - return nzTextureWrap_Unknown; - } -} - bool NzTexture::HasMipmaps() const { #if NAZARA_RENDERER_SAFE @@ -689,7 +592,7 @@ bool NzTexture::IsValid() const return m_impl != nullptr; } -bool NzTexture::LoadFromFile(const NzString& filePath, const NzImageParams& params) +bool NzTexture::LoadFromFile(const NzString& filePath, const NzImageParams& params, bool generateMipmaps) { NzImage image; if (!image.LoadFromFile(filePath, params)) @@ -698,10 +601,10 @@ bool NzTexture::LoadFromFile(const NzString& filePath, const NzImageParams& para return false; } - return LoadFromImage(image); + return LoadFromImage(image, generateMipmaps); } -bool NzTexture::LoadFromImage(const NzImage& image) +bool NzTexture::LoadFromImage(const NzImage& image, bool generateMipmaps) { #if NAZARA_RENDERER_SAFE if (!image.IsValid()) @@ -741,13 +644,14 @@ bool NzTexture::LoadFromImage(const NzImage& image) } nzImageType type = newImage.GetType(); - if (!Create(type, format, newImage.GetWidth(), newImage.GetHeight(), newImage.GetDepth(), newImage.GetLevelCount(), true)) + nzUInt8 levelCount = newImage.GetLevelCount(); + if (!Create(type, format, newImage.GetWidth(), newImage.GetHeight(), newImage.GetDepth(), (generateMipmaps) ? 0xFF : levelCount, true)) { NazaraError("Failed to create texture"); return false; } - for (nzUInt8 level = 0; level < m_impl->levelCount; ++level) + for (nzUInt8 level = 0; level < levelCount; ++level) { if (!Update(newImage.GetConstPixels(level), level)) { @@ -763,7 +667,7 @@ bool NzTexture::LoadFromImage(const NzImage& image) return true; } -bool NzTexture::LoadFromMemory(const void* data, std::size_t size, const NzImageParams& params) +bool NzTexture::LoadFromMemory(const void* data, std::size_t size, const NzImageParams& params, bool generateMipmaps) { NzImage image; if (!image.LoadFromMemory(data, size, params)) @@ -772,10 +676,10 @@ bool NzTexture::LoadFromMemory(const void* data, std::size_t size, const NzImage return false; } - return LoadFromImage(image); + return LoadFromImage(image, generateMipmaps); } -bool NzTexture::LoadFromStream(NzInputStream& stream, const NzImageParams& params) +bool NzTexture::LoadFromStream(NzInputStream& stream, const NzImageParams& params, bool generateMipmaps) { NzImage image; if (!image.LoadFromStream(stream, params)) @@ -784,7 +688,7 @@ bool NzTexture::LoadFromStream(NzInputStream& stream, const NzImageParams& param return false; } - return LoadFromImage(image); + return LoadFromImage(image, generateMipmaps); } bool NzTexture::Lock() @@ -802,84 +706,6 @@ bool NzTexture::Lock() return true; } -bool NzTexture::SetAnisotropyLevel(unsigned int anistropyLevel) -{ - #if NAZARA_RENDERER_SAFE - if (!m_impl) - { - NazaraError("Texture must be valid"); - return false; - } - #endif - - if (anistropyLevel > 1 && !NzOpenGL::IsSupported(nzOpenGLExtension_AnisotropicFilter)) - { - NazaraError("Anisotropic filter not supported"); - return false; - } - - LockTexture(m_impl); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anistropyLevel); - - UnlockTexture(m_impl); - - return true; -} - -bool NzTexture::SetFilterMode(nzTextureFilter filter) -{ - #if NAZARA_RENDERER_SAFE - if (!m_impl) - { - NazaraError("Texture must be valid"); - return false; - } - - if (filter == nzTextureFilter_Trilinear && m_impl->levelCount == 1) - { - NazaraError("Trilinear filter set wihout mipmaps"); - return false; - } - #endif - - LockTexture(m_impl); - - GLenum target = NzOpenGL::TextureTarget[m_impl->type]; - switch (filter) - { - case nzTextureFilter_Bilinear: - if (m_impl->mipmapping > 1) - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - else - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - break; - - case nzTextureFilter_Nearest: - if (m_impl->mipmapping > 1) - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); - else - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - break; - - case nzTextureFilter_Trilinear: - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - break; - - default: - NazaraError("Texture filter not handled (0x" + NzString::Number(filter, 16) + ')'); - } - - UnlockTexture(m_impl); - - return true; -} - bool NzTexture::SetMipmapRange(nzUInt8 minLevel, nzUInt8 maxLevel) { #if NAZARA_RENDERER_SAFE @@ -904,59 +730,7 @@ bool NzTexture::SetMipmapRange(nzUInt8 minLevel, nzUInt8 maxLevel) LockTexture(m_impl); glTexParameteri(NzOpenGL::TextureTarget[m_impl->type], GL_TEXTURE_BASE_LEVEL, minLevel); - glTexParameteri(NzOpenGL::TextureTarget[m_impl->type], GL_TEXTURE_MAX_LEVEL, std::min(m_impl->levelCount, maxLevel)); - UnlockTexture(m_impl); - - return true; -} - -bool NzTexture::SetWrapMode(nzTextureWrap wrap) -{ - #if NAZARA_RENDERER_SAFE - if (!m_impl) - { - NazaraError("Texture must be valid"); - return false; - } - #endif - - GLenum wrapMode; - switch (wrap) - { - case nzTextureWrap_Clamp: - wrapMode = GL_CLAMP_TO_EDGE; - break; - - case nzTextureWrap_Repeat: - wrapMode = GL_REPEAT; - break; - - default: - NazaraError("Texture wrap mode not handled (0x" + NzString::Number(wrap, 16) + ')'); - return false; - } - - LockTexture(m_impl); - - GLenum target = NzOpenGL::TextureTarget[m_impl->type]; - switch (m_impl->type) - { - // Notez l'absence de "break" ici - case nzImageType_3D: - glTexParameteri(target, GL_TEXTURE_WRAP_R, wrapMode); - case nzImageType_2D: - case nzImageType_2D_Array: - case nzImageType_Cubemap: - glTexParameteri(target, GL_TEXTURE_WRAP_T, wrapMode); - case nzImageType_1D: - case nzImageType_1D_Array: - glTexParameteri(target, GL_TEXTURE_WRAP_S, wrapMode); - break; - - default: - break; - } - + glTexParameteri(NzOpenGL::TextureTarget[m_impl->type], GL_TEXTURE_MAX_LEVEL, maxLevel); UnlockTexture(m_impl); return true; @@ -1411,20 +1185,7 @@ void NzTexture::Unlock() UnlockTexture(m_impl); } -unsigned int NzTexture::GetOpenGLID() const -{ - #if NAZARA_RENDERER_SAFE - if (!m_impl) - { - NazaraError("Texture must be valid"); - return 0; - } - #endif - - return m_impl->id; -} - -bool NzTexture::Prepare() const +bool NzTexture::Bind() const { #if NAZARA_RENDERER_SAFE if (lockedLevel[m_impl->type] > 0) @@ -1445,6 +1206,19 @@ bool NzTexture::Prepare() const return true; } +unsigned int NzTexture::GetOpenGLID() const +{ + #if NAZARA_RENDERER_SAFE + if (!m_impl) + { + NazaraError("Texture must be valid"); + return 0; + } + #endif + + return m_impl->id; +} + unsigned int NzTexture::GetValidSize(unsigned int size) { if (NzRenderer::HasCapability(nzRendererCap_TextureNPOT)) diff --git a/src/Nazara/Renderer/TextureSampler.cpp b/src/Nazara/Renderer/TextureSampler.cpp new file mode 100644 index 000000000..99e0f6388 --- /dev/null +++ b/src/Nazara/Renderer/TextureSampler.cpp @@ -0,0 +1,382 @@ +// 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 + +namespace +{ + std::map s_samplers; + nzUInt8 s_maxAnisotropyLevel; + bool s_useAnisotropicFilter; +} + +NzTextureSampler::NzTextureSampler() : +m_filterMode(nzSamplerFilter_Default), +m_wrapMode(nzSamplerWrap_Default), +m_anisotropicLevel(0), +m_mipmaps(true), +m_samplerId(0) +{ +} + +nzUInt8 NzTextureSampler::GetAnisotropicLevel() const +{ + return m_anisotropicLevel; +} + +nzSamplerFilter NzTextureSampler::GetFilterMode() const +{ + return m_filterMode; +} + +nzSamplerWrap NzTextureSampler::GetWrapMode() const +{ + return m_wrapMode; +} + +void NzTextureSampler::SetAnisotropyLevel(nzUInt8 anisotropyLevel) +{ + #ifdef NAZARA_DEBUG + if (!NzRenderer::IsInitialized()) + { + NazaraError("Renderer module must be initialized"); + return; + } + #endif + + if (m_anisotropicLevel != anisotropyLevel) + { + if (anisotropyLevel > s_maxAnisotropyLevel) + { + NazaraWarning("Anisotropy level is over maximum anisotropy level (" + NzString::Number(anisotropyLevel) + " > " + NzString::Number(s_maxAnisotropyLevel)); + anisotropyLevel = s_maxAnisotropyLevel; + } + + m_anisotropicLevel = anisotropyLevel; + m_samplerId = 0; + } +} + +void NzTextureSampler::SetFilterMode(nzSamplerFilter filterMode) +{ + if (m_filterMode != filterMode) + { + m_filterMode = filterMode; + m_samplerId = 0; + } +} + +void NzTextureSampler::SetWrapMode(nzSamplerWrap wrapMode) +{ + if (m_wrapMode != wrapMode) + { + m_wrapMode = wrapMode; + m_samplerId = 0; + } +} + +nzUInt8 NzTextureSampler::GetDefaultAnisotropicLevel() +{ + return s_defaultAnisotropyLevel; +} + +nzSamplerFilter NzTextureSampler::GetDefaultFilterMode() +{ + return s_defaultFilterMode; +} + +nzSamplerWrap NzTextureSampler::GetDefaultWrapMode() +{ + return s_defaultWrapMode; +} + +void NzTextureSampler::SetDefaultAnisotropyLevel(nzUInt8 anisotropyLevel) +{ + #if NAZARA_RENDERER_SAFE + if (anisotropyLevel == 0) + { + NazaraError("Default anisotropy level mode cannot be set to default value (0)"); + return; + } + #endif + + #ifdef NAZARA_DEBUG + if (!NzRenderer::IsInitialized()) + { + NazaraError("Renderer module must be initialized"); + return; + } + #endif + + if (anisotropyLevel > s_maxAnisotropyLevel) + { + NazaraWarning("Anisotropy level is over maximum anisotropy level (" + NzString::Number(anisotropyLevel) + " > " + NzString::Number(s_maxAnisotropyLevel)); + anisotropyLevel = s_maxAnisotropyLevel; + } + + s_defaultAnisotropyLevel = anisotropyLevel; + + if (s_useAnisotropicFilter) + { + for (auto pair : s_samplers) + { + if (((pair.first >> 5) & 0xFF) == 0) + glSamplerParameterf(pair.second, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast(anisotropyLevel)); + } + } +} + +void NzTextureSampler::SetDefaultFilterMode(nzSamplerFilter filterMode) +{ + #if NAZARA_RENDERER_SAFE + if (filterMode == nzSamplerFilter_Default) + { + NazaraError("Default filter mode cannot be set to default enum value (nzSamplerFilter_Default)"); + return; + } + #endif + + s_defaultFilterMode = filterMode; + + for (auto pair : s_samplers) + { + if (((pair.first >> 1) & 0x3) == nzSamplerFilter_Default) + { + bool mipmaps = pair.first & 0x1; + switch (filterMode) + { + case nzSamplerFilter_Bilinear: + if (mipmaps) + glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + else + glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glSamplerParameteri(pair.second, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + + case nzSamplerFilter_Nearest: + if (mipmaps) + glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + else + glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glSamplerParameteri(pair.second, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + + case nzSamplerFilter_Trilinear: + if (mipmaps) + glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + else + glSamplerParameteri(pair.second, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Filtrage bilinéaire + + glSamplerParameteri(pair.second, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + + default: + NazaraError("Texture filter not handled (0x" + NzString::Number(filterMode, 16) + ')'); + break; + } + } + } +} + +void NzTextureSampler::SetDefaultWrapMode(nzSamplerWrap wrapMode) +{ + #if NAZARA_RENDERER_SAFE + if (wrapMode == nzSamplerWrap_Default) + { + NazaraError("Default wrap mode cannot be set to default enum value (nzSamplerWrap_Default)"); + return; + } + #endif + + s_defaultWrapMode = wrapMode; + + GLenum wrapEnum = NzOpenGL::SamplerWrapMode[wrapMode]; + for (auto pair : s_samplers) + { + if (((pair.first >> 3) & 0x3) == nzSamplerWrap_Default) + { + glSamplerParameteri(pair.second, GL_TEXTURE_WRAP_R, wrapEnum); + glSamplerParameteri(pair.second, GL_TEXTURE_WRAP_T, wrapEnum); + glSamplerParameteri(pair.second, GL_TEXTURE_WRAP_S, wrapEnum); + } + } +} + +void NzTextureSampler::Apply(const NzTexture* texture) +{ + // On considère que la texture est déjà active lors de l'appel à cette fonction + GLenum target = NzOpenGL::TextureTarget[texture->GetType()]; + + if (s_useAnisotropicFilter) + { + nzUInt8 anisotropyLevel = (m_anisotropicLevel == 0) ? s_defaultAnisotropyLevel : m_anisotropicLevel; + glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast(anisotropyLevel)); + } + + nzSamplerFilter filterMode = (m_filterMode == nzSamplerFilter_Default) ? s_defaultFilterMode : m_filterMode; + switch (filterMode) + { + case nzSamplerFilter_Bilinear: + if (m_mipmaps) + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + else + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + + case nzSamplerFilter_Nearest: + if (m_mipmaps) + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + else + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + + case nzSamplerFilter_Trilinear: + if (m_mipmaps) + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + else + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Filtrage bilinéaire + + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + + default: + NazaraError("Texture filter not handled (0x" + NzString::Number(filterMode, 16) + ')'); + break; + } + + GLenum wrapMode = NzOpenGL::SamplerWrapMode[(m_wrapMode == nzSamplerWrap_Default) ? s_defaultWrapMode : m_wrapMode]; + switch (texture->GetType()) + { + // Notez l'absence de "break" ici + case nzImageType_3D: + glTexParameteri(target, GL_TEXTURE_WRAP_R, wrapMode); + case nzImageType_2D: + case nzImageType_2D_Array: + case nzImageType_Cubemap: + glTexParameteri(target, GL_TEXTURE_WRAP_T, wrapMode); + case nzImageType_1D: + case nzImageType_1D_Array: + glTexParameteri(target, GL_TEXTURE_WRAP_S, wrapMode); + break; + } +} + +void NzTextureSampler::Bind(unsigned int unit) +{ + static_assert(nzSamplerFilter_Max < 0x4, "Maximum sampler filter mode takes more than 2 bits"); + static_assert(nzSamplerWrap_Max < 0x4, "Maximum sampler wrap mode takes more than 2 bits"); + + if (!m_samplerId) + { + nzUInt32 key = (m_mipmaps << 0) | // 1 bit + (m_filterMode << 1) | // 2 bits + (m_wrapMode << 3) | // 2 bits + (m_anisotropicLevel << 5); // 8 bits + + auto it = s_samplers.find(key); + if (it == s_samplers.end()) + { + GLuint sampler; + glGenSamplers(1, &sampler); + + if (s_useAnisotropicFilter) + { + nzUInt8 anisotropyLevel = (m_anisotropicLevel == 0) ? s_defaultAnisotropyLevel : m_anisotropicLevel; + glSamplerParameterf(sampler, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast(anisotropyLevel)); + } + + nzSamplerFilter filterMode = (m_filterMode == nzSamplerFilter_Default) ? s_defaultFilterMode : m_filterMode; + switch (filterMode) + { + case nzSamplerFilter_Bilinear: + if (m_mipmaps) + glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + else + glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + + case nzSamplerFilter_Nearest: + if (m_mipmaps) + glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + else + glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + + case nzSamplerFilter_Trilinear: + if (m_mipmaps) + glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + else + glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Filtrage bilinéaire + + glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + + default: + NazaraError("Texture filter not handled (0x" + NzString::Number(filterMode, 16) + ')'); + break; + } + + GLenum wrapMode = NzOpenGL::SamplerWrapMode[(m_wrapMode == nzSamplerWrap_Default) ? s_defaultWrapMode : m_wrapMode]; + glSamplerParameteri(sampler, GL_TEXTURE_WRAP_R, wrapMode); + glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, wrapMode); + glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, wrapMode); + + s_samplers[key] = sampler; + m_samplerId = sampler; + } + else + m_samplerId = it->second; + } + + glBindSampler(unit, m_samplerId); +} + +bool NzTextureSampler::UseMipmaps(bool mipmaps) +{ + if (m_mipmaps != mipmaps) + { + m_mipmaps = mipmaps; + m_samplerId = 0; + + return true; // Renvoie true si la valeur a été changée (Donc s'il faut réappliquer le sampler) + } + else + return false; +} + +bool NzTextureSampler::Initialize() +{ + s_maxAnisotropyLevel = NzRenderer::GetMaxAnisotropyLevel(); + s_useAnisotropicFilter = NzOpenGL::IsSupported(nzOpenGLExtension_AnisotropicFilter); + + return true; +} + +void NzTextureSampler::Uninitialize() +{ + for (auto it = s_samplers.begin(); it != s_samplers.end(); ++it) + glDeleteSamplers(1, &it->second); + + s_samplers.clear(); +} + +nzUInt8 NzTextureSampler::s_defaultAnisotropyLevel = 1; +nzSamplerFilter NzTextureSampler::s_defaultFilterMode = nzSamplerFilter_Trilinear; +nzSamplerWrap NzTextureSampler::s_defaultWrapMode = nzSamplerWrap_Repeat;