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 // Adaptation for 32-bit screen coordinates (scanline32_u) has been sponsored by 17 // Liberty Technology Systems, Inc., visit http://lib-sys.com 18 // 19 // Liberty Technology Systems, Inc. is the provider of 20 // PostScript and PDF technology for software developers. 21 // 22 //---------------------------------------------------------------------------- 23 24 #ifndef AGG_SCANLINE_U_INCLUDED 25 #define AGG_SCANLINE_U_INCLUDED 26 27 #include <cstring> 28 #include "agg_array.h" 29 30 namespace agg 31 { 32 //=============================================================scanline_u8 33 // 34 // Unpacked scanline container class 35 // 36 // This class is used to transfer data from a scanline rasterizer 37 // to the rendering buffer. It's organized very simple. The class stores 38 // information of horizontal spans to render it into a pixel-map buffer. 39 // Each span has staring X, length, and an array of bytes that determine the 40 // cover-values for each pixel. 41 // Before using this class you should know the minimal and maximal pixel 42 // coordinates of your scanline. The protocol of using is: 43 // 1. reset(min_x, max_x) 44 // 2. add_cell() / add_span() - accumulate scanline. 45 // When forming one scanline the next X coordinate must be always greater 46 // than the last stored one, i.e. it works only with ordered coordinates. 47 // 3. Call finalize(y) and render the scanline. 48 // 3. Call reset_spans() to prepare for the new scanline. 49 // 50 // 4. Rendering: 51 // 52 // Scanline provides an iterator class that allows you to extract 53 // the spans and the cover values for each pixel. Be aware that clipping 54 // has not been done yet, so you should perform it yourself. 55 // Use scanline_u8::iterator to render spans: 56 //------------------------------------------------------------------------- 57 // 58 // int y = sl.y(); // Y-coordinate of the scanline 59 // 60 // ************************************ 61 // ...Perform vertical clipping here... 62 // ************************************ 63 // 64 // scanline_u8::const_iterator span = sl.begin(); 65 // 66 // unsigned char* row = m_rbuf->row(y); // The address of the beginning 67 // // of the current row 68 // 69 // unsigned num_spans = sl.num_spans(); // Number of spans. It's guaranteed that 70 // // num_spans is always greater than 0. 71 // 72 // do 73 // { 74 // const scanline_u8::cover_type* covers = 75 // span->covers; // The array of the cover values 76 // 77 // int num_pix = span->len; // Number of pixels of the span. 78 // // Always greater than 0, still it's 79 // // better to use "int" instead of 80 // // "unsigned" because it's more 81 // // convenient for clipping 82 // int x = span->x; 83 // 84 // ************************************** 85 // ...Perform horizontal clipping here... 86 // ...you have x, covers, and pix_count.. 87 // ************************************** 88 // 89 // unsigned char* dst = row + x; // Calculate the start address of the row. 90 // // In this case we assume a simple 91 // // grayscale image 1-byte per pixel. 92 // do 93 // { 94 // *dst++ = *covers++; // Hypotetical rendering. 95 // } 96 // while(--num_pix); 97 // 98 // ++span; 99 // } 100 // while(--num_spans); // num_spans cannot be 0, so this loop is quite safe 101 //------------------------------------------------------------------------ 102 // 103 // The question is: why should we accumulate the whole scanline when we 104 // could render just separate spans when they're ready? 105 // That's because using the scanline is generally faster. When is consists 106 // of more than one span the conditions for the processor cash system 107 // are better, because switching between two different areas of memory 108 // (that can be very large) occurs less frequently. 109 //------------------------------------------------------------------------ 110 class scanline_u8 111 { 112 public: 113 typedef scanline_u8 self_type; 114 typedef int8u cover_type; 115 typedef int16 coord_type; 116 117 //-------------------------------------------------------------------- 118 struct span 119 { 120 coord_type x; 121 coord_type len; 122 cover_type* covers; 123 }; 124 125 typedef span* iterator; 126 typedef const span* const_iterator; 127 128 //-------------------------------------------------------------------- scanline_u8()129 scanline_u8() : 130 m_min_x(0), 131 m_last_x(0x7FFFFFF0), 132 m_cur_span(0) 133 {} 134 135 //-------------------------------------------------------------------- reset(int min_x,int max_x)136 void reset(int min_x, int max_x) 137 { 138 unsigned max_len = max_x - min_x + 2; 139 if(max_len > m_spans.size()) 140 { 141 m_spans.resize(max_len); 142 m_covers.resize(max_len); 143 } 144 m_last_x = 0x7FFFFFF0; 145 m_min_x = min_x; 146 m_cur_span = &m_spans[0]; 147 } 148 149 //-------------------------------------------------------------------- add_cell(int x,unsigned cover)150 void add_cell(int x, unsigned cover) 151 { 152 x -= m_min_x; 153 m_covers[x] = (cover_type)cover; 154 if(x == m_last_x+1) 155 { 156 m_cur_span->len++; 157 } 158 else 159 { 160 m_cur_span++; 161 m_cur_span->x = (coord_type)(x + m_min_x); 162 m_cur_span->len = 1; 163 m_cur_span->covers = &m_covers[x]; 164 } 165 m_last_x = x; 166 } 167 168 //-------------------------------------------------------------------- add_cells(int x,unsigned len,const cover_type * covers)169 void add_cells(int x, unsigned len, const cover_type* covers) 170 { 171 x -= m_min_x; 172 std::memcpy(&m_covers[x], covers, len * sizeof(cover_type)); 173 if(x == m_last_x+1) 174 { 175 m_cur_span->len += (coord_type)len; 176 } 177 else 178 { 179 m_cur_span++; 180 m_cur_span->x = (coord_type)(x + m_min_x); 181 m_cur_span->len = (coord_type)len; 182 m_cur_span->covers = &m_covers[x]; 183 } 184 m_last_x = x + len - 1; 185 } 186 187 //-------------------------------------------------------------------- add_span(int x,unsigned len,unsigned cover)188 void add_span(int x, unsigned len, unsigned cover) 189 { 190 x -= m_min_x; 191 std::memset(&m_covers[x], cover, len); 192 if(x == m_last_x+1) 193 { 194 m_cur_span->len += (coord_type)len; 195 } 196 else 197 { 198 m_cur_span++; 199 m_cur_span->x = (coord_type)(x + m_min_x); 200 m_cur_span->len = (coord_type)len; 201 m_cur_span->covers = &m_covers[x]; 202 } 203 m_last_x = x + len - 1; 204 } 205 206 //-------------------------------------------------------------------- finalize(int y)207 void finalize(int y) 208 { 209 m_y = y; 210 } 211 212 //-------------------------------------------------------------------- reset_spans()213 void reset_spans() 214 { 215 m_last_x = 0x7FFFFFF0; 216 m_cur_span = &m_spans[0]; 217 } 218 219 //-------------------------------------------------------------------- y()220 int y() const { return m_y; } num_spans()221 unsigned num_spans() const { return unsigned(m_cur_span - &m_spans[0]); } begin()222 const_iterator begin() const { return &m_spans[1]; } begin()223 iterator begin() { return &m_spans[1]; } 224 225 private: 226 scanline_u8(const self_type&); 227 const self_type& operator = (const self_type&); 228 229 private: 230 int m_min_x; 231 int m_last_x; 232 int m_y; 233 pod_array<cover_type> m_covers; 234 pod_array<span> m_spans; 235 span* m_cur_span; 236 }; 237 238 239 240 241 //==========================================================scanline_u8_am 242 // 243 // The scanline container with alpha-masking 244 // 245 //------------------------------------------------------------------------ 246 template<class AlphaMask> 247 class scanline_u8_am : public scanline_u8 248 { 249 public: 250 typedef scanline_u8 base_type; 251 typedef AlphaMask alpha_mask_type; 252 typedef base_type::cover_type cover_type; 253 typedef base_type::coord_type coord_type; 254 scanline_u8_am()255 scanline_u8_am() : base_type(), m_alpha_mask(0) {} scanline_u8_am(AlphaMask & am)256 scanline_u8_am(AlphaMask& am) : base_type(), m_alpha_mask(&am) {} 257 258 //-------------------------------------------------------------------- finalize(int span_y)259 void finalize(int span_y) 260 { 261 base_type::finalize(span_y); 262 if(m_alpha_mask) 263 { 264 typename base_type::iterator span = base_type::begin(); 265 unsigned count = base_type::num_spans(); 266 do 267 { 268 m_alpha_mask->combine_hspan(span->x, 269 base_type::y(), 270 span->covers, 271 span->len); 272 ++span; 273 } 274 while(--count); 275 } 276 } 277 278 private: 279 AlphaMask* m_alpha_mask; 280 }; 281 282 283 284 285 //===========================================================scanline32_u8 286 class scanline32_u8 287 { 288 public: 289 typedef scanline32_u8 self_type; 290 typedef int8u cover_type; 291 typedef int32 coord_type; 292 293 //-------------------------------------------------------------------- 294 struct span 295 { spanspan296 span() {} spanspan297 span(coord_type x_, coord_type len_, cover_type* covers_) : 298 x(x_), len(len_), covers(covers_) {} 299 300 coord_type x; 301 coord_type len; 302 cover_type* covers; 303 }; 304 305 typedef pod_bvector<span, 4> span_array_type; 306 307 //-------------------------------------------------------------------- 308 class const_iterator 309 { 310 public: const_iterator(const span_array_type & spans)311 const_iterator(const span_array_type& spans) : 312 m_spans(spans), 313 m_span_idx(0) 314 {} 315 316 const span& operator*() const { return m_spans[m_span_idx]; } 317 const span* operator->() const { return &m_spans[m_span_idx]; } 318 319 void operator ++ () { ++m_span_idx; } 320 321 private: 322 const span_array_type& m_spans; 323 unsigned m_span_idx; 324 }; 325 326 //-------------------------------------------------------------------- 327 class iterator 328 { 329 public: iterator(span_array_type & spans)330 iterator(span_array_type& spans) : 331 m_spans(spans), 332 m_span_idx(0) 333 {} 334 335 span& operator*() { return m_spans[m_span_idx]; } 336 span* operator->() { return &m_spans[m_span_idx]; } 337 338 void operator ++ () { ++m_span_idx; } 339 340 private: 341 span_array_type& m_spans; 342 unsigned m_span_idx; 343 }; 344 345 346 347 //-------------------------------------------------------------------- scanline32_u8()348 scanline32_u8() : 349 m_min_x(0), 350 m_last_x(0x7FFFFFF0), 351 m_covers() 352 {} 353 354 //-------------------------------------------------------------------- reset(int min_x,int max_x)355 void reset(int min_x, int max_x) 356 { 357 unsigned max_len = max_x - min_x + 2; 358 if(max_len > m_covers.size()) 359 { 360 m_covers.resize(max_len); 361 } 362 m_last_x = 0x7FFFFFF0; 363 m_min_x = min_x; 364 m_spans.remove_all(); 365 } 366 367 //-------------------------------------------------------------------- add_cell(int x,unsigned cover)368 void add_cell(int x, unsigned cover) 369 { 370 x -= m_min_x; 371 m_covers[x] = cover_type(cover); 372 if(x == m_last_x+1) 373 { 374 m_spans.last().len++; 375 } 376 else 377 { 378 m_spans.add(span(coord_type(x + m_min_x), 1, &m_covers[x])); 379 } 380 m_last_x = x; 381 } 382 383 //-------------------------------------------------------------------- add_cells(int x,unsigned len,const cover_type * covers)384 void add_cells(int x, unsigned len, const cover_type* covers) 385 { 386 x -= m_min_x; 387 std::memcpy(&m_covers[x], covers, len * sizeof(cover_type)); 388 if(x == m_last_x+1) 389 { 390 m_spans.last().len += coord_type(len); 391 } 392 else 393 { 394 m_spans.add(span(coord_type(x + m_min_x), 395 coord_type(len), 396 &m_covers[x])); 397 } 398 m_last_x = x + len - 1; 399 } 400 401 //-------------------------------------------------------------------- add_span(int x,unsigned len,unsigned cover)402 void add_span(int x, unsigned len, unsigned cover) 403 { 404 x -= m_min_x; 405 std::memset(&m_covers[x], cover, len); 406 if(x == m_last_x+1) 407 { 408 m_spans.last().len += coord_type(len); 409 } 410 else 411 { 412 m_spans.add(span(coord_type(x + m_min_x), 413 coord_type(len), 414 &m_covers[x])); 415 } 416 m_last_x = x + len - 1; 417 } 418 419 //-------------------------------------------------------------------- finalize(int y)420 void finalize(int y) 421 { 422 m_y = y; 423 } 424 425 //-------------------------------------------------------------------- reset_spans()426 void reset_spans() 427 { 428 m_last_x = 0x7FFFFFF0; 429 m_spans.remove_all(); 430 } 431 432 //-------------------------------------------------------------------- y()433 int y() const { return m_y; } num_spans()434 unsigned num_spans() const { return m_spans.size(); } begin()435 const_iterator begin() const { return const_iterator(m_spans); } begin()436 iterator begin() { return iterator(m_spans); } 437 438 private: 439 scanline32_u8(const self_type&); 440 const self_type& operator = (const self_type&); 441 442 private: 443 int m_min_x; 444 int m_last_x; 445 int m_y; 446 pod_array<cover_type> m_covers; 447 span_array_type m_spans; 448 }; 449 450 451 452 453 //========================================================scanline32_u8_am 454 // 455 // The scanline container with alpha-masking 456 // 457 //------------------------------------------------------------------------ 458 template<class AlphaMask> 459 class scanline32_u8_am : public scanline32_u8 460 { 461 public: 462 typedef scanline32_u8 base_type; 463 typedef AlphaMask alpha_mask_type; 464 typedef base_type::cover_type cover_type; 465 typedef base_type::coord_type coord_type; 466 467 scanline32_u8_am()468 scanline32_u8_am() : base_type(), m_alpha_mask(0) {} scanline32_u8_am(AlphaMask & am)469 scanline32_u8_am(AlphaMask& am) : base_type(), m_alpha_mask(&am) {} 470 471 //-------------------------------------------------------------------- finalize(int span_y)472 void finalize(int span_y) 473 { 474 base_type::finalize(span_y); 475 if(m_alpha_mask) 476 { 477 typename base_type::iterator span = base_type::begin(); 478 unsigned count = base_type::num_spans(); 479 do 480 { 481 m_alpha_mask->combine_hspan(span->x, 482 base_type::y(), 483 span->covers, 484 span->len); 485 ++span; 486 } 487 while(--count); 488 } 489 } 490 491 private: 492 AlphaMask* m_alpha_mask; 493 }; 494 495 496 497 } 498 499 #endif 500 501