From 36c5259e12d90d8cafe64535fed6b4823cc21990 Mon Sep 17 00:00:00 2001 From: Alexander Szpakowski Date: Mon, 7 Jan 2013 16:31:48 -0400 Subject: [PATCH] Font objects now have mipmap filter and mipmap sharpness support --- src/modules/graphics/opengl/Font.cpp | 78 ++++++++++++++++++++--- src/modules/graphics/opengl/Font.h | 13 +++- src/modules/graphics/opengl/wrap_Font.cpp | 46 ++++++++++++- src/modules/graphics/opengl/wrap_Font.h | 2 + 4 files changed, 127 insertions(+), 12 deletions(-) diff --git a/src/modules/graphics/opengl/Font.cpp b/src/modules/graphics/opengl/Font.cpp index ba0b7464b..d7f511188 100644 --- a/src/modules/graphics/opengl/Font.cpp +++ b/src/modules/graphics/opengl/Font.cpp @@ -21,15 +21,15 @@ #include "Font.h" #include "font/GlyphData.h" #include "Quad.h" +#include "Image.h" #include "libraries/utf8/utf8.h" #include "common/math.h" #include "common/Matrix.h" + #include - #include - #include // for max namespace love @@ -39,8 +39,8 @@ namespace graphics namespace opengl { -const int Font::TEXTURE_WIDTHS[] = {128, 256, 256, 512, 512, 1024, 1024}; -const int Font::TEXTURE_HEIGHTS[] = {128, 128, 256, 256, 512, 512, 1024}; +const int Font::TEXTURE_WIDTHS[] = {128, 256, 256, 512, 512, 1024, 1024}; +const int Font::TEXTURE_HEIGHTS[] = {128, 128, 256, 256, 512, 512, 1024}; Font::Font(love::font::Rasterizer *r, const Image::Filter &filter) : rasterizer(r) @@ -48,6 +48,7 @@ Font::Font(love::font::Rasterizer *r, const Image::Filter &filter) , lineHeight(1) , mSpacing(1) , filter(filter) + , mipmapsharpness(0.0f) { love::font::GlyphData *gd = r->getGlyphData(32); type = (gd->getFormat() == love::font::GlyphData::FORMAT_LUMINANCE_ALPHA ? FONT_TRUETYPE : FONT_IMAGE); @@ -70,7 +71,7 @@ Font::Font(love::font::Rasterizer *r, const Image::Filter &filter) texture_width = TEXTURE_WIDTHS[texture_size_index]; texture_height = TEXTURE_HEIGHTS[texture_size_index]; - createTexture(); + loadVolatile(); r->retain(); } @@ -111,7 +112,8 @@ void Font::createTexture() bindTexture(t); - setTextureFilter(filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -153,6 +155,9 @@ void Font::createTexture() format, GL_UNSIGNED_BYTE, &emptyData[0]); + + setFilter(filter); + setMipmapSharpness(mipmapsharpness); } Font::Glyph *Font::addGlyph(const int glyph) @@ -484,30 +489,85 @@ float Font::getSpacing() const return mSpacing; } +void Font::checkMipmapsCreated() const +{ + if (filter.mipmap != Image::FILTER_NEAREST && filter.mipmap != Image::FILTER_LINEAR) + return; + + if (!Image::hasMipmapSupport()) + throw love::Exception("Mipmap filtering is not supported on this system!"); + + GLboolean mipmapscreated; + glGetTexParameteriv(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLint *)&mipmapscreated); + + // generate mipmaps for this image if we haven't already + if (!mipmapscreated) + { + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); + + if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object) + glGenerateMipmap(GL_TEXTURE_2D); + else if (GLEE_EXT_framebuffer_object) + glGenerateMipmapEXT(GL_TEXTURE_2D); + else + { + // modify single texel to trigger mipmap chain generation + std::vector emptydata(type == FONT_TRUETYPE ? 2 : 4); + glTexSubImage2D(GL_TEXTURE_2D, + 0, + 0, 0, + 1, 1, + type == FONT_TRUETYPE ? GL_LUMINANCE_ALPHA : GL_RGBA, + GL_UNSIGNED_BYTE, + &emptydata[0]); + } + } +} + void Font::setFilter(const Image::Filter &f) { + filter = f; + std::vector::const_iterator it; for (it = textures.begin(); it != textures.end(); ++it) { bindTexture(*it); + checkMipmapsCreated(); setTextureFilter(f); } } -Image::Filter Font::getFilter() +const Image::Filter &Font::getFilter() { + return filter; +} + +void Font::setMipmapSharpness(float sharpness) +{ + if (!Image::hasMipmapSharpnessSupport()) + return; + + // LOD bias has the range (-maxbias, maxbias) + mipmapsharpness = std::min(std::max(sharpness, -maxmipmapsharpness + 0.01f), maxmipmapsharpness - 0.01f); + std::vector::const_iterator it; for (it = textures.begin(); it != textures.end(); ++it) { bindTexture(*it); - return getTextureFilter(); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapsharpness); // negative bias is sharper } +} - return Image::getDefaultFilter(); +float Font::getMipmapSharpness() const +{ + return mipmapsharpness; } bool Font::loadVolatile() { + if (Image::hasMipmapSharpnessSupport()) + glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxmipmapsharpness); + createTexture(); return true; } diff --git a/src/modules/graphics/opengl/Font.h b/src/modules/graphics/opengl/Font.h index 299836cdd..73baccd9b 100644 --- a/src/modules/graphics/opengl/Font.h +++ b/src/modules/graphics/opengl/Font.h @@ -127,7 +127,10 @@ public: float getSpacing() const; void setFilter(const Image::Filter &f); - Image::Filter getFilter(); + const Image::Filter &getFilter(); + + void setMipmapSharpness(float sharpness); + float getMipmapSharpness() const; // Implements Volatile. bool loadVolatile(); @@ -196,6 +199,14 @@ private: int texture_x, texture_y; int rowHeight; + // Mipmap texture LOD bias value + float mipmapsharpness; + + // Implementation-dependent maximum/minimum mipmap sharpness values + float maxmipmapsharpness; + + void checkMipmapsCreated() const; + bool initializeTexture(GLint format); void createTexture(); Glyph *addGlyph(const int glyph); diff --git a/src/modules/graphics/opengl/wrap_Font.cpp b/src/modules/graphics/opengl/wrap_Font.cpp index cc71ec88b..5306a10e3 100644 --- a/src/modules/graphics/opengl/wrap_Font.cpp +++ b/src/modules/graphics/opengl/wrap_Font.cpp @@ -104,7 +104,23 @@ int w_Font_setFilter(lua_State *L) if (!Image::getConstant(magstr, f.mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); - t->setFilter(f); + if (lua_isnoneornil(L, 4)) + f.mipmap = Image::FILTER_NONE; // mipmapping is disabled unless third argument is given + else + { + const char *mipmapstr = luaL_checkstring(L, 4); + if (!Image::getConstant(mipmapstr, f.mipmap)) + return luaL_error(L, "Invalid filter mode: %s", mipmapstr); + } + + try + { + t->setFilter(f); + } + catch(love::Exception &e) + { + return luaL_error(L, "%s", e.what()); + } return 0; } @@ -119,7 +135,31 @@ int w_Font_getFilter(lua_State *L) Image::getConstant(f.mag, magstr); lua_pushstring(L, minstr); lua_pushstring(L, magstr); - return 2; + + const char *mipmapstr; + if (Image::getConstant(f.mipmap, mipmapstr)) + lua_pushstring(L, mipmapstr); + else + lua_pushnil(L); // only return a mipmap filter if mipmapping is enabled + + return 3; +} + +int w_Font_setMipmapSharpness(lua_State *L) +{ + Font *t = luax_checkfont(L, 1); + + float sharpness = (float) luaL_checknumber(L, 2); + t->setMipmapSharpness(sharpness); + + return 0; +} + +int w_Font_getMipmapSharpness(lua_State *L) +{ + Font *t = luax_checkfont(L, 1); + lua_pushnumber(L, t->getMipmapSharpness()); + return 1; } static const luaL_Reg functions[] = @@ -131,6 +171,8 @@ static const luaL_Reg functions[] = { "getLineHeight", w_Font_getLineHeight }, { "setFilter", w_Font_setFilter }, { "getFilter", w_Font_getFilter }, + { "setMipmapSharpness", w_Font_setMipmapSharpness }, + { "getMipmapSharpness", w_Font_getMipmapSharpness }, { 0, 0 } }; diff --git a/src/modules/graphics/opengl/wrap_Font.h b/src/modules/graphics/opengl/wrap_Font.h index c145167b2..a64be5863 100644 --- a/src/modules/graphics/opengl/wrap_Font.h +++ b/src/modules/graphics/opengl/wrap_Font.h @@ -40,6 +40,8 @@ int w_Font_setLineHeight(lua_State *L); int w_Font_getLineHeight(lua_State *L); int w_Font_setFilter(lua_State *L); int w_Font_getFilter(lua_State *L); +int w_Font_setMipmapSharpness(lua_State *L); +int w_Font_getMipmapSharpness(lua_State *L); extern "C" int luaopen_font(lua_State *L); } // opengl