diff --git a/src/modules/font/ImageRasterizer.cpp b/src/modules/font/ImageRasterizer.cpp index da97c27df..2cce08d3f 100644 --- a/src/modules/font/ImageRasterizer.cpp +++ b/src/modules/font/ImageRasterizer.cpp @@ -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::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 diff --git a/src/modules/font/ImageRasterizer.h b/src/modules/font/ImageRasterizer.h index beb6b338c..1623a14f7 100644 --- a/src/modules/font/ImageRasterizer.h +++ b/src/modules/font/ImageRasterizer.h @@ -26,6 +26,8 @@ #include "font/Rasterizer.h" #include "image/ImageData.h" +#include + 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 imageGlyphData; + }; // ImageRasterizer } // font diff --git a/src/modules/font/freetype/Font.cpp b/src/modules/font/freetype/Font.cpp index b0aaf894e..53aaf1c59 100644 --- a/src/modules/font/freetype/Font.cpp +++ b/src/modules/font/freetype/Font.cpp @@ -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 i(text.begin(), text.begin(), text.end()); + utf8::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) diff --git a/src/modules/font/freetype/Font.h b/src/modules/font/freetype/Font.h index d87ca641d..671954007 100644 --- a/src/modules/font/freetype/Font.h +++ b/src/modules/font/freetype/Font.h @@ -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