1{target:win} 2// 3// AggPas 2.4 RM3 Demo application 4// Note: Press F1 key on run to see more info about this demo 5// 6// Paths: src;src\ctrl;src\svg;src\util;src\platform\win;expat-wrap 7// 8program 9 truetype_test ; 10 11uses 12 Windows ,SysUtils , 13 14 agg_basics , 15 agg_platform_support , 16 17 agg_color , 18 agg_pixfmt , 19 agg_pixfmt_rgb , 20 21 agg_ctrl , 22 agg_slider_ctrl , 23 agg_cbox_ctrl , 24 agg_rbox_ctrl , 25 26 agg_rendering_buffer , 27 agg_renderer_base , 28 agg_renderer_scanline , 29 agg_renderer_primitives , 30 agg_rasterizer_scanline_aa , 31 agg_scanline , 32 agg_scanline_u , 33 agg_scanline_bin , 34 agg_render_scanlines , 35 36 agg_trans_affine , 37 agg_curves , 38 agg_conv_curve , 39 agg_conv_contour , 40 agg_gamma_lut , 41 agg_gamma_functions , 42 agg_font_win32_tt , 43 agg_font_cache_manager ; 44 45{$I agg_mode.inc } 46 47const 48 flip_y = true; 49 50 angle_step = 0.5; 51 52 text_ : PChar = 53 //'0123456789ABCDEFGHIJKLMNOPRSTUVWXYZabcdefghijklmnoprstuvwxyz ' + 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 ' + 92 'on demand. ' + 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. '; 164 165var 166 text_flip : boolean; 167 font_name : AnsiString; 168 169type 170 the_application = object(platform_support ) 171 m_ren_type : rbox_ctrl; 172 173 m_height , 174 m_width , 175 m_weight , 176 m_gamma : slider_ctrl; 177 178 m_hinting , 179 m_kerning , 180 m_performance : cbox_ctrl; 181 182 m_feng : font_engine_win32_tt_int32; 183 m_fman : font_cache_manager; 184 185 m_old_height : double; 186 m_gamma_lut : gamma_lut; 187 188 // Pipeline to process the vectors glyph paths (curves + contour) 189 m_curves : conv_curve; 190 m_contour : conv_contour; 191 192 m_angle : double; 193 194 constructor Construct(dc : HDC; format_ : pix_format_e; flip_y_ : boolean ); 195 destructor Destruct; 196 197 function draw_text( 198 ras : rasterizer_scanline_aa_ptr; 199 sl : scanline_ptr; 200 ren_solid : renderer_scanline_aa_solid_ptr; 201 ren_bin : renderer_scanline_bin_solid_ptr ) : unsigned; 202 203 procedure on_draw; virtual; 204 205 procedure on_key(x ,y : int; key ,flags : unsigned ); virtual; 206 procedure on_ctrl_change; virtual; 207 208 end; 209 210{ CONSTRUCT } 211constructor the_application.Construct; 212begin 213 inherited Construct(format_ ,flip_y_ ); 214 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_ ); 223 224 m_feng.Construct(dc ); 225 m_fman.Construct(@m_feng ); 226 227 m_old_height:=0.0; 228 229 m_gamma_lut.Construct_(8 ,16 ); 230 m_curves.Construct (m_fman.path_adaptor ); 231 m_contour.Construct (@m_curves ); 232 233 m_ren_type.add_item ('Native Mono' ); 234 m_ren_type.add_item ('Native Gray 8' ); 235 m_ren_type.add_item ('AGG 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 ); 239 240 add_ctrl(@m_ren_type ); 241 242 m_ren_type.no_transform; 243 244 m_height.label_('Font Height=%.2f' ); 245 m_height.range_(8, 32); 246 m_height.value_(18 ); 247 248 m_height.num_steps_ (32 - 8 ); 249 m_height.text_thickness_(1.5 ); 250 251 add_ctrl(@m_height ); 252 253 m_height.no_transform; 254 255 m_width.label_('Font Width=%.2f' ); 256 m_width.range_(8 ,32 ); 257 m_width.value_(18 ); 258 259 m_width.num_steps_ (32 - 8 ); 260 m_width.text_thickness_(1.5 ); 261 262 add_ctrl(@m_width ); 263 264 m_width.no_transform; 265 266 m_weight.label_('Font Weight=%.2f' ); 267 m_weight.range_(-1 ,1 ); 268 269 m_weight.text_thickness_(1.5 ); 270 271 add_ctrl(@m_weight ); 272 273 m_weight.no_transform; 274 275 m_gamma.label_('Gamma=%.2f' ); 276 m_gamma.range_(0.1 ,2.0 ); 277 m_gamma.value_(1.0 ); 278 279 m_gamma.text_thickness_(1.5 ); 280 281 add_ctrl(@m_gamma ); 282 283 m_gamma.no_transform; 284 285 add_ctrl(@m_hinting ); 286 287 m_hinting.status_(true ); 288 m_hinting.no_transform; 289 290 add_ctrl(@m_kerning ); 291 292 m_kerning.status_(true ); 293 m_kerning.no_transform; 294 295 add_ctrl(@m_performance ); 296 297 m_performance.no_transform; 298 299 //m_curves.approximation_method_(curve_div ); 300 //m_curves.approximation_scale_ (0.5 ); 301 //m_curves.angle_tolerance_ (0.3 ); 302 303 m_contour.auto_detect_orientation_(false ); 304 305end; 306 307{ DESTRUCT } 308destructor the_application.Destruct; 309begin 310 inherited Destruct; 311 312 m_ren_type.Destruct; 313 m_height.Destruct; 314 m_width.Destruct; 315 m_weight.Destruct; 316 m_gamma.Destruct; 317 m_hinting.Destruct; 318 m_kerning.Destruct; 319 m_performance.Destruct; 320 321 m_feng.Destruct; 322 m_fman.Destruct; 323 324 m_gamma_lut.Destruct; 325 m_curves.Destruct; 326 m_contour.Destruct; 327 328end; 329 330{ DRAW_TEXT } 331function the_application.draw_text; 332var 333 gren : glyph_rendering; 334 335 num_glyphs : unsigned; 336 337 mtx : trans_affine; 338 taw : trans_affine_skewing; 339 tar : trans_affine_rotation; 340 341 x ,y0 ,y : double; 342 343 p : int8u_ptr; 344 345 rgba : aggclr; 346 glyph : glyph_cache_ptr; 347 348begin 349 gren:=glyph_ren_native_mono; 350 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; 357 358 end; 359 360 num_glyphs:=0; 361 362 m_contour.width_(-m_weight._value * m_height._value * 0.05 ); 363 364 m_feng.hinting_(m_hinting._status ); 365 m_feng.height_ (m_height._value ); 366 367// Font width in Windows is strange. MSDN says, 368// "specifies the average width", but there's no clue what 369// this "average width" means. It'd be logical to specify 370// the width with regard to the font height, like it's done in 371// FreeType. That is, width == height should mean the "natural", 372// not distorted glyphs. In Windows you have to specify 373// the absolute width, which is very stupid and hard to use 374// in practice. 375 if m_width._value = m_height._value then 376 m_feng.width_(0.0 ) 377 else 378 m_feng.width_(m_width._value / 2.4 ); 379 380// m_feng.italic_(true ); 381 m_feng.flip_y_(text_flip ); 382 383 mtx.Construct; 384 385 if m_angle <> 0 then 386 begin 387 tar.Construct(deg2rad(m_angle ) ); 388 mtx.multiply (@tar ); 389 390 end; 391 392 //taw.Construct(-0.3 ,0 ); mtx.multiply(@taw ); 393 394 m_feng.transform_(@mtx ); 395 396 if m_feng.create_font(@font_name[1 ] ,gren ) then 397 begin 398 m_fman.precache(unsigned(' ' ) ,127 ); 399 400 x :=10.0; 401 y0:=_height - m_height._value - 10.0; 402 y :=y0; 403 p :=@text_[0 ]; 404 405 while p^ <> 0 do 406 begin 407 glyph:=m_fman.glyph(p^ ); 408 409 if glyph <> NIL then 410 begin 411 if m_kerning._status then 412 m_fman.add_kerning(@x ,@y ); 413 414 if x >= _width - m_height._value then 415 begin 416 x :=10.0; 417 y0:=y0 - m_height._value; 418 419 if y0 <= 120 then 420 break; 421 422 y:=y0; 423 424 end; 425 426 m_fman.init_embedded_adaptors(glyph ,x ,y ); 427 428 case glyph.data_type of 429 glyph_data_mono : 430 begin 431 rgba.ConstrInt(0 ,0 ,0 ); 432 ren_bin.color_(@rgba ); 433 434 render_scanlines( 435 m_fman.mono_adaptor , 436 m_fman.mono_scanline , 437 ren_bin ); 438 439 end; 440 441 glyph_data_gray8 : 442 begin 443 rgba.ConstrInt (0 ,0 ,0 ); 444 ren_solid.color_(@rgba ); 445 446 render_scanlines( 447 m_fman.gray8_adaptor , 448 m_fman.gray8_scanline , 449 ren_solid ); 450 451 end; 452 453 glyph_data_outline : 454 begin 455 ras.reset; 456 457 if Abs(m_weight._value ) <= 0.01 then 458 // For the sake of efficiency skip the 459 // contour converter if the weight is about zero. 460 ras.add_path(@m_curves ) 461 else 462 ras.add_path(@m_contour ); 463 464 rgba.ConstrInt (0 ,0 ,0 ); 465 ren_solid.color_(@rgba ); 466 467 render_scanlines(ras ,sl ,ren_solid ); 468 469 end; 470 471 end; 472 473 // increment pen position 474 x:=x + glyph.advance_x; 475 y:=y + glyph.advance_y; 476 477 inc(num_glyphs ); 478 479 end; 480 481 inc(ptrcomp(p ) ,sizeof(int8u ) ); 482 483 end; 484 485 end; 486 487 result:=num_glyphs; 488 489end; 490 491{ ON_DRAW } 492procedure the_application.on_draw; 493var 494 pf : pixel_formats; 495 496 rgba : aggclr; 497 498 ren_base : renderer_base; 499 ren_solid : renderer_scanline_aa_solid; 500 ren_bin : renderer_scanline_bin_solid; 501 502 sl : scanline_u8; 503 ras : rasterizer_scanline_aa; 504 505 gm_th : gamma_threshold; 506 gm_no : gamma_none; 507 gm_pw : gamma_power; 508 509begin 510// Initialize structures 511 pixfmt_bgr24_gamma(pf ,rbuf_window ,@m_gamma_lut ); 512 513 ren_base.Construct (@pf ); 514 ren_solid.Construct(@ren_base ); 515 ren_bin.Construct (@ren_base ); 516 517 rgba.ConstrDbl(1 ,1 ,1 ); 518 ren_base.clear(@rgba ); 519 520 sl.Construct; 521 ras.Construct; 522 523 if m_height._value <> m_old_height then 524 begin 525 m_old_height:=m_height._value; 526 527 m_width.value_(m_old_height ); 528 529 end; 530 531// Setup Gamma 532 if m_ren_type._cur_item = 3 then 533 begin 534 // When rendering in mono format, 535 // Set threshold gamma = 0.5 536 gm_th.Construct(m_gamma._value / 2.0 ); 537 m_feng.gamma_ (@gm_th ); 538 539 end 540 else 541 begin 542 gm_no.Construct; 543 m_feng.gamma_(@gm_no ); 544 545 m_gamma_lut.gamma_(m_gamma._value ); 546 547 end; 548 549// Render the text 550 draw_text(@ras ,@sl ,@ren_solid ,@ren_bin ); 551 552// Render the controls 553 gm_pw.Construct(1.0 ); 554 ras.gamma (@gm_pw ); 555 556 render_ctrl(@ras ,@sl ,@ren_solid ,@m_ren_type ); 557 render_ctrl(@ras ,@sl ,@ren_solid ,@m_height ); 558 render_ctrl(@ras ,@sl ,@ren_solid ,@m_width ); 559 render_ctrl(@ras ,@sl ,@ren_solid ,@m_weight ); 560 render_ctrl(@ras ,@sl ,@ren_solid ,@m_gamma ); 561 render_ctrl(@ras ,@sl ,@ren_solid ,@m_hinting ); 562 render_ctrl(@ras ,@sl ,@ren_solid ,@m_kerning ); 563 render_ctrl(@ras ,@sl ,@ren_solid ,@m_performance ); 564 565// Free AGG resources 566 sl.Destruct; 567 ras.Destruct; 568 569end; 570 571{ ON_KEY } 572procedure the_application.on_key; 573begin 574 if key = byte(' ' ) then 575 begin 576 text_flip:=not text_flip; 577 578 force_redraw; 579 580 end; 581 582 if key = key_kp_minus then 583 begin 584 m_angle:=m_angle + angle_step; 585 586 if m_angle > 360 then 587 m_angle:=0; 588 589 force_redraw; 590 591 end; 592 593 if key = key_kp_plus then 594 begin 595 m_angle:=m_angle - angle_step; 596 597 if m_angle < 0 then 598 m_angle:=360 - angle_step; 599 600 force_redraw; 601 602 end; 603 604 if key = key_f1 then 605 message_( 606 'This example demonstrates the use of the Win32 TrueType font engine with cache. '#13 + 607 'Cache can keep three types of data, vector path, Anti-Aliased scanline shape, '#13 + 608 'and monochrome scanline shape. In case of caching scanline shapes the speed '#13 + 609 'is pretty good and comparable with Windows hardware accelerated font rendering.'#13#13 + 610 'How to play with:'#13#13 + 611 'Press the spacebar to flip the text vertically.'#13#13 + 612 'Key Plus - Increase font angle (not for Natives)'#13 + 613 'Key Minus - Decrease font angle (not for Natives)' + 614 #13#13'Note: F2 key saves current "screenshot" file in this demo''s directory. ' ); 615 616end; 617 618{ ON_CTRL_CHANGE } 619procedure the_application.on_ctrl_change; 620var 621 pf : pixel_formats; 622 623 rgba : aggclr; 624 625 ren_base : renderer_base; 626 ren_solid : renderer_scanline_aa_solid; 627 ren_bin : renderer_scanline_bin_solid; 628 629 sl : scanline_u8; 630 ras : rasterizer_scanline_aa; 631 632 num_glyphs ,i : unsigned; 633 634 t : double; 635 636 buf : array[0..99 ] of char; 637 638begin 639 if m_performance._status then 640 begin 641 pixfmt_bgr24_gamma(pf ,rbuf_window ,@m_gamma_lut ); 642 643 ren_base.Construct (@pf ); 644 ren_solid.Construct(@ren_base ); 645 ren_bin.Construct (@ren_base ); 646 647 rgba.ConstrDbl(1 ,1 ,1 ); 648 ren_base.clear(@rgba ); 649 650 sl.Construct; 651 ras.Construct; 652 653 num_glyphs:=0; 654 655 start_timer; 656 657 for i:=0 to 49 do 658 inc(num_glyphs ,draw_text(@ras ,@sl ,@ren_solid ,@ren_bin ) ); 659 660 t:=elapsed_time; 661 662 sprintf(@buf[0 ] ,'Glyphs=%u, ' ,num_glyphs ); 663 sprintf(@buf[StrLen(@buf ) ] ,'Time=%.3fms, ' ,t ); 664 sprintf(@buf[StrLen(@buf ) ] ,'%.3f glyps/sec, ' ,(num_glyphs / t ) * 1000.0 ); 665 sprintf(@buf[StrLen(@buf ) ] ,'%.3f microsecond/glyph' , (t / num_glyphs) * 1000.0); 666 667 message_(@buf[0 ] ); 668 669 m_performance.status_(false ); 670 671 force_redraw; 672 673 sl.Destruct; 674 ras.Destruct; 675 676 end; 677 678end; 679 680VAR 681 app : the_application; 682 dc : HDC; 683 684BEGIN 685 text_flip:=false; 686 font_name:='Arial'; 687 688{$IFDEF WIN32 } 689 if ParamCount > 0 then 690 font_name:=ParamStr(1 ); 691 692{$ENDIF } 693 694 dc:=GetDC(0 ); 695 696 app.Construct(dc ,pix_format_bgr24 ,flip_y ); 697 app.caption_ ('AGG Example. Rendering TrueType Fonts with WinAPI (F1-Help)' ); 698 699 if app.init(640 ,520 ,window_resize ) then 700 app.run; 701 702 app.Destruct; 703 704 ReleaseDC(0 ,dc ); 705 706END.