diff --git a/c++/freetype/src/SConstruct b/c++/freetype/src/SConstruct index 77fbf44..65b3dfd 100644 --- a/c++/freetype/src/SConstruct +++ b/c++/freetype/src/SConstruct @@ -19,6 +19,7 @@ target = 'freetype' sources = [ 'main.cpp', 'freetypeview.cpp', + 'labpangorenderer.cpp', 'matrix.cpp', 'surface.cpp', 'view.cpp' ] diff --git a/c++/freetype/src/freetypeview.cpp b/c++/freetype/src/freetypeview.cpp index 8be9d7b..ca83a72 100644 --- a/c++/freetype/src/freetypeview.cpp +++ b/c++/freetype/src/freetypeview.cpp @@ -2,14 +2,9 @@ #include #include -#include #include -#include -#include FT_BITMAP_H -#include -#include -#include +#include "labpangorenderer.h" #include "surface.h" #include "log.h" @@ -17,147 +12,13 @@ #include "freetypeview.h" -static void put_bitmap(Surface &surface, FT_Bitmap &bitmap, int x, int y, const Color &color); - - -// my pango renderer - -#define MY_TYPE_PANGO_RENDERER (my_pango_renderer_get_type ()) - -struct _MyPangoRenderer { - PangoRenderer parent_instance; - Surface *surface; - ColorReal color[4]; -}; - -struct _MyPangoRendererClass { - PangoRendererClass parent_class; -}; - -typedef _MyPangoRenderer MyPangoRenderer; -typedef _PangoRendererClass MyPangoRendererClass; - -#define PANGO_FT2_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_FT2_RENDERER, PangoFT2RendererClass)) -#define PANGO_IS_FT2_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_FT2_RENDERER)) -#define PANGO_FT2_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_FT2_RENDERER, PangoFT2RendererClass)) - -G_DEFINE_TYPE(MyPangoRenderer, my_pango_renderer, PANGO_TYPE_RENDERER) - -static void -my_pango_renderer_draw_glyph( - PangoRenderer *renderer, - PangoFont *font, - PangoGlyph glyph, - double x, - double y ) -{ - MyPangoRenderer *my_renderer = (MyPangoRenderer*)renderer; - if (!my_renderer->surface) - return; - const Color &color = *(const Color*)my_renderer->color; - - const int fx = (int)round(x*64); - const int fy = (int)round(y*64); - const int ix = fx / 64; - const int iy = fy / 64; - FT_Vector vec = {}; - vec.x = fx % 64; - vec.y = fy % 64; - - FT_Face face = pango_fc_font_lock_face((PangoFcFont*)font); - FT_Set_Transform(face, nullptr, &vec); - if (!FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING)) { - if (!FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL)) { - put_bitmap( - *my_renderer->surface, - face->glyph->bitmap, - face->glyph->bitmap_left + ix, - iy - face->glyph->bitmap_top, - color ); - } - } - pango_fc_font_unlock_face((PangoFcFont*)font); -} - -static void -my_pango_renderer_draw_trapezoid( - PangoRenderer *renderer, - PangoRenderPart part, - double y1, - double x11, - double x21, - double y2, - double x12, - double x22 ) -{ - std::cout << "my_pango_renderer_draw_trapezoid" << std::endl; -} - -static void -my_pango_renderer_init(MyPangoRenderer *renderer) { - renderer->surface = nullptr; - *(Color*)renderer->color = Color(); -} - -static void -my_pango_renderer_class_init(MyPangoRendererClass *klass) -{ - PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS(klass); - renderer_class->draw_glyph = my_pango_renderer_draw_glyph; - renderer_class->draw_trapezoid = my_pango_renderer_draw_trapezoid; -} - -PangoRenderer* -my_pango_renderer_new(Surface &surface, const Color &color) { - MyPangoRenderer *renderer = (MyPangoRenderer*)g_object_new(MY_TYPE_PANGO_RENDERER, nullptr); - renderer->surface = &surface; - *(Color*)renderer->color = color; - return (PangoRenderer*)renderer; -} - - - -static void set_substitute(FcPattern *pattern, gpointer) { - FcPatternDel(pattern, FC_HINTING); - FcPatternAddBool(pattern, FC_HINTING, FcFalse); -} - -static void put_bitmap(Surface &surface, FT_Bitmap &bitmap, int x, int y, const Color &color) { - if (x >= surface.width() || y >= surface.height()) - return; - if (x + (int)bitmap.width <= 0 || y + (int)bitmap.rows <= 0) - return; - - const int bx = std::max(0, -x); - const int by = std::max(0, -y); - x = std::max(0, x); - y = std::max(0, y); - const int w = std::min(surface.width() - x, (int)bitmap.width - bx); - const int h = std::min(surface.height() - y, (int)bitmap.rows - by); - const int pitch = surface.pitch(); - - Color *dst_pixel = &surface[y][x]; - const int dst_row_step = pitch - w; - - const unsigned char *src_pixel = bitmap.buffer + by*bitmap.pitch + bx; - const int src_row_step = bitmap.pitch - w; - - for(const Color *end = dst_pixel + pitch*h; dst_pixel != end; dst_pixel += dst_row_step, src_pixel += src_row_step) { - for(const Color *row_end = dst_pixel + w; dst_pixel != row_end; ++dst_pixel, ++src_pixel) { - Real a = *src_pixel * (1/255.0); - *dst_pixel = *dst_pixel*(1-a) + color*a; - } - } -} - - FreeTypeView::FreeTypeView() { params.family = "Ani"; params.bold = false; params.italic = false; params.size = 12; - params.position = Vector2(15.5, 18.4); + params.matrix = Matrix().translation(Vector2(15.5, 18.4)); params.color = Color(1, 1, 0, 1); params.text = "Hello World! 123456"; @@ -174,7 +35,7 @@ FreeTypeView::~FreeTypeView() bool FreeTypeView::on_timeout() { if (!is_visible()) return false; - params.position.x += 0.01; + params.matrix.m20 += 0.01; update_surface(); return true; } @@ -187,24 +48,28 @@ FreeTypeView::update_surface() { if (width <= 0 || height <= 0) return; + Matrix matrix = params.matrix; + Real det2 = matrix.m00*matrix.m11 - matrix.m01*matrix.m10; + if (det2 <= real_precision_sqr) + return; + Real scale = sqrt(det2); + matrix.row_x() /= scale; + matrix.row_y() /= scale; + Real size = params.size*scale; + // init - PangoFontMap *font_map = pango_ft2_font_map_new(); - pango_ft2_font_map_set_default_substitute( - (PangoFT2FontMap*)font_map, - &set_substitute, - nullptr, - nullptr ); + PangoFontMap *font_map = lab_pango_font_map_new(params.hinting); PangoContext *context = pango_font_map_create_context(font_map); - + // load font PangoFontDescription *font_desc = pango_font_description_new(); pango_font_description_set_family(font_desc, params.family.c_str()); pango_font_description_set_weight(font_desc, params.bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL); pango_font_description_set_style(font_desc, params.italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); - pango_font_description_set_absolute_size(font_desc, params.size * PANGO_SCALE); + pango_font_description_set_absolute_size(font_desc, size * PANGO_SCALE); + + PangoFont *font = pango_context_load_font(context, font_desc); - PangoFont *font = pango_font_map_load_font(font_map, context, font_desc); - // create layout PangoLayout *layout = pango_layout_new(context); pango_layout_set_font_description(layout, font_desc); @@ -212,13 +77,12 @@ FreeTypeView::update_surface() { // reneder DataSurface surface(width, height); - PangoRenderer *renderer = my_pango_renderer_new(surface, params.color); - pango_renderer_draw_layout( - renderer, - layout, - (int)round(params.position.x*PANGO_SCALE), - (int)round(params.position.y*PANGO_SCALE) ); - + PangoRenderer *renderer = lab_pango_renderer_new(); + lab_pango_renderer_set_surface((LabPangoRenderer*)renderer, &surface); + lab_pango_renderer_set_matrix((LabPangoRenderer*)renderer, ¶ms.matrix); + lab_pango_renderer_set_color((LabPangoRenderer*)renderer, ¶ms.color); + pango_renderer_draw_layout(renderer, layout, 0, 0); + // free pango g_object_unref(renderer); pango_font_description_free(font_desc); diff --git a/c++/freetype/src/freetypeview.h b/c++/freetype/src/freetypeview.h index c66aceb..efacb19 100644 --- a/c++/freetype/src/freetypeview.h +++ b/c++/freetype/src/freetypeview.h @@ -12,12 +12,14 @@ public: bool italic; Real size; - Vector2 position; + bool hinting; + + Matrix matrix; Color color; std::string text; - Params(): bold(), italic(), size() { } + Params(): bold(), italic(), size(), hinting() { } }; Params params; diff --git a/c++/freetype/src/labpangorenderer.cpp b/c++/freetype/src/labpangorenderer.cpp new file mode 100644 index 0000000..2347f64 --- /dev/null +++ b/c++/freetype/src/labpangorenderer.cpp @@ -0,0 +1,166 @@ + +#include + +#include +#include FT_BITMAP_H + +#include + + +#include "surface.h" +#include "matrix.h" + +#include "labpangorenderer.h" + + + +struct _LabPangoRenderer { + PangoRenderer parent_instance; + Surface *surface; + Color color; + Matrix matrix; +}; + +struct _LabPangoRendererClass { + PangoRendererClass parent_class; +}; + +G_DEFINE_TYPE(LabPangoRenderer, lab_pango_renderer, PANGO_TYPE_RENDERER) + + + +static void +put_ft_bitmap(Surface &surface, FT_Bitmap &bitmap, int x, int y, const Color &color) { + if (x >= surface.width() || y >= surface.height()) + return; + if (x + (int)bitmap.width <= 0 || y + (int)bitmap.rows <= 0) + return; + + const int bx = std::max(0, -x); + const int by = std::max(0, -y); + x = std::max(0, x); + y = std::max(0, y); + const int w = std::min(surface.width() - x, (int)bitmap.width - bx); + const int h = std::min(surface.height() - y, (int)bitmap.rows - by); + const int pitch = surface.pitch(); + + Color *dst_pixel = &surface[y][x]; + const int dst_row_step = pitch - w; + + const unsigned char *src_pixel = bitmap.buffer + by*bitmap.pitch + bx; + const int src_row_step = bitmap.pitch - w; + + for(const Color *end = dst_pixel + pitch*h; dst_pixel != end; dst_pixel += dst_row_step, src_pixel += src_row_step) { + for(const Color *row_end = dst_pixel + w; dst_pixel != row_end; ++dst_pixel, ++src_pixel) { + Real a = *src_pixel * (1/255.0); + *dst_pixel = *dst_pixel*(1-a) + color*a; + } + } +} + + +static void +lab_pango_renderer_draw_glyph( + PangoRenderer *renderer, + PangoFont *font, + PangoGlyph glyph, + double x, + double y ) +{ + LabPangoRenderer *lab_renderer = (LabPangoRenderer*)renderer; + if (!lab_renderer->surface) + return; + + Vector3 pos = lab_renderer->matrix*Vector3(x, y, 1); + + const int fx = (int)round(pos.x*64); + const int fy = (int)round(pos.y*64); + const int ix = fx / 64; + const int iy = fy / 64; + FT_Vector vec = {}; + vec.x = fx % 64; + vec.y = fy % 64; + + FT_Face face = pango_fc_font_lock_face((PangoFcFont*)font); + FT_Set_Transform(face, nullptr, &vec); + if (!FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING)) { + if (!FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL)) { + put_ft_bitmap( + *lab_renderer->surface, + face->glyph->bitmap, + face->glyph->bitmap_left + ix, + iy - face->glyph->bitmap_top, + lab_renderer->color ); + } + } + pango_fc_font_unlock_face((PangoFcFont*)font); +} + + +static void +lab_pango_renderer_init(LabPangoRenderer *renderer) { + memset( renderer + sizeof(renderer->parent_instance), 0, + sizeof(*renderer) - sizeof(renderer->parent_instance) ); + renderer->matrix = Matrix(); +} + +static void +lab_pango_renderer_class_init(LabPangoRendererClass *klass) +{ + PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS(klass); + renderer_class->draw_glyph = lab_pango_renderer_draw_glyph; +} + + +static void +lab_pango_fc_pattern_unset_hinting(FcPattern *pattern, gpointer) + { FcPatternDel(pattern, FC_HINTING); } + +static void +lab_pango_fc_pattern_set_hinting(FcPattern *pattern, gpointer) { + FcPatternDel(pattern, FC_HINTING); + FcPatternAddBool(pattern, FC_HINTING, FcFalse); +} + + +PangoRenderer* +lab_pango_renderer_new() + { return (PangoRenderer*)g_object_new(LAB_TYPE_PANGO_RENDERER, nullptr); } + +void +lab_pango_renderer_set_matrix(LabPangoRenderer *renderer, Matrix *matrix) + { renderer->matrix = matrix ? *matrix : Matrix(); } + +void +lab_pango_renderer_get_matrix(LabPangoRenderer *renderer, Matrix *matrix) + { if (matrix) *matrix = renderer->matrix; } + +void +lab_pango_renderer_set_color(LabPangoRenderer *renderer, Color *color) + { renderer->color = color ? *color : Color(); } + +void +lab_pango_renderer_get_color(LabPangoRenderer *renderer, Color *color) + { if (color) *color = renderer->color; } + +void +lab_pango_renderer_set_surface(LabPangoRenderer *renderer, Surface *surface) + { renderer->surface = surface; } + +Surface* +lab_pango_renderer_get_surface(LabPangoRenderer *renderer) + { return renderer->surface; } + + +PangoFontMap* +lab_pango_font_map_new(bool hinting) { + PangoFontMap *font_map = pango_ft2_font_map_new(); + pango_ft2_font_map_set_default_substitute( + (PangoFT2FontMap*)font_map, + hinting ? &lab_pango_fc_pattern_set_hinting + : &lab_pango_fc_pattern_unset_hinting, + nullptr, + nullptr ); + return font_map; +} + diff --git a/c++/freetype/src/labpangorenderer.h b/c++/freetype/src/labpangorenderer.h new file mode 100644 index 0000000..71b647a --- /dev/null +++ b/c++/freetype/src/labpangorenderer.h @@ -0,0 +1,43 @@ +#ifndef LABPANGORENDERER_H +#define LABPANGORENDERER_H + + +#include + + +class Surface; +class Matrix3; +class Color; + + +G_BEGIN_DECLS + +#define LAB_TYPE_PANGO_RENDERER (lab_pango_renderer_get_type ()) + +typedef struct _LabPangoRenderer LabPangoRenderer; +typedef struct _LabPangoRendererClass LabPangoRendererClass; + +#define LAB_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), LAB_TYPE_PANGO_RENDERER, LabPangoRendererClass)) +#define LAB_IS_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), LAB_TYPE_PANGO_RENDERER)) +#define LAB_PANGO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), LAB_TYPE_PANGO_RENDERER, LabPangoRendererClass)) + + +PangoRenderer* lab_pango_renderer_new(); + +void lab_pango_renderer_set_matrix(LabPangoRenderer *renderer, Matrix3 *matrix); +void lab_pango_renderer_get_matrix(LabPangoRenderer *renderer, Matrix3 *matrix); + +void lab_pango_renderer_set_color(LabPangoRenderer *renderer, Color *color); +void lab_pango_renderer_get_color(LabPangoRenderer *renderer, Color *color); + +void lab_pango_renderer_set_surface(LabPangoRenderer *renderer, Surface *surface); +Surface* lab_pango_renderer_get_surface(LabPangoRenderer *renderer); + + +PangoFontMap* lab_pango_font_map_new(bool hinting); + +G_END_DECLS + + +#endif +