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_u8_subpix_avrg_filtering, a slightly modified version of 10 * scanline_u8 customized to store 3 covers per pixel and to implement 11 * average-based color filtering 12 * 13 */ 14 15#ifndef AGG_SCANLINE_U_SUBPIX_AVRG_FILTERING_INCLUDED 16#define AGG_SCANLINE_U_SUBPIX_AVRG_FILTERING_INCLUDED 17 18#include "GlobalSubpixelSettings.h" 19 20namespace agg 21{ 22 //=======================================scanline_u8_subpix_avrg_filtering 23 //------------------------------------------------------------------------ 24 class scanline_u8_subpix_avrg_filtering 25 { 26 public: 27 typedef scanline_u8_subpix_avrg_filtering self_type; 28 typedef int8u cover_type; 29 typedef int16 coord_type; 30 31 //-------------------------------------------------------------------- 32 struct span 33 { 34 coord_type x; 35 coord_type len; 36 cover_type* covers; 37 }; 38 39 typedef span* iterator; 40 typedef const span* const_iterator; 41 42 //-------------------------------------------------------------------- 43 scanline_u8_subpix_avrg_filtering() : 44 m_min_x(0), 45 m_last_x(0x7FFFFFF0), 46 m_cur_span(0) 47 {} 48 49 //-------------------------------------------------------------------- 50 void reset(int min_x, int max_x) 51 { 52 unsigned max_len = 3*(max_x - min_x + 2); 53 if(max_len > m_spans.size()) 54 { 55 m_spans.resize(max_len); 56 m_covers.resize(max_len); 57 } 58 m_last_x = 0x7FFFFFF0; 59 m_min_x = min_x; 60 m_cur_span = &m_spans[0]; 61 } 62 63 //-------------------------------------------------------------------- 64 void add_cell(int x, unsigned cover1, unsigned cover2, unsigned cover3) 65 { 66 67 // NOTE stippi: My basic idea is that filtering tries to minimize colored 68 // edges, but it does so by blurring the coverage values. This will also 69 // affect neighboring pixels and add blur where there were perfectly sharp 70 // edges. Andrej's method of filtering adds a special case for perfectly 71 // sharp edges, but the drawback here is that there will be a visible 72 // transition between blurred and non-blurred subpixels. I had the idea that 73 // when simply fading the subpixels towards the plain gray-scale-aa values, 74 // there must be a sweet spot for when colored edges become non-disturbing 75 // and there is still a benefit of sharpness compared to straight gray-scale- 76 // aa. The define above enables this method against the colored edges. My 77 // method still has a drawback, since jaggies in diagonal lines will be more 78 // visible again than with the filter method. 79 80 unsigned char averageWeight = gSubpixelAverageWeight; 81 unsigned char subpixelWeight = 255 - averageWeight; 82 83 unsigned int coverR; 84 unsigned int coverG; 85 unsigned int coverB; 86 87 unsigned int average = (cover1 + cover2 + cover3 + 2) / 3; 88 89 coverR = (cover1 * subpixelWeight + average * averageWeight) >> 8; 90 coverG = (cover2 * subpixelWeight + average * averageWeight) >> 8; 91 coverB = (cover3 * subpixelWeight + average * averageWeight) >> 8; 92 93 x -= m_min_x; 94 m_covers[3 * x] = (cover_type)coverR; 95 m_covers[3 * x + 1] = (cover_type)coverG; 96 m_covers[3 * x + 2] = (cover_type)coverB; 97 if(x == m_last_x + 1) 98 { 99 m_cur_span->len += 3; 100 } 101 else 102 { 103 m_cur_span++; 104 m_cur_span->x = (coord_type)(x + m_min_x); 105 m_cur_span->len = 3; 106 m_cur_span->covers = &m_covers[3 * x]; 107 } 108 m_last_x = x; 109 } 110 111 //-------------------------------------------------------------------- 112 void add_span(int x, unsigned len, unsigned cover) 113 { 114 x -= m_min_x; 115 memset(&m_covers[3 * x], cover, 3 * len); 116 if(x == m_last_x+1) 117 { 118 m_cur_span->len += 3 * (coord_type)len; 119 } 120 else 121 { 122 m_cur_span++; 123 m_cur_span->x = (coord_type)(x + m_min_x); 124 m_cur_span->len = 3 * (coord_type)len; 125 m_cur_span->covers = &m_covers[3 * x]; 126 } 127 m_last_x = x + len - 1; 128 } 129 130 //-------------------------------------------------------------------- 131 void finalize(int y) 132 { 133 m_y = y; 134 } 135 136 //-------------------------------------------------------------------- 137 void reset_spans() 138 { 139 m_last_x = 0x7FFFFFF0; 140 m_cur_span = &m_spans[0]; 141 } 142 143 //-------------------------------------------------------------------- 144 int y() const { return m_y; } 145 unsigned num_spans() const { return unsigned(m_cur_span - &m_spans[0]); } 146 const_iterator begin() const { return &m_spans[1]; } 147 iterator begin() { return &m_spans[1]; } 148 149 private: 150 scanline_u8_subpix_avrg_filtering(const self_type&); 151 const self_type& operator = (const self_type&); 152 153 private: 154 int m_min_x; 155 int m_last_x; 156 int m_y; 157 pod_array<cover_type> m_covers; 158 pod_array<span> m_spans; 159 span* m_cur_span; 160 }; 161 162} 163 164#endif 165 166