Adding FreeType font generation
This commit is contained in:
55
lime/graphics/Font.hx
Normal file
55
lime/graphics/Font.hx
Normal 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
|
||||
|
||||
}
|
||||
@@ -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,14 +117,14 @@ 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
|
||||
|
||||
|
||||
@@ -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" />
|
||||
|
||||
34
project/include/graphics/Font.h
Normal file
34
project/include/graphics/Font.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
185
project/src/graphics/Font.cpp
Normal file
185
project/src/graphics/Font.cpp
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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 ();
|
||||
|
||||
Reference in New Issue
Block a user