Anti-Grain Geometry - AGG (libagg)  2.5
agg-2.5/include/agg_span_gouraud_rgba.h
Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 // Anti-Grain Geometry (AGG) - Version 2.5
00003 // A high quality rendering engine for C++
00004 // Copyright (C) 2002-2006 Maxim Shemanarev
00005 // Contact: mcseem@antigrain.com
00006 //          mcseemagg@yahoo.com
00007 //          http://antigrain.com
00008 // 
00009 // AGG is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU General Public License
00011 // as published by the Free Software Foundation; either version 2
00012 // of the License, or (at your option) any later version.
00013 // 
00014 // AGG is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 // GNU General Public License for more details.
00018 // 
00019 // You should have received a copy of the GNU General Public License
00020 // along with AGG; if not, write to the Free Software
00021 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
00022 // MA 02110-1301, USA.
00023 //----------------------------------------------------------------------------
00024 //
00025 // Adaptation for high precision colors has been sponsored by 
00026 // Liberty Technology Systems, Inc., visit http://lib-sys.com
00027 //
00028 // Liberty Technology Systems, Inc. is the provider of
00029 // PostScript and PDF technology for software developers.
00030 // 
00031 //----------------------------------------------------------------------------
00032 
00033 #ifndef AGG_SPAN_GOURAUD_RGBA_INCLUDED
00034 #define AGG_SPAN_GOURAUD_RGBA_INCLUDED
00035 
00036 #include "agg_basics.h"
00037 #include "agg_color_rgba.h"
00038 #include "agg_dda_line.h"
00039 #include "agg_span_gouraud.h"
00040 
00041 namespace agg
00042 {
00043 
00044     //=======================================================span_gouraud_rgba
00045     template<class ColorT> class span_gouraud_rgba : public span_gouraud<ColorT>
00046     {
00047     public:
00048         typedef ColorT color_type;
00049         typedef typename ColorT::value_type value_type;
00050         typedef span_gouraud<color_type> base_type;
00051         typedef typename base_type::coord_type coord_type;
00052         enum subpixel_scale_e
00053         { 
00054             subpixel_shift = 4, 
00055             subpixel_scale = 1 << subpixel_shift
00056         };
00057 
00058     private:
00059         //--------------------------------------------------------------------
00060         struct rgba_calc
00061         {
00062             void init(const coord_type& c1, const coord_type& c2)
00063             {
00064                 m_x1  = c1.x - 0.5; 
00065                 m_y1  = c1.y - 0.5;
00066                 m_dx  = c2.x - c1.x;
00067                 double dy = c2.y - c1.y;
00068                 m_1dy = (dy < 1e-5) ? 1e5 : 1.0 / dy;
00069                 m_r1  = c1.color.r;
00070                 m_g1  = c1.color.g;
00071                 m_b1  = c1.color.b;
00072                 m_a1  = c1.color.a;
00073                 m_dr  = c2.color.r - m_r1;
00074                 m_dg  = c2.color.g - m_g1;
00075                 m_db  = c2.color.b - m_b1;
00076                 m_da  = c2.color.a - m_a1;
00077             }
00078 
00079             void calc(double y)
00080             {
00081                 double k = (y - m_y1) * m_1dy;
00082                 if(k < 0.0) k = 0.0;
00083                 if(k > 1.0) k = 1.0;
00084                 m_r = m_r1 + iround(m_dr * k);
00085                 m_g = m_g1 + iround(m_dg * k);
00086                 m_b = m_b1 + iround(m_db * k);
00087                 m_a = m_a1 + iround(m_da * k);
00088                 m_x = iround((m_x1 + m_dx * k) * subpixel_scale);
00089             }
00090 
00091             double m_x1;
00092             double m_y1;
00093             double m_dx;
00094             double m_1dy;
00095             int    m_r1;
00096             int    m_g1;
00097             int    m_b1;
00098             int    m_a1;
00099             int    m_dr;
00100             int    m_dg;
00101             int    m_db;
00102             int    m_da;
00103             int    m_r;
00104             int    m_g;
00105             int    m_b;
00106             int    m_a;
00107             int    m_x;
00108         };
00109 
00110     public:
00111 
00112         //--------------------------------------------------------------------
00113         span_gouraud_rgba() {}
00114         span_gouraud_rgba(const color_type& c1, 
00115                           const color_type& c2, 
00116                           const color_type& c3,
00117                           double x1, double y1, 
00118                           double x2, double y2,
00119                           double x3, double y3, 
00120                           double d = 0) : 
00121             base_type(c1, c2, c3, x1, y1, x2, y2, x3, y3, d)
00122         {}
00123 
00124         //--------------------------------------------------------------------
00125         void prepare()
00126         {
00127             coord_type coord[3];
00128             base_type::arrange_vertices(coord);
00129 
00130             m_y2 = int(coord[1].y);
00131 
00132             m_swap = cross_product(coord[0].x, coord[0].y, 
00133                                    coord[2].x, coord[2].y,
00134                                    coord[1].x, coord[1].y) < 0.0;
00135 
00136             m_rgba1.init(coord[0], coord[2]);
00137             m_rgba2.init(coord[0], coord[1]);
00138             m_rgba3.init(coord[1], coord[2]);
00139         }
00140 
00141         //--------------------------------------------------------------------
00142         void generate(color_type* span, int x, int y, unsigned len)
00143         {
00144             m_rgba1.calc(y);//(m_rgba1.m_1dy > 2) ? m_rgba1.m_y1 : y);
00145             const rgba_calc* pc1 = &m_rgba1;
00146             const rgba_calc* pc2 = &m_rgba2;
00147 
00148             if(y <= m_y2)
00149             {          
00150                 // Bottom part of the triangle (first subtriangle)
00151                 //-------------------------
00152                 m_rgba2.calc(y + m_rgba2.m_1dy);
00153             }
00154             else
00155             {
00156                 // Upper part (second subtriangle)
00157                 m_rgba3.calc(y - m_rgba3.m_1dy);
00158                 //-------------------------
00159                 pc2 = &m_rgba3;
00160             }
00161 
00162             if(m_swap)
00163             {
00164                 // It means that the triangle is oriented clockwise, 
00165                 // so that we need to swap the controlling structures
00166                 //-------------------------
00167                 const rgba_calc* t = pc2;
00168                 pc2 = pc1;
00169                 pc1 = t;
00170             }
00171 
00172             // Get the horizontal length with subpixel accuracy
00173             // and protect it from division by zero
00174             //-------------------------
00175             int nlen = abs(pc2->m_x - pc1->m_x);
00176             if(nlen <= 0) nlen = 1;
00177 
00178             dda_line_interpolator<14> r(pc1->m_r, pc2->m_r, nlen);
00179             dda_line_interpolator<14> g(pc1->m_g, pc2->m_g, nlen);
00180             dda_line_interpolator<14> b(pc1->m_b, pc2->m_b, nlen);
00181             dda_line_interpolator<14> a(pc1->m_a, pc2->m_a, nlen);
00182 
00183             // Calculate the starting point of the gradient with subpixel 
00184             // accuracy and correct (roll back) the interpolators.
00185             // This operation will also clip the beginning of the span
00186             // if necessary.
00187             //-------------------------
00188             int start = pc1->m_x - (x << subpixel_shift);
00189             r    -= start; 
00190             g    -= start; 
00191             b    -= start; 
00192             a    -= start;
00193             nlen += start;
00194 
00195             int vr, vg, vb, va;
00196             enum lim_e { lim = color_type::base_mask };
00197 
00198             // Beginning part of the span. Since we rolled back the 
00199             // interpolators, the color values may have overflow.
00200             // So that, we render the beginning part with checking 
00201             // for overflow. It lasts until "start" is positive;
00202             // typically it's 1-2 pixels, but may be more in some cases.
00203             //-------------------------
00204             while(len && start > 0)
00205             {
00206                 vr = r.y();
00207                 vg = g.y();
00208                 vb = b.y();
00209                 va = a.y();
00210                 if(vr < 0) vr = 0; if(vr > lim) vr = lim;
00211                 if(vg < 0) vg = 0; if(vg > lim) vg = lim;
00212                 if(vb < 0) vb = 0; if(vb > lim) vb = lim;
00213                 if(va < 0) va = 0; if(va > lim) va = lim;
00214                 span->r = (value_type)vr;
00215                 span->g = (value_type)vg;
00216                 span->b = (value_type)vb;
00217                 span->a = (value_type)va;
00218                 r     += subpixel_scale; 
00219                 g     += subpixel_scale; 
00220                 b     += subpixel_scale; 
00221                 a     += subpixel_scale;
00222                 nlen  -= subpixel_scale;
00223                 start -= subpixel_scale;
00224                 ++span;
00225                 --len;
00226             }
00227 
00228             // Middle part, no checking for overflow.
00229             // Actual spans can be longer than the calculated length
00230             // because of anti-aliasing, thus, the interpolators can 
00231             // overflow. But while "nlen" is positive we are safe.
00232             //-------------------------
00233             while(len && nlen > 0)
00234             {
00235                 span->r = (value_type)r.y();
00236                 span->g = (value_type)g.y();
00237                 span->b = (value_type)b.y();
00238                 span->a = (value_type)a.y();
00239                 r    += subpixel_scale; 
00240                 g    += subpixel_scale; 
00241                 b    += subpixel_scale; 
00242                 a    += subpixel_scale;
00243                 nlen -= subpixel_scale;
00244                 ++span;
00245                 --len;
00246             }
00247 
00248             // Ending part; checking for overflow.
00249             // Typically it's 1-2 pixels, but may be more in some cases.
00250             //-------------------------
00251             while(len)
00252             {
00253                 vr = r.y();
00254                 vg = g.y();
00255                 vb = b.y();
00256                 va = a.y();
00257                 if(vr < 0) vr = 0; if(vr > lim) vr = lim;
00258                 if(vg < 0) vg = 0; if(vg > lim) vg = lim;
00259                 if(vb < 0) vb = 0; if(vb > lim) vb = lim;
00260                 if(va < 0) va = 0; if(va > lim) va = lim;
00261                 span->r = (value_type)vr;
00262                 span->g = (value_type)vg;
00263                 span->b = (value_type)vb;
00264                 span->a = (value_type)va;
00265                 r += subpixel_scale; 
00266                 g += subpixel_scale; 
00267                 b += subpixel_scale; 
00268                 a += subpixel_scale;
00269                 ++span;
00270                 --len;
00271             }
00272         }
00273 
00274     private:
00275         bool      m_swap;
00276         int       m_y2;
00277         rgba_calc m_rgba1;
00278         rgba_calc m_rgba2;
00279         rgba_calc m_rgba3;
00280     };
00281 
00282 
00283 
00284 }
00285 
00286 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines