Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

freetype_test.cpp

Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include "agg_basics.h"
00003 #include "agg_rendering_buffer.h"
00004 #include "agg_scanline_u.h"
00005 #include "agg_scanline_bin.h"
00006 #include "agg_renderer_scanline.h"
00007 #include "agg_renderer_primitives.h"
00008 #include "agg_rasterizer_scanline_aa.h"
00009 #include "agg_conv_curve.h"
00010 #include "agg_conv_contour.h"
00011 #include "agg_pixfmt_rgb.h"
00012 #include "agg_font_freetype.h"
00013 #include "platform/agg_platform_support.h"
00014 
00015 #include "ctrl/agg_slider_ctrl.h"
00016 #include "ctrl/agg_cbox_ctrl.h"
00017 #include "ctrl/agg_rbox_ctrl.h"
00018 
00019 
00020 enum flip_y_e { flip_y = true };
00021 bool font_flip_y = !flip_y;
00022 
00023 
00024 #define pix_format agg::pix_format_bgr24
00025 typedef agg::pixfmt_bgr24 pixfmt_type;
00026 
00027 
00028 static char text[] = 
00029 "Anti-Grain Geometry is designed as a set of loosely coupled "
00030 "algorithms and class templates united with a common idea, "
00031 "so that all the components can be easily combined. Also, "
00032 "the template based design allows you to replace any part of "
00033 "the library without the necessity to modify a single byte in "
00034 "the existing code. "
00035 "AGG is designed keeping in mind extensibility and flexibility. "
00036 "Basically I just wanted to create a toolkit that would allow me "
00037 "(and anyone else) to add new fancy algorithms very easily. "
00038 "AGG does not dictate you any style of its use, you are free to "
00039 "use any part of it. However, AGG is often associated with a tool "
00040 "for rendering images in memory. That is not quite true, but it can "
00041 "be a good starting point in studying. The tutorials describe the "
00042 "use of AGG starting from the low level functionality that deals with "
00043 "frame buffers and pixels. Then you will gradually understand how to "
00044 "abstract different parts of the library and how to use them separately. "
00045 "Remember, the raster picture is often not the only thing you want to "
00046 "obtain, you will probably want to print your graphics with highest "
00047 "possible quality and in this case you can easily combine the \"vectorial\" "
00048 "part of the library with some API like Windows GDI, having a common "
00049 "external interface. If that API can render multi-polygons with non-zero "
00050 "and even-odd filling rules it's all you need to incorporate AGG into "
00051 "your application. For example, Windows API PolyPolygon perfectly fits "
00052 "these needs, except certain advanced things like gradient filling, "
00053 "Gouraud shading, image transformations, and so on. Or, as an alternative, "
00054 "you can use all AGG algorithms producing high resolution pixel images and "
00055 "then to send the result to the printer as a pixel map."
00056 "Below is a typical brief scheme of the AGG rendering pipeline. "
00057 "Please note that any component between the Vertex Source "
00058 "and Screen Output is not mandatory. It all depends on your "
00059 "particular needs. For example, you can use your own rasterizer, "
00060 "based on Windows API. In this case you won't need the AGG rasterizer "
00061 "and renderers. Or, if you need to draw only lines, you can use the "
00062 "AGG outline rasterizer that has certain restrictions but works faster. "
00063 "The number of possibilities is endless. "
00064 "Vertex Source is some object that produces polygons or polylines as "
00065 "a set of consecutive 2D vertices with commands like MoveTo, LineTo. "
00066 "It can be a container or some other object that generates vertices "
00067 "on demand. "
00068 "Coordinate conversion pipeline consists of a number of coordinate "
00069 "converters. It always works with vectorial data (X,Y) represented "
00070 "as floating point numbers (double). For example, it can contain an "
00071 "affine transformer, outline (stroke) generator, some marker "
00072 "generator (like arrowheads/arrowtails), dashed lines generator, "
00073 "and so on. The pipeline can have branches and you also can have "
00074 "any number of different pipelines. You also can write your own "
00075 "converter and include it into the pipeline. "
00076 "Scanline Rasterizer converts vectorial data into a number of "
00077 "horizontal scanlines. The scanlines usually (but not obligatory) "
00078 "carry information about Anti-Aliasing as coverage values. "
00079 "Renderers render scanlines, sorry for the tautology. The simplest "
00080 "example is solid filling. The renderer just adds a color to the "
00081 "scanline and writes the result into the rendering buffer. "
00082 "More complex renderers can produce multi-color result, "
00083 "like gradients, Gouraud shading, image transformations, "
00084 "patterns, and so on. Rendering Buffer is a buffer in memory "
00085 "that will be displayed afterwards. Usually but not obligatory "
00086 "it contains pixels in format that fits your video system. "
00087 "For example, 24 bits B-G-R, 32 bits B-G-R-A, or 15 "
00088 "bits R-G-B-555 for Windows. But in general, there're no "
00089 "restrictions on pixel formats or color space if you write "
00090 "your own low level class that supports that format. "
00091 "Colors in AGG appear only in renderers, that is, when you "
00092 "actually put some data to the rendering buffer. In general, "
00093 "there's no general purpose structure or class like color, "
00094 "instead, AGG always operates with concrete color space. "
00095 "There are plenty of color spaces in the world, like RGB, "
00096 "HSV, CMYK, etc., and all of them have certain restrictions. "
00097 "For example, the RGB color space is just a poor subset of "
00098 "colors that a human eye can recognize. If you look at the full "
00099 "CIE Chromaticity Diagram, you will see that the RGB triangle "
00100 "is just a little part of it. "
00101 "In other words there are plenty of colors in the real world "
00102 "that cannot be reproduced with RGB, CMYK, HSV, etc. Any color "
00103 "space except the one existing in Nature is restrictive. Thus, "
00104 "it was decided not to introduce such an object like color in "
00105 "order not to restrict the possibilities in advance. Instead, "
00106 "there are objects that operate with concrete color spaces. "
00107 "Currently there are agg::rgba and agg::rgba8 that operate "
00108 "with the most popular RGB color space (strictly speaking there's "
00109 "RGB plus Alpha). The RGB color space is used with different "
00110 "pixel formats, like 24-bit RGB or 32-bit RGBA with different "
00111 "order of color components. But the common property of all of "
00112 "them is that they are essentially RGB. Although, AGG doesn't "
00113 "explicitly support any other color spaces, there is at least "
00114 "a potential possibility of adding them. It means that all "
00115 "class and function templates that depend on the color type "
00116 "are parameterized with the ColorT argument. "
00117 "Basically, AGG operates with coordinates of the output device. "
00118 "On your screen there are pixels. But unlike many other libraries "
00119 "and APIs AGG initially supports Subpixel Accuracy. It means "
00120 "that the coordinates are represented as doubles, where fractional "
00121 "values actually take effect. AGG doesn't have an embedded "
00122 "conversion mechanism from world to screen coordinates in order "
00123 "not to restrict your freedom. It's very important where and when "
00124 "you do that conversion, so, different applications can require "
00125 "different approaches. AGG just provides you a transformer of "
00126 "that kind, namely, that can convert your own view port to the "
00127 "device one. And it's your responsibility to include it into "
00128 "the proper place of the pipeline. You can also write your "
00129 "own very simple class that will allow you to operate with "
00130 "millimeters, inches, or any other physical units. "
00131 "Internally, the rasterizers use integer coordinates of the "
00132 "format 24.8 bits, that is, 24 bits for the integer part and 8 "
00133 "bits for the fractional one. In other words, all the internal "
00134 "coordinates are multiplied by 256. If you intend to use AGG in "
00135 "some embedded system that has inefficient floating point "
00136 "processing, you still can use the rasterizers with their "
00137 "integer interfaces. Although, you won't be able to use the "
00138 "floating point coordinate pipelines in this case. ";
00139  
00140 
00141 
00142 
00143 
00144 
00145 
00146 template<class VS> void dump_path(VS& path)
00147 {
00148     FILE* fd = fopen("dump_path", "a");
00149     fprintf(fd, "-------\n");
00150     path.rewind(0);
00151     unsigned cmd;
00152     double x, y;
00153     while(!agg::is_stop(cmd = path.vertex(&x, &y)))
00154     {
00155         fprintf(fd, "%02X %8.2f %8.2f\n", cmd, x, y);
00156     }
00157     fclose(fd);
00158 }
00159 
00160 
00161 
00162 
00163 class the_application : public agg::platform_support
00164 {
00165     typedef agg::renderer_base<pixfmt_type> base_ren_type;
00166     typedef agg::renderer_scanline_aa_solid<base_ren_type> renderer_solid;
00167     typedef agg::renderer_scanline_bin_solid<base_ren_type> renderer_bin;
00168     typedef agg::font_engine_freetype_int32 font_engine_type;
00169     typedef agg::font_cache_manager<font_engine_type> font_manager_type;
00170 
00171     agg::rbox_ctrl<agg::rgba8>   m_ren_type;
00172     agg::slider_ctrl<agg::rgba8> m_height;
00173     agg::slider_ctrl<agg::rgba8> m_width;
00174     agg::slider_ctrl<agg::rgba8> m_weight;
00175     agg::slider_ctrl<agg::rgba8> m_gamma;
00176     agg::cbox_ctrl<agg::rgba8>   m_hinting;
00177     agg::cbox_ctrl<agg::rgba8>   m_kerning;
00178     agg::cbox_ctrl<agg::rgba8>   m_performance;
00179     font_engine_type             m_feng;
00180     font_manager_type            m_fman;
00181     double                       m_old_height;
00182 
00183     // Pipeline to process the vectors glyph paths (curves + contour)
00184     agg::conv_curve<font_manager_type::path_adaptor_type> m_curves;
00185     agg::conv_contour<agg::conv_curve<font_manager_type::path_adaptor_type> > m_contour;
00186 
00187 
00188 
00189 
00190 public:
00191     the_application(agg::pix_format_e format, bool flip_y) :
00192         agg::platform_support(format, flip_y),
00193         m_ren_type     (5.0, 5.0, 5.0+150.0,   110.0,  !flip_y),
00194         m_height       (160, 10.0, 640-5.0,    18.0,   !flip_y),
00195         m_width        (160, 30.0, 640-5.0,    38.0,   !flip_y),
00196         m_weight       (160, 50.0, 640-5.0,    58.0,   !flip_y),
00197         m_gamma        (260, 70.0, 640-5.0,    78.0,   !flip_y),
00198         m_hinting      (160, 65.0, "Hinting", !flip_y),
00199         m_kerning      (160, 80.0, "Kerning", !flip_y),
00200         m_performance  (160, 95.0, "Test Performance", !flip_y),
00201         m_feng(),
00202         m_fman(m_feng),
00203         m_old_height(0.0),
00204         m_curves(m_fman.path_adaptor()),
00205         m_contour(m_curves)
00206     {
00207         m_ren_type.add_item("Native Mono");
00208         m_ren_type.add_item("Native Gray 8");
00209         m_ren_type.add_item("Outline");
00210         m_ren_type.add_item("AGG Mono");
00211         m_ren_type.add_item("AGG Gray 8");
00212         m_ren_type.cur_item(1);
00213         add_ctrl(m_ren_type);
00214         m_ren_type.no_transform();
00215 
00216         m_height.label("Font Height=%.2f");
00217         m_height.range(8, 32);
00218         m_height.num_steps(32-8);
00219         m_height.value(18);
00220         m_height.text_thickness(1.5);
00221         add_ctrl(m_height);
00222         m_height.no_transform();
00223 
00224         m_width.label("Font Width=%.2f");
00225         m_width.range(8, 32);
00226         m_width.num_steps(32-8);
00227         m_width.text_thickness(1.5);
00228         m_width.value(18);
00229         add_ctrl(m_width);
00230         m_width.no_transform();
00231 
00232         m_weight.label("Font Weight=%.2f");
00233         m_weight.range(-1, 1);
00234         m_weight.text_thickness(1.5);
00235         add_ctrl(m_weight);
00236         m_weight.no_transform();
00237 
00238         m_gamma.label("Gamma=%.2f");
00239         m_gamma.range(0.1, 2.0);
00240         m_gamma.value(1.0);
00241         m_gamma.text_thickness(1.5);
00242         add_ctrl(m_gamma);
00243         m_gamma.no_transform();
00244 
00245         add_ctrl(m_hinting);
00246         m_hinting.status(true);
00247         m_hinting.no_transform();
00248 
00249         add_ctrl(m_kerning);
00250         m_kerning.status(true);
00251         m_kerning.no_transform();
00252 
00253         add_ctrl(m_performance);
00254         m_performance.no_transform();
00255 
00256         m_curves.approximation_scale(2.0);
00257         m_contour.auto_detect_orientation(false);
00258     }
00259 
00260 
00261     template<class Rasterizer, class Scanline, class RenSolid, class RenBin>
00262     unsigned draw_text(Rasterizer& ras, Scanline& sl, 
00263                        RenSolid& ren_solid, RenBin& ren_bin)
00264     {
00265         agg::glyph_rendering gren = agg::glyph_ren_native_mono;
00266         switch(m_ren_type.cur_item())
00267         {
00268         case 0: gren = agg::glyph_ren_native_mono;  break;
00269         case 1: gren = agg::glyph_ren_native_gray8; break;
00270         case 2: gren = agg::glyph_ren_outline;      break;
00271         case 3: gren = agg::glyph_ren_agg_mono;     break;
00272         case 4: gren = agg::glyph_ren_agg_gray8;    break;
00273         }
00274 
00275         unsigned num_glyphs = 0;
00276 
00277         m_contour.width(-m_weight.value() * m_height.value() * 0.05);
00278 
00279         if(m_feng.load_font(full_file_name("timesi.ttf"), 0, gren))
00280         {
00281             m_feng.hinting(m_hinting.status());
00282             m_feng.height(m_height.value());
00283             m_feng.width(m_width.value());
00284             m_feng.flip_y(font_flip_y);
00285 
00286             agg::trans_affine mtx;
00287             mtx *= agg::trans_affine_rotation(agg::deg2rad(-4.0));
00288             //mtx *= agg::trans_affine_skewing(-0.4, 0);
00289             //mtx *= agg::trans_affine_translation(1, 0);
00290             m_feng.transform(mtx);
00291 
00292             double x  = 10.0;
00293             double y0 = height() - m_height.value() - 10.0;
00294             double y  = y0;
00295             const char* p = text;
00296 
00297             while(*p)
00298             {
00299                 const agg::glyph_cache* glyph = m_fman.glyph(*p);
00300                 if(glyph)
00301                 {
00302                     if(m_kerning.status())
00303                     {
00304                         m_fman.add_kerning(&x, &y);
00305                     }
00306 
00307                     if(x >= width() - m_height.value())
00308                     {
00309                         x = 10.0;
00310                         y0 -= m_height.value();
00311                         if(y0 <= 120) break;
00312                         y = y0;
00313                     }
00314 
00315                     m_fman.init_embedded_adaptors(glyph, x, y);
00316 
00317                     switch(glyph->data_type)
00318                     {
00319                     default: break;
00320                     case agg::glyph_data_mono:
00321                         ren_bin.color(agg::rgba8(0, 0, 0));
00322                         agg::render_scanlines(m_fman.mono_adaptor(), 
00323                                               m_fman.mono_scanline(), 
00324                                               ren_bin);
00325                         break;
00326 
00327                     case agg::glyph_data_gray8:
00328                         ren_solid.color(agg::rgba8(0, 0, 0));
00329                         agg::render_scanlines(m_fman.gray8_adaptor(), 
00330                                               m_fman.gray8_scanline(), 
00331                                               ren_solid);
00332                         break;
00333 
00334                     case agg::glyph_data_outline:
00335                         ras.reset();
00336                         if(fabs(m_weight.value()) <= 0.01)
00337                         {
00338                             // For the sake of efficiency skip the
00339                             // contour converter if the weight is about zero.
00340                             //-----------------------
00341                             ras.add_path(m_curves);
00342                         }
00343                         else
00344                         {
00345                             ras.add_path(m_contour);
00346                         }
00347                         ren_solid.color(agg::rgba8(0, 0, 0));
00348                         agg::render_scanlines(ras, sl, ren_solid);
00349 //dump_path(m_fman.path_adaptor());
00350                         break;
00351                     }
00352 
00353                     // increment pen position
00354                     x += glyph->advance_x;
00355                     y += glyph->advance_y;
00356                     ++num_glyphs;
00357                 }
00358                 ++p;
00359             }
00360         }
00361         else
00362         {
00363             message("Please copy file timesi.ttf to the current directory\n"
00364                     "or download it from http://www.antigrain.com/timesi.zip");
00365         }
00366 
00367         return num_glyphs;
00368     }
00369 
00370 
00371     virtual void on_draw()
00372     {
00373         pixfmt_type pf(rbuf_window());
00374         base_ren_type ren_base(pf);
00375         renderer_solid ren_solid(ren_base);
00376         renderer_bin ren_bin(ren_base);
00377         ren_base.clear(agg::rgba(1,1,1));
00378 
00379         agg::scanline_u8 sl;
00380         agg::rasterizer_scanline_aa<> ras;
00381 
00382         if(m_height.value() != m_old_height)
00383         {
00384             m_width.value(m_old_height = m_height.value());
00385         }
00386 
00387         if(m_ren_type.cur_item() == 3)
00388         {
00389             // When rendering in mono format, 
00390             // Set threshold gamma = 0.5
00391             //-------------------
00392             m_feng.gamma(agg::gamma_threshold(m_gamma.value() / 2.0));
00393         }
00394         else
00395         {
00396             m_feng.gamma(agg::gamma_power(m_gamma.value()));
00397         }
00398 
00399         if(m_ren_type.cur_item() == 2)
00400         {
00401             // For outline cache set gamma for the rasterizer
00402             //-------------------
00403             ras.gamma(agg::gamma_power(m_gamma.value()));
00404         }
00405 
00406 //ren_base.copy_hline(0, int(height() - m_height.value()) - 10, 100, agg::rgba(0,0,0));
00407         draw_text(ras, sl, ren_solid, ren_bin);
00408 
00409         ras.gamma(agg::gamma_power(1.0));
00410 
00411 
00412         agg::render_ctrl(ras, sl, ren_base, m_ren_type);
00413         agg::render_ctrl(ras, sl, ren_base, m_height);
00414         agg::render_ctrl(ras, sl, ren_base, m_width);
00415         agg::render_ctrl(ras, sl, ren_base, m_weight);
00416         agg::render_ctrl(ras, sl, ren_base, m_gamma);
00417         agg::render_ctrl(ras, sl, ren_base, m_hinting);
00418         agg::render_ctrl(ras, sl, ren_base, m_kerning);
00419         agg::render_ctrl(ras, sl, ren_base, m_performance);
00420     }
00421 
00422 
00423 
00424     virtual void on_ctrl_change()
00425     {
00426         if(m_performance.status())
00427         {
00428             pixfmt_type pf(rbuf_window());
00429             base_ren_type ren_base(pf);
00430             renderer_solid ren_solid(ren_base);
00431             renderer_bin ren_bin(ren_base);
00432             ren_base.clear(agg::rgba(1,1,1));
00433 
00434             agg::scanline_u8 sl;
00435             agg::rasterizer_scanline_aa<> ras;
00436 
00437             unsigned num_glyphs = 0;
00438             start_timer();
00439             for(int i = 0; i < 50; i++)
00440             {
00441                 num_glyphs += draw_text(ras, sl, ren_solid, ren_bin);
00442             }
00443             double t = elapsed_time();
00444             char buf[100];
00445             sprintf(buf, 
00446                     "Glyphs=%u, Time=%.3fms, %.3f glyps/sec, %.3f microsecond/glyph", 
00447                     num_glyphs,
00448                     t, 
00449                     (num_glyphs / t) * 1000.0, 
00450                     (t / num_glyphs) * 1000.0);
00451             message(buf);
00452 
00453             m_performance.status(false);
00454             force_redraw();
00455         }
00456     }
00457 
00458 
00459     virtual void on_key(int x, int y, unsigned key, unsigned flags)
00460     {
00461         if(key == ' ')
00462         {
00463             font_flip_y = !font_flip_y;
00464             force_redraw();
00465         }
00466     }
00467 
00468 };
00469 
00470 
00471 
00472 int agg_main(int argc, char* argv[])
00473 {
00474     the_application app(pix_format, flip_y);
00475     app.caption("AGG Example. Rendering Fonts with FreeType");
00476 
00477     if(app.init(640, 520, agg::window_resize))
00478     {
00479         return app.run();
00480     }
00481     return 1;
00482 }
00483 
00484 

© sourcejam.com 2005-2008