diff --git a/lime/graphics/Font.hx b/lime/graphics/Font.hx new file mode 100644 index 000000000..7c013031b --- /dev/null +++ b/lime/graphics/Font.hx @@ -0,0 +1,55 @@ +package lime.graphics; + +import lime.utils.UInt8Array; +import lime.system.System; + +typedef GlyphData = { + var image:Image; + var glyphs:Array; +}; + +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 + +} diff --git a/lime/graphics/Image.hx b/lime/graphics/Image.hx index 2bd028794..a12885f26 100644 --- a/lime/graphics/Image.hx +++ b/lime/graphics/Image.hx @@ -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 } diff --git a/project/Build.xml b/project/Build.xml index 8943ad8bd..43b41e5fe 100644 --- a/project/Build.xml +++ b/project/Build.xml @@ -10,6 +10,7 @@ + @@ -37,6 +38,12 @@ +
+ + + +
+
@@ -83,9 +90,10 @@ + - - + + @@ -97,6 +105,7 @@ + @@ -116,6 +125,7 @@ + diff --git a/project/include/graphics/Font.h b/project/include/graphics/Font.h new file mode 100644 index 000000000..b564dc71d --- /dev/null +++ b/project/include/graphics/Font.h @@ -0,0 +1,34 @@ +#ifndef LIME_GRAPHICS_FONT_H +#define LIME_GRAPHICS_FONT_H + + +#include +#include +#include +#include +#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 diff --git a/project/include/graphics/Image.h b/project/include/graphics/Image.h index 1b46c0e28..a763b558e 100644 --- a/project/include/graphics/Image.h +++ b/project/include/graphics/Image.h @@ -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; diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 97fa02881..0ce79f57c 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/project/src/graphics/Font.cpp b/project/src/graphics/Font.cpp new file mode 100644 index 000000000..6ab9f0e33 --- /dev/null +++ b/project/src/graphics/Font.cpp @@ -0,0 +1,185 @@ +#include + +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 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::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; + + } + + +} diff --git a/project/src/graphics/Image.cpp b/project/src/graphics/Image.cpp index f42b1ea34..4cc70c653 100644 --- a/project/src/graphics/Image.cpp +++ b/project/src/graphics/Image.cpp @@ -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; diff --git a/project/src/graphics/JPEG.cpp b/project/src/graphics/JPEG.cpp index faf556373..7ef8bc55c 100644 --- a/project/src/graphics/JPEG.cpp +++ b/project/src/graphics/JPEG.cpp @@ -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]; diff --git a/project/src/graphics/PNG.cpp b/project/src/graphics/PNG.cpp index 37725b3f5..e5a2c7ef2 100644 --- a/project/src/graphics/PNG.cpp +++ b/project/src/graphics/PNG.cpp @@ -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 ();