Added texture samplers

I hate Git branchs


Former-commit-id: 6978f1489cdc841d36fbcd6f1a8e01a4adbfcb8a
This commit is contained in:
Lynix 2012-12-17 14:56:29 +01:00
parent dc30b918a1
commit 8b67d17e38
13 changed files with 669 additions and 341 deletions

View File

@ -2,6 +2,7 @@
#include <Nazara/Core/Clock.hpp>
#include <Nazara/Math.hpp>
#include <Nazara/Renderer.hpp>
#include <Nazara/Renderer/TextureSampler.hpp>
#include <Nazara/Utility.hpp>
#include <iostream>
#include <map>
@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -12,8 +12,8 @@
#include <Nazara/Math/Matrix4.hpp>
#include <Nazara/Math/Rect.hpp>
#include <Nazara/Renderer/Enums.hpp>
#include <Nazara/Renderer/TextureSampler.hpp>
#include <Nazara/Utility/Enums.hpp>
#include <map>
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);

View File

@ -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);

View File

@ -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 <Nazara/Prerequesites.hpp>
#include <Nazara/Renderer/Enums.hpp>
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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -21,8 +21,10 @@
#include <Nazara/Utility/Utility.hpp>
#include <Nazara/Utility/VertexBuffer.hpp>
#include <Nazara/Utility/VertexDeclaration.hpp>
#include <map>
#include <stdexcept>
#include <tuple>
#include <vector>
#include <Nazara/Renderer/Debug.hpp>
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<const NzContext*, const NzIndexBuffer*, const NzVertexBuffer*, const NzVertexDeclaration*>;
std::map<VAO_Key, unsigned int> s_vaos;
std::vector<TextureUnit> 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<unsigned int>(maxAnisotropy);
s_maxAnisotropyLevel = static_cast<nzUInt8>(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)
{

View File

@ -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<GLenum>(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<GLenum>(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))

View File

@ -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 <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/TextureSampler.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/Texture.hpp>
#include <Nazara/Renderer/Debug.hpp>
namespace
{
std::map<nzUInt32, GLuint> 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<float>(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<float>(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<float>(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;