Commits

Alex Szpakowski committed 7f8c25d

Font objects now have mipmap filter and mipmap sharpness support

Comments (0)

Files changed (4)

src/modules/graphics/opengl/Font.cpp

 #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 <math.h>
-
 #include <sstream>
-
 #include <algorithm> // for max
 
 namespace love
 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)
 	, 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);
 	texture_width = TEXTURE_WIDTHS[texture_size_index];
 	texture_height = TEXTURE_HEIGHTS[texture_size_index];
 
-	createTexture();
+	loadVolatile();
 
 	r->retain();
 }
 
 	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);
 					format,
 					GL_UNSIGNED_BYTE,
 					&emptyData[0]);
+
+	setFilter(filter);
+	setMipmapSharpness(mipmapsharpness);
 }
 
 Font::Glyph *Font::addGlyph(const int glyph)
 	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<GLubyte> 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<GLuint>::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<GLuint>::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;
 }

src/modules/graphics/opengl/Font.h

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

src/modules/graphics/opengl/wrap_Font.cpp

 	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;
 }
 	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[] =
 	{ "getLineHeight", w_Font_getLineHeight },
 	{ "setFilter", w_Font_setFilter },
 	{ "getFilter", w_Font_getFilter },
+	{ "setMipmapSharpness", w_Font_setMipmapSharpness },
+	{ "getMipmapSharpness", w_Font_getMipmapSharpness },
 	{ 0, 0 }
 };
 

src/modules/graphics/opengl/wrap_Font.h

 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