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

55
lime/graphics/Font.hx Normal file
View File

@@ -0,0 +1,55 @@
package lime.graphics;
import lime.utils.UInt8Array;
import lime.system.System;
typedef GlyphData = {
var image:Image;
var glyphs:Array<Dynamic>;
};
class Font {
#if (cpp || neko)
public var handle:Dynamic;
#end
public function new (fontFace:String) {
#if (cpp || neko)
handle = lime_font_load (fontFace);
#end
}
public function createImage (size:Int, glyphs:String="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^`'\"/\\&*()[]{}<>|:;_-+=?,. "):GlyphData {
#if (cpp || neko)
var data = lime_font_load_glyphs (handle, size, glyphs);
if (data == null) {
return null;
} else {
return {
glyphs: data.glyphs,
image: new Image (new UInt8Array (data.image.data), data.image.width, data.image.height, data.image.bpp)
};
}
#end
return null;
}
#if (cpp || neko)
private static var lime_font_load = System.load ("lime", "lime_font_load", 1);
private static var lime_font_load_glyphs = System.load ("lime", "lime_font_load_glyphs", 3);
#end
}

View File

@@ -21,6 +21,7 @@ class Image {
private static var __context:CanvasRenderingContext2D;
#end
public var bpp:Int;
public var data (get, set):ImageData;
public var height:Int;
public var offsetX:Int;
@@ -35,7 +36,7 @@ class Image {
private var __data:ImageData;
public function new (src:ImageSource = null, width:Int = 0, height:Int = 0) {
public function new (src:ImageSource = null, width:Int = 0, height:Int = 0, bpp:Int = 4) {
this.src = src;
#if (!js && !flash)
@@ -44,6 +45,7 @@ class Image {
this.width = textureWidth = width;
this.height = textureHeight = height;
this.bpp = bpp;
}
@@ -100,7 +102,7 @@ class Image {
for (x in 0...width) {
newData.setPixel (y * textureWidth * 4 + x * 4, newData.getPixel (y * width * 4 + x * 4));
newData.setPixel (y * textureWidth + x, newData.getPixel (y * width + x));
}
@@ -115,15 +117,15 @@ class Image {
public static function loadFromFile (path:String) {
#if flash
throw "Can not load image from file in Flash";
#elseif (cpp || neko)
#if (cpp || neko)
var imageData = lime_image_load (path);
return (imageData == null ? null : new Image (new UInt8Array (imageData.data), imageData.width, imageData.height));
return (imageData == null ? null : new Image (new UInt8Array (imageData.data), imageData.width, imageData.height, imageData.bpp));
#else
throw "Image.loadFromFile not supported on this target";
#end
}

View File

@@ -10,6 +10,7 @@
<set name="LIME_CURL" value="1" />
<set name="LIME_JPEG" value="1" />
<set name="LIME_FREETYPE" value="1" />
<!-- <set name="LIME_NEKO" value="1" if="linux" /> -->
<set name="LIME_OGG" value="1" />
<set name="LIME_OPENAL" value="1" />
@@ -37,6 +38,12 @@
</section>
<section if="LIME_FREETYPE">
<compilerflag value="-I${NATIVE_TOOLKIT_PATH}/freetype/include" />
</section>
<section if="LIME_NEKO">
<compilerflag value="-I${NATIVE_TOOLKIT_PATH}/neko/vm/" />
@@ -83,9 +90,10 @@
<file name="src/system/ios/System.mm" if="ios" />
<file name="src/app/UpdateEvent.cpp" />
<file name="src/graphics/Font.cpp" if="LIME_FREETYPE" />
<file name="src/graphics/Image.cpp" />
<file name="src/graphics/JPEG.cpp" />
<file name="src/graphics/PNG.cpp" />
<file name="src/graphics/JPEG.cpp" if="LIME_JPEG" />
<file name="src/graphics/PNG.cpp" if="LIME_PNG" />
<file name="src/graphics/RenderEvent.cpp" />
<file name="src/system/System.cpp" />
<file name="src/ui/KeyEvent.cpp" />
@@ -97,6 +105,7 @@
</files>
<include name="lib/curl/files.xml" />
<include name="lib/freetype/files.xml" />
<include name="lib/jpeg/files.xml" />
<include name="lib/neko/files.xml" />
<include name="lib/ogg/files.xml" />
@@ -116,6 +125,7 @@
<files id="native-toolkit-curl" if="LIME_CURL" />
<files id="native-toolkit-jpeg" if="LIME_JPEG" />
<files id="native-toolkit-freetype" if="LIME_JPEG" />
<files id="native-toolkit-neko" if="LIME_NEKO" />
<files id="native-toolkit-ogg" if="LIME_OGG" />
<files id="native-toolkit-openal" if="LIME_OPENAL" unless="mac || iphone" />

View File

@@ -0,0 +1,34 @@
#ifndef LIME_GRAPHICS_FONT_H
#define LIME_GRAPHICS_FONT_H
#include <hx/CFFI.h>
#include <list>
#include <graphics/Image.h>
#include <ft2build.h>
#include FT_FREETYPE_H
namespace lime {
class Font {
public:
Font (const char *fontFace);
value LoadGlyphs (int size, const char *glyphs, Image *image);
private:
FT_Face face;
};
}
#endif

View File

@@ -17,10 +17,13 @@ namespace lime {
Image ();
~Image ();
void Resize (int width, int height, int bpp = 4);
void Blit (const unsigned char *data, int x, int y, int width, int height);
value Value ();
int width;
int height;
int bpp; // bytes per pixel
ByteArray *data;

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 ();