Commits

Alex Szpakowski committed 3b8cb8b

Exposed the internal Rasterizer and GlyphData object methods to Lua. Also added Font:hasGlyph.

Comments (0)

Files changed (21)

src/modules/font/Font.h

 	virtual Rasterizer *newRasterizer(Data *data, int size) = 0;
 	virtual Rasterizer *newRasterizer(love::image::ImageData *data, const std::string &glyphs) = 0;
 	virtual Rasterizer *newRasterizer(love::image::ImageData *data, unsigned int *glyphs, int length) = 0;
+	virtual GlyphData *newGlyphData(Rasterizer *r, const std::string &glyph) = 0;
 	virtual GlyphData *newGlyphData(Rasterizer *r, unsigned int glyph) = 0;
 
 	// Implement Module

src/modules/font/GlyphData.cpp

  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
+// LOVE
 #include "GlyphData.h"
 
+// UTF-8
+#include "libraries/utf8/utf8.h"
+
+// stdlib
 #include <iostream>
 
 namespace love
 	, data(0)
 	, format(f)
 {
-	if (metrics.width && metrics.height)
+	if (metrics.width > 0 && metrics.height > 0)
 	{
 		switch (f)
 		{
 	return glyph;
 }
 
+std::string GlyphData::getGlyphString() const
+{
+	char u[5] = {0, 0, 0, 0, 0};
+	ptrdiff_t length = 0;
+
+	try
+	{
+		char *end = utf8::append(glyph, u);
+		length = end - u;
+	}
+	catch (utf8::exception &e)
+	{
+		throw love::Exception("Decoding error: %s", e.what());
+	}
+
+	// Just in case...
+	if (length < 0)
+		return "";
+
+	return std::string(u, length);
+}
+
 int GlyphData::getAdvance() const
 {
 	return metrics.advance;
 	return format;
 }
 
+bool GlyphData::getConstant(const char *in, GlyphData::Format &out)
+{
+	return formats.find(in, out);
+}
+
+bool GlyphData::getConstant(GlyphData::Format in, const char *&out)
+{
+	return formats.find(in, out);
+}
+
+StringMap<GlyphData::Format, GlyphData::FORMAT_MAX_ENUM>::Entry GlyphData::formatEntries[] =
+{
+	{"luminance alpha", GlyphData::FORMAT_LUMINANCE_ALPHA},
+	{"rgba", GlyphData::FORMAT_RGBA},
+};
+
+StringMap<GlyphData::Format, GlyphData::FORMAT_MAX_ENUM> GlyphData::formats(GlyphData::formatEntries, sizeof(GlyphData::formatEntries));
+
 } // font
 } // love

src/modules/font/GlyphData.h

 // LOVE
 #include "common/config.h"
 #include "common/Data.h"
+#include "common/Exception.h"
+#include "common/StringMap.h"
+
+// stdlib
+#include <string>
 
 namespace love
 {
  **/
 class GlyphData : public Data
 {
+public:
 
-public:
 	enum Format
 	{
 		FORMAT_LUMINANCE_ALPHA,
-		FORMAT_RGBA
+		FORMAT_RGBA,
+		FORMAT_MAX_ENUM
 	};
 
 	GlyphData(unsigned int glyph, GlyphMetrics glyphMetrics, Format f);
 	unsigned int getGlyph() const;
 
 	/**
+	 * Gets the glyph as a UTF-8 string (instead of a UTF-8 code point.)
+	 **/
+	std::string getGlyphString() const;
+
+	/**
 	 * Gets the advance (the space the glyph takes up) of the glyph.
 	 **/
 	int getAdvance() const;
 	 **/
 	Format getFormat() const;
 
+	static bool getConstant(const char *in, Format &out);
+	static bool getConstant(Format in, const char *&out);
+
 private:
-	// The glyph itself
+
+	// The glyph codepoint itself.
 	unsigned int glyph;
 
-	// Glyph metrics
+	// Glyph metrics.
 	GlyphMetrics metrics;
 
-	// Glyph texture data
+	// Glyph texture data.
 	unsigned char *data;
 
-	// The format the data's in
+	// The format the data's in.
 	Format format;
 
+	static StringMap<Format, FORMAT_MAX_ENUM>::Entry formatEntries[];
+	static StringMap<Format, FORMAT_MAX_ENUM> formats;
+
 }; // GlyphData
 
 } // font

src/modules/font/ImageRasterizer.cpp

 	return numglyphs;
 }
 
+bool ImageRasterizer::hasGlyph(unsigned int glyph) const
+{
+	return imageGlyphs.find(glyph) != imageGlyphs.end();
+}
+
 } // font
 } // love

src/modules/font/ImageRasterizer.h

 	virtual int getLineHeight() const;
 	virtual GlyphData *getGlyphData(unsigned int glyph) const;
 	virtual int getGlyphCount() const;
+	virtual bool hasGlyph(unsigned int glyph) const;
 
 private:
 	// Load all the glyph positions into memory

src/modules/font/Rasterizer.cpp

 // LOVE
 #include "Rasterizer.h"
 
+// UTF-8
+#include "libraries/utf8/utf8.h"
+
 namespace love
 {
 namespace font
 	return metrics.descent;
 }
 
+GlyphData *Rasterizer::getGlyphData(const std::string &text) const
+{
+	unsigned int codepoint = 0;
+
+	try
+	{
+		codepoint = utf8::peek_next(text.begin(), text.end());
+	}
+	catch (utf8::exception &e)
+	{
+		throw love::Exception("Decoding error: %s", e.what());
+	}
+
+	return getGlyphData(codepoint);
+}
+
+bool Rasterizer::hasGlyph(const std::string &text) const
+{
+	if (text.size() == 0)
+		return false;
+
+	unsigned int codepoint = 0;
+
+	try
+	{
+		codepoint = utf8::peek_next(text.begin(), text.end());
+	}
+	catch (utf8::exception &e)
+	{
+		throw love::Exception("Decoding error: %s", e.what());
+	}
+
+	return hasGlyph(codepoint);
+}
+
 } // font
 } // love

src/modules/font/Rasterizer.h

  **/
 class Rasterizer : public Object
 {
-protected:
-	FontMetrics metrics;
-
 public:
 
 	virtual ~Rasterizer();
 
 	/**
 	 * Gets a specific glyph.
-	 * @param glyph The (UNICODE) glyph to get data for
+	 * @param glyph The (UNICODE) glyph codepoint to get data for.
 	 **/
 	virtual GlyphData *getGlyphData(unsigned int glyph) const = 0;
 
 	/**
+	 * Gets a specific glyph.
+	 * @param text The (UNICODE) glyph character to get the data for.
+	 **/
+	virtual GlyphData *getGlyphData(const std::string &text) const;
+
+	/**
 	 * Gets the number of glyphs the rasterizer has data for.
 	 **/
 	virtual int getGlyphCount() const = 0;
 
+	/**
+	 * Gets whether this Rasterizer has a specific glyph.
+	 * @param glyph The (UNICODE) glyph codepoint.
+	 **/
+	virtual bool hasGlyph(unsigned int glyph) const = 0;
+
+	/**
+	 * Gets whether this Rasterizer has a specific glyph.
+	 * @param text The (UNICODE) glyph character.
+	 **/
+	virtual bool hasGlyph(const std::string &text) const;
+
+protected:
+
+	FontMetrics metrics;
 
 }; // Rasterizer
 

src/modules/font/freetype/Font.cpp

 	catch (utf8::exception &e)
 	{
 		delete [] glyphs;
-		throw love::Exception("%s", e.what());
+		throw love::Exception("Decoding error: %s", e.what());
 	}
-	
+
 	Rasterizer *r = newRasterizer(data, glyphs, numglyphs);
 	delete [] glyphs;
-	
+
 	return r;
 }
 
 	return new ImageRasterizer(data, glyphs, numglyphs);
 }
 
+GlyphData *Font::newGlyphData(Rasterizer *r, const std::string &text)
+{
+	unsigned int codepoint = 0;
+
+	try
+	{
+		codepoint = utf8::peek_next(text.begin(), text.end());
+	}
+	catch (utf8::exception &e)
+	{
+		throw love::Exception("Decoding error: %s", e.what());
+	}
+
+	return r->getGlyphData(codepoint);
+}
+
 GlyphData *Font::newGlyphData(Rasterizer *r, unsigned int glyph)
 {
 	return r->getGlyphData(glyph);

src/modules/font/freetype/Font.h

 	Rasterizer *newRasterizer(Data *data, int size);
 	Rasterizer *newRasterizer(love::image::ImageData *data, const std::string &text);
 	Rasterizer *newRasterizer(love::image::ImageData *data, unsigned int *glyphs, int numglyphs);
+	GlyphData *newGlyphData(Rasterizer *r, const std::string &glyph);
 	GlyphData *newGlyphData(Rasterizer *r, unsigned int glyph);
 
 	// Implement Module

src/modules/font/freetype/TrueTypeRasterizer.cpp

 	int size = bitmap.rows * bitmap.width;
 	unsigned char *dst = (unsigned char *) glyphData->getData();
 
-	// Note that bitmap.buffer contains only luminosity. We copy that single value to
-	// our luminosity-alpha format.
+	// Note that bitmap.buffer contains only luminosity. We copy that single 
+	// value to our luminosity-alpha format.
 	for (int i = 0; i < size; i++)
 	{
 		dst[2*i] = 255;
 	return face->num_glyphs;
 }
 
+bool TrueTypeRasterizer::hasGlyph(unsigned int glyph) const
+{
+	return FT_Get_Char_Index(face, glyph) != 0;
+}
+
 } // freetype
 } // font
 } // love

src/modules/font/freetype/TrueTypeRasterizer.h

 	virtual int getLineHeight() const;
 	virtual GlyphData *getGlyphData(unsigned int glyph) const;
 	virtual int getGlyphCount() const;
+	virtual bool hasGlyph(unsigned int glyph) const;
 
 private:
 

src/modules/font/freetype/wrap_Font.cpp

 
 int w_newRasterizer(lua_State *L)
 {
+	// Convert to FileData, if necessary.
+	if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
+		luax_convobj(L, 1, "filesystem", "newFileData");
+
 	Rasterizer *t = NULL;
 	try
 	{
 int w_newGlyphData(lua_State *L)
 {
 	Rasterizer *r = luax_checkrasterizer(L, 1);
-	unsigned int g = (unsigned int)luaL_checknumber(L, 2);
+	GlyphData *t = 0;
 
-	GlyphData *t = instance->newGlyphData(r, g);
+	// newGlyphData accepts a unicode character or a codepoint number.
+	if (lua_type(L, 2) == LUA_TSTRING)
+	{
+		std::string glyph = luax_checkstring(L, 2);
+		try
+		{
+			t = instance->newGlyphData(r, glyph);
+		}
+		catch (love::Exception &e)
+		{
+			return luaL_error(L, "%s", e.what());
+		}
+	}
+	else
+	{
+		unsigned int g = (unsigned int) luaL_checknumber(L, 2);
+		t = instance->newGlyphData(r, g);
+	}
+
 	luax_newtype(L, "GlyphData", FONT_GLYPH_DATA_T, t);
 	return 1;
 }

src/modules/font/wrap_GlyphData.cpp

 	return luax_checktype<GlyphData>(L, idx, "GlyphData", FONT_GLYPH_DATA_T);
 }
 
+int w_GlyphData_getWidth(lua_State *L)
+{
+	GlyphData *t = luax_checkglyphdata(L, 1);
+	lua_pushinteger(L, t->getWidth());
+	return 1;
+}
+
+int w_GlyphData_getHeight(lua_State *L)
+{
+	GlyphData *t = luax_checkglyphdata(L, 1);
+	lua_pushinteger(L, t->getHeight());
+	return 1;
+}
+
+int w_GlyphData_getDimensions(lua_State *L)
+{
+	GlyphData *t = luax_checkglyphdata(L, 1);
+	lua_pushinteger(L, t->getWidth());
+	lua_pushinteger(L, t->getHeight());
+	return 2;
+}
+
+int w_GlyphData_getGlyph(lua_State *L)
+{
+	GlyphData *t = luax_checkglyphdata(L, 1);
+	unsigned int glyph = t->getGlyph();
+	lua_pushnumber(L, (lua_Number) glyph);
+	return 1;
+}
+	
+int w_GlyphData_getGlyphString(lua_State *L)
+{
+	GlyphData *t = luax_checkglyphdata(L, 1);
+	try
+	{
+		luax_pushstring(L, t->getGlyphString());
+	}
+	catch (love::Exception &e)
+	{
+		return luaL_error(L, "%s", e.what());
+	}
+	return 1;
+}
+
+int w_GlyphData_getAdvance(lua_State *L)
+{
+	GlyphData *t = luax_checkglyphdata(L, 1);
+	lua_pushinteger(L, t->getAdvance());
+	return 1;
+}
+
+int w_GlyphData_getBearing(lua_State *L)
+{
+	GlyphData *t = luax_checkglyphdata(L, 1);
+	lua_pushinteger(L, t->getBearingX());
+	lua_pushinteger(L, t->getBearingY());
+	return 2;
+}
+
+int w_GlyphData_getBoundingBox(lua_State *L)
+{
+	GlyphData *t = luax_checkglyphdata(L, 1);
+
+	int minX = t->getMinX();
+	int minY = t->getMinY();
+	int maxX = t->getMaxX();
+	int maxY = t->getMaxY();
+
+	int width = maxX - minX;
+	int height = maxY - minY;
+
+	lua_pushinteger(L, minX);
+	lua_pushinteger(L, minY);
+	lua_pushinteger(L, width);
+	lua_pushinteger(L, height);
+
+	return 4;
+}
+
+int w_GlyphData_getFormat(lua_State *L)
+{
+	GlyphData *t = luax_checkglyphdata(L, 1);
+
+	const char *str;
+	if (!GlyphData::getConstant(t->getFormat(), str))
+		return luaL_error(L, "unknown GlyphData format.");
+
+	lua_pushstring(L, str);
+	return 1;
+}
+
 static const luaL_Reg functions[] =
 {
 	// Data
 	{ "getString", w_Data_getString },
 	{ "getSize", w_Data_getSize },
+
+	{ "getWidth", w_GlyphData_getWidth },
+	{ "getHeight", w_GlyphData_getHeight },
+	{ "getDimensions", w_GlyphData_getDimensions },
+	{ "getGlyph", w_GlyphData_getGlyph },
+	{ "getGlyphString", w_GlyphData_getGlyphString },
+	{ "getAdvance", w_GlyphData_getAdvance },
+	{ "getBearing", w_GlyphData_getBearing },
+	{ "getBoundingBox", w_GlyphData_getBoundingBox },
+	{ "getFormat", w_GlyphData_getFormat },
 	{ 0, 0 }
 };
 

src/modules/font/wrap_GlyphData.h

 {
 
 GlyphData *luax_checkglyphdata(lua_State *L, int idx);
+int w_GlyphData_getWidth(lua_State *L);
+int w_GlyphData_getHeight(lua_State *L);
+int w_GlyphData_getDimensions(lua_State *L);
+int w_GlyphData_getGlyph(lua_State *L);
+int w_GlyphData_getGlyphString(lua_State *L);
+int w_GlyphData_getAdvance(lua_State *L);
+int w_GlyphData_getBearing(lua_State *L);
+int w_GlyphData_getBoundingBox(lua_State *L);
+int w_GlyphData_getFormat(lua_State *L);
 extern "C" int luaopen_glyphdata(lua_State *L);
 
 } // font

src/modules/font/wrap_Rasterizer.cpp

 	return luax_checktype<Rasterizer>(L, idx, "Rasterizer", FONT_RASTERIZER_T);
 }
 
+int w_Rasterizer_getHeight(lua_State *L)
+{
+	Rasterizer *t = luax_checkrasterizer(L, 1);
+	lua_pushinteger(L, t->getHeight());
+	return 1;
+}
+
+int w_Rasterizer_getAdvance(lua_State *L)
+{
+	Rasterizer *t = luax_checkrasterizer(L, 1);
+	lua_pushinteger(L, t->getAdvance());
+	return 1;
+}
+
+int w_Rasterizer_getAscent(lua_State *L)
+{
+	Rasterizer *t = luax_checkrasterizer(L, 1);
+	lua_pushinteger(L, t->getAscent());
+	return 1;
+}
+
+int w_Rasterizer_getDescent(lua_State *L)
+{
+	Rasterizer *t = luax_checkrasterizer(L, 1);
+	lua_pushinteger(L, t->getDescent());
+	return 1;
+}
+
+int w_Rasterizer_getLineHeight(lua_State *L)
+{
+	Rasterizer *t = luax_checkrasterizer(L, 1);
+	lua_pushinteger(L, t->getLineHeight());
+	return 1;
+}
+
+int w_Rasterizer_getGlyphData(lua_State *L)
+{
+	Rasterizer *t = luax_checkrasterizer(L, 1);
+	GlyphData *g = 0;
+
+	try
+	{
+		// getGlyphData accepts a unicode character or a codepoint number.
+		if (lua_type(L, 2) == LUA_TSTRING)
+		{
+			std::string glyph = luax_checkstring(L, 2);
+			g = t->getGlyphData(glyph);
+		}
+		else
+		{
+			unsigned int glyph = (unsigned int) luaL_checknumber(L, 2);
+			g = t->getGlyphData(glyph);
+		}
+	}
+	catch (love::Exception &e)
+	{
+		return luaL_error(L, "%s", e.what());
+	}
+
+	luax_newtype(L, "GlyphData", FONT_GLYPH_DATA_T, (void *) g);
+	return 1;
+}
+
+int w_Rasterizer_getGlyphCount(lua_State *L)
+{
+	Rasterizer *t = luax_checkrasterizer(L, 1);
+	lua_pushinteger(L, t->getGlyphCount());
+	return 1;
+}
+
+int w_Rasterizer_hasGlyph(lua_State *L)
+{
+	Rasterizer *t = luax_checkrasterizer(L, 1);
+
+	bool hasglyph = false;
+
+	try
+	{
+		if (lua_type(L, 2) == LUA_TSTRING)
+			hasglyph = t->hasGlyph(luax_checkstring(L, 2));
+		else
+			hasglyph = t->hasGlyph((unsigned int) luaL_checknumber(L, 2));
+	}
+	catch (love::Exception &e)
+	{
+		return luaL_error(L, "%s", e.what());
+	}
+
+	luax_pushboolean(L, hasglyph);
+	return 1;
+}
+
 static const luaL_Reg functions[] =
 {
+	{ "getHeight", w_Rasterizer_getHeight },
+	{ "getAdvance", w_Rasterizer_getAdvance },
+	{ "getAscent", w_Rasterizer_getAscent },
+	{ "getDescent", w_Rasterizer_getDescent },
+	{ "getLineHeight", w_Rasterizer_getLineHeight },
+	{ "getGlyphData", w_Rasterizer_getGlyphData },
+	{ "getGlyphCount", w_Rasterizer_getGlyphCount },
+	{ "hasGlyph", w_Rasterizer_hasGlyph },
 	{ 0, 0 }
 };
 

src/modules/font/wrap_Rasterizer.h

 {
 
 Rasterizer *luax_checkrasterizer(lua_State *L, int idx);
+int w_Rasterizer_getHeight(lua_State *L);
+int w_Rasterizer_getAdvance(lua_State *L);
+int w_Rasterizer_getAscent(lua_State *L);
+int w_Rasterizer_getDescent(lua_State *L);
+int w_Rasterizer_getLineHeight(lua_State *L);
+int w_Rasterizer_getGlyphData(lua_State *L);
+int w_Rasterizer_getGlyphCount(lua_State *L);
+int w_Rasterizer_hasGlyph(lua_State *L);
 extern "C" int luaopen_rasterizer(lua_State *L);
 
 } // font

src/modules/graphics/opengl/Font.cpp

 	catch (utf8::exception &e)
 	{
 		glPopMatrix();
-		throw love::Exception("%s", e.what());
+		throw love::Exception("Decoding error: %s", e.what());
 	}
 
 	if (quadindex > 0 && glyphinfolist.size() > 0)
 		}
 		catch(utf8::exception &e)
 		{
-			throw love::Exception("%s", e.what());
+			throw love::Exception("Decoding error: %s", e.what());
 		}
 
 		if (width > max_width)
 	return (type == FONT_TRUETYPE) ? floor(getHeight() / 1.25f + 0.5f) : 0.0f;
 }
 
+bool Font::hasGlyph(unsigned int glyph) const
+{
+	return rasterizer->hasGlyph(glyph);
+}
+
+bool Font::hasGlyph(const std::string &text) const
+{
+	return rasterizer->hasGlyph(text);
+}
+
 } // opengl
 } // graphics
 } // love

src/modules/graphics/opengl/Font.h

 	int getDescent() const;
 	float getBaseline() const;
 
+	bool hasGlyph(unsigned int glyph) const;
+	bool hasGlyph(const std::string &text) const;
+
 private:
 
 	enum FontType

src/modules/graphics/opengl/wrap_Font.cpp

 	return 1;
 }
 
+int w_Font_hasGlyph(lua_State *L)
+{
+	Font *t = luax_checkfont(L, 1);
+	bool hasglyph = false;
+
+	try
+	{
+		if (lua_type(L, 2) == LUA_TSTRING)
+			hasglyph = t->hasGlyph(luax_checkstring(L, 2));
+		else
+			hasglyph = t->hasGlyph((unsigned int) luaL_checknumber(L, 2));
+	}
+	catch (love::Exception &e)
+	{
+		return luaL_error(L, "%s", e.what());
+	}
+
+	luax_pushboolean(L, hasglyph);
+	return 1;
+}
+
 static const luaL_Reg functions[] =
 {
 	{ "getHeight", w_Font_getHeight },
 	{ "getAscent", w_Font_getAscent },
 	{ "getDescent", w_Font_getDescent },
 	{ "getBaseline", w_Font_getBaseline },
+	{ "hasGlyph", w_Font_hasGlyph },
 	{ 0, 0 }
 };
 

src/modules/graphics/opengl/wrap_Font.h

 int w_Font_getAscent(lua_State *L);
 int w_Font_getDescent(lua_State *L);
 int w_Font_getBaseline(lua_State *L);
+int w_Font_hasGlyph(lua_State *L);
 extern "C" int luaopen_font(lua_State *L);
 
 } // opengl

src/modules/graphics/opengl/wrap_Graphics.cpp

 	{
 		instance->print(str, x, y, angle, sx, sy, ox, oy, kx,ky);
 	}
-	catch(love::Exception e)
+	catch(love::Exception &e)
 	{
-		return luaL_error(L, "Decoding error: %s", e.what());
+		return luaL_error(L, "%s", e.what());
 	}
 	return 0;
 }
 	{
 		instance->printf(str, x, y, wrap, align, angle, sx, sy, ox, oy, kx, ky);
 	}
-	catch(love::Exception e)
+	catch(love::Exception &e)
 	{
-		return luaL_error(L, "Decoding error: %s", e.what());
+		return luaL_error(L, "%s", e.what());
 	}
 	return 0;
 }