1 //---------------------------------------------------------------------------- 2 // Anti-Grain Geometry - Version 2.4 3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) 4 // 5 // Permission to copy, use, modify, sell and distribute this software 6 // is granted provided this copyright notice appears in all copies. 7 // This software is provided "as is" without express or implied 8 // warranty, and with no claim as to its suitability for any purpose. 9 // 10 //---------------------------------------------------------------------------- 11 // Contact: mcseem@antigrain.com 12 // mcseemagg@yahoo.com 13 // http://www.antigrain.com 14 //---------------------------------------------------------------------------- 15 // 16 // class renderer_base 17 // 18 //---------------------------------------------------------------------------- 19 20 #ifndef AGG_RENDERER_BASE_INCLUDED 21 #define AGG_RENDERER_BASE_INCLUDED 22 23 #include "agg_basics.h" 24 #include "agg_rendering_buffer.h" 25 26 namespace agg 27 { 28 29 //-----------------------------------------------------------renderer_base 30 template<class PixelFormat> class renderer_base 31 { 32 public: 33 typedef PixelFormat pixfmt_type; 34 typedef typename pixfmt_type::color_type color_type; 35 typedef typename pixfmt_type::row_data row_data; 36 37 //-------------------------------------------------------------------- 38 renderer_base() : m_ren(0), m_clip_box(1, 1, 0, 0) {} 39 renderer_base(pixfmt_type& ren) : 40 m_ren(&ren), 41 m_clip_box(0, 0, ren.width() - 1, ren.height() - 1) 42 {} 43 void attach(pixfmt_type& ren) 44 { 45 m_ren = &ren; 46 m_clip_box = rect_i(0, 0, ren.width() - 1, ren.height() - 1); 47 } 48 49 //-------------------------------------------------------------------- 50 const pixfmt_type& ren() const { return *m_ren; } 51 pixfmt_type& ren() { return *m_ren; } 52 53 //-------------------------------------------------------------------- 54 unsigned width() const { return m_ren->width(); } 55 unsigned height() const { return m_ren->height(); } 56 57 //-------------------------------------------------------------------- 58 bool clip_box(int x1, int y1, int x2, int y2) 59 { 60 rect_i cb(x1, y1, x2, y2); 61 cb.normalize(); 62 if(cb.clip(rect_i(0, 0, width() - 1, height() - 1))) 63 { 64 m_clip_box = cb; 65 return true; 66 } 67 m_clip_box.x1 = 1; 68 m_clip_box.y1 = 1; 69 m_clip_box.x2 = 0; 70 m_clip_box.y2 = 0; 71 return false; 72 } 73 74 //-------------------------------------------------------------------- 75 void reset_clipping(bool visibility) 76 { 77 if(visibility) 78 { 79 m_clip_box.x1 = 0; 80 m_clip_box.y1 = 0; 81 m_clip_box.x2 = width() - 1; 82 m_clip_box.y2 = height() - 1; 83 } 84 else 85 { 86 m_clip_box.x1 = 1; 87 m_clip_box.y1 = 1; 88 m_clip_box.x2 = 0; 89 m_clip_box.y2 = 0; 90 } 91 } 92 93 //-------------------------------------------------------------------- 94 void clip_box_naked(int x1, int y1, int x2, int y2) 95 { 96 m_clip_box.x1 = x1; 97 m_clip_box.y1 = y1; 98 m_clip_box.x2 = x2; 99 m_clip_box.y2 = y2; 100 } 101 102 //-------------------------------------------------------------------- 103 bool inbox(int x, int y) const 104 { 105 return x >= m_clip_box.x1 && y >= m_clip_box.y1 && 106 x <= m_clip_box.x2 && y <= m_clip_box.y2; 107 } 108 109 //-------------------------------------------------------------------- 110 const rect_i& clip_box() const { return m_clip_box; } 111 int xmin() const { return m_clip_box.x1; } 112 int ymin() const { return m_clip_box.y1; } 113 int xmax() const { return m_clip_box.x2; } 114 int ymax() const { return m_clip_box.y2; } 115 116 //-------------------------------------------------------------------- 117 const rect_i& bounding_clip_box() const { return m_clip_box; } 118 int bounding_xmin() const { return m_clip_box.x1; } 119 int bounding_ymin() const { return m_clip_box.y1; } 120 int bounding_xmax() const { return m_clip_box.x2; } 121 int bounding_ymax() const { return m_clip_box.y2; } 122 123 //-------------------------------------------------------------------- 124 void clear(const color_type& c) 125 { 126 unsigned y; 127 if(width()) 128 { 129 for(y = 0; y < height(); y++) 130 { 131 m_ren->copy_hline(0, y, width(), c); 132 } 133 } 134 } 135 136 137 //-------------------------------------------------------------------- 138 void copy_pixel(int x, int y, const color_type& c) 139 { 140 if(inbox(x, y)) 141 { 142 m_ren->copy_pixel(x, y, c); 143 } 144 } 145 146 //-------------------------------------------------------------------- 147 void blend_pixel(int x, int y, const color_type& c, cover_type cover) 148 { 149 if(inbox(x, y)) 150 { 151 m_ren->blend_pixel(x, y, c, cover); 152 } 153 } 154 155 //-------------------------------------------------------------------- 156 color_type pixel(int x, int y) const 157 { 158 return inbox(x, y) ? 159 m_ren->pixel(x, y) : 160 color_type::no_color(); 161 } 162 163 //-------------------------------------------------------------------- 164 void copy_hline(int x1, int y, int x2, const color_type& c) 165 { 166 if(x1 > x2) { int t = x2; x2 = x1; x1 = t; } 167 if(y > ymax()) return; 168 if(y < ymin()) return; 169 if(x1 > xmax()) return; 170 if(x2 < xmin()) return; 171 172 if(x1 < xmin()) x1 = xmin(); 173 if(x2 > xmax()) x2 = xmax(); 174 175 m_ren->copy_hline(x1, y, x2 - x1 + 1, c); 176 } 177 178 //-------------------------------------------------------------------- 179 void copy_vline(int x, int y1, int y2, const color_type& c) 180 { 181 if(y1 > y2) { int t = y2; y2 = y1; y1 = t; } 182 if(x > xmax()) return; 183 if(x < xmin()) return; 184 if(y1 > ymax()) return; 185 if(y2 < ymin()) return; 186 187 if(y1 < ymin()) y1 = ymin(); 188 if(y2 > ymax()) y2 = ymax(); 189 190 m_ren->copy_vline(x, y1, y2 - y1 + 1, c); 191 } 192 193 //-------------------------------------------------------------------- 194 void blend_hline(int x1, int y, int x2, 195 const color_type& c, cover_type cover) 196 { 197 if(x1 > x2) { int t = x2; x2 = x1; x1 = t; } 198 if(y > ymax()) return; 199 if(y < ymin()) return; 200 if(x1 > xmax()) return; 201 if(x2 < xmin()) return; 202 203 if(x1 < xmin()) x1 = xmin(); 204 if(x2 > xmax()) x2 = xmax(); 205 206 m_ren->blend_hline(x1, y, x2 - x1 + 1, c, cover); 207 } 208 209 210 //-------------------------------------------------------------------- 211 void blend_vline(int x, int y1, int y2, 212 const color_type& c, cover_type cover) 213 { 214 if(y1 > y2) { int t = y2; y2 = y1; y1 = t; } 215 if(x > xmax()) return; 216 if(x < xmin()) return; 217 if(y1 > ymax()) return; 218 if(y2 < ymin()) return; 219 220 if(y1 < ymin()) y1 = ymin(); 221 if(y2 > ymax()) y2 = ymax(); 222 223 m_ren->blend_vline(x, y1, y2 - y1 + 1, c, cover); 224 } 225 226 227 //-------------------------------------------------------------------- 228 void copy_bar(int x1, int y1, int x2, int y2, const color_type& c) 229 { 230 rect_i rc(x1, y1, x2, y2); 231 rc.normalize(); 232 if(rc.clip(clip_box())) 233 { 234 int y; 235 for(y = rc.y1; y <= rc.y2; y++) 236 { 237 m_ren->copy_hline(rc.x1, y, unsigned(rc.x2 - rc.x1 + 1), c); 238 } 239 } 240 } 241 242 //-------------------------------------------------------------------- 243 void blend_bar(int x1, int y1, int x2, int y2, 244 const color_type& c, cover_type cover) 245 { 246 rect_i rc(x1, y1, x2, y2); 247 rc.normalize(); 248 if(rc.clip(clip_box())) 249 { 250 int y; 251 for(y = rc.y1; y <= rc.y2; y++) 252 { 253 m_ren->blend_hline(rc.x1, 254 y, 255 unsigned(rc.x2 - rc.x1 + 1), 256 c, 257 cover); 258 } 259 } 260 } 261 262 //-------------------------------------------------------------------- 263 void blend_solid_hspan(int x, int y, int len, 264 const color_type& c, 265 const cover_type* covers) 266 { 267 if(y > ymax()) return; 268 if(y < ymin()) return; 269 270 if(x < xmin()) 271 { 272 len -= xmin() - x; 273 if(len <= 0) return; 274 covers += xmin() - x; 275 x = xmin(); 276 } 277 if(x + len > xmax()) 278 { 279 len = xmax() - x + 1; 280 if(len <= 0) return; 281 } 282 m_ren->blend_solid_hspan(x, y, len, c, covers); 283 } 284 285 //-------------------------------------------------------------------- 286 void blend_solid_hspan_subpix(int x, int y, int len, 287 const color_type& c, 288 const cover_type* covers) 289 { 290 if(y > ymax()) return; 291 if(y < ymin()) return; 292 293 if(x < xmin()) 294 { 295 len -= 3 * (xmin() - x); 296 if(len <= 0) return; 297 covers += 3 * (xmin() - x); 298 x = xmin(); 299 } 300 if(x + len / 3 > xmax()) 301 { 302 len = 3 * (xmax() - x + 1); 303 if(len <= 0) return; 304 } 305 m_ren->blend_solid_hspan_subpix(x, y, len, c, covers); 306 } 307 308 //-------------------------------------------------------------------- 309 void blend_solid_vspan(int x, int y, int len, 310 const color_type& c, 311 const cover_type* covers) 312 { 313 if(x > xmax()) return; 314 if(x < xmin()) return; 315 316 if(y < ymin()) 317 { 318 len -= ymin() - y; 319 if(len <= 0) return; 320 covers += ymin() - y; 321 y = ymin(); 322 } 323 if(y + len > ymax()) 324 { 325 len = ymax() - y + 1; 326 if(len <= 0) return; 327 } 328 m_ren->blend_solid_vspan(x, y, len, c, covers); 329 } 330 331 332 //-------------------------------------------------------------------- 333 void copy_color_hspan(int x, int y, int len, const color_type* colors) 334 { 335 if(y > ymax()) return; 336 if(y < ymin()) return; 337 338 if(x < xmin()) 339 { 340 int d = xmin() - x; 341 len -= d; 342 if(len <= 0) return; 343 colors += d; 344 x = xmin(); 345 } 346 if(x + len > xmax()) 347 { 348 len = xmax() - x + 1; 349 if(len <= 0) return; 350 } 351 m_ren->copy_color_hspan(x, y, len, colors); 352 } 353 354 355 //-------------------------------------------------------------------- 356 void copy_color_vspan(int x, int y, int len, const color_type* colors) 357 { 358 if(x > xmax()) return; 359 if(x < xmin()) return; 360 361 if(y < ymin()) 362 { 363 int d = ymin() - y; 364 len -= d; 365 if(len <= 0) return; 366 colors += d; 367 y = ymin(); 368 } 369 if(y + len > ymax()) 370 { 371 len = ymax() - y + 1; 372 if(len <= 0) return; 373 } 374 m_ren->copy_color_vspan(x, y, len, colors); 375 } 376 377 378 //-------------------------------------------------------------------- 379 void blend_color_hspan(int x, int y, int len, 380 const color_type* colors, 381 const cover_type* covers, 382 cover_type cover = agg::cover_full) 383 { 384 if(y > ymax()) return; 385 if(y < ymin()) return; 386 387 if(x < xmin()) 388 { 389 int d = xmin() - x; 390 len -= d; 391 if(len <= 0) return; 392 if(covers) covers += d; 393 colors += d; 394 x = xmin(); 395 } 396 if(x + len > xmax()) 397 { 398 len = xmax() - x + 1; 399 if(len <= 0) return; 400 } 401 m_ren->blend_color_hspan(x, y, len, colors, covers, cover); 402 } 403 404 //-------------------------------------------------------------------- 405 void blend_color_vspan(int x, int y, int len, 406 const color_type* colors, 407 const cover_type* covers, 408 cover_type cover = agg::cover_full) 409 { 410 if(x > xmax()) return; 411 if(x < xmin()) return; 412 413 if(y < ymin()) 414 { 415 int d = ymin() - y; 416 len -= d; 417 if(len <= 0) return; 418 if(covers) covers += d; 419 colors += d; 420 y = ymin(); 421 } 422 if(y + len > ymax()) 423 { 424 len = ymax() - y + 1; 425 if(len <= 0) return; 426 } 427 m_ren->blend_color_vspan(x, y, len, colors, covers, cover); 428 } 429 430 //-------------------------------------------------------------------- 431 rect_i clip_rect_area(rect_i& dst, rect_i& src, int wsrc, int hsrc) const 432 { 433 rect_i rc(0,0,0,0); 434 rect_i cb = clip_box(); 435 ++cb.x2; 436 ++cb.y2; 437 438 if(src.x1 < 0) 439 { 440 dst.x1 -= src.x1; 441 src.x1 = 0; 442 } 443 if(src.y1 < 0) 444 { 445 dst.y1 -= src.y1; 446 src.y1 = 0; 447 } 448 449 if(src.x2 > wsrc) src.x2 = wsrc; 450 if(src.y2 > hsrc) src.y2 = hsrc; 451 452 if(dst.x1 < cb.x1) 453 { 454 src.x1 += cb.x1 - dst.x1; 455 dst.x1 = cb.x1; 456 } 457 if(dst.y1 < cb.y1) 458 { 459 src.y1 += cb.y1 - dst.y1; 460 dst.y1 = cb.y1; 461 } 462 463 if(dst.x2 > cb.x2) dst.x2 = cb.x2; 464 if(dst.y2 > cb.y2) dst.y2 = cb.y2; 465 466 rc.x2 = dst.x2 - dst.x1; 467 rc.y2 = dst.y2 - dst.y1; 468 469 if(rc.x2 > src.x2 - src.x1) rc.x2 = src.x2 - src.x1; 470 if(rc.y2 > src.y2 - src.y1) rc.y2 = src.y2 - src.y1; 471 return rc; 472 } 473 474 //-------------------------------------------------------------------- 475 template<class RenBuf> 476 void copy_from(const RenBuf& src, 477 const rect_i* rect_src_ptr = 0, 478 int dx = 0, 479 int dy = 0) 480 { 481 rect_i rsrc(0, 0, src.width(), src.height()); 482 if(rect_src_ptr) 483 { 484 rsrc.x1 = rect_src_ptr->x1; 485 rsrc.y1 = rect_src_ptr->y1; 486 rsrc.x2 = rect_src_ptr->x2 + 1; 487 rsrc.y2 = rect_src_ptr->y2 + 1; 488 } 489 490 // Version with xdst, ydst (absolute positioning) 491 //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); 492 493 // Version with dx, dy (relative positioning) 494 rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); 495 496 rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); 497 498 if(rc.x2 > 0) 499 { 500 int incy = 1; 501 if(rdst.y1 > rsrc.y1) 502 { 503 rsrc.y1 += rc.y2 - 1; 504 rdst.y1 += rc.y2 - 1; 505 incy = -1; 506 } 507 while(rc.y2 > 0) 508 { 509 m_ren->copy_from(src, 510 rdst.x1, rdst.y1, 511 rsrc.x1, rsrc.y1, 512 rc.x2); 513 rdst.y1 += incy; 514 rsrc.y1 += incy; 515 --rc.y2; 516 } 517 } 518 } 519 520 //-------------------------------------------------------------------- 521 template<class SrcPixelFormatRenderer> 522 void blend_from(const SrcPixelFormatRenderer& src, 523 const rect_i* rect_src_ptr = 0, 524 int dx = 0, 525 int dy = 0, 526 cover_type cover = agg::cover_full) 527 { 528 rect_i rsrc(0, 0, src.width(), src.height()); 529 if(rect_src_ptr) 530 { 531 rsrc.x1 = rect_src_ptr->x1; 532 rsrc.y1 = rect_src_ptr->y1; 533 rsrc.x2 = rect_src_ptr->x2 + 1; 534 rsrc.y2 = rect_src_ptr->y2 + 1; 535 } 536 537 // Version with xdst, ydst (absolute positioning) 538 //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); 539 540 // Version with dx, dy (relative positioning) 541 rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); 542 rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); 543 544 if(rc.x2 > 0) 545 { 546 int incy = 1; 547 if(rdst.y1 > rsrc.y1) 548 { 549 rsrc.y1 += rc.y2 - 1; 550 rdst.y1 += rc.y2 - 1; 551 incy = -1; 552 } 553 while(rc.y2 > 0) 554 { 555 typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1); 556 if(rw.ptr) 557 { 558 int x1src = rsrc.x1; 559 int x1dst = rdst.x1; 560 int len = rc.x2; 561 if(rw.x1 > x1src) 562 { 563 x1dst += rw.x1 - x1src; 564 len -= rw.x1 - x1src; 565 x1src = rw.x1; 566 } 567 if(len > 0) 568 { 569 if(x1src + len-1 > rw.x2) 570 { 571 len -= x1src + len - rw.x2 - 1; 572 } 573 if(len > 0) 574 { 575 m_ren->blend_from(src, 576 x1dst, rdst.y1, 577 x1src, rsrc.y1, 578 len, 579 cover); 580 } 581 } 582 } 583 rdst.y1 += incy; 584 rsrc.y1 += incy; 585 --rc.y2; 586 } 587 } 588 } 589 590 private: 591 pixfmt_type* m_ren; 592 rect_i m_clip_box; 593 }; 594 595 596 } 597 598 #endif 599