1{mac_copy:spheres.bmp} 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 image_resample ; 10 11uses 12 Math ,SysUtils , 13 14 agg_basics , 15 agg_platform_support , 16 17 agg_color , 18 agg_pixfmt , 19 agg_pixfmt_rgba , 20 21 agg_ctrl , 22 agg_rbox_ctrl , 23 agg_slider_ctrl , 24 25 agg_rendering_buffer , 26 agg_renderer_base , 27 agg_renderer_scanline , 28 agg_rasterizer_scanline_aa , 29 agg_scanline , 30 agg_scanline_u , 31 agg_render_scanlines , 32 33 agg_path_storage , 34 agg_conv_transform , 35 agg_conv_stroke , 36 agg_trans_affine , 37 agg_trans_perspective , 38 agg_span_interpolator_linear , 39 agg_span_interpolator_trans , 40 agg_span_interpolator_persp , 41 agg_span_subdiv_adaptor , 42 agg_span_image_filter , 43 agg_span_image_filter_rgba , 44 agg_span_image_resample , 45 agg_span_image_resample_rgba , 46 agg_span_allocator , 47 agg_image_filters , 48 agg_gsv_text , 49 agg_gamma_lut , 50 interactive_polygon_ , 51 file_utils_ ; 52 53{$I agg_mode.inc } 54 55const 56 flip_y = true; 57 58 base_shift = agg_color.base_shift; 59 60var 61 g_x1 , 62 g_y1 , 63 g_x2 , 64 g_y2 : double; 65 66 global_offset : int; 67 68 g_rasterizer : rasterizer_scanline_aa; 69 g_scanline : scanline_u8; 70 71 img_name ,p ,n ,x : shortstring; 72 73type 74 the_application = object(platform_support ) 75 m_gamma_lut : gamma_lut; 76 m_quad : interactive_polygon; 77 m_trans_type : rbox_ctrl; 78 m_gamma , 79 m_blur : slider_ctrl; 80 m_old_gamma : double; 81 82 constructor Construct(format_ : pix_format_e; flip_y_ : boolean ); 83 destructor Destruct; 84 85 procedure on_init; virtual; 86 procedure on_draw; virtual; 87 88 procedure on_mouse_move (x ,y : int; flags : unsigned ); virtual; 89 procedure on_mouse_button_down(x ,y : int; flags : unsigned ); virtual; 90 procedure on_mouse_button_up (x ,y : int; flags : unsigned ); virtual; 91 92 procedure on_key(x ,y : int; key ,flags : unsigned ); virtual; 93 94 end; 95 96{ CONSTRUCT } 97constructor the_application.Construct; 98begin 99 inherited Construct(format_ ,flip_y_ ); 100 101 m_gamma_lut.Construct(2.0 ,base_shift ,base_shift ); 102 m_quad.Construct (4 ,5.0 ); 103 104 m_trans_type.Construct(400 ,5.0 ,430 + 170.0 ,100.0 ,not flip_y_ ); 105 m_gamma.Construct (5.0 ,5.0 + 15 * 0 ,400-5 ,10.0 + 15 * 0 ,not flip_y_ ); 106 m_blur.Construct (5.0 ,5.0 + 15 * 1 ,400-5 ,10.0 + 15 * 1 ,not flip_y_ ); 107 108 m_old_gamma:=2.0; 109 110 m_trans_type.text_size_(7 ); 111 m_trans_type.add_item ('Affine No Resample' ); 112 m_trans_type.add_item ('Affine Resample' ); 113 m_trans_type.add_item ('Perspective No Resample LERP' ); 114 m_trans_type.add_item ('Perspective No Resample Exact' ); 115 m_trans_type.add_item ('Perspective Resample LERP' ); 116 m_trans_type.add_item ('Perspective Resample Exact' ); 117 m_trans_type.cur_item_ (4 ); 118 119 add_ctrl(@m_trans_type ); 120 121 m_gamma.range_(0.5 ,3.0 ); 122 m_gamma.value_(2.0 ); 123 m_gamma.label_('Gamma=%.3f' ); 124 125 add_ctrl(@m_gamma ); 126 127 m_blur.range_(0.5, 2.0); 128 m_blur.value_(1.0 ); 129 m_blur.label_('Blur=%.3f' ); 130 131 add_ctrl(@m_blur ); 132 133end; 134 135{ DESTRUCT } 136destructor the_application.Destruct; 137begin 138 inherited Destruct; 139 140 m_gamma_lut.Destruct; 141 m_quad.Destruct; 142 143 m_trans_type.Destruct; 144 m_gamma.Destruct; 145 m_blur.Destruct; 146 147end; 148 149{ ON_INIT } 150procedure the_application.on_init; 151var 152 x1 ,y1 ,x2 ,y2 ,dx ,dy : double; 153 154 pixf : pixel_formats; 155 156begin 157 g_x1:=0.0; 158 g_y1:=0.0; 159 g_x2:=rbuf_img(0 )._width; 160 g_y2:=rbuf_img(0 )._height; 161 162 x1:=g_x1;// * 100.0; 163 y1:=g_y1;// * 100.0; 164 x2:=g_x2;// * 100.0; 165 y2:=g_y2;// * 100.0; 166 167 dx:=_width / 2.0 - (x2 - x1 ) / 2.0; 168 dy:=_height / 2.0 - (y2 - y1 ) / 2.0; 169 170 m_quad.xn_ptr(0 )^:=Floor(x1 + dx ); 171 m_quad.yn_ptr(0 )^:=Floor(y1 + dy );// - 150; 172 m_quad.xn_ptr(1 )^:=Floor(x2 + dx ); 173 m_quad.yn_ptr(1 )^:=Floor(y1 + dy );// - 110; 174 m_quad.xn_ptr(2 )^:=Floor(x2 + dx ); 175 m_quad.yn_ptr(2 )^:=Floor(y2 + dy );// - 300; 176 m_quad.xn_ptr(3 )^:=Floor(x1 + dx ); 177 m_quad.yn_ptr(3 )^:=Floor(y2 + dy );// - 200; 178 179 pixfmt_bgra32(pixf ,rbuf_img(0 ) ); 180 181 pixf.apply_gamma_dir(@m_gamma_lut ,bgra_order ); 182 183end; 184 185{ ON_DRAW } 186procedure the_application.on_draw; 187var 188 pixf ,pixf_pre : pixel_formats; 189 190 rb ,rb_pre : renderer_base; 191 192 rgba : aggclr; 193 194 r : renderer_scanline_aa_solid; 195 b : int; 196 197 sa : span_allocator; 198 tr : trans_affine; 199 sg : span_image_filter_ptr; 200 ri : renderer_scanline_aa; 201 202 trp : trans_perspective23; 203 204 interpolator : span_interpolator_linear; 205 interpsubdiv : span_interpolator_linear_subdiv; 206 interp_trans : span_interpolator_trans; 207 interp_plerp : span_interpolator_persp_lerp; 208 interp_exact : span_interpolator_persp_exact; 209 subdiv_adaptor : span_subdiv_adaptor; 210 211 filter_kernel : image_filter_hanning; 212 filter : image_filter_lut; 213 214 tm : double; 215 buf : array[0..63 ] of char; 216 t : gsv_text; 217 pt : conv_stroke; 218 219begin 220 sg:=NIL; 221 222 if m_gamma._value <> m_old_gamma then 223 begin 224 m_gamma_lut.gamma_(m_gamma._value ); 225 226 load_img(0 ,img_name ); 227 228 pixfmt_bgra32(pixf ,rbuf_img(0 ) ); 229 230 pixf.apply_gamma_dir(@m_gamma_lut ,bgra_order ); 231 232 m_old_gamma:=m_gamma._value; 233 234 end; 235 236// Initialize structures 237 pixfmt_bgra32 (pixf ,rbuf_window ); 238 pixfmt_bgra32_pre(pixf_pre ,rbuf_window ); 239 240 rb.Construct (@pixf ); 241 rb_pre.Construct(@pixf_pre ); 242 243 r.Construct(@rb ); 244 245 rgba.ConstrDbl(1 ,1 ,1 ); 246 rb.clear (@rgba ); 247 248 if m_trans_type._cur_item < 2 then 249 begin 250 // For the affine parallelogram transformations we 251 // calculate the 4-th (implicit) point of the parallelogram 252 m_quad.xn_ptr(3 )^:=m_quad.xn(0 ) + (m_quad.xn(2 ) - m_quad.xn(1 ) ); 253 m_quad.yn_ptr(3 )^:=m_quad.yn(0 ) + (m_quad.yn(2 ) - m_quad.yn(1 ) ); 254 255 end; 256 257// Render the "quad" tool and controls 258 g_rasterizer.add_path(@m_quad ); 259 260 rgba.ConstrDbl (0 ,0.3 ,0.5 ,0.1 ); 261 r.color_ (@rgba ); 262 render_scanlines(@g_rasterizer ,@g_scanline ,@r ); 263 264// Prepare the polygon to rasterize. Here we need to fill 265// the destination (transformed) polygon. 266 g_rasterizer.clip_box(0 ,0 ,_width ,_height ); 267 g_rasterizer.reset; 268 269 b:=0; 270 271 g_rasterizer.move_to_d(m_quad.xn(0 ) - b ,m_quad.yn(0 ) - b ); 272 g_rasterizer.line_to_d(m_quad.xn(1 ) + b ,m_quad.yn(1 ) - b ); 273 g_rasterizer.line_to_d(m_quad.xn(2 ) + b ,m_quad.yn(2 ) + b ); 274 g_rasterizer.line_to_d(m_quad.xn(3 ) - b ,m_quad.yn(3 ) + b ); 275 276 sa.Construct; 277 filter_kernel.Construct; 278 filter.Construct(@filter_kernel ,true ); 279 280 rgba.ConstrPre(0 ,0 ,0 ,0 ); 281 282 start_timer; 283 284 case m_trans_type._cur_item of 285 0 : 286 begin 287 tr.Construct(parallelo_ptr(m_quad.polygon ) ,g_x1 ,g_y1 ,g_x2 ,g_y2 ); 288 289 interpolator.Construct(@tr ); 290 291 sg:=new( 292 span_image_filter_rgba_2x2_ptr , 293 Construct( 294 @sa ,rbuf_img(0 ) ,@rgba ,@interpolator ,@filter ,bgra_order ) ); 295 296 ri.Construct (@rb_pre ,sg ); 297 render_scanlines(@g_rasterizer ,@g_scanline ,@ri ); 298 299 end; 300 301 1 : 302 begin 303 tr.Construct(parallelo_ptr(m_quad.polygon ) ,g_x1 ,g_y1 ,g_x2 ,g_y2 ); 304 305 interpolator.Construct(@tr ); 306 307 sg:=new( 308 span_image_resample_rgba_affine_ptr , 309 Construct( 310 @sa ,rbuf_img(0 ) ,@rgba ,@interpolator ,@filter ,bgra_order ) ); 311 312 span_image_resample_ptr(sg ).blur_(m_blur._value ); 313 314 ri.Construct (@rb_pre ,sg ); 315 render_scanlines(@g_rasterizer ,@g_scanline ,@ri ); 316 317 end; 318 319 2 : 320 begin 321 trp.Construct(m_quad.polygon ,g_x1 ,g_y1 ,g_x2 ,g_y2 ); 322 323 if trp.is_valid then 324 begin 325 interpsubdiv.Construct(@trp ); 326 327 sg:=new( 328 span_image_filter_rgba_2x2_ptr , 329 Construct( 330 @sa ,rbuf_img(0 ) ,@rgba ,@interpsubdiv ,@filter ,bgra_order ) ); 331 332 ri.Construct (@rb_pre ,sg ); 333 render_scanlines(@g_rasterizer ,@g_scanline ,@ri ); 334 335 end; 336 337 end; 338 339 3 : 340 begin 341 trp.Construct(m_quad.polygon ,g_x1 ,g_y1 ,g_x2 ,g_y2 ); 342 343 if trp.is_valid then 344 begin 345 interp_trans.Construct(@trp ); 346 347 sg:=new( 348 span_image_filter_rgba_2x2_ptr , 349 Construct( 350 @sa ,rbuf_img(0 ) ,@rgba ,@interp_trans ,@filter ,bgra_order ) ); 351 352 ri.Construct (@rb_pre ,sg ); 353 render_scanlines(@g_rasterizer ,@g_scanline ,@ri ); 354 355 end; 356 357 end; 358 359 4 : 360 begin 361 interp_plerp.Construct (m_quad.polygon ,g_x1 ,g_y1 ,g_x2 ,g_y2 ); 362 subdiv_adaptor.Construct(@interp_plerp ); 363 364 if interp_plerp.is_valid then 365 begin 366 sg:=new( 367 span_image_resample_rgba_ptr , 368 Construct( 369 @sa ,rbuf_img(0 ) ,@rgba ,@subdiv_adaptor ,@filter ,bgra_order ) ); 370 371 span_image_resample_ptr(sg ).blur_(m_blur._value ); 372 373 ri.Construct (@rb_pre ,sg ); 374 render_scanlines(@g_rasterizer ,@g_scanline ,@ri ); 375 376 end; 377 378 end; 379 380 5 : 381 begin 382 interp_exact.Construct (m_quad.polygon ,g_x1 ,g_y1 ,g_x2 ,g_y2 ); 383 subdiv_adaptor.Construct(@interp_exact ); 384 385 if interp_exact.is_valid then 386 begin 387 sg:=new( 388 span_image_resample_rgba_ptr , 389 Construct( 390 @sa ,rbuf_img(0 ) ,@rgba ,@subdiv_adaptor ,@filter ,bgra_order ) ); 391 392 span_image_resample_ptr(sg ).blur_(m_blur._value ); 393 394 ri.Construct (@rb_pre ,sg ); 395 render_scanlines(@g_rasterizer ,@g_scanline ,@ri ); 396 397 end; 398 399 end; 400 401 end; 402 403// Render Text 404 tm:=elapsed_time; 405 406 pixf.apply_gamma_inv(@m_gamma_lut ,bgra_order ); 407 408 t.Construct; 409 t.size_(10.0 ); 410 411 pt.Construct(@t ); 412 pt.width_ (1.5 ); 413 414 sprintf (@buf[0 ] ,'%3.2f ms' ,tm ); 415 t.start_point_(10.0 ,70.0 ); 416 t.text_ (@buf[0 ] ); 417 418 g_rasterizer.add_path(@pt ); 419 420 rgba.ConstrDbl (0 ,0 ,0 ); 421 r.color_ (@rgba ); 422 render_scanlines(@g_rasterizer ,@g_scanline ,@r ); 423 424// Render the controls 425 render_ctrl(@g_rasterizer ,@g_scanline ,@r ,@m_trans_type ); 426 render_ctrl(@g_rasterizer ,@g_scanline ,@r ,@m_gamma ); 427 render_ctrl(@g_rasterizer ,@g_scanline ,@r ,@m_blur ); 428 429// Free AGG resources 430 sa.Destruct; 431 filter.Destruct; 432 433 if sg <> NIL then 434 dispose(sg ,Destruct ); 435 436 t.Destruct; 437 pt.Destruct; 438 439end; 440 441{ ON_MOUSE_MOVE } 442procedure the_application.on_mouse_move; 443begin 444 if flags and mouse_left <> 0 then 445 if m_quad.on_mouse_move(x ,y ) then 446 force_redraw; 447 448 if flags and mouse_left = 0 then 449 on_mouse_button_up(x ,y ,flags ); 450 451end; 452 453{ ON_MOUSE_BUTTON_DOWN } 454procedure the_application.on_mouse_button_down; 455begin 456 if flags and mouse_left <> 0 then 457 if m_quad.on_mouse_button_down(x ,y ) then 458 force_redraw; 459 460end; 461 462{ ON_MOUSE_BUTTON_UP } 463procedure the_application.on_mouse_button_up; 464begin 465 if m_quad.on_mouse_button_up(x ,y ) then 466 force_redraw; 467 468end; 469 470{ ON_KEY } 471procedure the_application.on_key; 472var 473 cx ,cy : double; 474 475 tr : trans_affine; 476 tar : trans_affine_rotation; 477 tat : trans_affine_translation; 478 479begin 480 if key = byte(' ' ) then 481 begin 482 cx:=(m_quad.xn(0 ) + m_quad.xn(1 ) + m_quad.xn(2 ) + m_quad.xn(3 ) ) / 4; 483 cy:=(m_quad.yn(0 ) + m_quad.yn(1 ) + m_quad.yn(2 ) + m_quad.yn(3 ) ) / 4; 484 485 tr.Construct; 486 tat.construct(-cx ,-cy ); 487 488 tr:=tat; 489 490 tar.Construct(pi / 20{2.0} ); tr.multiply(@tar ); 491 tat.Construct(cx ,cy ); tr.multiply(@tat ); 492 493 tr.transform(@tr ,m_quad.xn_ptr(0 ) ,m_quad.yn_ptr(0 ) ); 494 tr.transform(@tr ,m_quad.xn_ptr(1 ) ,m_quad.yn_ptr(1 ) ); 495 tr.transform(@tr ,m_quad.xn_ptr(2 ) ,m_quad.yn_ptr(2 ) ); 496 tr.transform(@tr ,m_quad.xn_ptr(3 ) ,m_quad.yn_ptr(3 ) ); 497 498 force_redraw; 499 500 end; 501 502 if key = key_f1 then 503 message_( 504 'The demonstration of image transformations with resampling. '#13 + 505 'You can see the difference in quality between regular image transformers and '#13 + 506 'the ones with resampling. Of course, image tranformations with resampling work '#13 + 507 'slower because they provide the best possible quality.'#13#13 + 508 'How to play with:'#13#13 + 509 'Use the left mouse button to manipulate with image.'#13 + 510 'Press the spacebar to rotate the image by 1/20 of pi.' + 511 #13#13'Note: F2 key saves current "screenshot" file in this demo''s directory. ' ); 512 513end; 514 515VAR 516 app : the_application; 517 buf : array [0..255 ] of char; 518 ext : string[10 ]; 519 520BEGIN 521 g_x1:=0; 522 g_y1:=0; 523 g_x2:=0; 524 g_y2:=0; 525 526 global_offset:=0; 527 528 g_rasterizer.Construct; 529 g_scanline.Construct; 530 531 app.Construct(pix_format_bgra32 ,flip_y ); 532 app.caption_ ('AGG Example. Image Transformations with Resampling (F1-Help)' ); 533 534 img_name:='spheres'; 535 536{$IFDEF WIN32 } 537 if ParamCount > 0 then 538 begin 539 spread_name(ParamStr(1 ) ,p ,n ,x ); 540 541 img_name:=fold_name(p ,n ,'' ); 542 543 end; 544 545{$ENDIF } 546 547 if not app.load_img(0 ,img_name ) then 548 begin 549 img_name:=img_name + #0; 550 ext :=app._img_ext + #0; 551 552 if img_name = 'spheres'#0 then 553 begin 554 sprintf(@buf[0 ] ,'File not found: %s' ,ptrcomp(@img_name[1 ] ) ); 555 sprintf(@buf[StrLen(@buf ) ] ,'%s. '#13'Download http://www.antigrain.com/' ,ptrcomp(@ext[1 ] ) ); 556 sprintf(@buf[StrLen(@buf ) ] ,'%s' ,ptrcomp(@img_name[1 ] ) ); 557 sprintf(@buf[StrLen(@buf ) ] ,'%s'#13'or copy it from another directory if available.' ,ptrcomp(@ext[1 ] ) ); 558 559 end 560 else 561 begin 562 sprintf(@buf[0 ] ,'File not found: %s' ,ptrcomp(@img_name[1 ] ) ); 563 sprintf(@buf[StrLen(@buf ) ] ,'%s' ,ptrcomp(@ext[1 ] ) ); 564 565 end; 566 567 app.message_(@buf[0 ] ); 568 569 end 570 else 571 if app.init(600 ,600 ,window_resize ) then 572 app.run; 573 574 app.Destruct; 575 576 g_rasterizer.Destruct; 577 g_scanline.Destruct; 578 579END.