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

This commit is contained in:
Alex Szpakowski
2013-01-23 03:02:46 -04:00
parent 022f549554
commit e51a9eb25d
4 changed files with 105 additions and 67 deletions
+42 -38
View File
@@ -34,27 +34,18 @@ inline bool equal(const love::image::pixel &a, const love::image::pixel &b)
return (a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a); 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) : imageData(data)
, glyphs(glyphs) , glyphs(glyphs)
, length(length) , numglyphs(numglyphs)
{ {
imageData->retain(); 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(); load();
} }
ImageRasterizer::~ImageRasterizer() ImageRasterizer::~ImageRasterizer()
{ {
imageData->release(); imageData->release();
delete[] positions;
delete[] widths;
delete[] spacing;
} }
int ImageRasterizer::getLineHeight() const int ImageRasterizer::getLineHeight() const
@@ -65,23 +56,36 @@ int ImageRasterizer::getLineHeight() const
GlyphData *ImageRasterizer::getGlyphData(unsigned int glyph) const GlyphData *ImageRasterizer::getGlyphData(unsigned int glyph) const
{ {
GlyphMetrics gm; GlyphMetrics gm;
gm.height = metrics.height; memset(&gm, 0, sizeof(GlyphMetrics));
gm.width = widths[glyph];
gm.advance = spacing[glyph] + widths[glyph]; // Set relevant glyph metrics if the glyph is in this ImageFont
gm.bearingX = 0; std::map<unsigned int, ImageGlyphData>::const_iterator it = imageGlyphData.find(glyph);
gm.bearingY = 0; if (it != imageGlyphData.end())
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++)
{ {
love::image::pixel p = pixels[ positions[glyph] + (i % widths[glyph]) + (imageData->getWidth() * (i / widths[glyph])) ]; gm.width = it->second.width;
gd[i*4] = p.r; gm.advance = it->second.width + it->second.spacing;
}
gm.height = metrics.height;
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();
// copy glyph from imagedata to glyphdata
for (unsigned int i = 0; i < gm.width * (unsigned int) getHeight(); i++)
{
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+1] = p.g;
gd[i*4+2] = p.b; gd[i*4+2] = p.b;
gd[i*4+3] = p.a; gd[i*4+3] = p.a;
} }
return g; return g;
} }
@@ -89,9 +93,9 @@ void ImageRasterizer::load()
{ {
love::image::pixel *pixels = (love::image::pixel *)(imageData->getData()); love::image::pixel *pixels = (love::image::pixel *)(imageData->getData());
unsigned imgw = (unsigned)imageData->getWidth(); unsigned int imgw = (unsigned int) imageData->getWidth();
unsigned imgh = (unsigned)imageData->getHeight(); unsigned int imgh = (unsigned int) imageData->getHeight();
unsigned imgs = imgw*imgh; unsigned int imgs = imgw*imgh;
// Set the only metric that matters // Set the only metric that matters
metrics.height = imgh; metrics.height = imgh;
@@ -102,19 +106,17 @@ void ImageRasterizer::load()
unsigned int start = 0; unsigned int start = 0;
unsigned int end = 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; start = end;
// Finds out where the first character starts // Finds out where the first character starts
while (start < imgw && equal(pixels[start], spacer)) while (start < imgw && equal(pixels[start], spacer))
++start; ++start;
if (i > 0) // set previous glyph's spacing
spacing[glyphs[i - 1]] = (start > end) ? (start - end) : 0; if (i > 0 && imageGlyphData.size() > 0)
imageGlyphData[glyphs[i - 1]].spacing = (start > end) ? (start - end) : 0;
end = start; end = start;
@@ -125,20 +127,22 @@ void ImageRasterizer::load()
if (start >= end) if (start >= end)
break; break;
unsigned c = glyphs[i]; ImageGlyphData igd;
igd.x = start;
igd.y = 0; // todo?
igd.width = end - start;
positions[c] = start; imageGlyphData[glyphs[i]] = igd;
widths[c] = (end - start);
} }
// Find spacing of last glyph // Find spacing of last glyph
if (length > 0) if (numglyphs > 0)
{ {
start = end; start = end;
while (start < imgw && equal(pixels[start], spacer)) while (start < imgw && equal(pixels[start], spacer))
++start; ++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 // Replace spacer color with an empty pixel
@@ -156,7 +160,7 @@ void ImageRasterizer::load()
int ImageRasterizer::getNumGlyphs() const int ImageRasterizer::getNumGlyphs() const
{ {
return length; return numglyphs;
} }
} // font } // font
+26 -18
View File
@@ -26,6 +26,8 @@
#include "font/Rasterizer.h" #include "font/Rasterizer.h"
#include "image/ImageData.h" #include "image/ImageData.h"
#include <map>
namespace love namespace love
{ {
namespace font namespace font
@@ -36,25 +38,8 @@ namespace font
**/ **/
class ImageRasterizer : public Rasterizer 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: public:
ImageRasterizer(love::image::ImageData *imageData, unsigned int *glyphs, int length); ImageRasterizer(love::image::ImageData *imageData, unsigned int *glyphs, int numglyphs);
virtual ~ImageRasterizer(); virtual ~ImageRasterizer();
// Implement Rasterizer // Implement Rasterizer
@@ -64,6 +49,29 @@ public:
static const unsigned int MAX_CHARS = 256; 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 }; // ImageRasterizer
} // font } // font
+35 -9
View File
@@ -23,6 +23,8 @@
#include "TrueTypeRasterizer.h" #include "TrueTypeRasterizer.h"
#include "font/ImageRasterizer.h" #include "font/ImageRasterizer.h"
#include "libraries/utf8/utf8.h"
namespace love namespace love
{ {
namespace font namespace font
@@ -46,22 +48,46 @@ Rasterizer *Font::newRasterizer(Data *data, int size)
return new TrueTypeRasterizer(library, data, size); 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(); size_t strlen = text.size();
unsigned int *g = new unsigned int[length]; size_t numglyphs = 0;
for (int i = 0; i < length; i++)
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); catch (love::Exception &)
delete [] g; {
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; 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) GlyphData *Font::newGlyphData(Rasterizer *r, unsigned int glyph)
+2 -2
View File
@@ -55,8 +55,8 @@ public:
// Implements Font // Implements Font
Rasterizer *newRasterizer(Data *data, int size); Rasterizer *newRasterizer(Data *data, int size);
Rasterizer *newRasterizer(love::image::ImageData *data, std::string glyphs); Rasterizer *newRasterizer(love::image::ImageData *data, std::string text);
Rasterizer *newRasterizer(love::image::ImageData *data, unsigned int *glyphs, int length); Rasterizer *newRasterizer(love::image::ImageData *data, unsigned int *glyphs, int numglyphs);
GlyphData *newGlyphData(Rasterizer *r, unsigned int glyph); GlyphData *newGlyphData(Rasterizer *r, unsigned int glyph);
// Implement Module // Implement Module