From 314c32865b4367fe9549f4c2a71e2b0a6e3ae45a Mon Sep 17 00:00:00 2001 From: Benau <Benau@users.noreply.github.com> Date: Sat, 7 Jan 2017 16:36:25 +0800 Subject: [PATCH] Allow using single color channel for font texture --- src/font/font_with_face.cpp | 98 +++++++++++++++++-------------- src/graphics/central_settings.cpp | 14 ++++- src/graphics/central_settings.hpp | 2 + src/graphics/stk_texture.cpp | 22 +++++-- 4 files changed, 84 insertions(+), 52 deletions(-) diff --git a/src/font/font_with_face.cpp b/src/font/font_with_face.cpp index 7dd4691f5..37c5af420 100644 --- a/src/font/font_with_face.cpp +++ b/src/font/font_with_face.cpp @@ -22,6 +22,7 @@ #include "font/font_manager.hpp" #include "font/font_settings.hpp" #include "graphics/2dutils.hpp" +#include "graphics/central_settings.hpp" #include "graphics/irr_driver.hpp" #include "graphics/stk_texture.hpp" #include "graphics/stk_tex_manager.hpp" @@ -131,13 +132,24 @@ void FontWithFace::loadGlyphInfo(wchar_t c) */ void FontWithFace::createNewGlyphPage() { - uint8_t* data = new uint8_t[getGlyphPageSize() * getGlyphPageSize() * 4](); +#ifndef SERVER_ONLY + uint8_t* data = new uint8_t[getGlyphPageSize() * getGlyphPageSize() * + (CVS->isARBTextureSwizzleUsable() ? 1 : 4)]; +#else + uint8_t* data = NULL; +#endif m_current_height = 0; m_used_width = 0; m_used_height = 0; STKTexture* stkt = new STKTexture(data, typeid(*this).name() + StringUtils::toString(m_spritebank->getTextureCount()), - getGlyphPageSize()); + getGlyphPageSize(), +#ifndef SERVER_ONLY + CVS->isARBTextureSwizzleUsable() +#else + false +#endif + ); m_spritebank->addTexture(stkt); STKTexManager::getInstance()->addTexture(stkt); } // createNewGlyphPage @@ -180,36 +192,6 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi) createNewGlyphPage(); } - std::vector<uint32_t> image_data; - image_data.resize(texture_size.Width * texture_size.Height, - video::SColor(0, 255, 255, 255).color); - switch (bits.pixel_mode) - { - case FT_PIXEL_MODE_GRAY: - { - // Load the grayscale data in. - const float gray_count = static_cast<float>(bits.num_grays); - const unsigned int image_pitch = - 4 * texture_size.Width / sizeof(unsigned int); - uint8_t* glyph_data = bits.buffer; - for (unsigned int y = 0; y < (unsigned int)bits.rows; y++) - { - uint8_t* row = glyph_data; - for (unsigned int x = 0; x < (unsigned int)bits.width; x++) - { - image_data.data()[y * image_pitch + x] |= - static_cast<uint32_t>(255.0f * - (static_cast<float>(*row++) / gray_count)) << 24; - } - glyph_data += bits.pitch; - } - break; - } - default: - assert(false); - } - - // Done creating a single glyph, now copy to the glyph page... // Determine the linebreak location if (m_used_width + texture_size.Width > getGlyphPageSize()) { @@ -222,19 +204,45 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi) #ifndef SERVER_ONLY video::ITexture* tex = m_spritebank->getTexture(cur_tex); glBindTexture(GL_TEXTURE_2D, tex->getOpenGLTextureName()); - unsigned int format = GL_BGRA; -#if defined(USE_GLES2) - if (!CVS->isEXTTextureFormatBGRA8888Usable()) - format = GL_RGBA; -#endif - glTexSubImage2D(GL_TEXTURE_2D, 0, m_used_width, m_used_height, - texture_size.Width, texture_size.Height, format, GL_UNSIGNED_BYTE, - image_data.data()); - //glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - //static GLint swizzle_mask[] = { GL_ONE, GL_ONE, GL_ONE, GL_RED }; - //glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_mask); - //glTexSubImage2D(GL_TEXTURE_2D, 0, m_used_width, m_used_height, bits.width, bits.rows, GL_RED, GL_UNSIGNED_BYTE, bits.buffer); - //glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + if (CVS->isARBTextureSwizzleUsable()) + { + glTexSubImage2D(GL_TEXTURE_2D, 0, m_used_width, m_used_height, + bits.width, bits.rows, GL_RED, GL_UNSIGNED_BYTE, bits.buffer); + } + else + { + std::vector<uint32_t> image_data; + image_data.resize(texture_size.Width * texture_size.Height, + video::SColor(0, 255, 255, 255).color); + switch (bits.pixel_mode) + { + case FT_PIXEL_MODE_GRAY: + { + // Load the grayscale data in. + const float gray_count = static_cast<float>(bits.num_grays); + const unsigned int image_pitch = + 4 * texture_size.Width / sizeof(unsigned int); + uint8_t* glyph_data = bits.buffer; + for (unsigned int y = 0; y < (unsigned int)bits.rows; y++) + { + uint8_t* row = glyph_data; + for (unsigned int x = 0; x < (unsigned int)bits.width; x++) + { + image_data.data()[y * image_pitch + x] |= + static_cast<uint32_t>(255.0f * + (static_cast<float>(*row++) / gray_count)) << 24; + } + glyph_data += bits.pitch; + } + break; + } + default: + assert(false); + } + glTexSubImage2D(GL_TEXTURE_2D, 0, m_used_width, m_used_height, + texture_size.Width, texture_size.Height, GL_BGRA, GL_UNSIGNED_BYTE, + image_data.data()); + } if (tex->hasMipMaps()) glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); diff --git a/src/graphics/central_settings.cpp b/src/graphics/central_settings.cpp index dbe7ad034..ea245cfaa 100644 --- a/src/graphics/central_settings.cpp +++ b/src/graphics/central_settings.cpp @@ -51,6 +51,7 @@ void CentralVideoSettings::init() hasExplicitAttribLocation = false; hasGS = false; hasTextureFilterAnisotropic = false; + hasTextureSwizzle = false; #if defined(USE_GLES2) hasBGRA = false; @@ -182,7 +183,11 @@ void CentralVideoSettings::init() hasGS = true; Log::info("GLDriver", "Geometry Shaders Present"); } - + if (hasGLExtension("GL_ARB_texture_swizzle")) + { + hasTextureSwizzle = true; + Log::info("GLDriver", "ARB Texture Swizzle Present"); + } // Only unset the high def textures if they are set as default. If the // user has enabled them (bit 1 set), then leave them enabled. if (GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_HIGHDEFINITION_TEXTURES) && @@ -228,6 +233,7 @@ void CentralVideoSettings::init() if (m_glsl == true) { hasTextureStorage = true; + hasTextureSwizzle = true; } if (!GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_TEXTURE_FORMAT_BGRA8888) && @@ -447,4 +453,10 @@ bool CentralVideoSettings::supportsHardwareSkinning() const { return isARBUniformBufferObjectUsable(); } + +bool CentralVideoSettings::isARBTextureSwizzleUsable() const +{ + return m_glsl && hasTextureSwizzle; +} + #endif // !SERVER_ONLY diff --git a/src/graphics/central_settings.hpp b/src/graphics/central_settings.hpp index 71a50fdf1..146160e0b 100644 --- a/src/graphics/central_settings.hpp +++ b/src/graphics/central_settings.hpp @@ -43,6 +43,7 @@ private: bool hasImageLoadStore; bool hasMultiDrawIndirect; bool hasTextureFilterAnisotropic; + bool hasTextureSwizzle; #if defined(USE_GLES2) bool hasBGRA; @@ -82,6 +83,7 @@ public: bool isARBMultiDrawIndirectUsable() const; bool isARBExplicitAttribLocationUsable() const; bool isEXTTextureFilterAnisotropicUsable() const; + bool isARBTextureSwizzleUsable() const; #if defined(USE_GLES2) bool isEXTTextureFormatBGRA8888Usable() const; diff --git a/src/graphics/stk_texture.cpp b/src/graphics/stk_texture.cpp index 1afb76433..e2a3ec6b7 100644 --- a/src/graphics/stk_texture.cpp +++ b/src/graphics/stk_texture.cpp @@ -82,6 +82,8 @@ void STKTexture::reload(bool no_upload, uint8_t* preload_data, if (ProfileWorld::isNoGraphics()) { m_texture_name = 1; + if (preload_data) + delete[] preload_data; return; } #ifndef SERVER_ONLY @@ -156,8 +158,8 @@ void STKTexture::reload(bool no_upload, uint8_t* preload_data, const unsigned int w = m_size.Width; const unsigned int h = m_size.Height; - unsigned int format = GL_BGRA; - unsigned int internal_format = GL_RGBA; + unsigned int format = single_channel ? GL_RED : GL_BGRA; + unsigned int internal_format = single_channel ? GL_RED : GL_RGBA; #if !defined(USE_GLES2) if (m_mesh_texture && CVS->isTextureCompressionEnabled()) @@ -166,14 +168,14 @@ void STKTexture::reload(bool no_upload, uint8_t* preload_data, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; } - else + else if (!single_channel) { internal_format = m_srgb ? GL_SRGB_ALPHA : GL_RGBA; } #endif #if defined(USE_GLES2) - if (!CVS->isEXTTextureFormatBGRA8888Usable()) + if (!CVS->isEXTTextureFormatBGRA8888Usable() && !single_channel) { format = GL_RGBA; for (unsigned int i = 0; i < w * h; i++) @@ -206,6 +208,14 @@ void STKTexture::reload(bool no_upload, uint8_t* preload_data, glBindTexture(GL_TEXTURE_2D, m_texture_name); if (!reload) { + if (single_channel) + { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED); + } glTexImage2D(GL_TEXTURE_2D, 0, internal_format, w, h, 0, format, GL_UNSIGNED_BYTE, data); } @@ -220,7 +230,7 @@ void STKTexture::reload(bool no_upload, uint8_t* preload_data, glGenerateMipmap(GL_TEXTURE_2D); } - m_texture_size = w * h * 4 /*BRGA*/; + m_texture_size = w * h * (single_channel ? 1 : 4); if (no_upload) m_texture_image = orig_img; else if (orig_img) @@ -454,10 +464,10 @@ bool STKTexture::hasMipMaps() const //----------------------------------------------------------------------------- void* STKTexture::lock(video::E_TEXTURE_LOCK_MODE mode, u32 mipmap_level) { -#ifndef SERVER_ONLY if (m_texture_image) return m_texture_image->lock(); +#if !(defined(SERVER_ONLY) || defined(USE_GLES2)) uint8_t* pixels = new uint8_t[m_size.Width * m_size.Height * 4](); GLint tmp_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &tmp_texture);