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