egl/sfopenvg/riPixelPipe.cpp
branchEGL_MERGE
changeset 180 f767bd5f4cfc
parent 119 5f371025658c
child 181 c1509651cd2b
equal deleted inserted replaced
119:5f371025658c 180:f767bd5f4cfc
     1 /*------------------------------------------------------------------------
       
     2  *
       
     3  * OpenVG 1.1 Reference Implementation
       
     4  * -----------------------------------
       
     5  *
       
     6  * Copyright (c) 2007 The Khronos Group Inc.
       
     7  *
       
     8  * Permission is hereby granted, free of charge, to any person obtaining a
       
     9  * copy of this software and /or associated documentation files
       
    10  * (the "Materials "), to deal in the Materials without restriction,
       
    11  * including without limitation the rights to use, copy, modify, merge,
       
    12  * publish, distribute, sublicense, and/or sell copies of the Materials,
       
    13  * and to permit persons to whom the Materials are furnished to do so,
       
    14  * subject to the following conditions: 
       
    15  *
       
    16  * The above copyright notice and this permission notice shall be included 
       
    17  * in all copies or substantial portions of the Materials. 
       
    18  *
       
    19  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
       
    20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
       
    21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
       
    22  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
       
    23  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
       
    24  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
       
    25  * THE USE OR OTHER DEALINGS IN THE MATERIALS.
       
    26  *
       
    27  *//**
       
    28  * \file
       
    29  * \brief   Implementation of Paint and pixel pipe functionality.
       
    30  * \note    
       
    31  *//*-------------------------------------------------------------------*/
       
    32 
       
    33 #include "riPixelPipe.h"
       
    34 
       
    35 //==============================================================================================
       
    36 
       
    37 namespace OpenVGRI
       
    38 {
       
    39 
       
    40 /*-------------------------------------------------------------------*//*!
       
    41 * \brief    Paint constructor.
       
    42 * \param    
       
    43 * \return   
       
    44 * \note     
       
    45 *//*-------------------------------------------------------------------*/
       
    46 
       
    47 Paint::Paint() :
       
    48     m_paintType(VG_PAINT_TYPE_COLOR),
       
    49     m_paintColor(0,0,0,1,Color::sRGBA_PRE),
       
    50     m_inputPaintColor(0,0,0,1,Color::sRGBA),
       
    51     m_colorRampSpreadMode(VG_COLOR_RAMP_SPREAD_PAD),
       
    52     m_colorRampStops(),
       
    53     m_inputColorRampStops(),
       
    54     m_colorRampPremultiplied(VG_TRUE),
       
    55     m_inputLinearGradientPoint0(0,0),
       
    56     m_inputLinearGradientPoint1(1,0),
       
    57     m_inputRadialGradientCenter(0,0),
       
    58     m_inputRadialGradientFocalPoint(0,0),
       
    59     m_inputRadialGradientRadius(1.0f),
       
    60     m_linearGradientPoint0(0,0),
       
    61     m_linearGradientPoint1(1,0),
       
    62     m_radialGradientCenter(0,0),
       
    63     m_radialGradientFocalPoint(0,0),
       
    64     m_radialGradientRadius(1.0f),
       
    65     m_patternTilingMode(VG_TILE_FILL),
       
    66     m_pattern(NULL),
       
    67     m_referenceCount(0)
       
    68 {
       
    69     Paint::GradientStop gs;
       
    70     gs.offset = 0.0f;
       
    71     gs.color.set(0,0,0,1,Color::sRGBA);
       
    72     m_colorRampStops.push_back(gs); //throws bad_alloc
       
    73     gs.offset = 1.0f;
       
    74     gs.color.set(1,1,1,1,Color::sRGBA);
       
    75     m_colorRampStops.push_back(gs); //throws bad_alloc
       
    76 }
       
    77 
       
    78 /*-------------------------------------------------------------------*//*!
       
    79 * \brief    Paint destructor.
       
    80 * \param    
       
    81 * \return   
       
    82 * \note     
       
    83 *//*-------------------------------------------------------------------*/
       
    84 
       
    85 Paint::~Paint()
       
    86 {
       
    87     RI_ASSERT(m_referenceCount == 0);
       
    88     if(m_pattern)
       
    89     {
       
    90         m_pattern->removeInUse();
       
    91         if(!m_pattern->removeReference())
       
    92             RI_DELETE(m_pattern);
       
    93     }
       
    94 }
       
    95 
       
    96 /*-------------------------------------------------------------------*//*!
       
    97 * \brief    PixelPipe constructor.
       
    98 * \param    
       
    99 * \return   
       
   100 * \note     
       
   101 *//*-------------------------------------------------------------------*/
       
   102 
       
   103 PixelPipe::PixelPipe() :
       
   104     m_drawable(NULL),
       
   105     m_image(NULL),
       
   106     m_paint(NULL),
       
   107     m_defaultPaint(),
       
   108     m_blendMode(VG_BLEND_SRC_OVER),
       
   109     m_imageMode(VG_DRAW_IMAGE_NORMAL),
       
   110     m_imageQuality(VG_IMAGE_QUALITY_FASTER),
       
   111     m_tileFillColor(0,0,0,0,Color::sRGBA),
       
   112     m_colorTransform(false),
       
   113     m_colorTransformValues(),
       
   114     m_surfaceToPaintMatrix(),
       
   115     m_surfaceToImageMatrix()
       
   116 {
       
   117     for(int i=0;i<8;i++)
       
   118         m_colorTransformValues[i] = (i < 4) ? 1.0f : 0.0f;
       
   119 }
       
   120 
       
   121 /*-------------------------------------------------------------------*//*!
       
   122 * \brief    PixelPipe destructor.
       
   123 * \param    
       
   124 * \return   
       
   125 * \note     
       
   126 *//*-------------------------------------------------------------------*/
       
   127 
       
   128 PixelPipe::~PixelPipe()
       
   129 {
       
   130 }
       
   131 
       
   132 /*-------------------------------------------------------------------*//*!
       
   133 * \brief    Sets the rendering surface.
       
   134 * \param    
       
   135 * \return   
       
   136 * \note     
       
   137 *//*-------------------------------------------------------------------*/
       
   138 
       
   139 void PixelPipe::setDrawable(Drawable* drawable)
       
   140 {
       
   141     RI_ASSERT(drawable);
       
   142     m_drawable = drawable;
       
   143 }
       
   144 
       
   145 /*-------------------------------------------------------------------*//*!
       
   146 * \brief    Sets the blend mode.
       
   147 * \param    
       
   148 * \return   
       
   149 * \note     
       
   150 *//*-------------------------------------------------------------------*/
       
   151 
       
   152 void PixelPipe::setBlendMode(VGBlendMode blendMode)
       
   153 {
       
   154     RI_ASSERT(blendMode >= VG_BLEND_SRC && blendMode <= VG_BLEND_ADDITIVE);
       
   155     m_blendMode = blendMode;
       
   156 }
       
   157 
       
   158 /*-------------------------------------------------------------------*//*!
       
   159 * \brief    Sets the mask image. NULL disables masking.
       
   160 * \param    
       
   161 * \return   
       
   162 * \note     
       
   163 *//*-------------------------------------------------------------------*/
       
   164 
       
   165 void PixelPipe::setMask(bool masking)
       
   166 {
       
   167     m_masking = masking;
       
   168 }
       
   169 
       
   170 /*-------------------------------------------------------------------*//*!
       
   171 * \brief    Sets the image to be drawn. NULL disables image drawing.
       
   172 * \param    
       
   173 * \return   
       
   174 * \note     
       
   175 *//*-------------------------------------------------------------------*/
       
   176 
       
   177 void PixelPipe::setImage(Image* image, VGImageMode imageMode)
       
   178 {
       
   179     RI_ASSERT(imageMode == VG_DRAW_IMAGE_NORMAL || imageMode == VG_DRAW_IMAGE_MULTIPLY || imageMode == VG_DRAW_IMAGE_STENCIL);
       
   180     m_image = image;
       
   181     m_imageMode = imageMode;
       
   182 }
       
   183 
       
   184 /*-------------------------------------------------------------------*//*!
       
   185 * \brief    Sets the surface-to-paint matrix.
       
   186 * \param    
       
   187 * \return   
       
   188 * \note     
       
   189 *//*-------------------------------------------------------------------*/
       
   190 
       
   191 void PixelPipe::setSurfaceToPaintMatrix(const Matrix3x3& surfaceToPaintMatrix)
       
   192 {
       
   193     m_surfaceToPaintMatrix = surfaceToPaintMatrix;
       
   194 }
       
   195 
       
   196 /*-------------------------------------------------------------------*//*!
       
   197 * \brief    Sets the surface-to-image matrix.
       
   198 * \param    
       
   199 * \return   
       
   200 * \note     
       
   201 *//*-------------------------------------------------------------------*/
       
   202 
       
   203 void PixelPipe::setSurfaceToImageMatrix(const Matrix3x3& surfaceToImageMatrix)
       
   204 {
       
   205     m_surfaceToImageMatrix = surfaceToImageMatrix;
       
   206 }
       
   207 
       
   208 /*-------------------------------------------------------------------*//*!
       
   209 * \brief    Sets image quality.
       
   210 * \param    
       
   211 * \return   
       
   212 * \note     
       
   213 *//*-------------------------------------------------------------------*/
       
   214 
       
   215 void PixelPipe::setImageQuality(VGImageQuality imageQuality)
       
   216 {
       
   217     RI_ASSERT(imageQuality == VG_IMAGE_QUALITY_NONANTIALIASED || imageQuality == VG_IMAGE_QUALITY_FASTER || imageQuality == VG_IMAGE_QUALITY_BETTER);
       
   218     m_imageQuality = imageQuality;
       
   219 }
       
   220 
       
   221 /*-------------------------------------------------------------------*//*!
       
   222 * \brief    Sets fill color for VG_TILE_FILL tiling mode (pattern only).
       
   223 * \param    
       
   224 * \return   
       
   225 * \note     
       
   226 *//*-------------------------------------------------------------------*/
       
   227 
       
   228 void PixelPipe::setTileFillColor(const Color& c)
       
   229 {
       
   230     m_tileFillColor = c;
       
   231     m_tileFillColor.clamp();
       
   232 }
       
   233 
       
   234 /*-------------------------------------------------------------------*//*!
       
   235 * \brief    Sets paint.
       
   236 * \param    
       
   237 * \return   
       
   238 * \note     
       
   239 *//*-------------------------------------------------------------------*/
       
   240 
       
   241 void PixelPipe::setPaint(const Paint* paint)
       
   242 {
       
   243     m_paint = paint;
       
   244     if(!m_paint)
       
   245         m_paint = &m_defaultPaint;
       
   246     if(m_paint->m_pattern)
       
   247         m_tileFillColor.convert(m_paint->m_pattern->getDescriptor().internalFormat);
       
   248 }
       
   249 
       
   250 /*-------------------------------------------------------------------*//*!
       
   251 * \brief    Color transform.
       
   252 * \param    
       
   253 * \return   
       
   254 * \note     
       
   255 *//*-------------------------------------------------------------------*/
       
   256 
       
   257 void PixelPipe::setColorTransform(bool enable, RIfloat values[8])
       
   258 {
       
   259     m_colorTransform = enable;
       
   260     for(int i=0;i<4;i++)
       
   261     {
       
   262         m_colorTransformValues[i] = RI_CLAMP(values[i], -127.0f, 127.0f);
       
   263         m_colorTransformValues[i+4] = RI_CLAMP(values[i+4], -1.0f, 1.0f);
       
   264     }
       
   265 }
       
   266 
       
   267 /*-------------------------------------------------------------------*//*!
       
   268 * \brief    Computes the linear gradient function at (x,y).
       
   269 * \param    
       
   270 * \return   
       
   271 * \note     
       
   272 *//*-------------------------------------------------------------------*/
       
   273 
       
   274 void PixelPipe::linearGradient(RIfloat& g, RIfloat& rho, RIfloat x, RIfloat y) const
       
   275 {
       
   276     RI_ASSERT(m_paint);
       
   277     Vector2 u = m_paint->m_linearGradientPoint1 - m_paint->m_linearGradientPoint0;
       
   278     RIfloat usq = dot(u,u);
       
   279     if( usq <= 0.0f )
       
   280     {   //points are equal, gradient is always 1.0f
       
   281         g = 1.0f;
       
   282         rho = 0.0f;
       
   283         return;
       
   284     }
       
   285     RIfloat oou = 1.0f / usq;
       
   286 
       
   287     Vector2 p(x, y);
       
   288     p = affineTransform(m_surfaceToPaintMatrix, p);
       
   289     p -= m_paint->m_linearGradientPoint0;
       
   290     RI_ASSERT(usq >= 0.0f);
       
   291     g = dot(p, u) * oou;
       
   292     RIfloat dgdx = oou * u.x * m_surfaceToPaintMatrix[0][0] + oou * u.y * m_surfaceToPaintMatrix[1][0];
       
   293     RIfloat dgdy = oou * u.x * m_surfaceToPaintMatrix[0][1] + oou * u.y * m_surfaceToPaintMatrix[1][1];
       
   294     rho = (RIfloat)sqrt(dgdx*dgdx + dgdy*dgdy);
       
   295     RI_ASSERT(rho >= 0.0f);
       
   296 }
       
   297 
       
   298 /*-------------------------------------------------------------------*//*!
       
   299 * \brief    Computes the radial gradient function at (x,y).
       
   300 * \param    
       
   301 * \return   
       
   302 * \note     
       
   303 *//*-------------------------------------------------------------------*/
       
   304 
       
   305 void PixelPipe::radialGradient(RIfloat &g, RIfloat &rho, RIfloat x, RIfloat y) const
       
   306 {
       
   307     RI_ASSERT(m_paint);
       
   308     if( m_paint->m_radialGradientRadius <= 0.0f )
       
   309     {
       
   310         g = 1.0f;
       
   311         rho = 0.0f;
       
   312         return;
       
   313     }
       
   314 
       
   315     RIfloat r = m_paint->m_radialGradientRadius;
       
   316     Vector2 c = m_paint->m_radialGradientCenter;
       
   317     Vector2 f = m_paint->m_radialGradientFocalPoint;
       
   318     Vector2 gx(m_surfaceToPaintMatrix[0][0], m_surfaceToPaintMatrix[1][0]);
       
   319     Vector2 gy(m_surfaceToPaintMatrix[0][1], m_surfaceToPaintMatrix[1][1]);
       
   320 
       
   321     Vector2 fp = f - c;
       
   322 
       
   323     //clamp the focal point inside the gradient circle
       
   324     RIfloat fpLen = fp.length();
       
   325     if( fpLen > 0.999f * r )
       
   326         fp *= 0.999f * r / fpLen;
       
   327 
       
   328     RIfloat D = -1.0f / (dot(fp,fp) - r*r);
       
   329     Vector2 p(x, y);
       
   330     p = affineTransform(m_surfaceToPaintMatrix, p) - c;
       
   331     Vector2 d = p - fp;
       
   332     RIfloat s = (RIfloat)sqrt(r*r*dot(d,d) - RI_SQR(p.x*fp.y - p.y*fp.x));
       
   333     g = (dot(fp,d) + s) * D;
       
   334     if(RI_ISNAN(g))
       
   335         g = 0.0f;
       
   336     RIfloat dgdx = D*dot(fp,gx) + (r*r*dot(d,gx) - (gx.x*fp.y - gx.y*fp.x)*(p.x*fp.y - p.y*fp.x)) * (D / s);
       
   337     RIfloat dgdy = D*dot(fp,gy) + (r*r*dot(d,gy) - (gy.x*fp.y - gy.y*fp.x)*(p.x*fp.y - p.y*fp.x)) * (D / s);
       
   338     rho = (RIfloat)sqrt(dgdx*dgdx + dgdy*dgdy);
       
   339     if(RI_ISNAN(rho))
       
   340         rho = 0.0f;
       
   341     RI_ASSERT(rho >= 0.0f);
       
   342 }
       
   343 
       
   344 /*-------------------------------------------------------------------*//*!
       
   345 * \brief    Returns the average color within an offset range in the color ramp.
       
   346 * \param    
       
   347 * \return   
       
   348 * \note     
       
   349 *//*-------------------------------------------------------------------*/
       
   350 
       
   351 static Color readStopColor(const Array<Paint::GradientStop>& colorRampStops, int i, VGboolean colorRampPremultiplied)
       
   352 {
       
   353     RI_ASSERT(i >= 0 && i < colorRampStops.size());
       
   354     Color c = colorRampStops[i].color;
       
   355     RI_ASSERT(c.getInternalFormat() == Color::sRGBA);
       
   356     if(colorRampPremultiplied)
       
   357         c.premultiply();
       
   358     return c;
       
   359 }
       
   360 
       
   361 Color PixelPipe::integrateColorRamp(RIfloat gmin, RIfloat gmax) const
       
   362 {
       
   363     RI_ASSERT(gmin <= gmax);
       
   364     RI_ASSERT(gmin >= 0.0f && gmin <= 1.0f);
       
   365     RI_ASSERT(gmax >= 0.0f && gmax <= 1.0f);
       
   366     RI_ASSERT(m_paint->m_colorRampStops.size() >= 2);   //there are at least two stops
       
   367 
       
   368     Color c(0,0,0,0,m_paint->m_colorRampPremultiplied ? Color::sRGBA_PRE : Color::sRGBA);
       
   369     if(gmin == 1.0f || gmax == 0.0f)
       
   370         return c;
       
   371 
       
   372     int i=0;
       
   373     for(;i<m_paint->m_colorRampStops.size()-1;i++)
       
   374     {
       
   375         if(gmin >= m_paint->m_colorRampStops[i].offset && gmin < m_paint->m_colorRampStops[i+1].offset)
       
   376         {
       
   377             RIfloat s = m_paint->m_colorRampStops[i].offset;
       
   378             RIfloat e = m_paint->m_colorRampStops[i+1].offset;
       
   379             RI_ASSERT(s < e);
       
   380             RIfloat g = (gmin - s) / (e - s);
       
   381 
       
   382             Color sc = readStopColor(m_paint->m_colorRampStops, i, m_paint->m_colorRampPremultiplied);
       
   383             Color ec = readStopColor(m_paint->m_colorRampStops, i+1, m_paint->m_colorRampPremultiplied);
       
   384             Color rc = (1.0f-g) * sc + g * ec;
       
   385 
       
   386             //subtract the average color from the start of the stop to gmin
       
   387             c -= 0.5f*(gmin - s)*(sc + rc);
       
   388             break;
       
   389         }
       
   390     }
       
   391 
       
   392     for(;i<m_paint->m_colorRampStops.size()-1;i++)
       
   393     {
       
   394         RIfloat s = m_paint->m_colorRampStops[i].offset;
       
   395         RIfloat e = m_paint->m_colorRampStops[i+1].offset;
       
   396         RI_ASSERT(s <= e);
       
   397 
       
   398         Color sc = readStopColor(m_paint->m_colorRampStops, i, m_paint->m_colorRampPremultiplied);
       
   399         Color ec = readStopColor(m_paint->m_colorRampStops, i+1, m_paint->m_colorRampPremultiplied);
       
   400 
       
   401         //average of the stop
       
   402         c += 0.5f*(e-s)*(sc + ec);
       
   403 
       
   404         if(gmax >= m_paint->m_colorRampStops[i].offset && gmax < m_paint->m_colorRampStops[i+1].offset)
       
   405         {
       
   406             RIfloat g = (gmax - s) / (e - s);
       
   407             Color rc = (1.0f-g) * sc + g * ec;
       
   408 
       
   409             //subtract the average color from gmax to the end of the stop
       
   410             c -= 0.5f*(e - gmax)*(rc + ec);
       
   411             break;
       
   412         }
       
   413     }
       
   414     return c;
       
   415 }
       
   416 
       
   417 /*-------------------------------------------------------------------*//*!
       
   418 * \brief    Maps a gradient function value to a color.
       
   419 * \param    
       
   420 * \return   
       
   421 * \note     
       
   422 *//*-------------------------------------------------------------------*/
       
   423 
       
   424 Color PixelPipe::colorRamp(RIfloat gradient, RIfloat rho) const
       
   425 {
       
   426     RI_ASSERT(m_paint);
       
   427     RI_ASSERT(rho >= 0.0f);
       
   428 
       
   429     Color c(0,0,0,0,m_paint->m_colorRampPremultiplied ? Color::sRGBA_PRE : Color::sRGBA);
       
   430     Color avg;
       
   431 
       
   432     if(rho == 0.0f)
       
   433     {   //filter size is zero or gradient is degenerate
       
   434         switch(m_paint->m_colorRampSpreadMode)
       
   435         {
       
   436         case VG_COLOR_RAMP_SPREAD_PAD:
       
   437             gradient = RI_CLAMP(gradient, 0.0f, 1.0f);
       
   438             break;
       
   439         case VG_COLOR_RAMP_SPREAD_REFLECT:
       
   440         {
       
   441             RIfloat g = RI_MOD(gradient, 2.0f);
       
   442             gradient = (g < 1.0f) ? g : 2.0f - g;
       
   443             break;
       
   444         }
       
   445         default:
       
   446             RI_ASSERT(m_paint->m_colorRampSpreadMode == VG_COLOR_RAMP_SPREAD_REPEAT);
       
   447             gradient = gradient - (RIfloat)floor(gradient);
       
   448             break;
       
   449         }
       
   450         RI_ASSERT(gradient >= 0.0f && gradient <= 1.0f);
       
   451 
       
   452         for(int i=0;i<m_paint->m_colorRampStops.size()-1;i++)
       
   453         {
       
   454             if(gradient >= m_paint->m_colorRampStops[i].offset && gradient < m_paint->m_colorRampStops[i+1].offset)
       
   455             {
       
   456                 RIfloat s = m_paint->m_colorRampStops[i].offset;
       
   457                 RIfloat e = m_paint->m_colorRampStops[i+1].offset;
       
   458                 RI_ASSERT(s < e);
       
   459                 RIfloat g = RI_CLAMP((gradient - s) / (e - s), 0.0f, 1.0f); //clamp needed due to numerical inaccuracies
       
   460 
       
   461                 Color sc = readStopColor(m_paint->m_colorRampStops, i, m_paint->m_colorRampPremultiplied);
       
   462                 Color ec = readStopColor(m_paint->m_colorRampStops, i+1, m_paint->m_colorRampPremultiplied);
       
   463                 return (1.0f-g) * sc + g * ec;  //return interpolated value
       
   464             }
       
   465         }
       
   466         return readStopColor(m_paint->m_colorRampStops, m_paint->m_colorRampStops.size()-1, m_paint->m_colorRampPremultiplied);
       
   467     }
       
   468 
       
   469     RIfloat gmin = gradient - rho*0.5f;         //filter starting from the gradient point (if starts earlier, radial gradient center will be an average of the first and the last stop, which doesn't look good)
       
   470     RIfloat gmax = gradient + rho*0.5f;
       
   471 
       
   472     switch(m_paint->m_colorRampSpreadMode)
       
   473     {
       
   474     case VG_COLOR_RAMP_SPREAD_PAD:
       
   475     {
       
   476         if(gmin < 0.0f)
       
   477             c += (RI_MIN(gmax, 0.0f) - gmin) * readStopColor(m_paint->m_colorRampStops, 0, m_paint->m_colorRampPremultiplied);
       
   478         if(gmax > 1.0f)
       
   479             c += (gmax - RI_MAX(gmin, 1.0f)) * readStopColor(m_paint->m_colorRampStops, m_paint->m_colorRampStops.size()-1, m_paint->m_colorRampPremultiplied);
       
   480         gmin = RI_CLAMP(gmin, 0.0f, 1.0f);
       
   481         gmax = RI_CLAMP(gmax, 0.0f, 1.0f);
       
   482         c += integrateColorRamp(gmin, gmax);
       
   483         c *= 1.0f/rho;
       
   484         c.clamp();  //clamp needed due to numerical inaccuracies
       
   485         return c;
       
   486     }
       
   487 
       
   488     case VG_COLOR_RAMP_SPREAD_REFLECT:
       
   489     {
       
   490         avg = integrateColorRamp(0.0f, 1.0f);
       
   491         RIfloat gmini = (RIfloat)floor(gmin);
       
   492         RIfloat gmaxi = (RIfloat)floor(gmax);
       
   493         c = (gmaxi + 1.0f - gmini) * avg;       //full ramps
       
   494 
       
   495         //subtract beginning
       
   496         if(((int)gmini) & 1)
       
   497             c -= integrateColorRamp(RI_CLAMP(1.0f - (gmin - gmini), 0.0f, 1.0f), 1.0f);
       
   498         else
       
   499             c -= integrateColorRamp(0.0f, RI_CLAMP(gmin - gmini, 0.0f, 1.0f));
       
   500 
       
   501         //subtract end
       
   502         if(((int)gmaxi) & 1)
       
   503             c -= integrateColorRamp(0.0f, RI_CLAMP(1.0f - (gmax - gmaxi), 0.0f, 1.0f));
       
   504         else
       
   505             c -= integrateColorRamp(RI_CLAMP(gmax - gmaxi, 0.0f, 1.0f), 1.0f);
       
   506         break;
       
   507     }
       
   508 
       
   509     default:
       
   510     {
       
   511         RI_ASSERT(m_paint->m_colorRampSpreadMode == VG_COLOR_RAMP_SPREAD_REPEAT);
       
   512         avg = integrateColorRamp(0.0f, 1.0f);
       
   513         RIfloat gmini = (RIfloat)floor(gmin);
       
   514         RIfloat gmaxi = (RIfloat)floor(gmax);
       
   515         c = (gmaxi + 1.0f - gmini) * avg;       //full ramps
       
   516         c -= integrateColorRamp(0.0f, RI_CLAMP(gmin - gmini, 0.0f, 1.0f));  //subtract beginning
       
   517         c -= integrateColorRamp(RI_CLAMP(gmax - gmaxi, 0.0f, 1.0f), 1.0f);  //subtract end
       
   518         break;
       
   519     }
       
   520     }
       
   521 
       
   522     //divide color by the length of the range
       
   523     c *= 1.0f / rho;
       
   524     c.clamp();  //clamp needed due to numerical inaccuracies
       
   525 
       
   526     //hide aliasing by fading to the average color
       
   527     const RIfloat fadeStart = 0.5f;
       
   528     const RIfloat fadeMultiplier = 2.0f;    //the larger, the earlier fade to average is done
       
   529 
       
   530     if(rho < fadeStart)
       
   531         return c;
       
   532 
       
   533     RIfloat ratio = RI_MIN((rho - fadeStart) * fadeMultiplier, 1.0f);
       
   534     return ratio * avg + (1.0f - ratio) * c;
       
   535 }
       
   536 
       
   537 /*-------------------------------------------------------------------*//*!
       
   538 * \brief    Computes blend.
       
   539 * \param    
       
   540 * \return   
       
   541 * \note     premultiplied blending formulas
       
   542             //src
       
   543             a = asrc
       
   544             r = rsrc
       
   545             //src over
       
   546             a = asrc + adst * (1-asrc)
       
   547             r = rsrc + rdst * (1-asrc)
       
   548             //dst over
       
   549             a = asrc * (1-adst) + adst
       
   550             r = rsrc * (1-adst) + adst
       
   551             //src in
       
   552             a = asrc * adst
       
   553             r = rsrc * adst
       
   554             //dst in
       
   555             a = adst * asrc
       
   556             r = rdst * asrc
       
   557             //multiply
       
   558             a = asrc + adst * (1-asrc)
       
   559             r = rsrc * (1-adst) + rdst * (1-asrc) + rsrc * rdst
       
   560             //screen
       
   561             a = asrc + adst * (1-asrc)
       
   562             r = rsrc + rdst - rsrc * rdst
       
   563             //darken
       
   564             a = asrc + adst * (1-asrc)
       
   565             r = MIN(rsrc + rdst * (1-asrc), rdst + rsrc * (1-adst))
       
   566             //lighten
       
   567             a = asrc + adst * (1-asrc)
       
   568             r = MAX(rsrc + rdst * (1-asrc), rdst + rsrc * (1-adst))
       
   569             //additive
       
   570             a = MIN(asrc+adst,1)
       
   571             r = rsrc + rdst
       
   572 *//*-------------------------------------------------------------------*/
       
   573 
       
   574 Color PixelPipe::blend(const Color& s, RIfloat ar, RIfloat ag, RIfloat ab, const Color& d, VGBlendMode blendMode) const
       
   575 {
       
   576     //apply blending in the premultiplied format
       
   577     Color r(0,0,0,0,d.getInternalFormat());
       
   578     RI_ASSERT(s.a >= 0.0f && s.a <= 1.0f);
       
   579     RI_ASSERT(s.r >= 0.0f && s.r <= s.a && s.r <= ar);
       
   580     RI_ASSERT(s.g >= 0.0f && s.g <= s.a && s.g <= ag);
       
   581     RI_ASSERT(s.b >= 0.0f && s.b <= s.a && s.b <= ab);
       
   582     RI_ASSERT(d.a >= 0.0f && d.a <= 1.0f);
       
   583     RI_ASSERT(d.r >= 0.0f && d.r <= d.a);
       
   584     RI_ASSERT(d.g >= 0.0f && d.g <= d.a);
       
   585     RI_ASSERT(d.b >= 0.0f && d.b <= d.a);
       
   586     switch(blendMode)
       
   587     {
       
   588     case VG_BLEND_SRC:
       
   589         r = s;
       
   590         break;
       
   591 
       
   592     case VG_BLEND_SRC_OVER:
       
   593         r.r = s.r + d.r * (1.0f - ar);
       
   594         r.g = s.g + d.g * (1.0f - ag);
       
   595         r.b = s.b + d.b * (1.0f - ab);
       
   596         r.a = s.a + d.a * (1.0f - s.a);
       
   597         break;
       
   598 
       
   599     case VG_BLEND_DST_OVER:
       
   600         r.r = s.r * (1.0f - d.a) + d.r;
       
   601         r.g = s.g * (1.0f - d.a) + d.g;
       
   602         r.b = s.b * (1.0f - d.a) + d.b;
       
   603         r.a = s.a * (1.0f - d.a) + d.a;
       
   604         break;
       
   605 
       
   606     case VG_BLEND_SRC_IN:
       
   607         r.r = s.r * d.a;
       
   608         r.g = s.g * d.a;
       
   609         r.b = s.b * d.a;
       
   610         r.a = s.a * d.a;
       
   611         break;
       
   612 
       
   613     case VG_BLEND_DST_IN:
       
   614         r.r = d.r * ar;
       
   615         r.g = d.g * ag;
       
   616         r.b = d.b * ab;
       
   617         r.a = d.a * s.a;
       
   618         break;
       
   619 
       
   620     case VG_BLEND_MULTIPLY:
       
   621         r.r = s.r * (1.0f - d.a + d.r) + d.r * (1.0f - ar);
       
   622         r.g = s.g * (1.0f - d.a + d.g) + d.g * (1.0f - ag);
       
   623         r.b = s.b * (1.0f - d.a + d.b) + d.b * (1.0f - ab);
       
   624         r.a = s.a + d.a * (1.0f - s.a);
       
   625         break;
       
   626 
       
   627     case VG_BLEND_SCREEN:
       
   628         r.r = s.r + d.r * (1.0f - s.r);
       
   629         r.g = s.g + d.g * (1.0f - s.g);
       
   630         r.b = s.b + d.b * (1.0f - s.b);
       
   631         r.a = s.a + d.a * (1.0f - s.a);
       
   632         break;
       
   633 
       
   634     case VG_BLEND_DARKEN:
       
   635         r.r = RI_MIN(s.r + d.r * (1.0f - ar), d.r + s.r * (1.0f - d.a));
       
   636         r.g = RI_MIN(s.g + d.g * (1.0f - ag), d.g + s.g * (1.0f - d.a));
       
   637         r.b = RI_MIN(s.b + d.b * (1.0f - ab), d.b + s.b * (1.0f - d.a));
       
   638         r.a = s.a + d.a * (1.0f - s.a);
       
   639         break;
       
   640 
       
   641     case VG_BLEND_LIGHTEN:
       
   642         r.r = RI_MAX(s.r + d.r * (1.0f - ar), d.r + s.r * (1.0f - d.a));
       
   643         r.g = RI_MAX(s.g + d.g * (1.0f - ag), d.g + s.g * (1.0f - d.a));
       
   644         r.b = RI_MAX(s.b + d.b * (1.0f - ab), d.b + s.b * (1.0f - d.a));
       
   645         //although the statement below is equivalent to r.a = s.a + d.a * (1.0f - s.a)
       
   646         //in practice there can be a very slight difference because
       
   647         //of the max operation in the blending formula that may cause color to exceed alpha.
       
   648         //Because of this, we compute the result both ways and return the maximum.
       
   649         r.a = RI_MAX(s.a + d.a * (1.0f - s.a), d.a + s.a * (1.0f - d.a));
       
   650         break;
       
   651 
       
   652     default:
       
   653         RI_ASSERT(blendMode == VG_BLEND_ADDITIVE);
       
   654         r.r = RI_MIN(s.r + d.r, 1.0f);
       
   655         r.g = RI_MIN(s.g + d.g, 1.0f);
       
   656         r.b = RI_MIN(s.b + d.b, 1.0f);
       
   657         r.a = RI_MIN(s.a + d.a, 1.0f);
       
   658         break;
       
   659     }
       
   660     return r;
       
   661 }
       
   662 
       
   663 /*-------------------------------------------------------------------*//*!
       
   664 * \brief    Applies color transform.
       
   665 * \param    
       
   666 * \return   
       
   667 * \note
       
   668 *//*-------------------------------------------------------------------*/
       
   669 
       
   670 void PixelPipe::colorTransform(Color& c) const
       
   671 {
       
   672     if(m_colorTransform)
       
   673     {
       
   674         c.unpremultiply();
       
   675         c.luminanceToRGB();
       
   676         c.r = c.r * m_colorTransformValues[0] + m_colorTransformValues[4];
       
   677         c.g = c.g * m_colorTransformValues[1] + m_colorTransformValues[5];
       
   678         c.b = c.b * m_colorTransformValues[2] + m_colorTransformValues[6];
       
   679         c.a = c.a * m_colorTransformValues[3] + m_colorTransformValues[7];
       
   680         c.clamp();
       
   681         c.premultiply();
       
   682     }
       
   683 }
       
   684 
       
   685 /*-------------------------------------------------------------------*//*!
       
   686 * \brief    Applies paint, image drawing, masking and blending at pixel (x,y).
       
   687 * \param    
       
   688 * \return   
       
   689 * \note
       
   690 *//*-------------------------------------------------------------------*/
       
   691 
       
   692 void PixelPipe::pixelPipe(int x, int y, RIfloat coverage, unsigned int sampleMask) const
       
   693 {
       
   694     RI_ASSERT(m_drawable);
       
   695     RI_ASSERT(sampleMask);
       
   696     RI_ASSERT(coverage > 0.0f);
       
   697     Color::InternalFormat dstFormat = (Color::InternalFormat)(m_drawable->getDescriptor().internalFormat | Color::PREMULTIPLIED);
       
   698 
       
   699     //evaluate paint
       
   700     RI_ASSERT(m_paint);
       
   701     Color s;
       
   702     switch(m_paint->m_paintType)
       
   703     {
       
   704     case VG_PAINT_TYPE_COLOR:
       
   705         s = m_paint->m_paintColor;
       
   706         break;
       
   707 
       
   708     case VG_PAINT_TYPE_LINEAR_GRADIENT:
       
   709     {
       
   710         RIfloat g, rho;
       
   711         linearGradient(g, rho, x+0.5f, y+0.5f);
       
   712         s = colorRamp(g, rho);
       
   713         RI_ASSERT((s.getInternalFormat() == Color::sRGBA && !m_paint->m_colorRampPremultiplied) || (s.getInternalFormat() == Color::sRGBA_PRE && m_paint->m_colorRampPremultiplied));
       
   714         s.premultiply();
       
   715         break;
       
   716     }
       
   717 
       
   718     case VG_PAINT_TYPE_RADIAL_GRADIENT:
       
   719     {
       
   720         RIfloat g, rho;
       
   721         radialGradient(g, rho, x+0.5f, y+0.5f);
       
   722         s = colorRamp(g, rho);
       
   723         RI_ASSERT((s.getInternalFormat() == Color::sRGBA && !m_paint->m_colorRampPremultiplied) || (s.getInternalFormat() == Color::sRGBA_PRE && m_paint->m_colorRampPremultiplied));
       
   724         s.premultiply();
       
   725         break;
       
   726     }
       
   727 
       
   728     default:
       
   729         RI_ASSERT(m_paint->m_paintType == VG_PAINT_TYPE_PATTERN);
       
   730         if(m_paint->m_pattern)
       
   731             s = m_paint->m_pattern->resample(x+0.5f, y+0.5f, m_surfaceToPaintMatrix, m_imageQuality, m_paint->m_patternTilingMode, m_tileFillColor);
       
   732         else
       
   733             s = m_paint->m_paintColor;
       
   734         break;
       
   735     }
       
   736     s.assertConsistency();
       
   737 
       
   738     //apply image (vgDrawImage only)
       
   739     //1. paint: convert paint to dst space
       
   740     //2. image: convert image to dst space
       
   741     //3. paint MULTIPLY image: convert paint to image number of channels, multiply with image, and convert to dst
       
   742     //4. paint STENCIL image: convert paint to dst, convert image to dst number of channels, multiply
       
   743 
       
   744     //color transform:
       
   745     //paint => transform paint color
       
   746     //image normal => transform image color
       
   747     //image multiply => transform paint*image color
       
   748     //image stencil => transform paint color
       
   749 
       
   750     RIfloat ar = 0.0f, ag = 0.0f, ab = 0.0f;
       
   751     if(m_image)
       
   752     {
       
   753         Color im = m_image->resample(x+0.5f, y+0.5f, m_surfaceToImageMatrix, m_imageQuality, VG_TILE_PAD, Color(0,0,0,0,m_image->getDescriptor().internalFormat));
       
   754         im.assertConsistency();
       
   755 
       
   756         switch(m_imageMode)
       
   757         {
       
   758         case VG_DRAW_IMAGE_NORMAL:
       
   759             s = im;
       
   760             colorTransform(s);
       
   761             ar = s.a;
       
   762             ag = s.a;
       
   763             ab = s.a;
       
   764             s.convert(dstFormat);   //convert image color to destination color space
       
   765             break;
       
   766         case VG_DRAW_IMAGE_MULTIPLY:
       
   767             //the result will be in image color space, except when paint is RGB and image is L the result will be RGB.
       
   768             //paint == RGB && image == RGB: RGB*RGB
       
   769             //paint == RGB && image == L  : RGB*LLL
       
   770             //paint == L   && image == RGB: LLL*RGB
       
   771             //paint == L   && image == L  : L*L
       
   772             RI_ASSERT(m_surfaceToPaintMatrix.isAffine());
       
   773             if(!s.isLuminance() && im.isLuminance())
       
   774                 im.convert((Color::InternalFormat)(im.getInternalFormat() & ~Color::LUMINANCE));
       
   775             im.r *= s.r;
       
   776             im.g *= s.g;
       
   777             im.b *= s.b;
       
   778             im.a *= s.a;
       
   779             s = im;     //use image color space
       
   780             colorTransform(s);
       
   781             ar = s.a;
       
   782             ag = s.a;
       
   783             ab = s.a;
       
   784             s.convert(dstFormat);   //convert resulting color to destination color space
       
   785             break;
       
   786         default:
       
   787             //the result will be in paint color space.
       
   788             //dst == RGB && image == RGB: RGB*RGB
       
   789             //dst == RGB && image == L  : RGB*LLL
       
   790             //dst == L   && image == RGB: L*(0.2126 R + 0.7152 G + 0.0722 B)
       
   791             //dst == L   && image == L  : L*L
       
   792             RI_ASSERT(m_imageMode == VG_DRAW_IMAGE_STENCIL);
       
   793             if(dstFormat & Color::LUMINANCE && !im.isLuminance())
       
   794             {
       
   795                 im.r = im.g = im.b = RI_MIN(0.2126f*im.r + 0.7152f*im.g + 0.0722f*im.b, im.a);
       
   796             }
       
   797             RI_ASSERT(m_surfaceToPaintMatrix.isAffine());
       
   798             //s and im are both in premultiplied format. Each image channel acts as an alpha channel.
       
   799             colorTransform(s);
       
   800             s.convert(dstFormat);   //convert paint color to destination space already here, since convert cannot deal with per channel alphas used in this mode.
       
   801             //compute per channel alphas
       
   802             ar = s.a * im.r;
       
   803             ag = s.a * im.g;
       
   804             ab = s.a * im.b;
       
   805             //premultiply each channel by per channel alphas from the image
       
   806             s.r *= im.r;
       
   807             s.g *= im.g;
       
   808             s.b *= im.b;
       
   809             s.a *= im.a;
       
   810             //in nonpremultiplied form the result is
       
   811             // s.rgb = paint.a * paint.rgb * image.a * image.rgb
       
   812             // s.a = paint.a * image.a
       
   813             // argb = paint.a * image.a * image.rgb
       
   814             break;
       
   815         }
       
   816     }
       
   817     else
       
   818     {    //paint only
       
   819         colorTransform(s);
       
   820         ar = s.a;
       
   821         ag = s.a;
       
   822         ab = s.a;
       
   823         s.convert(dstFormat);   //convert paint color to destination color space
       
   824     }
       
   825     RI_ASSERT(s.getInternalFormat() == Color::lRGBA_PRE || s.getInternalFormat() == Color::sRGBA_PRE || s.getInternalFormat() == Color::lLA_PRE || s.getInternalFormat() == Color::sLA_PRE);
       
   826     s.assertConsistency();
       
   827 
       
   828     Surface* colorBuffer = m_drawable->getColorBuffer();
       
   829     Surface* maskBuffer = m_drawable->getMaskBuffer();
       
   830     RI_ASSERT(colorBuffer);
       
   831 
       
   832     if(m_drawable->getNumSamples() == 1)
       
   833     {   //coverage-based antialiasing
       
   834         RIfloat cov = coverage;
       
   835         if(m_masking && maskBuffer)
       
   836         {
       
   837             cov *= maskBuffer->readMaskCoverage(x, y);
       
   838             if(cov == 0.0f)
       
   839                 return;
       
   840         }
       
   841 
       
   842         //read destination color
       
   843         Color d = colorBuffer->readSample(x, y, 0);
       
   844         d.premultiply();
       
   845         RI_ASSERT(dstFormat == Color::lRGBA_PRE || dstFormat == Color::sRGBA_PRE || dstFormat == Color::lLA_PRE || dstFormat == Color::sLA_PRE);
       
   846 
       
   847         //blend
       
   848         Color r = blend(s, ar, ag, ab, d, m_blendMode);
       
   849 
       
   850         //apply antialiasing in linear color space
       
   851         Color::InternalFormat aaFormat = (dstFormat & Color::LUMINANCE) ? Color::lLA_PRE : Color::lRGBA_PRE;
       
   852         r.convert(aaFormat);
       
   853         d.convert(aaFormat);
       
   854         r = r * cov + d * (1.0f - cov);
       
   855 
       
   856         //write result to the destination surface
       
   857         r.convert(colorBuffer->getDescriptor().internalFormat);
       
   858         colorBuffer->writeSample(x, y, 0, r);
       
   859     }
       
   860     else
       
   861     {   //multisampling FSAA
       
   862         if(m_masking && maskBuffer)
       
   863         {
       
   864             sampleMask &= maskBuffer->readMaskMSAA(x, y);
       
   865             if(!sampleMask)
       
   866                 return;
       
   867         }
       
   868 
       
   869         {
       
   870             for(int i=0;i<m_drawable->getNumSamples();i++)
       
   871             {
       
   872                 if(sampleMask & (1<<i)) //1-bit coverage
       
   873                 {
       
   874                     //read destination color
       
   875                     Color d = colorBuffer->readSample(x, y, i);
       
   876 
       
   877                     d.premultiply();
       
   878                     RI_ASSERT(dstFormat == Color::lRGBA_PRE || dstFormat == Color::sRGBA_PRE || dstFormat == Color::lLA_PRE || dstFormat == Color::sLA_PRE);
       
   879 
       
   880                     //blend
       
   881                     Color r = blend(s, ar, ag, ab, d, m_blendMode);
       
   882 
       
   883                     //write result to the destination surface
       
   884                     r.convert(colorBuffer->getDescriptor().internalFormat);
       
   885                     colorBuffer->writeSample(x, y, i, r);
       
   886                 }
       
   887             }
       
   888         }
       
   889     }
       
   890 }
       
   891 
       
   892 //=======================================================================
       
   893     
       
   894 }   //namespace OpenVGRI