2
// AggPas 2.4 RM3 Demo application
3
// Note: Press F1 key on run to see more info about this demo
5
// Paths: src;src\ctrl;src\svg;src\util;src\platform\win;expat-wrap
14
agg_platform_support ,
25
agg_rendering_buffer ,
27
agg_renderer_scanline ,
28
agg_renderer_primitives ,
29
agg_rasterizer_scanline_aa ,
33
agg_render_scanlines ,
42
agg_font_cache_manager ;
52
//'0123456789ABCDEFGHIJKLMNOPRSTUVWXYZabcdefghijklmnoprstuvwxyz ' +
53
//'[ BRAVO ][ VALUE ] [ T.W.Lewis ] [ Kerning Examples ] ' +
54
'Anti-Grain Geometry is designed as a set of loosely coupled ' +
55
'algorithms and class templates united with a common idea, ' +
56
'so that all the components can be easily combined. Also, ' +
57
'the template based design allows you to replace any part of ' +
58
'the library without the necessity to modify a single byte in ' +
59
'the existing code. ' +
60
'AGG is designed keeping in mind extensibility and flexibility. ' +
61
'Basically I just wanted to create a toolkit that would allow me ' +
62
'(and anyone else) to add new fancy algorithms very easily. ' +
63
'AGG does not dictate you any style of its use, you are free to ' +
64
'use any part of it. However, AGG is often associated with a tool ' +
65
'for rendering images in memory. That is not quite true, but it can ' +
66
'be a good starting point in studying. The tutorials describe the ' +
67
'use of AGG starting from the low level functionality that deals with ' +
68
'frame buffers and pixels. Then you will gradually understand how to ' +
69
'abstract different parts of the library and how to use them separately. ' +
70
'Remember, the raster picture is often not the only thing you want to ' +
71
'obtain, you will probably want to print your graphics with highest ' +
72
'possible quality and in this case you can easily combine the "vectorial" ' +
73
'part of the library with some API like Windows GDI, having a common ' +
74
'external interface. If that API can render multi-polygons with non-zero ' +
75
'and even-odd filling rules it''s all you need to incorporate AGG into ' +
76
'your application. For example, Windows API PolyPolygon perfectly fits ' +
77
'these needs, except certain advanced things like gradient filling, ' +
78
'Gouraud shading, image transformations, and so on. Or, as an alternative, ' +
79
'you can use all AGG algorithms producing high resolution pixel images and ' +
80
'then to send the result to the printer as a pixel map.' +
81
'Below is a typical brief scheme of the AGG rendering pipeline. ' +
82
'Please note that any component between the Vertex Source ' +
83
'and Screen Output is not mandatory. It all depends on your ' +
84
'particular needs. For example, you can use your own rasterizer, ' +
85
'based on Windows API. In this case you won''t need the AGG rasterizer ' +
86
'and renderers. Or, if you need to draw only lines, you can use the ' +
87
'AGG outline rasterizer that has certain restrictions but works faster. ' +
88
'The number of possibilities is endless. ' +
89
'Vertex Source is some object that produces polygons or polylines as ' +
90
'a set of consecutive 2D vertices with commands like MoveTo, LineTo. ' +
91
'It can be a container or some other object that generates vertices ' +
93
'Coordinate conversion pipeline consists of a number of coordinate ' +
94
'converters. It always works with vectorial data (X,Y) represented ' +
95
'as floating point numbers (double). For example, it can contain an ' +
96
'affine transformer, outline (stroke) generator, some marker ' +
97
'generator (like arrowheads/arrowtails), dashed lines generator, ' +
98
'and so on. The pipeline can have branches and you also can have ' +
99
'any number of different pipelines. You also can write your own ' +
100
'converter and include it into the pipeline. ' +
101
'Scanline Rasterizer converts vectorial data into a number of ' +
102
'horizontal scanlines. The scanlines usually (but not obligatory) ' +
103
'carry information about Anti-Aliasing as coverage values. ' +
104
'Renderers render scanlines, sorry for the tautology. The simplest ' +
105
'example is solid filling. The renderer just adds a color to the ' +
106
'scanline and writes the result into the rendering buffer. ' +
107
'More complex renderers can produce multi-color result, ' +
108
'like gradients, Gouraud shading, image transformations, ' +
109
'patterns, and so on. Rendering Buffer is a buffer in memory ' +
110
'that will be displayed afterwards. Usually but not obligatory ' +
111
'it contains pixels in format that fits your video system. ' +
112
'For example, 24 bits B-G-R, 32 bits B-G-R-A, or 15 ' +
113
'bits R-G-B-555 for Windows. But in general, there''re no ' +
114
'restrictions on pixel formats or color space if you write ' +
115
'your own low level class that supports that format. ' +
116
'Colors in AGG appear only in renderers, that is, when you ' +
117
'actually put some data to the rendering buffer. In general, ' +
118
'there''s no general purpose structure or class like color, ' +
119
'instead, AGG always operates with concrete color space. ' +
120
'There are plenty of color spaces in the world, like RGB, ' +
121
'HSV, CMYK, etc., and all of them have certain restrictions. ' +
122
'For example, the RGB color space is just a poor subset of ' +
123
'colors that a human eye can recognize. If you look at the full ' +
124
'CIE Chromaticity Diagram, you will see that the RGB triangle ' +
125
'is just a little part of it. ' +
126
'In other words there are plenty of colors in the real world ' +
127
'that cannot be reproduced with RGB, CMYK, HSV, etc. Any color ' +
128
'space except the one existing in Nature is restrictive. Thus, ' +
129
'it was decided not to introduce such an object like color in ' +
130
'order not to restrict the possibilities in advance. Instead, ' +
131
'there are objects that operate with concrete color spaces. ' +
132
'Currently there are agg::rgba and agg::rgba8 that operate ' +
133
'with the most popular RGB color space (strictly speaking there''s ' +
134
'RGB plus Alpha). The RGB color space is used with different ' +
135
'pixel formats, like 24-bit RGB or 32-bit RGBA with different ' +
136
'order of color components. But the common property of all of ' +
137
'them is that they are essentially RGB. Although, AGG doesn''t ' +
138
'explicitly support any other color spaces, there is at least ' +
139
'a potential possibility of adding them. It means that all ' +
140
'class and function templates that depend on the color type ' +
141
'are parameterized with the ColorT argument. ' +
142
'Basically, AGG operates with coordinates of the output device. ' +
143
'On your screen there are pixels. But unlike many other libraries ' +
144
'and APIs AGG initially supports Subpixel Accuracy. It means ' +
145
'that the coordinates are represented as doubles, where fractional ' +
146
'values actually take effect. AGG doesn''t have an embedded ' +
147
'conversion mechanism from world to screen coordinates in order ' +
148
'not to restrict your freedom. It''s very important where and when ' +
149
'you do that conversion, so, different applications can require ' +
150
'different approaches. AGG just provides you a transformer of ' +
151
'that kind, namely, that can convert your own view port to the ' +
152
'device one. And it''s your responsibility to include it into ' +
153
'the proper place of the pipeline. You can also write your ' +
154
'own very simple class that will allow you to operate with ' +
155
'millimeters, inches, or any other physical units. ' +
156
'Internally, the rasterizers use integer coordinates of the ' +
157
'format 24.8 bits, that is, 24 bits for the integer part and 8 ' +
158
'bits for the fractional one. In other words, all the internal ' +
159
'coordinates are multiplied by 256. If you intend to use AGG in ' +
160
'some embedded system that has inefficient floating point ' +
161
'processing, you still can use the rasterizers with their ' +
162
'integer interfaces. Although, you won''t be able to use the ' +
163
'floating point coordinate pipelines in this case. ';
166
font_flip_y : boolean;
167
font_name : AnsiString;
170
the_application = object(platform_support )
171
m_ren_type : rbox_ctrl;
176
m_gamma : slider_ctrl;
180
m_performance : cbox_ctrl;
182
m_feng : font_engine_freetype_int32;
183
m_fman : font_cache_manager;
185
m_old_height : double;
186
m_gamma_lut : gamma_lut;
188
// Pipeline to process the vectors glyph paths (curves + contour)
189
m_curves : conv_curve;
190
m_contour : conv_contour;
194
constructor Construct(format_ : pix_format_e; flip_y_ : boolean );
198
ras : rasterizer_scanline_aa_ptr;
200
ren_solid : renderer_scanline_aa_solid_ptr;
201
ren_bin : renderer_scanline_bin_solid_ptr ) : unsigned;
203
procedure on_draw; virtual;
205
procedure on_key(x ,y : int; key ,flags : unsigned ); virtual;
206
procedure on_ctrl_change; virtual;
211
constructor the_application.Construct;
213
inherited Construct(format_ ,flip_y_ );
215
m_ren_type.Construct (5.0 ,5.0 ,5.0 + 150.0 ,110.0 ,not flip_y_ );
216
m_height.Construct (160 ,10.0 ,640 - 5.0 ,18.0 ,not flip_y_ );
217
m_width.Construct (160 ,30.0 ,640 - 5.0 ,38.0 ,not flip_y_ );
218
m_weight.Construct (160 ,50.0 ,640 - 5.0 ,58.0 ,not flip_y_ );
219
m_gamma.Construct (260 ,70.0 ,640 - 5.0 ,78.0 ,not flip_y_ );
220
m_hinting.Construct (160 ,65.0 ,'Hinting' ,not flip_y_ );
221
m_kerning.Construct (160 ,80.0 ,'Kerning' ,not flip_y_ );
222
m_performance.Construct(160 ,95.0 ,'Test Performance' ,not flip_y_ );
225
m_fman.Construct(@m_feng );
229
m_gamma_lut.Construct_(8 ,16 );
230
m_curves.Construct (m_fman.path_adaptor );
231
m_contour.Construct (@m_curves );
233
m_ren_type.add_item ('Native Mono' );
234
m_ren_type.add_item ('Native Gray 8' );
235
m_ren_type.add_item ('Outline' );
236
m_ren_type.add_item ('AGG Mono' );
237
m_ren_type.add_item ('AGG Gray 8' );
238
m_ren_type.cur_item_(1 );
240
add_ctrl(@m_ren_type );
242
m_ren_type.no_transform;
244
m_height.label_('Font Height=%.2f' );
245
m_height.range_(8, 32);
246
m_height.value_(18 );
248
m_height.num_steps_ (32 - 8 );
249
m_height.text_thickness_(1.5 );
251
add_ctrl(@m_height );
253
m_height.no_transform;
255
m_width.label_('Font Width=%.2f' );
256
m_width.range_(8 ,32 );
259
m_width.num_steps_ (32 - 8 );
260
m_width.text_thickness_(1.5 );
264
m_width.no_transform;
266
m_weight.label_('Font Weight=%.2f' );
267
m_weight.range_(-1 ,1 );
269
m_weight.text_thickness_(1.5 );
271
add_ctrl(@m_weight );
273
m_weight.no_transform;
275
m_gamma.label_('Gamma=%.2f' );
276
m_gamma.range_(0.1 ,2.0 );
277
m_gamma.value_(1.0 );
279
m_gamma.text_thickness_(1.5 );
283
m_gamma.no_transform;
285
add_ctrl(@m_hinting );
287
m_hinting.status_(true );
288
m_hinting.no_transform;
290
add_ctrl(@m_kerning );
292
m_kerning.status_(true );
293
m_kerning.no_transform;
295
add_ctrl(@m_performance );
297
m_performance.no_transform;
299
m_curves.approximation_scale_ (2.0 );
300
m_contour.auto_detect_orientation_(false );
307
destructor the_application.Destruct;
318
m_performance.Destruct;
323
m_gamma_lut.Destruct;
330
function the_application.draw_text;
332
gren : glyph_rendering;
334
num_glyphs : unsigned;
337
taw : trans_affine_skewing;
338
tar : trans_affine_rotation;
339
tat : trans_affine_translation;
346
glyph : glyph_cache_ptr;
349
gren:=glyph_ren_native_mono;
351
case m_ren_type._cur_item of
352
0 : gren:=glyph_ren_native_mono;
353
1 : gren:=glyph_ren_native_gray8;
354
2 : gren:=glyph_ren_outline;
355
3 : gren:=glyph_ren_agg_mono;
356
4 : gren:=glyph_ren_agg_gray8;
362
m_contour.width_(-m_weight._value * m_height._value * 0.05 );
364
if m_feng.load_font(@font_name[1 ] ,0 ,gren ) then
366
m_feng.hinting_(m_hinting._status );
367
m_feng.height_ (m_height._value );
368
m_feng.width_ (m_width._value );
369
m_feng.flip_y_ (font_flip_y);
375
tar.Construct(deg2rad(m_angle ) );
376
mtx.multiply (@tar );
380
//taw.Construct(-0.4 ,0 ); mtx.multiply(@taw );
381
//tat.Construct(1 ,0 ); mtx.multiply(@tat );
383
m_feng.transform_(@mtx );
386
y0:=_height - m_height._value - 10.0;
392
glyph:=m_fman.glyph(p^ );
396
if m_kerning._status then
397
m_fman.add_kerning(@x ,@y );
399
if x >= _width - m_height._value then
402
y0:=y0 - m_height._value;
411
m_fman.init_embedded_adaptors(glyph ,x ,y );
413
case glyph.data_type of
416
rgba.ConstrInt(0 ,0 ,0 );
417
ren_bin.color_(@rgba );
420
m_fman.mono_adaptor ,
421
m_fman.mono_scanline ,
428
rgba.ConstrInt (0 ,0 ,0 );
429
ren_solid.color_(@rgba );
432
m_fman.gray8_adaptor ,
433
m_fman.gray8_scanline ,
442
if Abs(m_weight._value ) <= 0.01 then
443
// For the sake of efficiency skip the
444
// contour converter if the weight is about zero.
445
ras.add_path(@m_curves )
447
ras.add_path(@m_contour );
449
rgba.ConstrInt (0 ,0 ,0 );
450
ren_solid.color_(@rgba );
452
render_scanlines(ras ,sl ,ren_solid );
458
// increment pen position
459
x:=x + glyph.advance_x;
460
y:=y + glyph.advance_y;
466
inc(ptrcomp(p ) ,sizeof(int8u ) );
473
'Please copy file timesi.ttf to the current directory'#13 +
474
'or download it from http://www.antigrain.com/timesi.zip' );
481
procedure the_application.on_draw;
487
ren_base : renderer_base;
488
ren_solid : renderer_scanline_aa_solid;
489
ren_bin : renderer_scanline_bin_solid;
492
ras : rasterizer_scanline_aa;
494
gm_th : gamma_threshold;
499
// Initialize structures
500
pixfmt_bgr24_gamma(pf ,rbuf_window ,@m_gamma_lut );
502
ren_base.Construct (@pf );
503
ren_solid.Construct(@ren_base );
504
ren_bin.Construct (@ren_base );
506
rgba.ConstrDbl(1 ,1 ,1 );
507
ren_base.clear(@rgba );
512
if m_height._value <> m_old_height then
514
m_old_height:=m_height._value;
516
m_width.value_(m_old_height );
521
if m_ren_type._cur_item = 3 then
523
// When rendering in mono format,
524
// Set threshold gamma = 0.5
525
gm_th.Construct(m_gamma._value / 2.0 );
526
m_feng.gamma_ (@gm_th );
532
m_feng.gamma_(@gm_no );
534
m_gamma_lut.gamma_(m_gamma._value );
538
if m_ren_type._cur_item = 2 then
540
// For outline cache set gamma for the rasterizer
541
gm_pw.Construct(m_gamma._value );
547
draw_text(@ras ,@sl ,@ren_solid ,@ren_bin );
549
// Render the controls
550
gm_pw.Construct(1.0 );
553
render_ctrl(@ras ,@sl ,@ren_solid ,@m_ren_type );
554
render_ctrl(@ras ,@sl ,@ren_solid ,@m_height );
555
render_ctrl(@ras ,@sl ,@ren_solid ,@m_width );
556
render_ctrl(@ras ,@sl ,@ren_solid ,@m_weight );
557
render_ctrl(@ras ,@sl ,@ren_solid ,@m_gamma );
558
render_ctrl(@ras ,@sl ,@ren_solid ,@m_hinting );
559
render_ctrl(@ras ,@sl ,@ren_solid ,@m_kerning );
560
render_ctrl(@ras ,@sl ,@ren_solid ,@m_performance );
562
// Free AGG resources
569
procedure the_application.on_key;
571
if key = byte(' ' ) then
573
font_flip_y:=not font_flip_y;
579
if key = key_kp_minus then
581
m_angle:=m_angle + angle_step;
583
if m_angle > 360 then
590
if key = key_kp_plus then
592
m_angle:=m_angle - angle_step;
595
m_angle:=360 - angle_step;
603
'This example demonstrates the use of the FreeType font engine with cache. '#13 +
604
'Cache can keep three types of data, vector path, Anti-Aliased scanline shape, '#13 +
605
'and monochrome scanline shape. In case of caching scanline shapes the speed '#13 +
606
'is pretty good and comparable with Windows hardware accelerated font rendering.'#13#13 +
607
'How to play with:'#13#13 +
608
'Press the spacebar to flip the text vertically.'#13#13 +
609
'Key Plus - Increase font angle (not for Natives)'#13 +
610
'Key Minus - Decrease font angle (not for Natives)' +
611
#13#13'Note: F2 key saves current "screenshot" file in this demo''s directory. ' );
616
procedure the_application.on_ctrl_change;
622
ren_base : renderer_base;
623
ren_solid : renderer_scanline_aa_solid;
624
ren_bin : renderer_scanline_bin_solid;
627
ras : rasterizer_scanline_aa;
629
num_glyphs ,i : unsigned;
633
buf : array[0..99 ] of char;
636
if m_performance._status then
638
pixfmt_bgr24_gamma(pf ,rbuf_window ,@m_gamma_lut );
640
ren_base.Construct (@pf );
641
ren_solid.Construct(@ren_base );
642
ren_bin.Construct (@ren_base );
644
rgba.ConstrDbl(1 ,1 ,1 );
645
ren_base.clear(@rgba );
655
inc(num_glyphs ,draw_text(@ras ,@sl ,@ren_solid ,@ren_bin ) );
659
sprintf(@buf[0 ] ,'Glyphs=%u, ' ,num_glyphs );
660
sprintf(@buf[StrLen(@buf ) ] ,'Time=%.3fms, ' ,t );
661
sprintf(@buf[StrLen(@buf ) ] ,'%.3f glyps/sec, ' ,(num_glyphs / t ) * 1000.0 );
662
sprintf(@buf[StrLen(@buf ) ] ,'%.3f microsecond/glyph' , (t / num_glyphs) * 1000.0);
666
m_performance.status_(false );
678
app : the_application;
682
font_name :='timesi.ttf';
685
if ParamCount > 0 then
686
font_name:=ParamStr(1 );
690
app.Construct(pix_format_bgr24 ,flip_y );
691
app.caption_ ('AGG Example. Rendering Fonts with FreeType (F1-Help)' );
693
if app.init(640 ,520 ,window_resize ) then