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 #ifndef AGG_RENDERER_OUTLINE_IMAGE_INCLUDED 16 #define AGG_RENDERER_OUTLINE_IMAGE_INCLUDED 17 18 #include <cstdlib> 19 #include "agg_array.h" 20 #include "agg_math.h" 21 #include "agg_line_aa_basics.h" 22 #include "agg_dda_line.h" 23 #include "agg_rendering_buffer.h" 24 #include "agg_clip_liang_barsky.h" 25 26 27 namespace agg 28 { 29 //========================================================line_image_scale 30 template<class Source> class line_image_scale 31 { 32 public: 33 typedef typename Source::color_type color_type; 34 line_image_scale(const Source & src,double height)35 line_image_scale(const Source& src, double height) : 36 m_source(src), 37 m_height(height), 38 m_scale(src.height() / height), 39 m_scale_inv(height / src.height()) 40 { 41 } 42 width()43 double width() const { return m_source.width(); } height()44 double height() const { return m_height; } 45 pixel(int x,int y)46 color_type pixel(int x, int y) const 47 { 48 if (m_scale < 1.0) 49 { 50 // Interpolate between nearest source pixels. 51 double src_y = (y + 0.5) * m_scale - 0.5; 52 int h = m_source.height() - 1; 53 int y1 = ifloor(src_y); 54 int y2 = y1 + 1; 55 rgba pix1 = (y1 < 0) ? rgba::no_color() : rgba(m_source.pixel(x, y1)); 56 rgba pix2 = (y2 > h) ? rgba::no_color() : rgba(m_source.pixel(x, y2)); 57 return pix1.gradient(pix2, src_y - y1); 58 } 59 else 60 { 61 // Average source pixels between y and y+1. 62 double src_y1 = (y + 0.5) * m_scale - 0.5; 63 double src_y2 = src_y1 + m_scale; 64 int h = m_source.height() - 1; 65 int y1 = ifloor(src_y1); 66 int y2 = ifloor(src_y2); 67 rgba c = rgba::no_color(); 68 if (y1 >= 0) c += rgba(m_source.pixel(x, y1)) *= y1 + 1 - src_y1; 69 while (++y1 < y2) 70 { 71 if (y1 <= h) c += m_source.pixel(x, y1); 72 } 73 if (y2 <= h) c += rgba(m_source.pixel(x, y2)) *= src_y2 - y2; 74 return c *= m_scale_inv; 75 } 76 } 77 78 private: 79 line_image_scale(const line_image_scale<Source>&); 80 const line_image_scale<Source>& operator = (const line_image_scale<Source>&); 81 82 const Source& m_source; 83 double m_height; 84 double m_scale; 85 double m_scale_inv; 86 }; 87 88 89 90 //======================================================line_image_pattern 91 template<class Filter> class line_image_pattern 92 { 93 public: 94 typedef Filter filter_type; 95 typedef typename filter_type::color_type color_type; 96 97 //-------------------------------------------------------------------- line_image_pattern(Filter & filter)98 line_image_pattern(Filter& filter) : 99 m_filter(&filter), 100 m_dilation(filter.dilation() + 1), 101 m_dilation_hr(m_dilation << line_subpixel_shift), 102 m_data(), 103 m_width(0), 104 m_height(0), 105 m_width_hr(0), 106 m_half_height_hr(0), 107 m_offset_y_hr(0) 108 { 109 } 110 111 // Create 112 //-------------------------------------------------------------------- 113 template<class Source> line_image_pattern(Filter & filter,const Source & src)114 line_image_pattern(Filter& filter, const Source& src) : 115 m_filter(&filter), 116 m_dilation(filter.dilation() + 1), 117 m_dilation_hr(m_dilation << line_subpixel_shift), 118 m_data(), 119 m_width(0), 120 m_height(0), 121 m_width_hr(0), 122 m_half_height_hr(0), 123 m_offset_y_hr(0) 124 { 125 create(src); 126 } 127 128 // Create 129 //-------------------------------------------------------------------- create(const Source & src)130 template<class Source> void create(const Source& src) 131 { 132 m_height = uceil(src.height()); 133 m_width = uceil(src.width()); 134 m_width_hr = uround(src.width() * line_subpixel_scale); 135 m_half_height_hr = uround(src.height() * line_subpixel_scale/2); 136 m_offset_y_hr = m_dilation_hr + m_half_height_hr - line_subpixel_scale/2; 137 m_half_height_hr += line_subpixel_scale/2; 138 139 m_data.resize((m_width + m_dilation * 2) * (m_height + m_dilation * 2)); 140 141 m_buf.attach(&m_data[0], m_width + m_dilation * 2, 142 m_height + m_dilation * 2, 143 m_width + m_dilation * 2); 144 unsigned x, y; 145 color_type* d1; 146 color_type* d2; 147 for(y = 0; y < m_height; y++) 148 { 149 d1 = m_buf.row_ptr(y + m_dilation) + m_dilation; 150 for(x = 0; x < m_width; x++) 151 { 152 *d1++ = src.pixel(x, y); 153 } 154 } 155 156 const color_type* s1; 157 const color_type* s2; 158 for(y = 0; y < m_dilation; y++) 159 { 160 //s1 = m_buf.row_ptr(m_height + m_dilation - 1) + m_dilation; 161 //s2 = m_buf.row_ptr(m_dilation) + m_dilation; 162 d1 = m_buf.row_ptr(m_dilation + m_height + y) + m_dilation; 163 d2 = m_buf.row_ptr(m_dilation - y - 1) + m_dilation; 164 for(x = 0; x < m_width; x++) 165 { 166 //*d1++ = color_type(*s1++, 0); 167 //*d2++ = color_type(*s2++, 0); 168 *d1++ = color_type::no_color(); 169 *d2++ = color_type::no_color(); 170 } 171 } 172 173 unsigned h = m_height + m_dilation * 2; 174 for(y = 0; y < h; y++) 175 { 176 s1 = m_buf.row_ptr(y) + m_dilation; 177 s2 = m_buf.row_ptr(y) + m_dilation + m_width; 178 d1 = m_buf.row_ptr(y) + m_dilation + m_width; 179 d2 = m_buf.row_ptr(y) + m_dilation; 180 181 for(x = 0; x < m_dilation; x++) 182 { 183 *d1++ = *s1++; 184 *--d2 = *--s2; 185 } 186 } 187 } 188 189 //-------------------------------------------------------------------- pattern_width()190 int pattern_width() const { return m_width_hr; } line_width()191 int line_width() const { return m_half_height_hr; } width()192 double width() const { return m_height; } 193 194 //-------------------------------------------------------------------- pixel(color_type * p,int x,int y)195 void pixel(color_type* p, int x, int y) const 196 { 197 m_filter->pixel_high_res(m_buf.rows(), 198 p, 199 x % m_width_hr + m_dilation_hr, 200 y + m_offset_y_hr); 201 } 202 203 //-------------------------------------------------------------------- filter()204 const filter_type& filter() const { return *m_filter; } 205 206 private: 207 line_image_pattern(const line_image_pattern<filter_type>&); 208 const line_image_pattern<filter_type>& 209 operator = (const line_image_pattern<filter_type>&); 210 211 protected: 212 row_ptr_cache<color_type> m_buf; 213 const filter_type* m_filter; 214 unsigned m_dilation; 215 int m_dilation_hr; 216 pod_array<color_type> m_data; 217 unsigned m_width; 218 unsigned m_height; 219 int m_width_hr; 220 int m_half_height_hr; 221 int m_offset_y_hr; 222 }; 223 224 225 226 227 228 229 //=================================================line_image_pattern_pow2 230 template<class Filter> class line_image_pattern_pow2 : 231 public line_image_pattern<Filter> 232 { 233 public: 234 typedef Filter filter_type; 235 typedef typename filter_type::color_type color_type; 236 typedef line_image_pattern<Filter> base_type; 237 238 //-------------------------------------------------------------------- line_image_pattern_pow2(Filter & filter)239 line_image_pattern_pow2(Filter& filter) : 240 line_image_pattern<Filter>(filter), m_mask(line_subpixel_mask) {} 241 242 //-------------------------------------------------------------------- 243 template<class Source> line_image_pattern_pow2(Filter & filter,const Source & src)244 line_image_pattern_pow2(Filter& filter, const Source& src) : 245 line_image_pattern<Filter>(filter), m_mask(line_subpixel_mask) 246 { 247 create(src); 248 } 249 250 //-------------------------------------------------------------------- create(const Source & src)251 template<class Source> void create(const Source& src) 252 { 253 line_image_pattern<Filter>::create(src); 254 m_mask = 1; 255 while(m_mask < base_type::m_width) 256 { 257 m_mask <<= 1; 258 m_mask |= 1; 259 } 260 m_mask <<= line_subpixel_shift - 1; 261 m_mask |= line_subpixel_mask; 262 base_type::m_width_hr = m_mask + 1; 263 } 264 265 //-------------------------------------------------------------------- pixel(color_type * p,int x,int y)266 void pixel(color_type* p, int x, int y) const 267 { 268 base_type::m_filter->pixel_high_res( 269 base_type::m_buf.rows(), 270 p, 271 (x & m_mask) + base_type::m_dilation_hr, 272 y + base_type::m_offset_y_hr); 273 } 274 private: 275 unsigned m_mask; 276 }; 277 278 279 280 281 282 283 284 //===================================================distance_interpolator4 285 class distance_interpolator4 286 { 287 public: 288 //--------------------------------------------------------------------- distance_interpolator4()289 distance_interpolator4() {} distance_interpolator4(int x1,int y1,int x2,int y2,int sx,int sy,int ex,int ey,int len,double scale,int x,int y)290 distance_interpolator4(int x1, int y1, int x2, int y2, 291 int sx, int sy, int ex, int ey, 292 int len, double scale, int x, int y) : 293 m_dx(x2 - x1), 294 m_dy(y2 - y1), 295 m_dx_start(line_mr(sx) - line_mr(x1)), 296 m_dy_start(line_mr(sy) - line_mr(y1)), 297 m_dx_end(line_mr(ex) - line_mr(x2)), 298 m_dy_end(line_mr(ey) - line_mr(y2)), 299 300 m_dist(iround(double(x + line_subpixel_scale/2 - x2) * double(m_dy) - 301 double(y + line_subpixel_scale/2 - y2) * double(m_dx))), 302 303 m_dist_start((line_mr(x + line_subpixel_scale/2) - line_mr(sx)) * m_dy_start - 304 (line_mr(y + line_subpixel_scale/2) - line_mr(sy)) * m_dx_start), 305 306 m_dist_end((line_mr(x + line_subpixel_scale/2) - line_mr(ex)) * m_dy_end - 307 (line_mr(y + line_subpixel_scale/2) - line_mr(ey)) * m_dx_end), 308 m_len(uround(len / scale)) 309 { 310 double d = len * scale; 311 int dx = iround(((x2 - x1) << line_subpixel_shift) / d); 312 int dy = iround(((y2 - y1) << line_subpixel_shift) / d); 313 m_dx_pict = -dy; 314 m_dy_pict = dx; 315 m_dist_pict = ((x + line_subpixel_scale/2 - (x1 - dy)) * m_dy_pict - 316 (y + line_subpixel_scale/2 - (y1 + dx)) * m_dx_pict) >> 317 line_subpixel_shift; 318 319 m_dx <<= line_subpixel_shift; 320 m_dy <<= line_subpixel_shift; 321 m_dx_start <<= line_mr_subpixel_shift; 322 m_dy_start <<= line_mr_subpixel_shift; 323 m_dx_end <<= line_mr_subpixel_shift; 324 m_dy_end <<= line_mr_subpixel_shift; 325 } 326 327 //--------------------------------------------------------------------- inc_x()328 void inc_x() 329 { 330 m_dist += m_dy; 331 m_dist_start += m_dy_start; 332 m_dist_pict += m_dy_pict; 333 m_dist_end += m_dy_end; 334 } 335 336 //--------------------------------------------------------------------- dec_x()337 void dec_x() 338 { 339 m_dist -= m_dy; 340 m_dist_start -= m_dy_start; 341 m_dist_pict -= m_dy_pict; 342 m_dist_end -= m_dy_end; 343 } 344 345 //--------------------------------------------------------------------- inc_y()346 void inc_y() 347 { 348 m_dist -= m_dx; 349 m_dist_start -= m_dx_start; 350 m_dist_pict -= m_dx_pict; 351 m_dist_end -= m_dx_end; 352 } 353 354 //--------------------------------------------------------------------- dec_y()355 void dec_y() 356 { 357 m_dist += m_dx; 358 m_dist_start += m_dx_start; 359 m_dist_pict += m_dx_pict; 360 m_dist_end += m_dx_end; 361 } 362 363 //--------------------------------------------------------------------- inc_x(int dy)364 void inc_x(int dy) 365 { 366 m_dist += m_dy; 367 m_dist_start += m_dy_start; 368 m_dist_pict += m_dy_pict; 369 m_dist_end += m_dy_end; 370 if(dy > 0) 371 { 372 m_dist -= m_dx; 373 m_dist_start -= m_dx_start; 374 m_dist_pict -= m_dx_pict; 375 m_dist_end -= m_dx_end; 376 } 377 if(dy < 0) 378 { 379 m_dist += m_dx; 380 m_dist_start += m_dx_start; 381 m_dist_pict += m_dx_pict; 382 m_dist_end += m_dx_end; 383 } 384 } 385 386 //--------------------------------------------------------------------- dec_x(int dy)387 void dec_x(int dy) 388 { 389 m_dist -= m_dy; 390 m_dist_start -= m_dy_start; 391 m_dist_pict -= m_dy_pict; 392 m_dist_end -= m_dy_end; 393 if(dy > 0) 394 { 395 m_dist -= m_dx; 396 m_dist_start -= m_dx_start; 397 m_dist_pict -= m_dx_pict; 398 m_dist_end -= m_dx_end; 399 } 400 if(dy < 0) 401 { 402 m_dist += m_dx; 403 m_dist_start += m_dx_start; 404 m_dist_pict += m_dx_pict; 405 m_dist_end += m_dx_end; 406 } 407 } 408 409 //--------------------------------------------------------------------- inc_y(int dx)410 void inc_y(int dx) 411 { 412 m_dist -= m_dx; 413 m_dist_start -= m_dx_start; 414 m_dist_pict -= m_dx_pict; 415 m_dist_end -= m_dx_end; 416 if(dx > 0) 417 { 418 m_dist += m_dy; 419 m_dist_start += m_dy_start; 420 m_dist_pict += m_dy_pict; 421 m_dist_end += m_dy_end; 422 } 423 if(dx < 0) 424 { 425 m_dist -= m_dy; 426 m_dist_start -= m_dy_start; 427 m_dist_pict -= m_dy_pict; 428 m_dist_end -= m_dy_end; 429 } 430 } 431 432 //--------------------------------------------------------------------- dec_y(int dx)433 void dec_y(int dx) 434 { 435 m_dist += m_dx; 436 m_dist_start += m_dx_start; 437 m_dist_pict += m_dx_pict; 438 m_dist_end += m_dx_end; 439 if(dx > 0) 440 { 441 m_dist += m_dy; 442 m_dist_start += m_dy_start; 443 m_dist_pict += m_dy_pict; 444 m_dist_end += m_dy_end; 445 } 446 if(dx < 0) 447 { 448 m_dist -= m_dy; 449 m_dist_start -= m_dy_start; 450 m_dist_pict -= m_dy_pict; 451 m_dist_end -= m_dy_end; 452 } 453 } 454 455 //--------------------------------------------------------------------- dist()456 int dist() const { return m_dist; } dist_start()457 int dist_start() const { return m_dist_start; } dist_pict()458 int dist_pict() const { return m_dist_pict; } dist_end()459 int dist_end() const { return m_dist_end; } 460 461 //--------------------------------------------------------------------- dx()462 int dx() const { return m_dx; } dy()463 int dy() const { return m_dy; } dx_start()464 int dx_start() const { return m_dx_start; } dy_start()465 int dy_start() const { return m_dy_start; } dx_pict()466 int dx_pict() const { return m_dx_pict; } dy_pict()467 int dy_pict() const { return m_dy_pict; } dx_end()468 int dx_end() const { return m_dx_end; } dy_end()469 int dy_end() const { return m_dy_end; } len()470 int len() const { return m_len; } 471 472 private: 473 //--------------------------------------------------------------------- 474 int m_dx; 475 int m_dy; 476 int m_dx_start; 477 int m_dy_start; 478 int m_dx_pict; 479 int m_dy_pict; 480 int m_dx_end; 481 int m_dy_end; 482 483 int m_dist; 484 int m_dist_start; 485 int m_dist_pict; 486 int m_dist_end; 487 int m_len; 488 }; 489 490 491 492 493 494 //==================================================line_interpolator_image 495 template<class Renderer> class line_interpolator_image 496 { 497 public: 498 typedef Renderer renderer_type; 499 typedef typename Renderer::color_type color_type; 500 501 //--------------------------------------------------------------------- 502 enum max_half_width_e 503 { 504 max_half_width = 64 505 }; 506 507 //--------------------------------------------------------------------- line_interpolator_image(renderer_type & ren,const line_parameters & lp,int sx,int sy,int ex,int ey,int pattern_start,double scale_x)508 line_interpolator_image(renderer_type& ren, const line_parameters& lp, 509 int sx, int sy, int ex, int ey, 510 int pattern_start, 511 double scale_x) : 512 m_lp(lp), 513 m_li(lp.vertical ? line_dbl_hr(lp.x2 - lp.x1) : 514 line_dbl_hr(lp.y2 - lp.y1), 515 lp.vertical ? std::abs(lp.y2 - lp.y1) : 516 std::abs(lp.x2 - lp.x1) + 1), 517 m_di(lp.x1, lp.y1, lp.x2, lp.y2, sx, sy, ex, ey, lp.len, scale_x, 518 lp.x1 & ~line_subpixel_mask, lp.y1 & ~line_subpixel_mask), 519 m_ren(ren), 520 m_x(lp.x1 >> line_subpixel_shift), 521 m_y(lp.y1 >> line_subpixel_shift), 522 m_old_x(m_x), 523 m_old_y(m_y), 524 m_count((lp.vertical ? std::abs((lp.y2 >> line_subpixel_shift) - m_y) : 525 std::abs((lp.x2 >> line_subpixel_shift) - m_x))), 526 m_width(ren.subpixel_width()), 527 //m_max_extent(m_width >> (line_subpixel_shift - 2)), 528 m_max_extent((m_width + line_subpixel_scale) >> line_subpixel_shift), 529 m_start(pattern_start + (m_max_extent + 2) * ren.pattern_width()), 530 m_step(0) 531 { 532 agg::dda2_line_interpolator li(0, lp.vertical ? 533 (lp.dy << agg::line_subpixel_shift) : 534 (lp.dx << agg::line_subpixel_shift), 535 lp.len); 536 537 unsigned i; 538 int stop = m_width + line_subpixel_scale * 2; 539 for(i = 0; i < max_half_width; ++i) 540 { 541 m_dist_pos[i] = li.y(); 542 if(m_dist_pos[i] >= stop) break; 543 ++li; 544 } 545 m_dist_pos[i] = 0x7FFF0000; 546 547 int dist1_start; 548 int dist2_start; 549 int npix = 1; 550 551 if(lp.vertical) 552 { 553 do 554 { 555 --m_li; 556 m_y -= lp.inc; 557 m_x = (m_lp.x1 + m_li.y()) >> line_subpixel_shift; 558 559 if(lp.inc > 0) m_di.dec_y(m_x - m_old_x); 560 else m_di.inc_y(m_x - m_old_x); 561 562 m_old_x = m_x; 563 564 dist1_start = dist2_start = m_di.dist_start(); 565 566 int dx = 0; 567 if(dist1_start < 0) ++npix; 568 do 569 { 570 dist1_start += m_di.dy_start(); 571 dist2_start -= m_di.dy_start(); 572 if(dist1_start < 0) ++npix; 573 if(dist2_start < 0) ++npix; 574 ++dx; 575 } 576 while(m_dist_pos[dx] <= m_width); 577 if(npix == 0) break; 578 579 npix = 0; 580 } 581 while(--m_step >= -m_max_extent); 582 } 583 else 584 { 585 do 586 { 587 --m_li; 588 589 m_x -= lp.inc; 590 m_y = (m_lp.y1 + m_li.y()) >> line_subpixel_shift; 591 592 if(lp.inc > 0) m_di.dec_x(m_y - m_old_y); 593 else m_di.inc_x(m_y - m_old_y); 594 595 m_old_y = m_y; 596 597 dist1_start = dist2_start = m_di.dist_start(); 598 599 int dy = 0; 600 if(dist1_start < 0) ++npix; 601 do 602 { 603 dist1_start -= m_di.dx_start(); 604 dist2_start += m_di.dx_start(); 605 if(dist1_start < 0) ++npix; 606 if(dist2_start < 0) ++npix; 607 ++dy; 608 } 609 while(m_dist_pos[dy] <= m_width); 610 if(npix == 0) break; 611 612 npix = 0; 613 } 614 while(--m_step >= -m_max_extent); 615 } 616 m_li.adjust_forward(); 617 m_step -= m_max_extent; 618 } 619 620 //--------------------------------------------------------------------- step_hor()621 bool step_hor() 622 { 623 ++m_li; 624 m_x += m_lp.inc; 625 m_y = (m_lp.y1 + m_li.y()) >> line_subpixel_shift; 626 627 if(m_lp.inc > 0) m_di.inc_x(m_y - m_old_y); 628 else m_di.dec_x(m_y - m_old_y); 629 630 m_old_y = m_y; 631 632 int s1 = m_di.dist() / m_lp.len; 633 int s2 = -s1; 634 635 if(m_lp.inc < 0) s1 = -s1; 636 637 int dist_start; 638 int dist_pict; 639 int dist_end; 640 int dy; 641 int dist; 642 643 dist_start = m_di.dist_start(); 644 dist_pict = m_di.dist_pict() + m_start; 645 dist_end = m_di.dist_end(); 646 color_type* p0 = m_colors + max_half_width + 2; 647 color_type* p1 = p0; 648 649 int npix = 0; 650 p1->clear(); 651 if(dist_end > 0) 652 { 653 if(dist_start <= 0) 654 { 655 m_ren.pixel(p1, dist_pict, s2); 656 } 657 ++npix; 658 } 659 ++p1; 660 661 dy = 1; 662 while((dist = m_dist_pos[dy]) - s1 <= m_width) 663 { 664 dist_start -= m_di.dx_start(); 665 dist_pict -= m_di.dx_pict(); 666 dist_end -= m_di.dx_end(); 667 p1->clear(); 668 if(dist_end > 0 && dist_start <= 0) 669 { 670 if(m_lp.inc > 0) dist = -dist; 671 m_ren.pixel(p1, dist_pict, s2 - dist); 672 ++npix; 673 } 674 ++p1; 675 ++dy; 676 } 677 678 dy = 1; 679 dist_start = m_di.dist_start(); 680 dist_pict = m_di.dist_pict() + m_start; 681 dist_end = m_di.dist_end(); 682 while((dist = m_dist_pos[dy]) + s1 <= m_width) 683 { 684 dist_start += m_di.dx_start(); 685 dist_pict += m_di.dx_pict(); 686 dist_end += m_di.dx_end(); 687 --p0; 688 p0->clear(); 689 if(dist_end > 0 && dist_start <= 0) 690 { 691 if(m_lp.inc > 0) dist = -dist; 692 m_ren.pixel(p0, dist_pict, s2 + dist); 693 ++npix; 694 } 695 ++dy; 696 } 697 m_ren.blend_color_vspan(m_x, 698 m_y - dy + 1, 699 unsigned(p1 - p0), 700 p0); 701 return npix && ++m_step < m_count; 702 } 703 704 705 706 //--------------------------------------------------------------------- step_ver()707 bool step_ver() 708 { 709 ++m_li; 710 m_y += m_lp.inc; 711 m_x = (m_lp.x1 + m_li.y()) >> line_subpixel_shift; 712 713 if(m_lp.inc > 0) m_di.inc_y(m_x - m_old_x); 714 else m_di.dec_y(m_x - m_old_x); 715 716 m_old_x = m_x; 717 718 int s1 = m_di.dist() / m_lp.len; 719 int s2 = -s1; 720 721 if(m_lp.inc > 0) s1 = -s1; 722 723 int dist_start; 724 int dist_pict; 725 int dist_end; 726 int dist; 727 int dx; 728 729 dist_start = m_di.dist_start(); 730 dist_pict = m_di.dist_pict() + m_start; 731 dist_end = m_di.dist_end(); 732 color_type* p0 = m_colors + max_half_width + 2; 733 color_type* p1 = p0; 734 735 int npix = 0; 736 p1->clear(); 737 if(dist_end > 0) 738 { 739 if(dist_start <= 0) 740 { 741 m_ren.pixel(p1, dist_pict, s2); 742 } 743 ++npix; 744 } 745 ++p1; 746 747 dx = 1; 748 while((dist = m_dist_pos[dx]) - s1 <= m_width) 749 { 750 dist_start += m_di.dy_start(); 751 dist_pict += m_di.dy_pict(); 752 dist_end += m_di.dy_end(); 753 p1->clear(); 754 if(dist_end > 0 && dist_start <= 0) 755 { 756 if(m_lp.inc > 0) dist = -dist; 757 m_ren.pixel(p1, dist_pict, s2 + dist); 758 ++npix; 759 } 760 ++p1; 761 ++dx; 762 } 763 764 dx = 1; 765 dist_start = m_di.dist_start(); 766 dist_pict = m_di.dist_pict() + m_start; 767 dist_end = m_di.dist_end(); 768 while((dist = m_dist_pos[dx]) + s1 <= m_width) 769 { 770 dist_start -= m_di.dy_start(); 771 dist_pict -= m_di.dy_pict(); 772 dist_end -= m_di.dy_end(); 773 --p0; 774 p0->clear(); 775 if(dist_end > 0 && dist_start <= 0) 776 { 777 if(m_lp.inc > 0) dist = -dist; 778 m_ren.pixel(p0, dist_pict, s2 - dist); 779 ++npix; 780 } 781 ++dx; 782 } 783 m_ren.blend_color_hspan(m_x - dx + 1, 784 m_y, 785 unsigned(p1 - p0), 786 p0); 787 return npix && ++m_step < m_count; 788 } 789 790 791 //--------------------------------------------------------------------- pattern_end()792 int pattern_end() const { return m_start + m_di.len(); } 793 794 //--------------------------------------------------------------------- vertical()795 bool vertical() const { return m_lp.vertical; } width()796 int width() const { return m_width; } count()797 int count() const { return m_count; } 798 799 private: 800 line_interpolator_image(const line_interpolator_image<Renderer>&); 801 const line_interpolator_image<Renderer>& 802 operator = (const line_interpolator_image<Renderer>&); 803 804 protected: 805 const line_parameters& m_lp; 806 dda2_line_interpolator m_li; 807 distance_interpolator4 m_di; 808 renderer_type& m_ren; 809 int m_plen; 810 int m_x; 811 int m_y; 812 int m_old_x; 813 int m_old_y; 814 int m_count; 815 int m_width; 816 int m_max_extent; 817 int m_start; 818 int m_step; 819 int m_dist_pos[max_half_width + 1]; 820 color_type m_colors[max_half_width * 2 + 4]; 821 }; 822 823 824 825 826 827 828 829 830 //===================================================renderer_outline_image 831 template<class BaseRenderer, class ImagePattern> 832 class renderer_outline_image 833 { 834 public: 835 //--------------------------------------------------------------------- 836 typedef BaseRenderer base_ren_type; 837 typedef renderer_outline_image<BaseRenderer, ImagePattern> self_type; 838 typedef typename base_ren_type::color_type color_type; 839 typedef ImagePattern pattern_type; 840 841 842 //--------------------------------------------------------------------- renderer_outline_image(base_ren_type & ren,pattern_type & patt)843 renderer_outline_image(base_ren_type& ren, pattern_type& patt) : 844 m_ren(&ren), 845 m_pattern(&patt), 846 m_start(0), 847 m_scale_x(1.0), 848 m_clip_box(0,0,0,0), 849 m_clipping(false) 850 {} attach(base_ren_type & ren)851 void attach(base_ren_type& ren) { m_ren = &ren; } 852 853 //--------------------------------------------------------------------- pattern(pattern_type & p)854 void pattern(pattern_type& p) { m_pattern = &p; } pattern()855 pattern_type& pattern() const { return *m_pattern; } 856 857 //--------------------------------------------------------------------- reset_clipping()858 void reset_clipping() { m_clipping = false; } clip_box(double x1,double y1,double x2,double y2)859 void clip_box(double x1, double y1, double x2, double y2) 860 { 861 m_clip_box.x1 = line_coord_sat::conv(x1); 862 m_clip_box.y1 = line_coord_sat::conv(y1); 863 m_clip_box.x2 = line_coord_sat::conv(x2); 864 m_clip_box.y2 = line_coord_sat::conv(y2); 865 m_clipping = true; 866 } 867 868 //--------------------------------------------------------------------- scale_x(double s)869 void scale_x(double s) { m_scale_x = s; } scale_x()870 double scale_x() const { return m_scale_x; } 871 872 //--------------------------------------------------------------------- start_x(double s)873 void start_x(double s) { m_start = iround(s * line_subpixel_scale); } start_x()874 double start_x() const { return double(m_start) / line_subpixel_scale; } 875 876 //--------------------------------------------------------------------- subpixel_width()877 int subpixel_width() const { return m_pattern->line_width(); } pattern_width()878 int pattern_width() const { return m_pattern->pattern_width(); } width()879 double width() const { return double(subpixel_width()) / line_subpixel_scale; } 880 881 //------------------------------------------------------------------------- pixel(color_type * p,int x,int y)882 void pixel(color_type* p, int x, int y) const 883 { 884 m_pattern->pixel(p, x, y); 885 } 886 887 //------------------------------------------------------------------------- blend_color_hspan(int x,int y,unsigned len,const color_type * colors)888 void blend_color_hspan(int x, int y, unsigned len, const color_type* colors) 889 { 890 m_ren->blend_color_hspan(x, y, len, colors, 0); 891 } 892 893 //------------------------------------------------------------------------- blend_color_vspan(int x,int y,unsigned len,const color_type * colors)894 void blend_color_vspan(int x, int y, unsigned len, const color_type* colors) 895 { 896 m_ren->blend_color_vspan(x, y, len, colors, 0); 897 } 898 899 //------------------------------------------------------------------------- accurate_join_only()900 static bool accurate_join_only() { return true; } 901 902 //------------------------------------------------------------------------- 903 template<class Cmp> semidot(Cmp,int,int,int,int)904 void semidot(Cmp, int, int, int, int) 905 { 906 } 907 908 //------------------------------------------------------------------------- pie(int,int,int,int,int,int)909 void pie(int, int, int, int, int, int) 910 { 911 } 912 913 //------------------------------------------------------------------------- line0(const line_parameters &)914 void line0(const line_parameters&) 915 { 916 } 917 918 //------------------------------------------------------------------------- line1(const line_parameters &,int,int)919 void line1(const line_parameters&, int, int) 920 { 921 } 922 923 //------------------------------------------------------------------------- line2(const line_parameters &,int,int)924 void line2(const line_parameters&, int, int) 925 { 926 } 927 928 //------------------------------------------------------------------------- line3_no_clip(const line_parameters & lp,int sx,int sy,int ex,int ey)929 void line3_no_clip(const line_parameters& lp, 930 int sx, int sy, int ex, int ey) 931 { 932 if(lp.len > line_max_length) 933 { 934 line_parameters lp1, lp2; 935 lp.divide(lp1, lp2); 936 int mx = lp1.x2 + (lp1.y2 - lp1.y1); 937 int my = lp1.y2 - (lp1.x2 - lp1.x1); 938 line3_no_clip(lp1, (lp.x1 + sx) >> 1, (lp.y1 + sy) >> 1, mx, my); 939 line3_no_clip(lp2, mx, my, (lp.x2 + ex) >> 1, (lp.y2 + ey) >> 1); 940 return; 941 } 942 943 fix_degenerate_bisectrix_start(lp, &sx, &sy); 944 fix_degenerate_bisectrix_end(lp, &ex, &ey); 945 line_interpolator_image<self_type> li(*this, lp, 946 sx, sy, 947 ex, ey, 948 m_start, m_scale_x); 949 if(li.vertical()) 950 { 951 while(li.step_ver()); 952 } 953 else 954 { 955 while(li.step_hor()); 956 } 957 m_start += uround(lp.len / m_scale_x); 958 } 959 960 //------------------------------------------------------------------------- line3(const line_parameters & lp,int sx,int sy,int ex,int ey)961 void line3(const line_parameters& lp, 962 int sx, int sy, int ex, int ey) 963 { 964 if(m_clipping) 965 { 966 int x1 = lp.x1; 967 int y1 = lp.y1; 968 int x2 = lp.x2; 969 int y2 = lp.y2; 970 unsigned flags = clip_line_segment(&x1, &y1, &x2, &y2, m_clip_box); 971 int start = m_start; 972 if((flags & 4) == 0) 973 { 974 if(flags) 975 { 976 line_parameters lp2(x1, y1, x2, y2, 977 uround(calc_distance(x1, y1, x2, y2))); 978 if(flags & 1) 979 { 980 m_start += uround(calc_distance(lp.x1, lp.y1, x1, y1) / m_scale_x); 981 sx = x1 + (y2 - y1); 982 sy = y1 - (x2 - x1); 983 } 984 else 985 { 986 while(std::abs(sx - lp.x1) + std::abs(sy - lp.y1) > lp2.len) 987 { 988 sx = (lp.x1 + sx) >> 1; 989 sy = (lp.y1 + sy) >> 1; 990 } 991 } 992 if(flags & 2) 993 { 994 ex = x2 + (y2 - y1); 995 ey = y2 - (x2 - x1); 996 } 997 else 998 { 999 while(std::abs(ex - lp.x2) + std::abs(ey - lp.y2) > lp2.len) 1000 { 1001 ex = (lp.x2 + ex) >> 1; 1002 ey = (lp.y2 + ey) >> 1; 1003 } 1004 } 1005 line3_no_clip(lp2, sx, sy, ex, ey); 1006 } 1007 else 1008 { 1009 line3_no_clip(lp, sx, sy, ex, ey); 1010 } 1011 } 1012 m_start = start + uround(lp.len / m_scale_x); 1013 } 1014 else 1015 { 1016 line3_no_clip(lp, sx, sy, ex, ey); 1017 } 1018 } 1019 1020 private: 1021 base_ren_type* m_ren; 1022 pattern_type* m_pattern; 1023 int m_start; 1024 double m_scale_x; 1025 rect_i m_clip_box; 1026 bool m_clipping; 1027 }; 1028 1029 1030 1031 1032 1033 } 1034 1035 1036 1037 #endif 1038