1 //---------------------------------------------------------------------------- 2 // Anti-Grain Geometry (AGG) - Version 2.5 3 // A high quality rendering engine for C++ 4 // Copyright (C) 2002-2006 Maxim Shemanarev 5 // Contact: mcseem@antigrain.com 6 // mcseemagg@yahoo.com 7 // http://antigrain.com 8 // 9 // AGG is free software; you can redistribute it and/or 10 // modify it under the terms of the GNU General Public License 11 // as published by the Free Software Foundation; either version 2 12 // of the License, or (at your option) any later version. 13 // 14 // AGG is distributed in the hope that it will be useful, 15 // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 // GNU General Public License for more details. 18 // 19 // You should have received a copy of the GNU General Public License 20 // along with AGG; if not, write to the Free Software 21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 22 // MA 02110-1301, USA. 23 //---------------------------------------------------------------------------- 24 25 #ifndef AGG_RENDERER_BASE_INCLUDED 26 #define AGG_RENDERER_BASE_INCLUDED 27 28 #include "agg_basics.h" 29 #include "agg_rendering_buffer.h" 30 31 namespace agg 32 { 33 34 //-----------------------------------------------------------renderer_base 35 template<class PixelFormat> class renderer_base 36 { 37 public: 38 typedef PixelFormat pixfmt_type; 39 typedef typename pixfmt_type::color_type color_type; 40 typedef typename pixfmt_type::row_data row_data; 41 42 //-------------------------------------------------------------------- renderer_base()43 renderer_base() : m_ren(0), m_clip_box(1, 1, 0, 0) {} renderer_base(pixfmt_type & ren)44 explicit renderer_base(pixfmt_type& ren) : 45 m_ren(&ren), 46 m_clip_box(0, 0, ren.width() - 1, ren.height() - 1) 47 {} attach(pixfmt_type & ren)48 void attach(pixfmt_type& ren) 49 { 50 m_ren = &ren; 51 m_clip_box = rect_i(0, 0, ren.width() - 1, ren.height() - 1); 52 } 53 54 //-------------------------------------------------------------------- ren()55 const pixfmt_type& ren() const { return *m_ren; } ren()56 pixfmt_type& ren() { return *m_ren; } 57 58 //-------------------------------------------------------------------- width()59 unsigned width() const { return m_ren->width(); } height()60 unsigned height() const { return m_ren->height(); } 61 62 //-------------------------------------------------------------------- clip_box(int x1,int y1,int x2,int y2)63 bool clip_box(int x1, int y1, int x2, int y2) 64 { 65 rect_i cb(x1, y1, x2, y2); 66 cb.normalize(); 67 if(cb.clip(rect_i(0, 0, width() - 1, height() - 1))) 68 { 69 m_clip_box = cb; 70 return true; 71 } 72 m_clip_box.x1 = 1; 73 m_clip_box.y1 = 1; 74 m_clip_box.x2 = 0; 75 m_clip_box.y2 = 0; 76 return false; 77 } 78 79 //-------------------------------------------------------------------- reset_clipping(bool visibility)80 void reset_clipping(bool visibility) 81 { 82 if(visibility) 83 { 84 m_clip_box.x1 = 0; 85 m_clip_box.y1 = 0; 86 m_clip_box.x2 = width() - 1; 87 m_clip_box.y2 = height() - 1; 88 } 89 else 90 { 91 m_clip_box.x1 = 1; 92 m_clip_box.y1 = 1; 93 m_clip_box.x2 = 0; 94 m_clip_box.y2 = 0; 95 } 96 } 97 98 //-------------------------------------------------------------------- clip_box_naked(int x1,int y1,int x2,int y2)99 void clip_box_naked(int x1, int y1, int x2, int y2) 100 { 101 m_clip_box.x1 = x1; 102 m_clip_box.y1 = y1; 103 m_clip_box.x2 = x2; 104 m_clip_box.y2 = y2; 105 } 106 107 //-------------------------------------------------------------------- inbox(int x,int y)108 bool inbox(int x, int y) const 109 { 110 return x >= m_clip_box.x1 && y >= m_clip_box.y1 && 111 x <= m_clip_box.x2 && y <= m_clip_box.y2; 112 } 113 114 //-------------------------------------------------------------------- clip_box()115 const rect_i& clip_box() const { return m_clip_box; } xmin()116 int xmin() const { return m_clip_box.x1; } ymin()117 int ymin() const { return m_clip_box.y1; } xmax()118 int xmax() const { return m_clip_box.x2; } ymax()119 int ymax() const { return m_clip_box.y2; } 120 121 //-------------------------------------------------------------------- bounding_clip_box()122 const rect_i& bounding_clip_box() const { return m_clip_box; } bounding_xmin()123 int bounding_xmin() const { return m_clip_box.x1; } bounding_ymin()124 int bounding_ymin() const { return m_clip_box.y1; } bounding_xmax()125 int bounding_xmax() const { return m_clip_box.x2; } bounding_ymax()126 int bounding_ymax() const { return m_clip_box.y2; } 127 128 //-------------------------------------------------------------------- clear(const color_type & c)129 void clear(const color_type& c) 130 { 131 unsigned y; 132 if(width()) 133 { 134 for(y = 0; y < height(); y++) 135 { 136 m_ren->copy_hline(0, y, width(), c); 137 } 138 } 139 } 140 141 142 //-------------------------------------------------------------------- copy_pixel(int x,int y,const color_type & c)143 void copy_pixel(int x, int y, const color_type& c) 144 { 145 if(inbox(x, y)) 146 { 147 m_ren->copy_pixel(x, y, c); 148 } 149 } 150 151 //-------------------------------------------------------------------- blend_pixel(int x,int y,const color_type & c,cover_type cover)152 void blend_pixel(int x, int y, const color_type& c, cover_type cover) 153 { 154 if(inbox(x, y)) 155 { 156 m_ren->blend_pixel(x, y, c, cover); 157 } 158 } 159 160 //-------------------------------------------------------------------- pixel(int x,int y)161 color_type pixel(int x, int y) const 162 { 163 return inbox(x, y) ? 164 m_ren->pixel(x, y) : 165 color_type::no_color(); 166 } 167 168 //-------------------------------------------------------------------- copy_hline(int x1,int y,int x2,const color_type & c)169 void copy_hline(int x1, int y, int x2, const color_type& c) 170 { 171 if(x1 > x2) { int t = x2; x2 = x1; x1 = t; } 172 if(y > ymax()) return; 173 if(y < ymin()) return; 174 if(x1 > xmax()) return; 175 if(x2 < xmin()) return; 176 177 if(x1 < xmin()) x1 = xmin(); 178 if(x2 > xmax()) x2 = xmax(); 179 180 m_ren->copy_hline(x1, y, x2 - x1 + 1, c); 181 } 182 183 //-------------------------------------------------------------------- copy_vline(int x,int y1,int y2,const color_type & c)184 void copy_vline(int x, int y1, int y2, const color_type& c) 185 { 186 if(y1 > y2) { int t = y2; y2 = y1; y1 = t; } 187 if(x > xmax()) return; 188 if(x < xmin()) return; 189 if(y1 > ymax()) return; 190 if(y2 < ymin()) return; 191 192 if(y1 < ymin()) y1 = ymin(); 193 if(y2 > ymax()) y2 = ymax(); 194 195 m_ren->copy_vline(x, y1, y2 - y1 + 1, c); 196 } 197 198 //-------------------------------------------------------------------- blend_hline(int x1,int y,int x2,const color_type & c,cover_type cover)199 void blend_hline(int x1, int y, int x2, 200 const color_type& c, cover_type cover) 201 { 202 if(x1 > x2) { int t = x2; x2 = x1; x1 = t; } 203 if(y > ymax()) return; 204 if(y < ymin()) return; 205 if(x1 > xmax()) return; 206 if(x2 < xmin()) return; 207 208 if(x1 < xmin()) x1 = xmin(); 209 if(x2 > xmax()) x2 = xmax(); 210 211 m_ren->blend_hline(x1, y, x2 - x1 + 1, c, cover); 212 } 213 214 //-------------------------------------------------------------------- blend_vline(int x,int y1,int y2,const color_type & c,cover_type cover)215 void blend_vline(int x, int y1, int y2, 216 const color_type& c, cover_type cover) 217 { 218 if(y1 > y2) { int t = y2; y2 = y1; y1 = t; } 219 if(x > xmax()) return; 220 if(x < xmin()) return; 221 if(y1 > ymax()) return; 222 if(y2 < ymin()) return; 223 224 if(y1 < ymin()) y1 = ymin(); 225 if(y2 > ymax()) y2 = ymax(); 226 227 m_ren->blend_vline(x, y1, y2 - y1 + 1, c, cover); 228 } 229 230 231 //-------------------------------------------------------------------- copy_bar(int x1,int y1,int x2,int y2,const color_type & c)232 void copy_bar(int x1, int y1, int x2, int y2, const color_type& c) 233 { 234 rect_i rc(x1, y1, x2, y2); 235 rc.normalize(); 236 if(rc.clip(clip_box())) 237 { 238 int y; 239 for(y = rc.y1; y <= rc.y2; y++) 240 { 241 m_ren->copy_hline(rc.x1, y, unsigned(rc.x2 - rc.x1 + 1), c); 242 } 243 } 244 } 245 246 //-------------------------------------------------------------------- blend_bar(int x1,int y1,int x2,int y2,const color_type & c,cover_type cover)247 void blend_bar(int x1, int y1, int x2, int y2, 248 const color_type& c, cover_type cover) 249 { 250 rect_i rc(x1, y1, x2, y2); 251 rc.normalize(); 252 if(rc.clip(clip_box())) 253 { 254 int y; 255 for(y = rc.y1; y <= rc.y2; y++) 256 { 257 m_ren->blend_hline(rc.x1, 258 y, 259 unsigned(rc.x2 - rc.x1 + 1), 260 c, 261 cover); 262 } 263 } 264 } 265 266 //-------------------------------------------------------------------- blend_solid_hspan(int x,int y,int len,const color_type & c,const cover_type * covers)267 void blend_solid_hspan(int x, int y, int len, 268 const color_type& c, 269 const cover_type* covers) 270 { 271 if(y > ymax()) return; 272 if(y < ymin()) return; 273 274 if(x < xmin()) 275 { 276 len -= xmin() - x; 277 if(len <= 0) return; 278 covers += xmin() - x; 279 x = xmin(); 280 } 281 if(x + len > xmax()) 282 { 283 len = xmax() - x + 1; 284 if(len <= 0) return; 285 } 286 m_ren->blend_solid_hspan(x, y, len, c, covers); 287 } 288 289 //-------------------------------------------------------------------- blend_solid_vspan(int x,int y,int len,const color_type & c,const cover_type * covers)290 void blend_solid_vspan(int x, int y, int len, 291 const color_type& c, 292 const cover_type* covers) 293 { 294 if(x > xmax()) return; 295 if(x < xmin()) return; 296 297 if(y < ymin()) 298 { 299 len -= ymin() - y; 300 if(len <= 0) return; 301 covers += ymin() - y; 302 y = ymin(); 303 } 304 if(y + len > ymax()) 305 { 306 len = ymax() - y + 1; 307 if(len <= 0) return; 308 } 309 m_ren->blend_solid_vspan(x, y, len, c, covers); 310 } 311 312 313 //-------------------------------------------------------------------- copy_color_hspan(int x,int y,int len,const color_type * colors)314 void copy_color_hspan(int x, int y, int len, const color_type* colors) 315 { 316 if(y > ymax()) return; 317 if(y < ymin()) return; 318 319 if(x < xmin()) 320 { 321 int d = xmin() - x; 322 len -= d; 323 if(len <= 0) return; 324 colors += d; 325 x = xmin(); 326 } 327 if(x + len > xmax()) 328 { 329 len = xmax() - x + 1; 330 if(len <= 0) return; 331 } 332 m_ren->copy_color_hspan(x, y, len, colors); 333 } 334 335 336 //-------------------------------------------------------------------- copy_color_vspan(int x,int y,int len,const color_type * colors)337 void copy_color_vspan(int x, int y, int len, const color_type* colors) 338 { 339 if(x > xmax()) return; 340 if(x < xmin()) return; 341 342 if(y < ymin()) 343 { 344 int d = ymin() - y; 345 len -= d; 346 if(len <= 0) return; 347 colors += d; 348 y = ymin(); 349 } 350 if(y + len > ymax()) 351 { 352 len = ymax() - y + 1; 353 if(len <= 0) return; 354 } 355 m_ren->copy_color_vspan(x, y, len, colors); 356 } 357 358 359 //-------------------------------------------------------------------- 360 void blend_color_hspan(int x, int y, int len, 361 const color_type* colors, 362 const cover_type* covers, 363 cover_type cover = agg::cover_full) 364 { 365 if(y > ymax()) return; 366 if(y < ymin()) return; 367 368 if(x < xmin()) 369 { 370 int d = xmin() - x; 371 len -= d; 372 if(len <= 0) return; 373 if(covers) covers += d; 374 colors += d; 375 x = xmin(); 376 } 377 if(x + len > xmax()) 378 { 379 len = xmax() - x + 1; 380 if(len <= 0) return; 381 } 382 m_ren->blend_color_hspan(x, y, len, colors, covers, cover); 383 } 384 385 //-------------------------------------------------------------------- 386 void blend_color_vspan(int x, int y, int len, 387 const color_type* colors, 388 const cover_type* covers, 389 cover_type cover = agg::cover_full) 390 { 391 if(x > xmax()) return; 392 if(x < xmin()) return; 393 394 if(y < ymin()) 395 { 396 int d = ymin() - y; 397 len -= d; 398 if(len <= 0) return; 399 if(covers) covers += d; 400 colors += d; 401 y = ymin(); 402 } 403 if(y + len > ymax()) 404 { 405 len = ymax() - y + 1; 406 if(len <= 0) return; 407 } 408 m_ren->blend_color_vspan(x, y, len, colors, covers, cover); 409 } 410 411 //-------------------------------------------------------------------- clip_rect_area(rect_i & dst,rect_i & src,int wsrc,int hsrc)412 rect_i clip_rect_area(rect_i& dst, rect_i& src, int wsrc, int hsrc) const 413 { 414 rect_i rc(0,0,0,0); 415 rect_i cb = clip_box(); 416 ++cb.x2; 417 ++cb.y2; 418 419 if(src.x1 < 0) 420 { 421 dst.x1 -= src.x1; 422 src.x1 = 0; 423 } 424 if(src.y1 < 0) 425 { 426 dst.y1 -= src.y1; 427 src.y1 = 0; 428 } 429 430 if(src.x2 > wsrc) src.x2 = wsrc; 431 if(src.y2 > hsrc) src.y2 = hsrc; 432 433 if(dst.x1 < cb.x1) 434 { 435 src.x1 += cb.x1 - dst.x1; 436 dst.x1 = cb.x1; 437 } 438 if(dst.y1 < cb.y1) 439 { 440 src.y1 += cb.y1 - dst.y1; 441 dst.y1 = cb.y1; 442 } 443 444 if(dst.x2 > cb.x2) dst.x2 = cb.x2; 445 if(dst.y2 > cb.y2) dst.y2 = cb.y2; 446 447 rc.x2 = dst.x2 - dst.x1; 448 rc.y2 = dst.y2 - dst.y1; 449 450 if(rc.x2 > src.x2 - src.x1) rc.x2 = src.x2 - src.x1; 451 if(rc.y2 > src.y2 - src.y1) rc.y2 = src.y2 - src.y1; 452 return rc; 453 } 454 455 //-------------------------------------------------------------------- 456 template<class RenBuf> 457 void copy_from(const RenBuf& src, 458 const rect_i* rect_src_ptr = 0, 459 int dx = 0, 460 int dy = 0) 461 { 462 rect_i rsrc(0, 0, src.width(), src.height()); 463 if(rect_src_ptr) 464 { 465 rsrc.x1 = rect_src_ptr->x1; 466 rsrc.y1 = rect_src_ptr->y1; 467 rsrc.x2 = rect_src_ptr->x2 + 1; 468 rsrc.y2 = rect_src_ptr->y2 + 1; 469 } 470 471 // Version with xdst, ydst (absolute positioning) 472 //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); 473 474 // Version with dx, dy (relative positioning) 475 rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); 476 477 rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); 478 479 if(rc.x2 > 0) 480 { 481 int incy = 1; 482 if(rdst.y1 > rsrc.y1) 483 { 484 rsrc.y1 += rc.y2 - 1; 485 rdst.y1 += rc.y2 - 1; 486 incy = -1; 487 } 488 while(rc.y2 > 0) 489 { 490 m_ren->copy_from(src, 491 rdst.x1, rdst.y1, 492 rsrc.x1, rsrc.y1, 493 rc.x2); 494 rdst.y1 += incy; 495 rsrc.y1 += incy; 496 --rc.y2; 497 } 498 } 499 } 500 501 //-------------------------------------------------------------------- 502 template<class SrcPixelFormatRenderer> 503 void blend_from(const SrcPixelFormatRenderer& src, 504 const rect_i* rect_src_ptr = 0, 505 int dx = 0, 506 int dy = 0, 507 cover_type cover = agg::cover_full) 508 { 509 rect_i rsrc(0, 0, src.width(), src.height()); 510 if(rect_src_ptr) 511 { 512 rsrc.x1 = rect_src_ptr->x1; 513 rsrc.y1 = rect_src_ptr->y1; 514 rsrc.x2 = rect_src_ptr->x2 + 1; 515 rsrc.y2 = rect_src_ptr->y2 + 1; 516 } 517 518 // Version with xdst, ydst (absolute positioning) 519 //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); 520 521 // Version with dx, dy (relative positioning) 522 rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); 523 rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); 524 525 if(rc.x2 > 0) 526 { 527 int incy = 1; 528 if(rdst.y1 > rsrc.y1) 529 { 530 rsrc.y1 += rc.y2 - 1; 531 rdst.y1 += rc.y2 - 1; 532 incy = -1; 533 } 534 while(rc.y2 > 0) 535 { 536 typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1); 537 if(rw.ptr) 538 { 539 int x1src = rsrc.x1; 540 int x1dst = rdst.x1; 541 int len = rc.x2; 542 if(rw.x1 > x1src) 543 { 544 x1dst += rw.x1 - x1src; 545 len -= rw.x1 - x1src; 546 x1src = rw.x1; 547 } 548 if(len > 0) 549 { 550 if(x1src + len-1 > rw.x2) 551 { 552 len -= x1src + len - rw.x2 - 1; 553 } 554 if(len > 0) 555 { 556 m_ren->blend_from(src, 557 x1dst, rdst.y1, 558 x1src, rsrc.y1, 559 len, 560 cover); 561 } 562 } 563 } 564 rdst.y1 += incy; 565 rsrc.y1 += incy; 566 --rc.y2; 567 } 568 } 569 } 570 571 //-------------------------------------------------------------------- 572 template<class SrcPixelFormatRenderer> 573 void blend_from_color(const SrcPixelFormatRenderer& src, 574 const color_type& color, 575 const rect_i* rect_src_ptr = 0, 576 int dx = 0, 577 int dy = 0, 578 cover_type cover = agg::cover_full) 579 { 580 rect_i rsrc(0, 0, src.width(), src.height()); 581 if(rect_src_ptr) 582 { 583 rsrc.x1 = rect_src_ptr->x1; 584 rsrc.y1 = rect_src_ptr->y1; 585 rsrc.x2 = rect_src_ptr->x2 + 1; 586 rsrc.y2 = rect_src_ptr->y2 + 1; 587 } 588 589 // Version with xdst, ydst (absolute positioning) 590 //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); 591 592 // Version with dx, dy (relative positioning) 593 rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); 594 rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); 595 596 if(rc.x2 > 0) 597 { 598 int incy = 1; 599 if(rdst.y1 > rsrc.y1) 600 { 601 rsrc.y1 += rc.y2 - 1; 602 rdst.y1 += rc.y2 - 1; 603 incy = -1; 604 } 605 while(rc.y2 > 0) 606 { 607 typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1); 608 if(rw.ptr) 609 { 610 int x1src = rsrc.x1; 611 int x1dst = rdst.x1; 612 int len = rc.x2; 613 if(rw.x1 > x1src) 614 { 615 x1dst += rw.x1 - x1src; 616 len -= rw.x1 - x1src; 617 x1src = rw.x1; 618 } 619 if(len > 0) 620 { 621 if(x1src + len-1 > rw.x2) 622 { 623 len -= x1src + len - rw.x2 - 1; 624 } 625 if(len > 0) 626 { 627 m_ren->blend_from_color(src, 628 color, 629 x1dst, rdst.y1, 630 x1src, rsrc.y1, 631 len, 632 cover); 633 } 634 } 635 } 636 rdst.y1 += incy; 637 rsrc.y1 += incy; 638 --rc.y2; 639 } 640 } 641 } 642 643 //-------------------------------------------------------------------- 644 template<class SrcPixelFormatRenderer> 645 void blend_from_lut(const SrcPixelFormatRenderer& src, 646 const color_type* color_lut, 647 const rect_i* rect_src_ptr = 0, 648 int dx = 0, 649 int dy = 0, 650 cover_type cover = agg::cover_full) 651 { 652 rect_i rsrc(0, 0, src.width(), src.height()); 653 if(rect_src_ptr) 654 { 655 rsrc.x1 = rect_src_ptr->x1; 656 rsrc.y1 = rect_src_ptr->y1; 657 rsrc.x2 = rect_src_ptr->x2 + 1; 658 rsrc.y2 = rect_src_ptr->y2 + 1; 659 } 660 661 // Version with xdst, ydst (absolute positioning) 662 //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); 663 664 // Version with dx, dy (relative positioning) 665 rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); 666 rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); 667 668 if(rc.x2 > 0) 669 { 670 int incy = 1; 671 if(rdst.y1 > rsrc.y1) 672 { 673 rsrc.y1 += rc.y2 - 1; 674 rdst.y1 += rc.y2 - 1; 675 incy = -1; 676 } 677 while(rc.y2 > 0) 678 { 679 typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1); 680 if(rw.ptr) 681 { 682 int x1src = rsrc.x1; 683 int x1dst = rdst.x1; 684 int len = rc.x2; 685 if(rw.x1 > x1src) 686 { 687 x1dst += rw.x1 - x1src; 688 len -= rw.x1 - x1src; 689 x1src = rw.x1; 690 } 691 if(len > 0) 692 { 693 if(x1src + len-1 > rw.x2) 694 { 695 len -= x1src + len - rw.x2 - 1; 696 } 697 if(len > 0) 698 { 699 m_ren->blend_from_lut(src, 700 color_lut, 701 x1dst, rdst.y1, 702 x1src, rsrc.y1, 703 len, 704 cover); 705 } 706 } 707 } 708 rdst.y1 += incy; 709 rsrc.y1 += incy; 710 --rc.y2; 711 } 712 } 713 } 714 715 private: 716 pixfmt_type* m_ren; 717 rect_i m_clip_box; 718 }; 719 720 721 } 722 723 #endif 724