1/* 2 * Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>. 3 * Copyright 2008, Stephan Aßmus <superstippi@gmx.de>. 4 * All rights reserved. Distributed under the terms of the MIT License. 5 * 6 * Copyright 2002-2004 Maxim Shemanarev (http://www.antigrain.com) 7 * 8 * 9 * Class scanline_p8_subpix_avrg_filtering, a slightly modified version of 10 * scanline_p8 customized to store 3 covers per pixel and to implement 11 * average-based color filtering 12 * 13 */ 14 15#ifndef AGG_SCANLINE_P_SUBPIX_AVRG_FILTERING_INCLUDED 16#define AGG_SCANLINE_P_SUBPIX_AVRG_FILTERING_INCLUDED 17 18#include "GlobalSubpixelSettings.h" 19 20namespace agg 21{ 22 //========================================scanline_p8_subpix_avrg_filtering 23 // 24 // This is a general purpose scaline container which supports the interface 25 // used in the rasterizer::render(). See description of scanline_u8 26 // for details. 27 // 28 //------------------------------------------------------------------------ 29 class scanline_p8_subpix_avrg_filtering 30 { 31 public: 32 typedef scanline_p8_subpix self_type; 33 typedef int8u cover_type; 34 typedef int16 coord_type; 35 36 //-------------------------------------------------------------------- 37 struct span 38 { 39 coord_type x; 40 coord_type len; // If negative, it's a solid span, covers is valid 41 const cover_type* covers; 42 }; 43 44 typedef span* iterator; 45 typedef const span* const_iterator; 46 47 scanline_p8_subpix_avrg_filtering() : 48 m_last_x(0x7FFFFFF0), 49 m_covers(), 50 m_cover_ptr(0), 51 m_spans(), 52 m_cur_span(0) 53 { 54 } 55 56 //-------------------------------------------------------------------- 57 void reset(int min_x, int max_x) 58 { 59 unsigned max_len = 3*(max_x - min_x + 3); 60 if(max_len > m_spans.size()) 61 { 62 m_spans.resize(max_len); 63 m_covers.resize(max_len); 64 } 65 m_last_x = 0x7FFFFFF0; 66 m_cover_ptr = &m_covers[0]; 67 m_cur_span = &m_spans[0]; 68 m_cur_span->len = 0; 69 } 70 71 //-------------------------------------------------------------------- 72 void add_cell(int x, unsigned cover1, unsigned cover2, unsigned cover3) 73 { 74 75 // NOTE stippi: My basic idea is that filtering tries to minimize colored 76 // edges, but it does so by blurring the coverage values. This will also 77 // affect neighboring pixels and add blur where there were perfectly sharp 78 // edges. Andrej's method of filtering adds a special case for perfectly 79 // sharp edges, but the drawback here is that there will be a visible 80 // transition between blurred and non-blurred subpixels. I had the idea that 81 // when simply fading the subpixels towards the plain gray-scale-aa values, 82 // there must be a sweet spot for when colored edges become non-disturbing 83 // and there is still a benefit of sharpness compared to straight gray-scale- 84 // aa. The define above enables this method against the colored edges. My 85 // method still has a drawback, since jaggies in diagonal lines will be more 86 // visible again than with the filter method. 87 88 unsigned char averageWeight = gSubpixelAverageWeight; 89 unsigned char subpixelWeight = 255 - averageWeight; 90 91 unsigned int coverR; 92 unsigned int coverG; 93 unsigned int coverB; 94 95 unsigned int average = (cover1 + cover2 + cover3 + 2) / 3; 96 97 coverR = (cover1 * subpixelWeight + average * averageWeight) >> 8; 98 coverG = (cover2 * subpixelWeight + average * averageWeight) >> 8; 99 coverB = (cover3 * subpixelWeight + average * averageWeight) >> 8; 100 101 m_cover_ptr[0] = (cover_type)coverR; 102 m_cover_ptr[1] = (cover_type)coverG; 103 m_cover_ptr[2] = (cover_type)coverB; 104 if(x == m_last_x+1 && m_cur_span->len > 0) 105 { 106 m_cur_span->len += 3; 107 } 108 else 109 { 110 m_cur_span++; 111 m_cur_span->covers = m_cover_ptr; 112 m_cur_span->x = (int16)x; 113 m_cur_span->len = 3; 114 } 115 m_last_x = x; 116 m_cover_ptr += 3; 117 } 118 119 //-------------------------------------------------------------------- 120 void add_cells(int x, unsigned len, const cover_type* covers) 121 { 122 memcpy(m_cover_ptr, covers, 3 * len * sizeof(cover_type)); 123 if(x == m_last_x+1 && m_cur_span->len > 0) 124 { 125 m_cur_span->len += 3 * (int16)len; 126 } 127 else 128 { 129 m_cur_span++; 130 m_cur_span->covers = m_cover_ptr; 131 m_cur_span->x = (int16)x; 132 m_cur_span->len = 3 * (int16)len; 133 } 134 m_cover_ptr += 3 * len; 135 m_last_x = x + len - 1; 136 } 137 138 //-------------------------------------------------------------------- 139 void add_span(int x, unsigned len, unsigned cover) 140 { 141 if(x == m_last_x+1 && 142 m_cur_span->len < 0 && 143 cover == *m_cur_span->covers) 144 { 145 m_cur_span->len -= 3 * (int16)len; 146 } 147 else 148 { 149 *m_cover_ptr = (cover_type)cover; 150 m_cur_span++; 151 m_cur_span->covers = m_cover_ptr; 152 m_cover_ptr += 3; 153 m_cur_span->x = (int16)x; 154 m_cur_span->len = 3 * (int16)(-int(len)); 155 } 156 m_last_x = x + len - 1; 157 } 158 159 //-------------------------------------------------------------------- 160 void finalize(int y) 161 { 162 m_y = y; 163 } 164 165 //-------------------------------------------------------------------- 166 void reset_spans() 167 { 168 m_last_x = 0x7FFFFFF0; 169 m_cover_ptr = &m_covers[0]; 170 m_cur_span = &m_spans[0]; 171 m_cur_span->len = 0; 172 } 173 174 //-------------------------------------------------------------------- 175 int y() const { return m_y; } 176 unsigned num_spans() const { return unsigned(m_cur_span - &m_spans[0]); } 177 const_iterator begin() const { return &m_spans[1]; } 178 179 private: 180 scanline_p8_subpix_avrg_filtering(const self_type&); 181 const self_type& operator = (const self_type&); 182 183 int m_last_x; 184 int m_y; 185 pod_array<cover_type> m_covers; 186 cover_type* m_cover_ptr; 187 pod_array<span> m_spans; 188 span* m_cur_span; 189 }; 190 191} 192 193 194#endif 195 196