Adding FreeType font generation

This commit is contained in:
Matt Tuttle
2014-07-13 15:49:08 -05:00
parent 7e207a8232
commit 6d7388212a
10 changed files with 361 additions and 17 deletions

View File

@@ -10,6 +10,7 @@
#include <hx/CFFI.h>
#include <app/Application.h>
#include <app/UpdateEvent.h>
#include <graphics/Font.h>
#include <graphics/Image.h>
#include <graphics/PNG.h>
#include <graphics/JPEG.h>
@@ -73,6 +74,26 @@ namespace lime {
}
value lime_font_load (value fontFace) {
Font *font = new Font (val_string (fontFace));
return alloc_float ((intptr_t)font);
}
value lime_font_load_glyphs (value fontHandle, value size, value glyphs) {
Image image;
Font *font = (Font*)(intptr_t)val_float (fontHandle);
value data = alloc_empty_object ();
alloc_field (data, val_id ("glyphs"), font->LoadGlyphs (val_int (size), val_string (glyphs), &image));
alloc_field (data, val_id ("image"), image.Value ());
return data;
}
value lime_key_event_manager_register (value callback, value eventObject) {
KeyEvent::callback = new AutoGCRoot (callback);
@@ -216,6 +237,8 @@ namespace lime {
DEFINE_PRIM (lime_application_exec, 1);
DEFINE_PRIM (lime_application_get_ticks, 0);
DEFINE_PRIM (lime_image_load, 1);
DEFINE_PRIM (lime_font_load, 1);
DEFINE_PRIM (lime_font_load_glyphs, 3);
DEFINE_PRIM (lime_key_event_manager_register, 2);
DEFINE_PRIM (lime_lzma_encode, 1);
DEFINE_PRIM (lime_lzma_decode, 1);

View File

@@ -0,0 +1,185 @@
#include <graphics/Font.h>
typedef struct {
char c;
FT_UInt index;
FT_Pos height;
} GlyphInfo;
namespace lime {
static int id_x;
static int id_y;
static int id_width;
static int id_height;
static int id_char;
static bool init = false;
bool CompareGlyph (const GlyphInfo &a, const GlyphInfo &b) {
return a.height > b.height;
}
Font::Font (const char *fontFace) {
int error;
FT_Library library;
error = FT_Init_FreeType (&library);
if (error) {
printf ("Could not initialize FreeType\n");
}
error = FT_New_Face (library, fontFace, 0, &face);
if (error == FT_Err_Unknown_File_Format) {
printf ("Invalid font type\n");
} else if (error) {
printf ("Failed to load font face %s\n", fontFace);
}
}
value Font::LoadGlyphs (int size, const char *glyphs, Image *image) {
if (!init) {
id_width = val_id ("width");
id_height = val_id ("height");
id_x = val_id ("x");
id_y = val_id ("y");
id_char = val_id ("char");
init = true;
}
std::list<GlyphInfo> glyphList;
int numGlyphs = strlen (glyphs);
char c[2] = " ";
FT_Set_Pixel_Sizes (face, 0, size);
for (int i = 0; i < numGlyphs; i++) {
GlyphInfo info;
info.c = glyphs[i];
info.index = FT_Get_Char_Index (face, info.c);
if (FT_Load_Glyph (face, info.index, FT_LOAD_DEFAULT) != 0) continue;
info.height = face->glyph->metrics.height;
glyphList.push_back(info);
}
glyphList.sort(CompareGlyph);
image->Resize(128, 128, 1);
int x = 0, y = 0, maxRows = 0;
unsigned char *bytes = image->data->Bytes ();
value rects = alloc_array (glyphList.size());
int rectsIndex = 0;
for (std::list<GlyphInfo>::iterator it = glyphList.begin(); it != glyphList.end(); it++) {
FT_Load_Glyph (face, (*it).index, FT_LOAD_DEFAULT);
c[0] = (*it).c;
if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL) != 0) continue;
FT_Bitmap bitmap = face->glyph->bitmap;
if (x + bitmap.width > image->width) {
y += maxRows + 1;
x = maxRows = 0;
}
if (y + bitmap.rows > image->height) {
if (image->width < image->height) {
image->width *= 2;
} else {
image->height *= 2;
}
image->Resize (image->width, image->height, 1);
rectsIndex = 0;
it = glyphList.begin ();
it--;
x = y = maxRows = 0;
continue;
}
if (image->bpp == 1) {
image->Blit (bitmap.buffer, x, y, bitmap.width, bitmap.rows);
} else {
for (int row = 0; row < bitmap.rows; row++) {
unsigned char *out = &bytes[((row + y) * image->width + x) * image->bpp];
const unsigned char *line = &bitmap.buffer[row * bitmap.width]; // scanline
const unsigned char *const end = line + bitmap.width;
while (line != end) {
*out++ = 0xFF;
*out++ = 0xFF;
*out++ = 0xFF;
*out++ = *line;
line++;
}
}
}
value v = alloc_empty_object ();
alloc_field (v, id_x, alloc_int (x));
alloc_field (v, id_y, alloc_int (y));
alloc_field (v, id_width, alloc_int (bitmap.width));
alloc_field (v, id_height, alloc_int (bitmap.rows));
alloc_field (v, id_char, alloc_string (c));
val_array_set_i (rects, rectsIndex++, v);
x += bitmap.width + 1;
if (bitmap.rows > maxRows) {
maxRows = bitmap.rows;
}
}
return rects;
}
}

View File

@@ -7,6 +7,7 @@ namespace lime {
static int id_data;
static int id_height;
static int id_width;
static int id_bpp;
static bool init = false;
@@ -14,6 +15,7 @@ namespace lime {
width = 0;
height = 0;
bpp = 4;
data = 0;
}
@@ -26,6 +28,37 @@ namespace lime {
}
void Image::Resize (int width, int height, int bpp) {
this->bpp = bpp;
this->width = width;
this->height = height;
if (this->data) delete this->data;
this->data = new ByteArray (width * height * bpp);
}
void Image::Blit (const unsigned char *data, int x, int y, int width, int height) {
if (x < 0 || x + width > this->width ||
y < 0 || y + height > this->height) {
return;
}
unsigned char *bytes = this->data->Bytes ();
for (int i = 0; i < height; i++) {
memcpy (&bytes[(i + y) * this->width + x], &data[i * width], width * bpp);
}
}
value Image::Value() {
if (!init) {
@@ -33,6 +66,7 @@ namespace lime {
id_width = val_id ("width");
id_height = val_id ("height");
id_data = val_id ("data");
id_bpp = val_id ("bpp");
init = true;
}
@@ -40,6 +74,7 @@ namespace lime {
mValue = alloc_empty_object ();
alloc_field (mValue, id_width, alloc_int (width));
alloc_field (mValue, id_height, alloc_int (height));
alloc_field (mValue, id_bpp, alloc_int (bpp));
alloc_field (mValue, id_data, data->mValue);
return mValue;

View File

@@ -28,10 +28,8 @@ namespace lime {
if (jpeg_read_header (&cinfo, TRUE) == JPEG_HEADER_OK) {
jpeg_start_decompress (&cinfo);
image->width = cinfo.output_width;
image->height = cinfo.output_height;
int components = cinfo.num_components;
image->data = new ByteArray (image->width * image->height * 4);
image->Resize(cinfo.output_width, cinfo.output_height);
unsigned char *bytes = image->data->Bytes ();
unsigned char *scanline = new unsigned char [image->width * image->height * components];

View File

@@ -72,10 +72,9 @@ namespace lime {
if (bit_depth == 16)
png_set_strip_16 (png_ptr);
const unsigned int stride = width * 4;
image->width = width;
image->height = height;
image->data = new ByteArray (height * stride);
int bpp = 4;
const unsigned int stride = width * bpp;
image->Resize(width, height, bpp);
png_bytepp row_ptrs = new png_bytep[height];
unsigned char *bytes = image->data->Bytes ();