mirror of
https://github.com/love2d/love.git
synced 2026-08-16 08:11:02 +02:00
Added support for UTF-8 ImageFont glyphs and ImageFonts with more than 256 characters
This commit is contained in:
@@ -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,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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user