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 void blend_vline(int x, int y1, int y2, 211 const color_type& c, cover_type cover) 212 { 213 if(y1 > y2) { int t = y2; y2 = y1; y1 = t; } 214 if(x > xmax()) return; 215 if(x < xmin()) return; 216 if(y1 > ymax()) return; 217 if(y2 < ymin()) return; 218 219 if(y1 < ymin()) y1 = ymin(); 220 if(y2 > ymax()) y2 = ymax(); 221 222 m_ren->blend_vline(x, y1, y2 - y1 + 1, c, cover); 223 } 224 225 226 //-------------------------------------------------------------------- 227 void copy_bar(int x1, int y1, int x2, int y2, const color_type& c) 228 { 229 rect_i rc(x1, y1, x2, y2); 230 rc.normalize(); 231 if(rc.clip(clip_box())) 232 { 233 int y; 234 for(y = rc.y1; y <= rc.y2; y++) 235 { 236 m_ren->copy_hline(rc.x1, y, unsigned(rc.x2 - rc.x1 + 1), c); 237 } 238 } 239 } 240 241 //-------------------------------------------------------------------- 242 void blend_bar(int x1, int y1, int x2, int y2, 243 const color_type& c, cover_type cover) 244 { 245 rect_i rc(x1, y1, x2, y2); 246 rc.normalize(); 247 if(rc.clip(clip_box())) 248 { 249 int y; 250 for(y = rc.y1; y <= rc.y2; y++) 251 { 252 m_ren->blend_hline(rc.x1, 253 y, 254 unsigned(rc.x2 - rc.x1 + 1), 255 c, 256 cover); 257 } 258 } 259 } 260 261 //-------------------------------------------------------------------- 262 void blend_solid_hspan(int x, int y, int len, 263 const color_type& c, 264 const cover_type* covers) 265 { 266 if(y > ymax()) return; 267 if(y < ymin()) return; 268 269 if(x < xmin()) 270 { 271 len -= xmin() - x; 272 if(len <= 0) return; 273 covers += xmin() - x; 274 x = xmin(); 275 } 276 if(x + len > xmax()) 277 { 278 len = xmax() - x + 1; 279 if(len <= 0) return; 280 } 281 m_ren->blend_solid_hspan(x, y, len, c, covers); 282 } 283 284 //-------------------------------------------------------------------- 285 void blend_solid_vspan(int x, int y, int len, 286 const color_type& c, 287 const cover_type* covers) 288 { 289 if(x > xmax()) return; 290 if(x < xmin()) return; 291 292 if(y < ymin()) 293 { 294 len -= ymin() - y; 295 if(len <= 0) return; 296 covers += ymin() - y; 297 y = ymin(); 298 } 299 if(y + len > ymax()) 300 { 301 len = ymax() - y + 1; 302 if(len <= 0) return; 303 } 304 m_ren->blend_solid_vspan(x, y, len, c, covers); 305 } 306 307 308 //-------------------------------------------------------------------- 309 void copy_color_hspan(int x, int y, int len, const color_type* colors) 310 { 311 if(y > ymax()) return; 312 if(y < ymin()) return; 313 314 if(x < xmin()) 315 { 316 int d = xmin() - x; 317 len -= d; 318 if(len <= 0) return; 319 colors += d; 320 x = xmin(); 321 } 322 if(x + len > xmax()) 323 { 324 len = xmax() - x + 1; 325 if(len <= 0) return; 326 } 327 m_ren->copy_color_hspan(x, y, len, colors); 328 } 329 330 331 //-------------------------------------------------------------------- 332 void copy_color_vspan(int x, int y, int len, const color_type* colors) 333 { 334 if(x > xmax()) return; 335 if(x < xmin()) return; 336 337 if(y < ymin()) 338 { 339 int d = ymin() - y; 340 len -= d; 341 if(len <= 0) return; 342 colors += d; 343 y = ymin(); 344 } 345 if(y + len > ymax()) 346 { 347 len = ymax() - y + 1; 348 if(len <= 0) return; 349 } 350 m_ren->copy_color_vspan(x, y, len, colors); 351 } 352 353 354 //-------------------------------------------------------------------- 355 void blend_color_hspan(int x, int y, int len, 356 const color_type* colors, 357 const cover_type* covers, 358 cover_type cover = agg::cover_full) 359 { 360 if(y > ymax()) return; 361 if(y < ymin()) return; 362 363 if(x < xmin()) 364 { 365 int d = xmin() - x; 366 len -= d; 367 if(len <= 0) return; 368 if(covers) covers += d; 369 colors += d; 370 x = xmin(); 371 } 372 if(x + len > xmax()) 373 { 374 len = xmax() - x + 1; 375 if(len <= 0) return; 376 } 377 m_ren->blend_color_hspan(x, y, len, colors, covers, cover); 378 } 379 380 //-------------------------------------------------------------------- 381 void blend_color_vspan(int x, int y, int len, 382 const color_type* colors, 383 const cover_type* covers, 384 cover_type cover = agg::cover_full) 385 { 386 if(x > xmax()) return; 387 if(x < xmin()) return; 388 389 if(y < ymin()) 390 { 391 int d = ymin() - y; 392 len -= d; 393 if(len <= 0) return; 394 if(covers) covers += d; 395 colors += d; 396 y = ymin(); 397 } 398 if(y + len > ymax()) 399 { 400 len = ymax() - y + 1; 401 if(len <= 0) return; 402 } 403 m_ren->blend_color_vspan(x, y, len, colors, covers, cover); 404 } 405 406 //-------------------------------------------------------------------- 407 rect_i clip_rect_area(rect_i& dst, rect_i& src, int wsrc, int hsrc) const 408 { 409 rect_i rc(0,0,0,0); 410 rect_i cb = clip_box(); 411 ++cb.x2; 412 ++cb.y2; 413 414 if(src.x1 < 0) 415 { 416 dst.x1 -= src.x1; 417 src.x1 = 0; 418 } 419 if(src.y1 < 0) 420 { 421 dst.y1 -= src.y1; 422 src.y1 = 0; 423 } 424 425 if(src.x2 > wsrc) src.x2 = wsrc; 426 if(src.y2 > hsrc) src.y2 = hsrc; 427 428 if(dst.x1 < cb.x1) 429 { 430 src.x1 += cb.x1 - dst.x1; 431 dst.x1 = cb.x1; 432 } 433 if(dst.y1 < cb.y1) 434 { 435 src.y1 += cb.y1 - dst.y1; 436 dst.y1 = cb.y1; 437 } 438 439 if(dst.x2 > cb.x2) dst.x2 = cb.x2; 440 if(dst.y2 > cb.y2) dst.y2 = cb.y2; 441 442 rc.x2 = dst.x2 - dst.x1; 443 rc.y2 = dst.y2 - dst.y1; 444 445 if(rc.x2 > src.x2 - src.x1) rc.x2 = src.x2 - src.x1; 446 if(rc.y2 > src.y2 - src.y1) rc.y2 = src.y2 - src.y1; 447 return rc; 448 } 449 450 //-------------------------------------------------------------------- 451 template<class RenBuf> 452 void copy_from(const RenBuf& src, 453 const rect_i* rect_src_ptr = 0, 454 int dx = 0, 455 int dy = 0) 456 { 457 rect_i rsrc(0, 0, src.width(), src.height()); 458 if(rect_src_ptr) 459 { 460 rsrc.x1 = rect_src_ptr->x1; 461 rsrc.y1 = rect_src_ptr->y1; 462 rsrc.x2 = rect_src_ptr->x2 + 1; 463 rsrc.y2 = rect_src_ptr->y2 + 1; 464 } 465 466 // Version with xdst, ydst (absolute positioning) 467 //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); 468 469 // Version with dx, dy (relative positioning) 470 rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); 471 472 rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); 473 474 if(rc.x2 > 0) 475 { 476 int incy = 1; 477 if(rdst.y1 > rsrc.y1) 478 { 479 rsrc.y1 += rc.y2 - 1; 480 rdst.y1 += rc.y2 - 1; 481 incy = -1; 482 } 483 while(rc.y2 > 0) 484 { 485 m_ren->copy_from(src, 486 rdst.x1, rdst.y1, 487 rsrc.x1, rsrc.y1, 488 rc.x2); 489 rdst.y1 += incy; 490 rsrc.y1 += incy; 491 --rc.y2; 492 } 493 } 494 } 495 496 //-------------------------------------------------------------------- 497 template<class SrcPixelFormatRenderer> 498 void blend_from(const SrcPixelFormatRenderer& src, 499 const rect_i* rect_src_ptr = 0, 500 int dx = 0, 501 int dy = 0, 502 cover_type cover = agg::cover_full) 503 { 504 rect_i rsrc(0, 0, src.width(), src.height()); 505 if(rect_src_ptr) 506 { 507 rsrc.x1 = rect_src_ptr->x1; 508 rsrc.y1 = rect_src_ptr->y1; 509 rsrc.x2 = rect_src_ptr->x2 + 1; 510 rsrc.y2 = rect_src_ptr->y2 + 1; 511 } 512 513 // Version with xdst, ydst (absolute positioning) 514 //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); 515 516 // Version with dx, dy (relative positioning) 517 rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); 518 rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); 519 520 if(rc.x2 > 0) 521 { 522 int incy = 1; 523 if(rdst.y1 > rsrc.y1) 524 { 525 rsrc.y1 += rc.y2 - 1; 526 rdst.y1 += rc.y2 - 1; 527 incy = -1; 528 } 529 while(rc.y2 > 0) 530 { 531 typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1); 532 if(rw.ptr) 533 { 534 int x1src = rsrc.x1; 535 int x1dst = rdst.x1; 536 int len = rc.x2; 537 if(rw.x1 > x1src) 538 { 539 x1dst += rw.x1 - x1src; 540 len -= rw.x1 - x1src; 541 x1src = rw.x1; 542 } 543 if(len > 0) 544 { 545 if(x1src + len-1 > rw.x2) 546 { 547 len -= x1src + len - rw.x2 - 1; 548 } 549 if(len > 0) 550 { 551 m_ren->blend_from(src, 552 x1dst, rdst.y1, 553 x1src, rsrc.y1, 554 len, 555 cover); 556 } 557 } 558 } 559 rdst.y1 += incy; 560 rsrc.y1 += incy; 561 --rc.y2; 562 } 563 } 564 } 565 566 private: 567 pixfmt_type* m_ren; 568 rect_i m_clip_box; 569 }; 570 571 572 } 573 574 #endif 575