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);
}
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
@@ -65,23 +56,36 @@ int ImageRasterizer::getLineHeight() const
GlyphData *ImageRasterizer::getGlyphData(unsigned int glyph) const
{
GlyphMetrics gm;
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++)
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())
{
love::image::pixel p = pixels[ positions[glyph] + (i % widths[glyph]) + (imageData->getWidth() * (i / widths[glyph])) ];
gd[i*4] = p.r;
gm.width = it->second.width;
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+2] = p.b;
gd[i*4+3] = p.a;
}
return g;
}
@@ -89,9 +93,9 @@ void ImageRasterizer::load()
{
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;
@@ -102,19 +106,17 @@ void ImageRasterizer::load()
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;
@@ -125,20 +127,22 @@ void ImageRasterizer::load()
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
@@ -156,7 +160,7 @@ void ImageRasterizer::load()
int ImageRasterizer::getNumGlyphs() const
{
return length;
return numglyphs;
}
} // font
+26 -18
View File
@@ -26,6 +26,8 @@
#include "font/Rasterizer.h"
#include "image/ImageData.h"
#include <map>
namespace love
{
namespace font
@@ -36,25 +38,8 @@ 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
@@ -64,6 +49,29 @@ public:
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
+35 -9
View File
@@ -23,6 +23,8 @@
#include "TrueTypeRasterizer.h"
#include "font/ImageRasterizer.h"
#include "libraries/utf8/utf8.h"
namespace love
{
namespace font
@@ -46,22 +48,46 @@ Rasterizer *Font::newRasterizer(Data *data, int 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();
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)
+2 -2
View File
@@ -55,8 +55,8 @@ public:
// 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