aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/agg_pixfmt_alpha8.h93
-rw-r--r--src/font_renderer_alpha.h160
2 files changed, 253 insertions, 0 deletions
diff --git a/src/agg_pixfmt_alpha8.h b/src/agg_pixfmt_alpha8.h
new file mode 100644
index 00000000..b7b84f8d
--- /dev/null
+++ b/src/agg_pixfmt_alpha8.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#include <string.h>
+#include "agg_basics.h"
+#include "agg_rendering_buffer.h"
+
+namespace agg
+{
+ // This is a special purpose color type that only has the alpha channel.
+ // It can be thought as a gray color but with the intensity always on.
+ // It is actually used to store coverage information.
+ struct alpha8
+ {
+ typedef int8u value_type;
+ typedef int32u calc_type;
+ typedef int32 long_type;
+ enum base_scale_e
+ {
+ base_shift = 8,
+ base_scale = 1 << base_shift,
+ base_mask = base_scale - 1
+ };
+
+ value_type a;
+
+ //--------------------------------------------------------------------
+ alpha8(unsigned a_=base_mask) :
+ a(int8u(a_)) {}
+ };
+
+ // Pixer format to store coverage information.
+ class pixfmt_alpha8
+ {
+ public:
+ typedef alpha8 color_type;
+ typedef int8u value_type;
+ typedef int32u calc_type;
+ typedef typename agg::rendering_buffer::row_data row_data;
+
+ //--------------------------------------------------------------------
+ pixfmt_alpha8(rendering_buffer& rb): m_rbuf(&rb)
+ {
+ }
+
+ //--------------------------------------------------------------------
+ unsigned width() const {
+ return m_rbuf->width();
+ }
+ unsigned height() const {
+ return m_rbuf->height();
+ }
+
+ // This method should never be called when using the scanline_u8.
+ // The use of scanline_p8 should be avoided because if does not works
+ // properly for rendering fonts because single hspan are split in many
+ // hline/hspan elements and pixel whitening happens.
+ void blend_hline(int x, int y, unsigned len,
+ const color_type& c, int8u cover)
+ { }
+
+ void copy_hline(int x, int y, unsigned len, const color_type& c)
+ {
+ value_type* p = (value_type*) m_rbuf->row_ptr(y) + x;
+ do
+ {
+ *p = c.a;
+ p++;
+ }
+ while(--len);
+ }
+
+ //--------------------------------------------------------------------
+ void blend_solid_hspan(int x, int y,
+ unsigned len,
+ const color_type& c,
+ const int8u* covers)
+ {
+ value_type* p = (value_type*) m_rbuf->row_ptr(y) + x;
+ do
+ {
+ calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8;
+ *p = alpha;
+ p++;
+ ++covers;
+ }
+ while(--len);
+ }
+
+ private:
+ rendering_buffer* m_rbuf;
+ };
+
+}
diff --git a/src/font_renderer_alpha.h b/src/font_renderer_alpha.h
new file mode 100644
index 00000000..5d8681f5
--- /dev/null
+++ b/src/font_renderer_alpha.h
@@ -0,0 +1,160 @@
+#pragma once
+
+#include "agg_basics.h"
+#include "agg_conv_curve.h"
+#include "agg_conv_transform.h"
+#include "agg_gamma_lut.h"
+#include "agg_font_freetype.h"
+#include "agg_pixfmt_alpha8.h"
+#include "agg_rasterizer_scanline_aa.h"
+#include "agg_renderer_primitives.h"
+#include "agg_renderer_scanline.h"
+#include "agg_rendering_buffer.h"
+#include "agg_scanline_u.h"
+
+class font_renderer_alpha
+{
+ typedef agg::pixfmt_alpha8 pixfmt_type;
+ typedef agg::renderer_base<pixfmt_type> base_ren_type;
+ typedef agg::renderer_scanline_aa_solid<base_ren_type> renderer_solid;
+ typedef agg::font_engine_freetype_int32 font_engine_type;
+ typedef agg::font_cache_manager<font_engine_type> font_manager_type;
+
+ font_engine_type m_feng;
+ font_manager_type m_fman;
+
+ // Font rendering options.
+ bool m_hinting;
+ bool m_kerning;
+
+ bool m_font_loaded;
+
+ // Pipeline to process the vectors glyph paths (curves + contour)
+ agg::trans_affine m_mtx;
+ agg::conv_curve<font_manager_type::path_adaptor_type> m_curves;
+ agg::conv_transform<agg::conv_curve<font_manager_type::path_adaptor_type> > m_trans;
+public:
+ typedef agg::pixfmt_alpha8::color_type color_type;
+
+ font_renderer_alpha(bool hinting, bool kerning):
+ m_feng(),
+ m_fman(m_feng),
+ m_hinting(hinting),
+ m_kerning(kerning),
+ m_font_loaded(false),
+ m_curves(m_fman.path_adaptor()),
+ m_trans(m_curves, m_mtx)
+ { }
+
+ bool get_font_vmetrics(int& ascender, int& descender) {
+ int face_height = m_feng.face_height();
+ if (face_height > 0) {
+ double current_height = m_feng.height();
+ m_feng.height(1.0);
+ ascender = m_feng.ascender() * face_height;
+ descender = m_feng.descender() * face_height;
+ m_feng.height(current_height);
+ return true;
+ }
+ return false;
+ }
+
+ float scale_for_em_to_pixels(float size) {
+ int units_per_em = m_feng.face_units_em();
+ if (units_per_em > 0) {
+ return size / units_per_em;
+ }
+ return 0.0;
+ }
+
+ bool load_font(const char *font_filename) {
+ if(m_feng.load_font(font_filename, 0, agg::glyph_ren_outline)) {
+ m_font_loaded = true;
+ }
+ return m_font_loaded;
+ }
+
+ template<class Rasterizer, class Scanline, class RenSolid>
+ void draw_text(Rasterizer& ras, Scanline& sl,
+ RenSolid& ren_solid, const color_type color,
+ const char* text,
+ double& x, double& y, double height)
+ {
+ const double scale_x = 100;
+
+ m_feng.height(height);
+ m_feng.width(height * scale_x);
+ m_feng.hinting(m_hinting);
+
+ const char* p = text;
+
+ // Represent the delta in x scaled by scale_x.
+ double x_delta = 0;
+ double start_x = x;
+
+ while(*p)
+ {
+ if(*p == '\n')
+ {
+ x_delta = 0;
+ y -= height * 1.25;
+ ++p;
+ continue;
+ }
+
+ const agg::glyph_cache* glyph = m_fman.glyph(*p);
+ if(glyph)
+ {
+ if(m_kerning)
+ {
+ m_fman.add_kerning(&x_delta, &y);
+ }
+
+ m_fman.init_embedded_adaptors(glyph, 0, 0);
+ if(glyph->data_type == agg::glyph_data_outline)
+ {
+ double ty = m_hinting ? floor(y + 0.5) : y;
+ ras.reset();
+ m_mtx.reset();
+ m_mtx *= agg::trans_affine_scaling(1.0 / scale_x, 1);
+ m_mtx *= agg::trans_affine_translation(start_x + x_delta / scale_x, ty);
+ ras.add_path(m_trans);
+ ren_solid.color(color);
+ agg::render_scanlines(ras, sl, ren_solid);
+ }
+
+ // increment pen position
+ x_delta += glyph->advance_x;
+ y += glyph->advance_y;
+ }
+ ++p;
+ }
+ // Update x value befor returning.
+ x += x_delta / scale_x;
+ }
+
+ void clear(agg::rendering_buffer& ren_buf, const color_type color) {
+ pixfmt_type pf(ren_buf);
+ base_ren_type ren_base(pf);
+ ren_base.clear(color);
+ }
+
+ void render_text(agg::rendering_buffer& ren_buf,
+ const double text_size,
+ const color_type text_color,
+ double& x, double& y,
+ const char *text)
+ {
+ if (!m_font_loaded) {
+ return;
+ }
+ agg::scanline_u8 sl;
+ agg::rasterizer_scanline_aa<> ras;
+ ras.clip_box(0, 0, ren_buf.width(), ren_buf.height());
+
+ agg::pixfmt_alpha8 pf(ren_buf);
+ base_ren_type ren_base(pf);
+ renderer_solid ren_solid(ren_base);
+ draw_text(ras, sl, ren_solid, text_color, text, x, y, text_size);
+ }
+};