1{mac_copy:agg.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 pattern_perspective ; 10 11uses 12 Math ,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_rbox_ctrl , 23 24 agg_rendering_buffer , 25 agg_renderer_base , 26 agg_renderer_scanline , 27 agg_rasterizer_scanline_aa , 28 agg_scanline , 29 agg_scanline_u , 30 agg_render_scanlines , 31 32 agg_path_storage , 33 agg_conv_transform , 34 agg_trans_affine , 35 agg_trans_bilinear , 36 agg_trans_perspective , 37 agg_span_pattern , 38 agg_span_allocator , 39 agg_image_filters , 40 agg_span_interpolator_linear , 41 agg_span_interpolator_trans , 42 agg_span_image_filter , 43 agg_span_pattern_filter_rgb , 44 interactive_polygon_ , 45 file_utils_ ; 46 47{$I agg_mode.inc } 48 49const 50 flip_y = true; 51 52var 53 g_x1 , 54 g_y1 , 55 g_x2 , 56 g_y2 : double; 57 58 g_rasterizer : rasterizer_scanline_aa; 59 g_scanline : scanline_u8; 60 61type 62 the_application = object(platform_support ) 63 m_quad : interactive_polygon; 64 m_trans_type : rbox_ctrl; 65 m_test_flag : boolean; 66 67 constructor Construct(format_ : pix_format_e; flip_y_ : boolean ); 68 destructor Destruct; 69 70 procedure on_init; virtual; 71 procedure on_draw; virtual; 72 73 procedure on_mouse_move (x ,y : int; flags : unsigned ); virtual; 74 procedure on_mouse_button_down(x ,y : int; flags : unsigned ); virtual; 75 procedure on_mouse_button_up (x ,y : int; flags : unsigned ); virtual; 76 77 procedure on_key(x ,y : int; key ,flags : unsigned ); virtual; 78 79 end; 80 81{ CONSTRUCT } 82constructor the_application.Construct; 83begin 84 inherited Construct(format_ ,flip_y_ ); 85 86 m_quad.Construct (4 ,5.0 ); 87 m_trans_type.Construct(460 ,5.0 ,420 + 170.0 ,60.0 ,not flip_y_ ); 88 89 m_test_flag:=false; 90 91 m_trans_type.text_size_ (8 ); 92 m_trans_type.text_thickness_(1 ); 93 94 m_trans_type.add_item ('Affine' ); 95 m_trans_type.add_item ('Bilinear' ); 96 m_trans_type.add_item ('Perspective' ); 97 m_trans_type.cur_item_(2 ); 98 99 add_ctrl(@m_trans_type ); 100 101end; 102 103{ DESTRUCT } 104destructor the_application.Destruct; 105begin 106 inherited Destruct; 107 108 m_quad.Destruct; 109 m_trans_type.Destruct; 110 111end; 112 113{ ON_INIT } 114procedure the_application.on_init; 115var 116 trans_x1 ,trans_y1 ,trans_x2 ,trans_y2 ,dx ,dy : double; 117 118begin 119 g_x1:=-150; 120 g_y1:=-150; 121 g_x2:=150; 122 g_y2:=150; 123 124 trans_x1:=-200; 125 trans_y1:=-200; 126 trans_x2:=200; 127 trans_y2:=200; 128 129 dx:=_width / 2.0 - (trans_x2 + trans_x1 ) / 2.0; 130 dy:=_height / 2.0 - (trans_y2 + trans_y1 ) / 2.0; 131 132 m_quad.xn_ptr(0 )^:=Floor(trans_x1 + dx ); 133 m_quad.yn_ptr(0 )^:=Floor(trans_y1 + dy ); 134 m_quad.xn_ptr(1 )^:=Floor(trans_x2 + dx );// - 150; 135 m_quad.yn_ptr(1 )^:=Floor(trans_y1 + dy );// + 150; 136 m_quad.xn_ptr(2 )^:=Floor(trans_x2 + dx ); 137 m_quad.yn_ptr(2 )^:=Floor(trans_y2 + dy ); 138 m_quad.xn_ptr(3 )^:=Floor(trans_x1 + dx ); 139 m_quad.yn_ptr(3 )^:=Floor(trans_y2 + dy ); 140 141end; 142 143{ ON_DRAW } 144procedure the_application.on_draw; 145const 146 subdiv_shift = 2; 147 148var 149 pixf ,pixf_pre : pixel_formats; 150 151 rb ,rb_pre : renderer_base; 152 153 rgba : aggclr; 154 155 r : renderer_scanline_aa_solid; 156 sa : span_allocator; 157 fi : image_filter_hanning; 158 sg : span_image_filter_ptr; 159 ri : renderer_scanline_aa; 160 wx , 161 wy : wrap_mode_reflect_auto_pow2; 162 163 interpolator : span_interpolator_linear; 164 interpsubdiv : span_interpolator_linear_subdiv; 165 166 filter : image_filter; 167 168 tr : trans_affine; 169 trb : trans_bilinear; 170 trp : trans_perspective23; 171 172begin 173 sg:=NIL; 174 175// Initialize structures 176 pixfmt_bgr24 (pixf ,rbuf_window ); 177 pixfmt_bgr24_pre(pixf_pre ,rbuf_window ); 178 179 rb.Construct (@pixf ); 180 rb_pre.Construct(@pixf_pre ); 181 182 r.Construct(@rb ); 183 184 if not m_test_flag then 185 begin 186 rgba.ConstrDbl(1 ,1 ,1 ); 187 rb.clear (@rgba ); 188 189 end; 190 191 if m_trans_type._cur_item = 0 then 192 begin 193 // For the affine parallelogram transformations we 194 // calculate the 4-th (implicit) point of the parallelogram 195 m_quad.xn_ptr(3 )^:=m_quad.xn(0 ) + (m_quad.xn(2 ) - m_quad.xn(1 ) ); 196 m_quad.yn_ptr(3 )^:=m_quad.yn(0 ) + (m_quad.yn(2 ) - m_quad.yn(1 ) ); 197 198 end; 199 200 if not m_test_flag then 201 begin 202 // Render the "quad" tool 203 g_rasterizer.add_path(@m_quad ); 204 205 rgba.ConstrDbl (0 ,0.3 ,0.5 ,0.6 ); 206 r.color_ (@rgba ); 207 render_scanlines(@g_rasterizer ,@g_scanline ,@r ); 208 209 // Render the controls 210 render_ctrl(@g_rasterizer ,@g_scanline ,@r ,@m_trans_type ); 211 212 end; 213 214// Prepare the polygon to rasterize. Here we need to fill 215// the destination (transformed) polygon. 216 g_rasterizer.clip_box(0 ,0 ,_width ,_height ); 217 g_rasterizer.reset; 218 g_rasterizer.move_to_d(m_quad.xn(0 ) ,m_quad.yn(0 ) ); 219 g_rasterizer.line_to_d(m_quad.xn(1 ) ,m_quad.yn(1 ) ); 220 g_rasterizer.line_to_d(m_quad.xn(2 ) ,m_quad.yn(2 ) ); 221 g_rasterizer.line_to_d(m_quad.xn(3 ) ,m_quad.yn(3 ) ); 222 223 sa.Construct; 224 fi.Construct; 225 filter.Construct(@fi ); 226 227// Render 228 wx.Construct; 229 wy.Construct; 230 231 case m_trans_type._cur_item of 232 0 : 233 begin 234 // Note that we consruct an affine matrix that transforms 235 // a parallelogram to a rectangle, i.e., it's inverted. 236 // It's actually the same as: 237 // tr(g_x1, g_y1, g_x2, g_y2, m_triangle.polygon()); 238 // tr.invert(); 239 tr.Construct(parallelo_ptr(m_quad.polygon ) ,g_x1 ,g_y1 ,g_x2 ,g_y2 ); 240 241 // Also note that we can use the linear interpolator instead of 242 // arbitrary span_interpolator_trans. It works much faster, 243 // but the transformations must be linear and parellel. 244 interpolator.Construct(@tr ); 245 246 sg:=new( 247 span_pattern_filter_rgb_2x2_ptr , 248 Construct( 249 @sa ,rbuf_img(0 ) ,@interpolator ,@filter ,@wx ,@wy ,bgr_order ) ); 250 251 ri.Construct (@rb_pre ,sg ); 252 render_scanlines(@g_rasterizer ,@g_scanline ,@ri ); 253 254 end; 255 256 1 : 257 begin 258 trb.Construct(m_quad.polygon ,g_x1 ,g_y1 ,g_x2 ,g_y2 ); 259 260 if trb.is_valid then 261 begin 262 interpolator.Construct(@trb ); 263 264 sg:=new( 265 span_pattern_filter_rgb_2x2_ptr , 266 Construct( 267 @sa ,rbuf_img(0 ) ,@interpolator ,@filter ,@wx ,@wy ,bgr_order ) ); 268 269 ri.Construct (@rb_pre ,sg ); 270 render_scanlines(@g_rasterizer ,@g_scanline ,@ri ); 271 272 end; 273 274 end; 275 276 2 : 277 begin 278 trp.Construct(m_quad.polygon ,g_x1 ,g_y1 ,g_x2 ,g_y2 ); 279 280 if trp.is_valid then 281 begin 282 interpsubdiv.Construct(@trp ); 283 284 sg:=new( 285 span_pattern_filter_rgb_2x2_ptr , 286 Construct( 287 @sa ,rbuf_img(0 ) ,@interpsubdiv ,@filter ,@wx ,@wy ,bgr_order ) ); 288 289 ri.Construct (@rb_pre ,sg ); 290 render_scanlines(@g_rasterizer ,@g_scanline ,@ri ); 291 292 end; 293 294 end; 295 296 end; 297 298// Free AGG resources 299 sa.Destruct; 300 filter.Destruct; 301 302 if sg <> NIL then 303 dispose(sg ,Destruct ); 304 305end; 306 307{ ON_MOUSE_MOVE } 308procedure the_application.on_mouse_move; 309begin 310 if flags and mouse_left <> 0 then 311 if m_quad.on_mouse_move(x ,y ) then 312 force_redraw(); 313 314 if flags and mouse_left = 0 then 315 on_mouse_button_up(x ,y ,flags ); 316 317end; 318 319{ ON_MOUSE_BUTTON_DOWN } 320procedure the_application.on_mouse_button_down; 321var 322 buf : array[0..99 ] of char; 323 324begin 325 if flags and mouse_left <> 0 then 326 if m_quad.on_mouse_button_down(x ,y ) then 327 force_redraw 328 else 329 begin 330 start_timer; 331 332 m_test_flag:=true; 333 334 on_draw; 335 on_draw; 336 on_draw; 337 on_draw; 338 339 sprintf(@buf[0 ] ,'time=%.3f' ,elapsed_time ); 340 341 m_test_flag:=false; 342 343 force_redraw; 344 345 message_(@buf[0 ] ); 346 347 end; 348 349end; 350 351{ ON_MOUSE_BUTTON_UP } 352procedure the_application.on_mouse_button_up; 353begin 354 if m_quad.on_mouse_button_up(x ,y ) then 355 force_redraw; 356 357end; 358 359{ ON_KEY } 360procedure the_application.on_key; 361begin 362 if key = key_f1 then 363 message_( 364 'Pattern perspective transformations. Essentially it''s the same as Demo '#13 + 365 '"image_perspective", but working with a repeating pattern. Can be used '#13 + 366 'for texturing.'#13#13 + 367 'How to play with:'#13#13 + 368 'Use the left mouse button to move and distort the pattern.'#13 + 369 'Click the left mouse outside the pattern to run the performance test.' + 370 #13#13'Note: F2 key saves current "screenshot" file in this demo''s directory. ' ); 371 372end; 373 374VAR 375 app : the_application; 376 buf : array [0..255 ] of char; 377 ext : string[10 ]; 378 379 img_name ,p ,n ,x : shortstring; 380 381BEGIN 382 g_x1:=0; 383 g_y1:=0; 384 g_x2:=0; 385 g_y2:=0; 386 387 g_rasterizer.Construct; 388 g_scanline.Construct; 389 390 app.Construct(pix_format_bgr24 ,flip_y ); 391 app.caption_ ('AGG Example. Pattern Perspective Transformations (F1-Help)' ); 392 393 img_name:='agg'; 394 395{$IFDEF WIN32 } 396 if ParamCount > 0 then 397 begin 398 spread_name(ParamStr(1 ) ,p ,n ,x ); 399 400 img_name:=fold_name(p ,n ,'' ); 401 402 end; 403 404{$ENDIF } 405 406 if not app.load_img(0 ,img_name ) then 407 begin 408 img_name:=img_name + #0; 409 ext :=app._img_ext + #0; 410 411 if img_name = 'spheres' then 412 begin 413 sprintf(@buf[0 ] ,'File not found: %s' ,ptrcomp(@img_name[1 ] ) ); 414 sprintf(@buf[StrLen(@buf ) ] ,'%s. Download http://www.antigrain.com/' ,ptrcomp(@ext[1 ] ) ); 415 sprintf(@buf[StrLen(@buf ) ] ,'%s' ,ptrcomp(@img_name[1 ] ) ); 416 sprintf(@buf[StrLen(@buf ) ] ,'%s'#13'or copy it from another directory if available.' ,ptrcomp(@ext[1 ] ) ); 417 418 end 419 else 420 begin 421 sprintf(@buf[0 ] ,'File not found: %s' ,ptrcomp(@img_name[1 ] ) ); 422 sprintf(@buf[StrLen(@buf ) ] ,'%s' ,ptrcomp(@ext[1 ] ) ); 423 424 end; 425 426 app.message_(@buf[0 ] ); 427 428 end 429 else 430 if app.init(600 ,600 ,window_resize ) then 431 app.run; 432 433 app.Destruct; 434 435 g_rasterizer.Destruct; 436 g_scanline.Destruct; 437 438END.