Commits

Alex Szpakowski  committed 60fab84

Added support for UTF-8 ImageFont glyphs and ImageFonts with more than 256 characters

  • Participants
  • Parent commits 0a944fe

Comments (0)

Files changed (4)

File src/modules/font/ImageRasterizer.cpp

 	return (a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a);
 }
 
-ImageRasterizer::ImageRasterizer(love::image::ImageData *data, unsigned int *glyphs, int length)
+ImageRasterizer::ImageRasterizer(love::image::ImageData *data, unsigned int *glyphs, int numglyphs)
 	: imageData(data)
 	, glyphs(glyphs)
-	, length(length)
+	, numglyphs(numglyphs)
 {
 	imageData->retain();
-	positions = new unsigned int[MAX_CHARS];
-	memset(positions, 0, MAX_CHARS*4);
-	widths = new unsigned int[MAX_CHARS];
-	memset(widths, 0, MAX_CHARS*4);
-	spacing = new unsigned int[MAX_CHARS];
-	memset(spacing, 0, MAX_CHARS*4);
 	load();
 }
 
 ImageRasterizer::~ImageRasterizer()
 {
 	imageData->release();
-	delete[] positions;
-	delete[] widths;
-	delete[] spacing;
 }
 
 int ImageRasterizer::getLineHeight() const
 GlyphData *ImageRasterizer::getGlyphData(unsigned int glyph) const
 {
 	GlyphMetrics gm;
+	memset(&gm, 0, sizeof(GlyphMetrics));
+
+	// Set relevant glyph metrics if the glyph is in this ImageFont
+	std::map<unsigned int, ImageGlyphData>::const_iterator it = imageGlyphData.find(glyph);
+	if (it != imageGlyphData.end())
+	{
+		gm.width = it->second.width;
+		gm.advance = it->second.width + it->second.spacing;
+	}
+
 	gm.height = metrics.height;
-	gm.width = widths[glyph];
-	gm.advance = spacing[glyph] + widths[glyph];
-	gm.bearingX = 0;
-	gm.bearingY = 0;
+	
 	GlyphData *g = new GlyphData(glyph, gm, GlyphData::FORMAT_RGBA);
-	if (gm.width == 0) return g;
-	unsigned char *gd = (unsigned char *)g->getData();
-	love::image::pixel *pixels = (love::image::pixel *)(imageData->getData());
-	for (unsigned int i = 0; i < widths[glyph]*getHeight(); i++)
+	
+	if (gm.width == 0)
+		return g;
+	
+	unsigned char *gd = (unsigned char *) g->getData();
+	love::image::pixel *pixels = (love::image::pixel *) imageData->getData();
+
+	// copy glyph from imagedata to glyphdata
+	for (unsigned int i = 0; i < gm.width * (unsigned int) getHeight(); i++)
 	{
-		love::image::pixel p = pixels[ positions[glyph] + (i % widths[glyph]) + (imageData->getWidth() * (i / widths[glyph])) ];
-		gd[i*4] = p.r;
+		love::image::pixel p = pixels[ it->second.x + (i % gm.width) + (imageData->getWidth() * (i / gm.width)) ];
+		gd[i*4+0] = p.r;
 		gd[i*4+1] = p.g;
 		gd[i*4+2] = p.b;
 		gd[i*4+3] = p.a;
 	}
+	
 	return g;
 }
 
 {
 	love::image::pixel *pixels = (love::image::pixel *)(imageData->getData());
 
-	unsigned imgw = (unsigned)imageData->getWidth();
-	unsigned imgh = (unsigned)imageData->getHeight();
-	unsigned imgs = imgw*imgh;
+	unsigned int imgw = (unsigned int) imageData->getWidth();
+	unsigned int imgh = (unsigned int) imageData->getHeight();
+	unsigned int imgs = imgw*imgh;
 
 	// Set the only metric that matters
 	metrics.height = imgh;
 	unsigned int start = 0;
 	unsigned int end = 0;
 
-	for (unsigned int i = 0; i < length; ++i)
+	for (unsigned int i = 0; i < numglyphs; ++i)
 	{
-		if (i >= MAX_CHARS)
-			break;
-
 		start = end;
 
 		// Finds out where the first character starts
 		while (start < imgw && equal(pixels[start], spacer))
 			++start;
 
-		if (i > 0)
-			spacing[glyphs[i - 1]] = (start > end) ? (start - end) : 0;
+		// set previous glyph's spacing
+		if (i > 0 && imageGlyphData.size() > 0)
+			imageGlyphData[glyphs[i - 1]].spacing = (start > end) ? (start - end) : 0;
 
 		end = start;
 
 		if (start >= end)
 			break;
 
-		unsigned c = glyphs[i];
+		ImageGlyphData igd;
+		igd.x = start;
+		igd.y = 0; // todo?
+		igd.width = end - start;
 
-		positions[c] = start;
-		widths[c] = (end - start);
+		imageGlyphData[glyphs[i]] = igd;
 	}
 
 	// Find spacing of last glyph
-	if (length > 0)
+	if (numglyphs > 0)
 	{
 		start = end;
 		while (start < imgw && equal(pixels[start], spacer))
 			++start;
 
-		spacing[glyphs[length - 1]] = (start > end) ? (start - end) : 0;
+		imageGlyphData[glyphs[numglyphs - 1]].spacing = (start > end) ? (start - end) : 0;
 	}
 
 	// Replace spacer color with an empty pixel
 
 int ImageRasterizer::getNumGlyphs() const
 {
-	return length;
+	return numglyphs;
 }
 
 } // font

File src/modules/font/ImageRasterizer.h

 #include "font/Rasterizer.h"
 #include "image/ImageData.h"
 
+#include <map>
+
 namespace love
 {
 namespace font
  **/
 class ImageRasterizer : public Rasterizer
 {
-private:
-	// Load all the glyph positions into memory
-	void load();
-
-	// The image data
-	love::image::ImageData *imageData;
-	// The glyphs in the font
-	unsigned int *glyphs;
-	// The length of the glyph array
-	unsigned int length;
-	// The positions of each glyph
-	unsigned int *positions;
-	// The widths of each glyph
-	unsigned int *widths;
-	// The spacing of each glyph
-	unsigned int *spacing;
-
 public:
-	ImageRasterizer(love::image::ImageData *imageData, unsigned int *glyphs, int length);
+	ImageRasterizer(love::image::ImageData *imageData, unsigned int *glyphs, int numglyphs);
 	virtual ~ImageRasterizer();
 
 	// Implement Rasterizer
 
 	static const unsigned int MAX_CHARS = 256;
 
+private:
+	// Load all the glyph positions into memory
+	void load();
+
+	// The image data
+	love::image::ImageData *imageData;
+
+	// The glyphs in the font
+	unsigned int *glyphs;
+
+	// Number of glyphs in the font
+	unsigned int numglyphs;
+
+	// Information about a glyph in the ImageData
+	struct ImageGlyphData
+	{
+		unsigned int x, y;
+		unsigned int width;
+		unsigned int spacing;
+	};
+
+	std::map<unsigned int, ImageGlyphData> imageGlyphData;
+
 }; // ImageRasterizer
 
 } // font

File src/modules/font/freetype/Font.cpp

 #include "TrueTypeRasterizer.h"
 #include "font/ImageRasterizer.h"
 
+#include "libraries/utf8/utf8.h"
+
 namespace love
 {
 namespace font
 	return new TrueTypeRasterizer(library, data, size);
 }
 
-Rasterizer *Font::newRasterizer(love::image::ImageData *data, std::string glyphs)
+Rasterizer *Font::newRasterizer(love::image::ImageData *data, std::string text)
 {
-	int length = glyphs.size();
-	unsigned int *g = new unsigned int[length];
-	for (int i = 0; i < length; i++)
+	size_t strlen = text.size();
+	size_t numglyphs = 0;
+	
+	unsigned int *glyphs = new unsigned int[strlen];
+
+	try
 	{
-		g[i] = (unsigned char)glyphs[i];
+		utf8::iterator<std::string::const_iterator> i(text.begin(), text.begin(), text.end());
+		utf8::iterator<std::string::const_iterator> end(text.end(), text.begin(), text.end());
+
+		while (i != end)
+		{
+			if (numglyphs >= strlen)
+				throw love::Exception("foo");
+
+			glyphs[numglyphs++] = *i++;
+		}
 	}
-	Rasterizer *r = newRasterizer(data, g, length);
-	delete [] g;
+	catch (love::Exception &)
+	{
+		delete [] glyphs;
+		throw;
+	}
+	catch (utf8::exception &e)
+	{
+		delete [] glyphs;
+		throw love::Exception("%s", e.what());
+	}
+	
+	Rasterizer *r = newRasterizer(data, glyphs, numglyphs);
+	delete [] glyphs;
+	
 	return r;
 }
 
-Rasterizer *Font::newRasterizer(love::image::ImageData *data, unsigned int *glyphs, int length)
+Rasterizer *Font::newRasterizer(love::image::ImageData *data, unsigned int *glyphs, int numglyphs)
 {
-	return new ImageRasterizer(data, glyphs, length);
+	return new ImageRasterizer(data, glyphs, numglyphs);
 }
 
 GlyphData *Font::newGlyphData(Rasterizer *r, unsigned int glyph)

File src/modules/font/freetype/Font.h

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