From d3b052f19b94d333bbeb6709efb73f180c06c440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kapu=C5=9Bci=C5=84ski?= Date: Wed, 6 May 2015 17:55:10 +0200 Subject: [PATCH] Implemented trilinear filtering, mipmap level setting and anisotropic filtering --- src/graphics/core/device.h | 3 +- src/graphics/core/texture.h | 22 ++++++--- src/graphics/engine/engine.cpp | 73 ++++++++++++++++++++++++--- src/graphics/engine/engine.h | 22 +++++++++ src/graphics/engine/text.cpp | 3 +- src/graphics/opengl/gldevice.cpp | 85 +++++++++++++++++++++++++------- src/graphics/opengl/gldevice.h | 6 +++ 7 files changed, 178 insertions(+), 36 deletions(-) diff --git a/src/graphics/core/device.h b/src/graphics/core/device.h index f52e07f7..f790c244 100644 --- a/src/graphics/core/device.h +++ b/src/graphics/core/device.h @@ -91,7 +91,8 @@ enum TransformType { TRANSFORM_WORLD, TRANSFORM_VIEW, - TRANSFORM_PROJECTION + TRANSFORM_PROJECTION, + TRANSFORM_TEXTURE }; /** diff --git a/src/graphics/core/texture.h b/src/graphics/core/texture.h index 3ce06eed..038bbbb6 100644 --- a/src/graphics/core/texture.h +++ b/src/graphics/core/texture.h @@ -52,6 +52,19 @@ enum TexImgFormat TEX_IMG_BGRA }; +/** + * \enum TexFilter + * \brief General texture filtering mode + * + * Corresponds to typical options in game graphics settings. + */ +enum TexFilter +{ + TEX_FILTER_NEAREST, + TEX_FILTER_BILINEAR, + TEX_FILTER_TRILINEAR +}; + /** * \enum TexMinFilter * \brief Texture minification filter @@ -135,10 +148,8 @@ struct TextureCreateParams bool mipmap; //! Format of source image data TexImgFormat format; - //! Minification filter - TexMinFilter minFilter; - //! Magnification filter - TexMagFilter magFilter; + //! General texture filtering mode + TexFilter filter; //! Pad the image to nearest power of 2 dimensions bool padToNearestPowerOfTwo; @@ -153,8 +164,7 @@ struct TextureCreateParams mipmap = false; padToNearestPowerOfTwo = false; - minFilter = TEX_MIN_FILTER_NEAREST; - magFilter = TEX_MAG_FILTER_NEAREST; + filter = TEX_FILTER_NEAREST; } }; diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index 2777396f..d26304d4 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -114,6 +114,8 @@ CEngine::CEngine(CApplication *app) m_terrainVision = 1000.0f; m_gadgetQuantity = 1.0f; m_textureQuality = 1; + m_textureMipmapLevel = 1; + m_textureAnisotropy = 1; m_totoMode = true; m_lensMode = true; m_waterMode = true; @@ -158,15 +160,34 @@ CEngine::CEngine(CApplication *app) m_lastFrameTime = GetSystemUtils()->CreateTimeStamp(); m_currentFrameTime = GetSystemUtils()->CreateTimeStamp(); + TexFilter filter = TEX_FILTER_BILINEAR; + bool mipmaps = false; + + int value; + if (CProfile::GetInstance().GetIntProperty("Setup", "FilterMode", value)) + { + if (value == 1) filter = TEX_FILTER_NEAREST; + else if (value == 2) filter = TEX_FILTER_BILINEAR; + else if (value == 3) filter = TEX_FILTER_TRILINEAR, mipmaps = true; + } + + if (CProfile::GetInstance().GetIntProperty("Setup", "MipmapLevel", value)) + { + m_textureMipmapLevel = value; + } + + if (CProfile::GetInstance().GetIntProperty("Setup", "Anisotropy", value)) + { + m_textureAnisotropy = value; + } + m_defaultTexParams.format = TEX_IMG_AUTO; - m_defaultTexParams.mipmap = true; - m_defaultTexParams.minFilter = TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR; - m_defaultTexParams.magFilter = TEX_MAG_FILTER_LINEAR; + m_defaultTexParams.mipmap = mipmaps; + m_defaultTexParams.filter = filter; m_terrainTexParams.format = TEX_IMG_AUTO; - m_terrainTexParams.mipmap = false; - m_terrainTexParams.minFilter = TEX_MIN_FILTER_LINEAR; - m_terrainTexParams.magFilter = TEX_MAG_FILTER_LINEAR; + m_terrainTexParams.mipmap = mipmaps; + m_terrainTexParams.filter = filter; } CEngine::~CEngine() @@ -282,8 +303,7 @@ bool CEngine::Create() TextureCreateParams params; params.format = TEX_IMG_AUTO; - params.minFilter = TEX_MIN_FILTER_NEAREST; - params.magFilter = TEX_MAG_FILTER_NEAREST; + params.filter = TEX_FILTER_NEAREST; params.mipmap = false; m_miceTexture = LoadTexture("textures/interface/mouse.png", params); @@ -2908,6 +2928,43 @@ int CEngine::GetTextureQuality() return m_textureQuality; } +void CEngine::SetTextureFilterMode(TexFilter value) +{ + m_defaultTexParams.filter = value; + m_terrainTexParams.filter = value; +} + +TexFilter CEngine::GetTextureFilterMode() +{ + return m_terrainTexParams.filter; +} + +void CEngine::SetTextureMipmapLevel(int value) +{ + if (value < 1) value = 1; + if (value > 16) value = 16; + + m_textureMipmapLevel = value; +} + +int CEngine::GetTextureMipmapLevel() +{ + return m_textureMipmapLevel; +} + +void CEngine::SetTextureAnisotropyLevel(int value) +{ + if (value < 1) value = 1; + if (value > 16) value = 16; + + m_textureAnisotropy = value; +} + +int CEngine::GetTextureAnisotropyLevel() +{ + return m_textureAnisotropy; +} + void CEngine::SetTotoMode(bool present) { m_totoMode = present; diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index a6d19216..903c22dd 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -1116,6 +1116,24 @@ public: int GetTextureQuality(); //@} + //@{ + //! Management the texture filter mode + void SetTextureFilterMode(TexFilter value); + TexFilter GetTextureFilterMode(); + //@} + + //@{ + //! Management the mipmap level for textures + void SetTextureMipmapLevel(int value); + int GetTextureMipmapLevel(); + //@} + + //@{ + //! Management the anisotropy level for textures + void SetTextureAnisotropyLevel(int value); + int GetTextureAnisotropyLevel(); + //@} + //@{ //! Management mode of toto void SetTotoMode(bool present); @@ -1414,6 +1432,10 @@ protected: TextureCreateParams m_defaultTexParams; //! Create params for terrain textures TextureCreateParams m_terrainTexParams; + //! Requested texture mipmap level + int m_textureMipmapLevel; + //! Requested texture anisotropy level + int m_textureAnisotropy; //! Map of loaded textures (by name) std::map m_texNameMap; diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp index 9ee190a5..d8a3acc7 100644 --- a/src/graphics/engine/text.cpp +++ b/src/graphics/engine/text.cpp @@ -1014,8 +1014,7 @@ CharTexture CText::CreateCharTexture(UTF8Char ch, CachedFont* font) TextureCreateParams createParams; createParams.format = TEX_IMG_RGBA; - createParams.minFilter = TEX_MIN_FILTER_NEAREST; - createParams.magFilter = TEX_MAG_FILTER_NEAREST; + createParams.filter = TEX_FILTER_NEAREST; createParams.mipmap = false; Texture tex = m_device->CreateTexture(&data, createParams); diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp index a197b185..582ed26d 100644 --- a/src/graphics/opengl/gldevice.cpp +++ b/src/graphics/opengl/gldevice.cpp @@ -19,6 +19,7 @@ #include "graphics/opengl/gldevice.h" +#include "graphics/engine/engine.h" #include "common/config.h" #include "common/image.h" @@ -69,6 +70,8 @@ CGLDevice::CGLDevice(const GLDeviceConfig &config) m_multitextureAvailable = false; m_vboAvailable = false; m_vertexBufferType = VBT_DISPLAY_LIST; + m_anisotropyAvailable = false; + m_maxAnisotropy = 1; } @@ -205,6 +208,23 @@ bool CGLDevice::Create() if (!m_multitextureAvailable) GetLogger()->Warn("GLEW reports multitexturing not supported - graphics quality will be degraded!\n"); + // Detect support of anisotropic filtering + m_anisotropyAvailable = glewIsSupported("GL_EXT_texture_filter_anisotropic"); + if(m_anisotropyAvailable) + { + // Obtain maximum anisotropy level available + float level; + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &level); + m_maxAnisotropy = static_cast(level); + + GetLogger()->Info("Anisotropic filtering available\n"); + GetLogger()->Info("Maximum anisotropy: %d\n", m_maxAnisotropy); + } + else + { + GetLogger()->Info("Anisotropic filtering not available\n"); + } + if (m_config.vboMode == VBO_MODE_ENABLE) { GetLogger()->Info("VBO enabled by override - using VBOs\n"); @@ -360,6 +380,12 @@ void CGLDevice::SetTransform(TransformType type, const Math::Matrix &matrix) glMatrixMode(GL_PROJECTION); glLoadMatrixf(m_projectionMat.Array()); } + else if (type == TRANSFORM_TEXTURE) + { + m_textureMat = matrix; + glMatrixMode(GL_TEXTURE); + glLoadMatrixf(m_textureMat.Array()); + } else { assert(false); @@ -511,7 +537,7 @@ Texture CGLDevice::CreateTexture(ImageData *data, const TextureCreateParams &par if (!Math::IsPowerOfTwo(result.size.x) || !Math::IsPowerOfTwo(result.size.y)) GetLogger()->Warn("Creating non-power-of-2 texture (%dx%d)!\n", result.size.x, result.size.y); - + result.originalSize = result.size; // Use & enable 1st texture stage @@ -523,31 +549,52 @@ Texture CGLDevice::CreateTexture(ImageData *data, const TextureCreateParams &par glGenTextures(1, &result.id); glBindTexture(GL_TEXTURE_2D, result.id); - // Set params + // Set texture parameters + GLint minF = 0, magF = 0; + int mipmapLevel = 1; - GLint minF = 0; - if (params.minFilter == TEX_MIN_FILTER_NEAREST) minF = GL_NEAREST; - else if (params.minFilter == TEX_MIN_FILTER_LINEAR) minF = GL_LINEAR; - else if (params.minFilter == TEX_MIN_FILTER_NEAREST_MIPMAP_NEAREST) minF = GL_NEAREST_MIPMAP_NEAREST; - else if (params.minFilter == TEX_MIN_FILTER_LINEAR_MIPMAP_NEAREST) minF = GL_LINEAR_MIPMAP_NEAREST; - else if (params.minFilter == TEX_MIN_FILTER_NEAREST_MIPMAP_LINEAR) minF = GL_NEAREST_MIPMAP_LINEAR; - else if (params.minFilter == TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR) minF = GL_LINEAR_MIPMAP_LINEAR; - else assert(false); + switch (params.filter) + { + case TEX_FILTER_NEAREST: + minF = GL_NEAREST; + magF = GL_NEAREST; + break; + case TEX_FILTER_BILINEAR: + minF = GL_LINEAR; + magF = GL_LINEAR; + break; + case TEX_FILTER_TRILINEAR: + minF = GL_LINEAR_MIPMAP_LINEAR; + magF = GL_LINEAR; + mipmapLevel = CEngine::GetInstance().GetTextureMipmapLevel(); + break; + } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minF); - - GLint magF = 0; - if (params.magFilter == TEX_MAG_FILTER_NEAREST) magF = GL_NEAREST; - else if (params.magFilter == TEX_MAG_FILTER_LINEAR) magF = GL_LINEAR; - else assert(false); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magF); + // Set mipmap level and automatic mipmap generation if neccesary if (params.mipmap) - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapLevel - 1); + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); + } else - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE); + { + // Has to be set to 0 because no mipmaps are generated + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE); + } + // Set anisotropy level if available + if (m_anisotropyAvailable) + { + float level = Math::Min(m_maxAnisotropy, CEngine::GetInstance().GetTextureAnisotropyLevel()); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, level); + } bool convert = false; GLenum sourceFormat = 0; @@ -653,7 +700,7 @@ Texture CGLDevice::CreateTexture(ImageData *data, const TextureCreateParams &par actualSurface = convertedSurface; } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, actualSurface->w, actualSurface->h, + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, actualSurface->w, actualSurface->h, 0, sourceFormat, GL_UNSIGNED_BYTE, actualSurface->pixels); SDL_FreeSurface(convertedSurface); diff --git a/src/graphics/opengl/gldevice.h b/src/graphics/opengl/gldevice.h index e932ab9e..e543f133 100644 --- a/src/graphics/opengl/gldevice.h +++ b/src/graphics/opengl/gldevice.h @@ -205,6 +205,8 @@ private: Math::Matrix m_modelviewMat; //! Current projection matrix Math::Matrix m_projectionMat; + //! Current texture matrix + Math::Matrix m_textureMat; //! The current material Material m_material; @@ -247,6 +249,10 @@ private: bool m_multitextureAvailable; //! Whether to use VBOs or display lists bool m_vboAvailable; + //! Whether anisotropic filtering is available + bool m_anisotropyAvailable; + //! Maximum anisotropy level + int m_maxAnisotropy; //! Which vertex buffer type to use VertexBufferType m_vertexBufferType; //! Map of saved VBO objects