hostsupport/hostopenvg/src/src/riImage.cpp
branchbug235_bringup_0
changeset 53 c2ef9095503a
parent 24 a3f46bb01be2
equal deleted inserted replaced
52:39e5f73667ba 53:c2ef9095503a
       
     1 /*------------------------------------------------------------------------
       
     2  *
       
     3  * OpenVG 1.1 Reference Implementation
       
     4  * -----------------------------------
       
     5  *
       
     6  * Copyright (c) 2007 The Khronos Group Inc.
       
     7  * Portions copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     8  *
       
     9  * Permission is hereby granted, free of charge, to any person obtaining a
       
    10  * copy of this software and /or associated documentation files
       
    11  * (the "Materials "), to deal in the Materials without restriction,
       
    12  * including without limitation the rights to use, copy, modify, merge,
       
    13  * publish, distribute, sublicense, and/or sell copies of the Materials,
       
    14  * and to permit persons to whom the Materials are furnished to do so,
       
    15  * subject to the following conditions:
       
    16  *
       
    17  * The above copyright notice and this permission notice shall be included
       
    18  * in all copies or substantial portions of the Materials.
       
    19  *
       
    20  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
       
    21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
       
    22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
       
    23  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
       
    24  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
       
    25  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
       
    26  * THE USE OR OTHER DEALINGS IN THE MATERIALS.
       
    27  *
       
    28  *//**
       
    29  * \file
       
    30  * \brief	Implementation of Color and Image functions.
       
    31  * \note
       
    32  *//*-------------------------------------------------------------------*/
       
    33 
       
    34 #include "riImage.h"
       
    35 #include "riRasterizer.h"
       
    36 #include "riContext.h"
       
    37 
       
    38 #ifndef __SFDYNAMICBLITTER_H
       
    39 #   include "sfDynamicBlitter.h"
       
    40 #endif
       
    41 
       
    42 //==============================================================================================
       
    43 
       
    44 namespace OpenVGRI
       
    45 {
       
    46 
       
    47 /*-------------------------------------------------------------------*//*!
       
    48 * \brief	Converts from numBits into a shifted mask
       
    49 * \param
       
    50 * \return
       
    51 * \note
       
    52 *//*-------------------------------------------------------------------*/
       
    53 
       
    54 static RI_INLINE unsigned int bitsToMask(unsigned int bits, unsigned int shift)
       
    55 {
       
    56     return ((1<<bits)-1) << shift;
       
    57 }
       
    58 
       
    59 /*-------------------------------------------------------------------*//*!
       
    60 * \brief	Converts from color (RIfloat) to an int with 1.0f mapped to the
       
    61 *			given maximum with round-to-nearest semantics.
       
    62 * \param
       
    63 * \return
       
    64 * \note
       
    65 *//*-------------------------------------------------------------------*/
       
    66 
       
    67 RI_INLINE int ffloor(RIfloat x)
       
    68 {
       
    69     return (x >= 0) ? (int)x : (int)(x-1);
       
    70 }
       
    71 
       
    72 //static const float FLOAT_0	 = 0.0f;
       
    73 static const float FLOAT_0_5 = 0.5f;
       
    74 
       
    75 /* \note Rewrite this if time. */
       
    76 static unsigned int colorToInt(RIfloat c, int maxc)
       
    77 {
       
    78 #if defined RI_USE_SSE
       
    79     /*
       
    80         Registers mapping:
       
    81         c		<->	xmm0,
       
    82         maxc	<-> xmm1
       
    83         0		<-> xmm2
       
    84     */
       
    85     _asm
       
    86     {
       
    87         xorps		xmm2, xmm2					; xmm2 = 0
       
    88 
       
    89         ;---------------------------------------------
       
    90         ; Computing: xmm0 = (c * (RIfloat)maxc + 0.5f)
       
    91         ;---------------------------------------------
       
    92         movss		xmm0, dword ptr [c]			; xmm0 = c
       
    93         cvtsi2ss	xmm1, dword ptr [maxc]		; xmm1 = (float)maxc
       
    94         mulss		xmm0, xmm1					; xmm0 = xmm0 * xmm1 = c * (float)maxc
       
    95         addss		xmm0, FLOAT_0_5				; xmm0 = xmm0 + 0.5f = c * (float)maxc + 0.5f
       
    96 
       
    97         ;---------------------------------------------
       
    98         ; Computing: xmm0 = floor(xmm0) = floor(c * (RIfloat)maxc + 0.5f)
       
    99         ;---------------------------------------------
       
   100         cvttss2si   ebx, xmm0					; ebx = (int)xmm0
       
   101         mov         eax, ebx					; eax = ebx = (int)xmm0
       
   102         shr         eax, 31						; eax = sign(eax) = sign((int)xmm0)
       
   103         sub         ebx, eax					; ebx = ebx - sign((int)xmm0) = (int)xmm0 - sign((int)xmm0) = (int)floor((int)xmm0)
       
   104         cvtsi2ss    xmm0, ebx					; xmm0 = floor(xmm0)
       
   105 
       
   106         pmaxsw		xmm0, xmm2;					; xmm0 = MAX(xmm0, 0)
       
   107         pminsw		xmm0, xmm1					; xmm0 = MIN(xmm0, maxc)
       
   108         cvttss2si   eax, xmm0					; return value = eax = (int)xmm0
       
   109     }
       
   110 #else
       
   111     return RI_INT_MIN(RI_INT_MAX((int)ffloor(c * (RIfloat)maxc + 0.5f), 0), maxc);
       
   112 #endif
       
   113 }
       
   114 
       
   115 /*-------------------------------------------------------------------*//*!
       
   116 * \brief	Converts from int to color (RIfloat) with the given maximum
       
   117 *			mapped to 1.0f.
       
   118 * \param
       
   119 * \return
       
   120 * \note
       
   121 *//*-------------------------------------------------------------------*/
       
   122 
       
   123 static RI_INLINE RIfloat intToColor(unsigned int i, unsigned int maxi)
       
   124 {
       
   125     return (RIfloat)(i & maxi) / (RIfloat)maxi;
       
   126 }
       
   127 
       
   128 void Color::Descriptor::toSmallDescriptor(Color::SmallDescriptor& smallDesc) const
       
   129 {
       
   130     switch (bitsPerPixel)
       
   131     {
       
   132     case 32:
       
   133         smallDesc.size = SIZE_32;
       
   134         break;
       
   135     case 24:
       
   136         smallDesc.size = SIZE_24;
       
   137         break;
       
   138     case 16:
       
   139         smallDesc.size = SIZE_16;
       
   140         break;
       
   141     case 8:
       
   142         smallDesc.size = SIZE_8;
       
   143         break;
       
   144     case 4:
       
   145         smallDesc.size = SIZE_4;
       
   146         break;
       
   147     default:
       
   148         RI_ASSERT(bitsPerPixel == 1);
       
   149         smallDesc.size = SIZE_1;
       
   150         break;
       
   151     }
       
   152     smallDesc.shape = shape;
       
   153     smallDesc.internalFormat = internalFormat;
       
   154 }
       
   155 
       
   156 Color::Descriptor Color::Descriptor::getDummyDescriptor()
       
   157 {
       
   158     static const Descriptor dummy = Color::Descriptor(8,0,8,8,8,16,8,24,0,0,sRGBA,32,SHAPE_ABGR);
       
   159     return dummy;
       
   160 }
       
   161 
       
   162 /**
       
   163  * \brief   Determine the shape of the color format from other data.
       
   164  * \todo    The naming is poor because it may be interpreted as returning the member
       
   165  *          "shape".
       
   166  */
       
   167 Color::Shape Color::Descriptor::getShape() const
       
   168 {
       
   169     // \todo There should be some easier way to define the shape so that it does
       
   170     // not need to be determined with so many conditions.
       
   171 
       
   172     if (isAlphaOnly())
       
   173     {
       
   174         return SHAPE_A;
       
   175     }
       
   176     else if (isLuminance())
       
   177     {
       
   178         if (alphaBits)
       
   179         {
       
   180             if (alphaShift == 0)
       
   181                 return SHAPE_LA;
       
   182             return SHAPE_AL;
       
   183         }
       
   184         return SHAPE_L;
       
   185     } 
       
   186     else if (!alphaBits)
       
   187     {
       
   188         if (bitsPerPixel == 32)
       
   189         {
       
   190             switch(redShift)
       
   191             {
       
   192             case 0:
       
   193                 return SHAPE_XBGR;
       
   194             case 8:
       
   195                 return SHAPE_BGRX;
       
   196             case 16:
       
   197                 return SHAPE_XRGB;
       
   198             default:
       
   199                 RI_ASSERT(redShift == 24);
       
   200                 return SHAPE_RGBX;
       
   201             }
       
   202         } else if (bitsPerPixel == 24)
       
   203         {
       
   204             if (!redShift)
       
   205                 return SHAPE_BGR;
       
   206             else
       
   207             {
       
   208                 RI_ASSERT(redShift == 16);
       
   209                 return SHAPE_RGB;
       
   210             }
       
   211         } else
       
   212         {
       
   213             RI_ASSERT(redBits == 5 && greenBits == 6 && blueBits == 5);
       
   214             if(redShift)
       
   215                 return SHAPE_RGB;
       
   216             else
       
   217                 return SHAPE_BGR;
       
   218         }
       
   219     }
       
   220     else
       
   221     {
       
   222         if (bitsPerPixel == 32)
       
   223         {
       
   224             switch(redShift)
       
   225             {
       
   226             case 0:
       
   227                 return SHAPE_ABGR;
       
   228             case 8:
       
   229                 return SHAPE_BGRA;
       
   230             case 16:
       
   231                 return SHAPE_ARGB;
       
   232             default:
       
   233                 RI_ASSERT(redShift == 24);
       
   234                 return SHAPE_RGBA;
       
   235             }
       
   236         } else
       
   237         {
       
   238             RI_ASSERT(bitsPerPixel == 16);
       
   239             if (redBits == 5)
       
   240             {
       
   241                 RI_ASSERT(greenBits == 5 && blueBits == 5 && alphaBits == 1);
       
   242                 switch(redShift)
       
   243                 {
       
   244                 case 0:
       
   245                     return SHAPE_ABGR;
       
   246                 case 1:
       
   247                     return SHAPE_BGRA;
       
   248                 case 10:
       
   249                     return SHAPE_ARGB;
       
   250                 default:
       
   251                     RI_ASSERT(redShift == 11);
       
   252                     return SHAPE_RGBA;
       
   253                 }
       
   254             } else
       
   255             {
       
   256                 RI_ASSERT(redBits == 4 && greenBits == 4 && alphaBits == 4);
       
   257                 switch(redShift)
       
   258                 {
       
   259                 case 0:
       
   260                     return SHAPE_ABGR;
       
   261                 case 4:
       
   262                     return SHAPE_BGRA;
       
   263                 case 8:
       
   264                     return SHAPE_ARGB;
       
   265                 default:
       
   266                     RI_ASSERT(redShift == 12);
       
   267                     return SHAPE_RGBA;
       
   268                 }
       
   269             }
       
   270         }
       
   271     }
       
   272 }
       
   273 
       
   274 /*-------------------------------------------------------------------*//*!
       
   275 * \brief	Converts from packed integer in a given format to a Color.
       
   276 * \param
       
   277 * \return
       
   278 * \note
       
   279 *//*-------------------------------------------------------------------*/
       
   280 
       
   281 void Color::unpack(unsigned int inputData, const Color::Descriptor& inputDesc)
       
   282 {
       
   283     int rb = inputDesc.redBits;
       
   284     int gb = inputDesc.greenBits;
       
   285     int bb = inputDesc.blueBits;
       
   286     int ab = inputDesc.alphaBits;
       
   287     int lb = inputDesc.luminanceBits;
       
   288     int rs = inputDesc.redShift;
       
   289     int gs = inputDesc.greenShift;
       
   290     int bs = inputDesc.blueShift;
       
   291     int as = inputDesc.alphaShift;
       
   292     int ls = inputDesc.luminanceShift;
       
   293 
       
   294     m_format = inputDesc.internalFormat;
       
   295     if(lb)
       
   296     {	//luminance
       
   297         r = g = b = intToColor(inputData >> ls, (1<<lb)-1);
       
   298         a = 1.0f;
       
   299     }
       
   300     else
       
   301     {	//rgba
       
   302         r = rb ? intToColor(inputData >> rs, (1<<rb)-1) : (RIfloat)1.0f;
       
   303         g = gb ? intToColor(inputData >> gs, (1<<gb)-1) : (RIfloat)1.0f;
       
   304         b = bb ? intToColor(inputData >> bs, (1<<bb)-1) : (RIfloat)1.0f;
       
   305         a = ab ? intToColor(inputData >> as, (1<<ab)-1) : (RIfloat)1.0f;
       
   306 
       
   307         if(isPremultiplied())
       
   308         {	//clamp premultiplied color to alpha to enforce consistency
       
   309             r = RI_MIN(r, a);
       
   310             g = RI_MIN(g, a);
       
   311             b = RI_MIN(b, a);
       
   312         }
       
   313     }
       
   314 
       
   315     assertConsistency();
       
   316 }
       
   317 
       
   318 /*-------------------------------------------------------------------*//*!
       
   319 * \brief	Converts from Color to a packed integer in a given format.
       
   320 * \param
       
   321 * \return
       
   322 * \note
       
   323 *//*-------------------------------------------------------------------*/
       
   324 
       
   325 unsigned int Color::pack(const Color::Descriptor& outputDesc) const
       
   326 {
       
   327     assertConsistency();
       
   328 
       
   329     int rb = outputDesc.redBits;
       
   330     int gb = outputDesc.greenBits;
       
   331     int bb = outputDesc.blueBits;
       
   332     int ab = outputDesc.alphaBits;
       
   333     int lb = outputDesc.luminanceBits;
       
   334     int rs = outputDesc.redShift;
       
   335     int gs = outputDesc.greenShift;
       
   336     int bs = outputDesc.blueShift;
       
   337     int as = outputDesc.alphaShift;
       
   338     int ls = outputDesc.luminanceShift;
       
   339 
       
   340     if(lb)
       
   341     {	//luminance
       
   342         RI_ASSERT(isLuminance());
       
   343         return colorToInt(r, (1<<lb)-1) << ls;
       
   344     }
       
   345     else
       
   346     {	//rgb
       
   347         RI_ASSERT(!isLuminance());
       
   348         unsigned int cr = rb ? colorToInt(r, (1<<rb)-1) : 0;
       
   349         unsigned int cg = gb ? colorToInt(g, (1<<gb)-1) : 0;
       
   350         unsigned int cb = bb ? colorToInt(b, (1<<bb)-1) : 0;
       
   351         unsigned int ca = ab ? colorToInt(a, (1<<ab)-1) : 0;
       
   352         return packRGBAInteger(cr, rs, cg, gs, cb, bs, ca, as);
       
   353     }
       
   354 }
       
   355 
       
   356 /*-------------------------------------------------------------------*//*!
       
   357 * \brief	Converts from the current internal format to another.
       
   358 * \param
       
   359 * \return
       
   360 * \note
       
   361 *//*-------------------------------------------------------------------*/
       
   362 
       
   363 /* \todo Integer & lookup versions */
       
   364 
       
   365 static RIfloat gamma(RIfloat c)
       
   366 {
       
   367     if( c <= 0.00304f )
       
   368         c *= 12.92f;
       
   369     else
       
   370         c = 1.0556f * (RIfloat)pow(c, 1.0f/2.4f) - 0.0556f;
       
   371     return c;
       
   372 }
       
   373 
       
   374 static RIfloat invgamma(RIfloat c)
       
   375 {
       
   376     if( c <= 0.03928f )
       
   377         c /= 12.92f;
       
   378     else
       
   379         c = (RIfloat)pow((c + 0.0556f)/1.0556f, 2.4f);
       
   380     return c;
       
   381 }
       
   382 
       
   383 static RIfloat lRGBtoL(RIfloat r, RIfloat g, RIfloat b)
       
   384 {
       
   385     return 0.2126f*r + 0.7152f*g + 0.0722f*b;
       
   386 }
       
   387 
       
   388 void Color::convert(InternalFormat outputFormat)
       
   389 {
       
   390     /* \todo This should probably be converted to integer code. */
       
   391 
       
   392     assertConsistency();
       
   393 
       
   394     if( m_format == outputFormat )
       
   395         return;
       
   396 
       
   397     if(isPremultiplied())
       
   398     {	//unpremultiply
       
   399         RIfloat ooa = (a != 0.0f) ? 1.0f / a : (RIfloat)0.0f;
       
   400         r *= ooa;
       
   401         g *= ooa;
       
   402         b *= ooa;
       
   403     }
       
   404 
       
   405     //From Section 3.4.2 of OpenVG spec
       
   406     //1: sRGB = gamma(lRGB)
       
   407     //2: lRGB = invgamma(sRGB)
       
   408     //3: lL = 0.2126 lR + 0.7152 lG + 0.0722 lB
       
   409     //4: lRGB = lL
       
   410     //5: sL = gamma(lL)
       
   411     //6: lL = invgamma(sL)
       
   412     //7: sRGB = sL
       
   413 
       
   414     //Source/Dest lRGB sRGB   lL   sL
       
   415     //lRGB          -    1    3    3,5
       
   416     //sRGB          2    -    2,3  2,3,5
       
   417     //lL            4    4,1  -    5
       
   418     //sL            7,2  7    6    -
       
   419 
       
   420     const unsigned int shift = 3;
       
   421     unsigned int conversion = (m_format & (NONLINEAR | LUMINANCE)) | ((outputFormat & (NONLINEAR | LUMINANCE)) << shift);
       
   422 
       
   423     switch(conversion)
       
   424     {
       
   425     case lRGBA | (sRGBA << shift): r = gamma(r); g = gamma(g); b = gamma(b); break;							//1
       
   426     case lRGBA | (lLA << shift)  : r = g = b = lRGBtoL(r, g, b); break;										//3
       
   427     case lRGBA | (sLA << shift)  : r = g = b = gamma(lRGBtoL(r, g, b)); break;								//3,5
       
   428     case sRGBA | (lRGBA << shift): r = invgamma(r); g = invgamma(g); b = invgamma(b); break;				//2
       
   429     case sRGBA | (lLA << shift)  : r = g = b = lRGBtoL(invgamma(r), invgamma(g), invgamma(b)); break;		//2,3
       
   430     case sRGBA | (sLA << shift)  : r = g = b = gamma(lRGBtoL(invgamma(r), invgamma(g), invgamma(b))); break;//2,3,5
       
   431     case lLA   | (lRGBA << shift): break;																	//4
       
   432     case lLA   | (sRGBA << shift): r = g = b = gamma(r); break;												//4,1
       
   433     case lLA   | (sLA << shift)  : r = g = b = gamma(r); break;												//5
       
   434     case sLA   | (lRGBA << shift): r = g = b = invgamma(r); break;											//7,2
       
   435     case sLA   | (sRGBA << shift): break;																	//7
       
   436     case sLA   | (lLA << shift)  : r = g = b = invgamma(r); break;											//6
       
   437     default: RI_ASSERT((m_format & (LUMINANCE | NONLINEAR)) == (outputFormat & (LUMINANCE | NONLINEAR))); break;	//nop
       
   438     }
       
   439 
       
   440     if(outputFormat & PREMULTIPLIED)
       
   441     {	//premultiply
       
   442         r *= a;
       
   443         g *= a;
       
   444         b *= a;
       
   445     }
       
   446     m_format = outputFormat;
       
   447 
       
   448     assertConsistency();
       
   449 }
       
   450 
       
   451 /*------------------------------------------------------------------------*//*!
       
   452 * \brief	Creates a pixel format descriptor out of VGImageFormat
       
   453 * \param
       
   454 * \return
       
   455 * \note     Remove this function and use the "const" version for consistency.
       
   456 *//*------------------------------------------------------------------------*/
       
   457 Color::Descriptor Color::formatToDescriptor(VGImageFormat format)
       
   458 {
       
   459     Descriptor desc;
       
   460     memset(&desc, 0, sizeof(Descriptor));
       
   461     RI_ASSERT(isValidImageFormat(format));
       
   462 
       
   463     int baseFormat = (int)format & 15;
       
   464     const int numBaseFormats = 15;
       
   465     RI_ASSERT(baseFormat >= 0 && baseFormat < numBaseFormats);
       
   466     int swizzleBits = ((int)format >> 6) & 3;
       
   467 
       
   468     /* base formats
       
   469     VG_sRGBX_8888                               =  0,
       
   470     VG_sRGBA_8888                               =  1,
       
   471     VG_sRGBA_8888_PRE                           =  2,
       
   472     VG_sRGB_565                                 =  3,
       
   473     VG_sRGBA_5551                               =  4,
       
   474     VG_sRGBA_4444                               =  5,
       
   475     VG_sL_8                                     =  6,
       
   476     VG_lRGBX_8888                               =  7,
       
   477     VG_lRGBA_8888                               =  8,
       
   478     VG_lRGBA_8888_PRE                           =  9,
       
   479     VG_lL_8                                     = 10,
       
   480     VG_A_8                                      = 11,
       
   481     VG_BW_1                                     = 12,
       
   482     VG_A_1                                      = 13,
       
   483     VG_A_4                                      = 14,
       
   484     */
       
   485 
       
   486     static const int redBits[numBaseFormats] =       {8, 8, 8, 5, 5, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0};
       
   487     static const int greenBits[numBaseFormats] =     {8, 8, 8, 6, 5, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0};
       
   488     static const int blueBits[numBaseFormats] =      {8, 8, 8, 5, 5, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0};
       
   489     static const int alphaBits[numBaseFormats] =     {0, 8, 8, 0, 1, 4, 0, 0, 8, 8, 0, 8, 0, 1, 4};
       
   490     static const int luminanceBits[numBaseFormats] = {0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 1, 0, 0};
       
   491 
       
   492     static const int redShifts[4*numBaseFormats] = {24, 24, 24, 11, 11, 12, 0, 24, 24, 24, 0, 0, 0, 0, 0,	//RGBA
       
   493                                                     16, 16, 16, 11, 10, 8,  0, 16, 16, 16, 0, 0, 0, 0, 0,	//ARGB
       
   494                                                     8,  8,  8,  0,  1,  4,  0, 8,  8,  8,  0, 0, 0, 0, 0,	//BGRA
       
   495                                                     0,  0,  0,  0,  0,  0,  0, 0,  0,  0,  0, 0, 0, 0, 0};	//ABGR
       
   496 
       
   497     static const int greenShifts[4*numBaseFormats] = {16, 16, 16, 5,  6,  8,  0, 16, 16, 16, 0, 0, 0, 0, 0,	//RGBA
       
   498                                                       8,  8,  8,  5,  5,  4,  0, 8,  8,  8,  0, 0, 0, 0, 0,	//ARGB
       
   499                                                       16, 16, 16, 5,  6,  8,  0, 16, 16, 16, 0, 0, 0, 0, 0,	//BGRA
       
   500                                                       8,  8,  8,  5,  5,  4,  0, 8,  8,  8,  0, 0, 0, 0, 0};//ABGR
       
   501 
       
   502     static const int blueShifts[4*numBaseFormats] =  {8,  8,  8,  0,  1,  4,  0, 8,  8,  8,  0, 0, 0, 0, 0,	//RGBA
       
   503                                                       0,  0,  0,  0,  0,  0,  0, 0,  0,  0,  0, 0, 0, 0, 0,	//ARGB
       
   504                                                       24, 24, 24, 11, 11, 12, 0, 24, 24, 24, 0, 0, 0, 0, 0,	//BGRA
       
   505                                                       16, 16, 16, 11, 10, 8,  0, 16, 16, 16, 0, 0, 0, 0, 0};//ABGR
       
   506 
       
   507     static const int alphaShifts[4*numBaseFormats] = {0,  0,  0,  0,  0,  0,  0, 0,  0,  0,  0, 0, 0, 0, 0,	//RGBA
       
   508                                                       0,  24, 24, 0,  15, 12, 0, 0,  24, 24, 0, 0, 0, 0, 0,	//ARGB
       
   509                                                       0,  0,  0,  0,  0,  0,  0, 0,  0,  0,  0, 0, 0, 0, 0,	//BGRA
       
   510                                                       0,  24, 24, 0,  15, 12, 0, 0,  24, 24, 0, 0, 0, 0, 0};//ABGR
       
   511 
       
   512     static const int bpps[numBaseFormats] = {32, 32, 32, 16, 16, 16, 8, 32, 32, 32, 8, 8, 1, 1, 4};
       
   513 
       
   514     static const InternalFormat internalFormats[numBaseFormats] = {sRGBA, sRGBA, sRGBA_PRE, sRGBA, sRGBA, sRGBA, sLA, lRGBA, lRGBA, lRGBA_PRE, lLA, lRGBA, lLA, lRGBA, lRGBA};
       
   515 
       
   516     desc.redBits = redBits[baseFormat];
       
   517     desc.greenBits = greenBits[baseFormat];
       
   518     desc.blueBits = blueBits[baseFormat];
       
   519     desc.alphaBits = alphaBits[baseFormat];
       
   520     desc.luminanceBits = luminanceBits[baseFormat];
       
   521 
       
   522     desc.redShift = redShifts[swizzleBits * numBaseFormats + baseFormat];
       
   523     desc.greenShift = greenShifts[swizzleBits * numBaseFormats + baseFormat];
       
   524     desc.blueShift = blueShifts[swizzleBits * numBaseFormats + baseFormat];
       
   525     desc.alphaShift = alphaShifts[swizzleBits * numBaseFormats + baseFormat];
       
   526     desc.luminanceShift = 0;	//always zero
       
   527 
       
   528     desc.vgFormat = format;
       
   529     desc.bitsPerPixel = bpps[baseFormat];
       
   530     desc.bytesPerPixel = desc.bitsPerPixel / 8;
       
   531     desc.internalFormat = internalFormats[baseFormat];
       
   532     desc.shape = desc.getShape();
       
   533 
       
   534     if (desc.alphaBits)
       
   535     {
       
   536         desc.maskBits = desc.alphaBits;
       
   537         desc.maskShift = desc.alphaShift;
       
   538     } 
       
   539     else if (!desc.isLuminance())
       
   540     {
       
   541         desc.maskBits = desc.redBits;
       
   542         desc.maskShift = desc.redShift;
       
   543     } 
       
   544     else
       
   545     {
       
   546         desc.maskBits = desc.luminanceBits;
       
   547         desc.maskShift = desc.luminanceShift;
       
   548     }
       
   549 
       
   550     return desc;
       
   551 }
       
   552 
       
   553 
       
   554 struct DescToFormatMapping
       
   555 {
       
   556     Color::Descriptor desc;
       
   557     VGImageFormat format;
       
   558 };
       
   559 
       
   560 RI_INLINE static bool isDescEqualToMapping(const Color::Descriptor& desc, const DescToFormatMapping &mapping)
       
   561 {
       
   562     if ((desc.redBits == mapping.desc.redBits) &&
       
   563         (desc.redShift == mapping.desc.redShift) &&
       
   564         (desc.greenBits == mapping.desc.greenBits) &&
       
   565         (desc.greenShift == mapping.desc.greenShift) &&
       
   566         (desc.blueBits == mapping.desc.blueBits) &&
       
   567         (desc.blueShift == mapping.desc.blueShift) &&
       
   568         (desc.alphaBits == mapping.desc.alphaBits) &&
       
   569         (desc.alphaShift == mapping.desc.alphaShift) &&
       
   570         (desc.luminanceBits == mapping.desc.luminanceBits) &&
       
   571         (desc.luminanceShift == mapping.desc.luminanceShift) &&
       
   572         (desc.internalFormat == mapping.desc.internalFormat) &&
       
   573         (desc.bitsPerPixel == mapping.desc.bitsPerPixel))
       
   574         return true;
       
   575 
       
   576     return false;
       
   577 }
       
   578 
       
   579 VGImageFormat Color::descriptorToVGImageFormat(const Descriptor& desc)
       
   580 {
       
   581 //Color::Descriptor::Descriptor(int dredBits, int dredShift, int dgreenBits, int dgreenShift, int dblueBits, int dblueShift, int dalphaBits, int dalphaShift, int dluminanceBits, int dluminanceShift, InternalFormat dinternalFormat, int dbpp) :
       
   582     // \todo These are hardcoded here only to allow constant initialization, they should be generated
       
   583     // using formatToDescriptor!
       
   584     static const DescToFormatMapping map[] = {
       
   585     /* RGB{A,X} channel ordering */
       
   586         { formatToDescriptorConst(VG_sRGBX_8888), VG_sRGBX_8888 },
       
   587         { formatToDescriptorConst(VG_sRGBA_8888), VG_sRGBA_8888 },
       
   588         { formatToDescriptorConst(VG_sRGBA_8888_PRE), VG_sRGBA_8888_PRE },
       
   589         { formatToDescriptorConst(VG_sRGB_565), VG_sRGB_565 },
       
   590         { formatToDescriptorConst(VG_sRGBA_5551), VG_sRGBA_5551 },
       
   591         { formatToDescriptorConst(VG_sRGBA_4444), VG_sRGBA_4444 },
       
   592         { formatToDescriptorConst(VG_sL_8), VG_sL_8 },
       
   593         { formatToDescriptorConst(VG_lRGBX_8888), VG_lRGBX_8888 },
       
   594         { formatToDescriptorConst(VG_lRGBA_8888), VG_lRGBA_8888 },
       
   595         { formatToDescriptorConst(VG_lRGBA_8888_PRE), VG_lRGBA_8888_PRE },
       
   596         { formatToDescriptorConst(VG_lL_8), VG_lL_8 },
       
   597         { formatToDescriptorConst(VG_A_8), VG_A_8 },
       
   598         { formatToDescriptorConst(VG_BW_1), VG_BW_1 },
       
   599         { formatToDescriptorConst(VG_A_1), VG_A_1 },
       
   600         { formatToDescriptorConst(VG_A_4), VG_A_4 },
       
   601 
       
   602   /* {A,X}RGB channel ordering */
       
   603         { formatToDescriptorConst(VG_sXRGB_8888), VG_sXRGB_8888 },
       
   604         { formatToDescriptorConst(VG_sARGB_8888), VG_sARGB_8888 },
       
   605         { formatToDescriptorConst(VG_sARGB_8888_PRE), VG_sARGB_8888_PRE },
       
   606         { formatToDescriptorConst(VG_sARGB_1555), VG_sARGB_1555 },
       
   607         { formatToDescriptorConst(VG_sARGB_4444), VG_sARGB_4444 },
       
   608         { formatToDescriptorConst(VG_lXRGB_8888), VG_lXRGB_8888 },
       
   609         { formatToDescriptorConst(VG_lARGB_8888), VG_lARGB_8888 },
       
   610         { formatToDescriptorConst(VG_lARGB_8888_PRE), VG_lARGB_8888_PRE },
       
   611 
       
   612   /* BGR{A,X} channel ordering */
       
   613         { formatToDescriptorConst(VG_sBGRX_8888), VG_sBGRX_8888 },
       
   614         { formatToDescriptorConst(VG_sBGRA_8888), VG_sBGRA_8888 },
       
   615         { formatToDescriptorConst(VG_sBGRA_8888_PRE), VG_sBGRA_8888_PRE },
       
   616         { formatToDescriptorConst(VG_sBGR_565), VG_sBGR_565 },
       
   617         { formatToDescriptorConst(VG_sBGRA_5551), VG_sBGRA_5551 },
       
   618         { formatToDescriptorConst(VG_sBGRA_4444), VG_sBGRA_4444 },
       
   619         { formatToDescriptorConst(VG_lBGRX_8888), VG_lBGRX_8888 },
       
   620         { formatToDescriptorConst(VG_lBGRA_8888), VG_lBGRA_8888 },
       
   621         { formatToDescriptorConst(VG_lBGRA_8888_PRE), VG_lBGRA_8888_PRE },
       
   622 
       
   623   /* {A,X}BGR channel ordering */
       
   624         { formatToDescriptorConst(VG_sXBGR_8888), VG_sXBGR_8888 },
       
   625         { formatToDescriptorConst(VG_sABGR_8888), VG_sABGR_8888 },
       
   626         { formatToDescriptorConst(VG_sABGR_8888_PRE), VG_sABGR_8888_PRE },
       
   627         { formatToDescriptorConst(VG_sABGR_1555), VG_sABGR_1555 },
       
   628         { formatToDescriptorConst(VG_sABGR_4444), VG_sABGR_4444 },
       
   629         { formatToDescriptorConst(VG_lXBGR_8888), VG_lXBGR_8888 },
       
   630         { formatToDescriptorConst(VG_lABGR_8888), VG_lABGR_8888 },
       
   631         { formatToDescriptorConst(VG_lABGR_8888_PRE), VG_lABGR_8888_PRE },
       
   632     };
       
   633 
       
   634     for (size_t i = 0; i < sizeof(map)/sizeof(map[0]); i++)
       
   635     {
       
   636         if (isDescEqualToMapping(desc, map[i]))
       
   637             return map[i].format;
       
   638     }
       
   639     RI_ASSERT(false);
       
   640     return (VGImageFormat)-1;
       
   641 }
       
   642 
       
   643 /*-------------------------------------------------------------------*//*!
       
   644 * \brief	Checks if the pixel format descriptor is valid (i.e. all the
       
   645 *           values are supported by the RI)
       
   646 * \param
       
   647 * \return
       
   648 * \note
       
   649 *//*-------------------------------------------------------------------*/
       
   650 
       
   651 bool Color::isValidDescriptor(const Color::Descriptor& desc)
       
   652 {
       
   653     //A valid descriptor has 1, 2, 4, 8, 16, or 32 bits per pixel, and either luminance or rgba channels, but not both.
       
   654     //Any of the rgba channels can be missing, and not all bits need to be used. Maximum channel bit depth is 8.
       
   655     int rb = desc.redBits;
       
   656     int gb = desc.greenBits;
       
   657     int bb = desc.blueBits;
       
   658     int ab = desc.alphaBits;
       
   659     int lb = desc.luminanceBits;
       
   660     int rs = desc.redShift;
       
   661     int gs = desc.greenShift;
       
   662     int bs = desc.blueShift;
       
   663     int as = desc.alphaShift;
       
   664     int ls = desc.luminanceShift;
       
   665     int bpp = desc.bitsPerPixel;
       
   666 
       
   667     int rgbaBits = rb + gb + bb + ab;
       
   668     if(rb < 0 || rb > 8 || rs < 0 || rs + rb > bpp || !(rb || !rs))
       
   669         return false;	//invalid channel description
       
   670     if(gb < 0 || gb > 8 || gs < 0 || gs + gb > bpp || !(gb || !gs))
       
   671         return false;	//invalid channel description
       
   672     if(bb < 0 || bb > 8 || bs < 0 || bs + bb > bpp || !(bb || !bs))
       
   673         return false;	//invalid channel description
       
   674     if(ab < 0 || ab > 8 || as < 0 || as + ab > bpp || !(ab || !as))
       
   675         return false;	//invalid channel description
       
   676     if(lb < 0 || lb > 8 || ls < 0 || ls + lb > bpp || !(lb || !ls))
       
   677         return false;	//invalid channel description
       
   678 
       
   679 #if 0
       
   680     if(rgbaBits && lb)
       
   681         return false;	//can't have both rgba and luminance
       
   682 #endif
       
   683     if(!rgbaBits && !lb)
       
   684         return false;	//must have either rgba or luminance
       
   685     if(rgbaBits)
       
   686     {	//rgba
       
   687         if(rb+gb+bb == 0)
       
   688         {	//alpha only
       
   689             if(rs || gs || bs || as || ls)
       
   690                 return false;	//wrong shifts (even alpha shift must be zero)
       
   691             if((ab != 1 && ab != 2  && ab != 4 && ab != 8) || bpp != ab)
       
   692                 return false;	//alpha size must be 1, 2, 4, or, 8, bpp must match
       
   693         }
       
   694         else
       
   695         {	//rgba
       
   696             if(rgbaBits > bpp)
       
   697                 return false;	//bpp must be greater than or equal to the sum of rgba bits
       
   698             if(!(bpp == 32 || bpp == 16 || bpp == 8))
       
   699                 return false;	//only 1, 2, and 4 byte formats are supported for rgba
       
   700 
       
   701             unsigned int rm = bitsToMask((unsigned int)rb, (unsigned int)rs);
       
   702             unsigned int gm = bitsToMask((unsigned int)gb, (unsigned int)gs);
       
   703             unsigned int bm = bitsToMask((unsigned int)bb, (unsigned int)bs);
       
   704             unsigned int am = bitsToMask((unsigned int)ab, (unsigned int)as);
       
   705             if((rm & gm) || (rm & bm) || (rm & am) || (gm & bm) || (gm & am) || (bm & am))
       
   706                 return false;	//channels overlap
       
   707         }
       
   708     }
       
   709     else
       
   710     {	//luminance
       
   711         if(rs || gs || bs || as || ls)
       
   712             return false;	//wrong shifts (even luminance shift must be zero)
       
   713         if(!(lb == 1 || lb == 8) || bpp != lb)
       
   714             return false;	//luminance size must be either 1 or 8, bpp must match
       
   715     }
       
   716 
       
   717     if(desc.vgFormat != -1)
       
   718     {
       
   719         if(!isValidImageFormat(desc.vgFormat))
       
   720             return false;	//invalid image format
       
   721 
       
   722         Descriptor d = formatToDescriptor(desc.vgFormat);
       
   723         if(d.redBits != rb || d.greenBits != gb || d.blueBits != bb || d.alphaBits != ab || d.luminanceBits != lb ||
       
   724            d.redShift != rs || d.greenShift != gs || d.blueShift != bs || d.alphaShift != as || d.luminanceShift != ls ||
       
   725            d.bitsPerPixel != bpp)
       
   726            return false;	//if the descriptor has a VGImageFormat, it must match the bits, shifts, and bpp
       
   727     } 
       
   728 
       
   729     if((unsigned int)desc.internalFormat & ~(Color::PREMULTIPLIED | Color::NONLINEAR | Color::LUMINANCE))
       
   730         return false;	//invalid internal format
       
   731 
       
   732     return true;
       
   733 }
       
   734 
       
   735 //==============================================================================================
       
   736 
       
   737 //==============================================================================================
       
   738 
       
   739 IntegerColor::IntegerColor(const Color& color)
       
   740 {
       
   741     r = (RIuint32)(color.r * 255.0f + 0.5f);
       
   742     g = (RIuint32)(color.g * 255.0f + 0.5f);
       
   743     b = (RIuint32)(color.b * 255.0f + 0.5f);
       
   744     a = (RIuint32)(color.a * 255.0f + 0.5f);
       
   745 }
       
   746 
       
   747 //==============================================================================================
       
   748 
       
   749 //==============================================================================================
       
   750 
       
   751 /*-------------------------------------------------------------------*//*!
       
   752 * \brief	Constructs a blank image.
       
   753 * \param
       
   754 * \return
       
   755 * \note
       
   756 *//*-------------------------------------------------------------------*/
       
   757 
       
   758 Image::Image(const Color::Descriptor& desc, int width, int height, VGbitfield allowedQuality) :
       
   759     m_desc(desc),
       
   760     m_width(width),
       
   761     m_height(height),
       
   762     m_allowedQuality(allowedQuality),
       
   763     m_inUse(0),
       
   764     m_stride(0),
       
   765     m_data(NULL),
       
   766     m_referenceCount(0),
       
   767     m_ownsData(true),
       
   768     m_parent(NULL),
       
   769     m_storageOffsetX(0),
       
   770     m_storageOffsetY(0),
       
   771     m_unsafeData(false)
       
   772 {
       
   773     RI_ASSERT(Color::isValidDescriptor(m_desc));
       
   774     RI_ASSERT(width > 0 && height > 0);
       
   775 
       
   776     m_stride = (m_width*m_desc.bitsPerPixel+7)/8;
       
   777 
       
   778     m_data = RI_NEW_ARRAY(RIuint8, m_stride*m_height);	//throws bad_alloc
       
   779     memset(m_data, 0, m_stride*m_height);	//clear image
       
   780 }
       
   781 
       
   782 /*-------------------------------------------------------------------*//*!
       
   783 * \brief	Constructs an image that uses an external array for its data
       
   784 *			storage.
       
   785 * \param
       
   786 * \return
       
   787 * \note		This is meant for internal use to make blitting easier
       
   788 * \note     Now this is "tagged" into m_unsafeData if necessary.
       
   789 *           Using this constructor may then affect performance.
       
   790 *//*-------------------------------------------------------------------*/
       
   791 
       
   792 Image::Image(const Color::Descriptor& desc, int width, int height, int stride, RIuint8* data) :
       
   793     m_desc(desc),
       
   794     m_width(width),
       
   795     m_height(height),
       
   796     m_allowedQuality(0),
       
   797     m_inUse(0),
       
   798     m_stride(stride),
       
   799     m_data(data),
       
   800     m_referenceCount(0),
       
   801     m_ownsData(false),
       
   802     m_parent(NULL),
       
   803     m_storageOffsetX(0),
       
   804     m_storageOffsetY(0),
       
   805     m_unsafeData(false)
       
   806 {
       
   807     RI_ASSERT(Color::isValidDescriptor(m_desc));
       
   808     RI_ASSERT(width > 0 && height > 0);
       
   809     RI_ASSERT(data);
       
   810     setUnsafe(true); // External data always potentially unsafe, see note above.
       
   811 }
       
   812 
       
   813 /*-------------------------------------------------------------------*//*!
       
   814 * \brief	Construcs a child image.
       
   815 * \param
       
   816 * \return
       
   817 * \note
       
   818 *//*-------------------------------------------------------------------*/
       
   819 
       
   820 Image::Image(Image* parent, int x, int y, int width, int height) :
       
   821     m_desc(Color::formatToDescriptor(VG_sRGBA_8888)),	//dummy initialization, will be overwritten below (can't read from parent->m_desc before knowing the pointer is valid)
       
   822     m_width(width),
       
   823     m_height(height),
       
   824     m_allowedQuality(0),
       
   825     m_inUse(0),
       
   826     m_stride(0),
       
   827     m_data(NULL),
       
   828     m_referenceCount(0),
       
   829     m_ownsData(false),
       
   830     m_parent(parent),
       
   831     m_storageOffsetX(0),
       
   832     m_storageOffsetY(0),
       
   833     m_unsafeData(false)
       
   834 {
       
   835     RI_ASSERT(parent);
       
   836     RI_ASSERT(x >= 0 && y >= 0 && width > 0 && height > 0);
       
   837     RI_ASSERT(RI_INT_ADDSATURATE(x,width) <= parent->m_width && RI_INT_ADDSATURATE(y,height) <= parent->m_height);	//child image must be contained in parent
       
   838 
       
   839     m_desc = parent->m_desc;
       
   840     RI_ASSERT(Color::isValidDescriptor(m_desc));
       
   841     m_allowedQuality = parent->m_allowedQuality;
       
   842     m_stride = parent->m_stride;
       
   843     m_data = parent->m_data;
       
   844     m_storageOffsetX = parent->m_storageOffsetX + x;
       
   845     m_storageOffsetY = parent->m_storageOffsetY + y;
       
   846 
       
   847     //increase the reference and use count of the parent
       
   848     addInUse();
       
   849     parent->addInUse();
       
   850     parent->addReference();
       
   851     m_unsafeData = parent->m_unsafeData;
       
   852 }
       
   853 
       
   854 /*-------------------------------------------------------------------*//*!
       
   855 * \brief	Image destructor.
       
   856 * \param
       
   857 * \return
       
   858 * \note
       
   859 *//*-------------------------------------------------------------------*/
       
   860 
       
   861 Image::~Image()
       
   862 {
       
   863     RI_ASSERT(m_referenceCount == 0);
       
   864 
       
   865     if(m_parent)
       
   866     {
       
   867         //decrease the reference and use count of the parent
       
   868         removeInUse();
       
   869         m_parent->removeInUse();
       
   870         if(!m_parent->removeReference())
       
   871             RI_DELETE(m_parent);
       
   872     }
       
   873     RI_ASSERT(m_inUse == 0);
       
   874 
       
   875 
       
   876     if(m_ownsData)
       
   877     {
       
   878         RI_ASSERT(!m_parent);		//can't have parent if owns the data
       
   879         RI_DELETE_ARRAY(m_data);	//delete image data if we own it
       
   880     }
       
   881 }
       
   882 
       
   883 /*-------------------------------------------------------------------*//*!
       
   884 * \brief	Returns true if the two images share pixels.
       
   885 * \param
       
   886 * \return
       
   887 * \note
       
   888 *//*-------------------------------------------------------------------*/
       
   889 
       
   890 bool Image::overlaps(const Image* src) const
       
   891 {
       
   892     RI_ASSERT(src);
       
   893 
       
   894     if(m_data != src->m_data)
       
   895         return false;	//images don't share data
       
   896 
       
   897     //check if the image storage regions overlap
       
   898     Rectangle r(m_storageOffsetX, m_storageOffsetY, m_width, m_height);
       
   899     r.intersect(Rectangle(src->m_storageOffsetX, src->m_storageOffsetY, src->m_width, src->m_height));
       
   900     if(!r.width || !r.height)
       
   901         return false;	//intersection is empty, images don't overlap
       
   902 
       
   903     return true;
       
   904 }
       
   905 
       
   906 /**
       
   907  * \brief   Expand log2 bpp packed pixel (single value) to 8 bits. This will
       
   908  *          Result in 8, 4, or 2 same pixel values to be packed into the return value.
       
   909  */
       
   910 RI_INLINE static RIuint32 logExpand8(RIuint32 packedColor, int srcBits)
       
   911 {
       
   912     RI_ASSERT(srcBits == 4 || srcBits == 2 || srcBits == 1);
       
   913     RIuint32 ret = packedColor;
       
   914     int n = srcBits;
       
   915     while (n < 8)
       
   916     {
       
   917         ret |= ret << n;
       
   918         n += n;
       
   919     }
       
   920     return ret;
       
   921 }
       
   922 
       
   923 RI_INLINE void Image::fillPacked(RIuint32 packedColor)
       
   924 {
       
   925     RIuint32 pc = packedColor;
       
   926     int Bpp = m_desc.bitsPerPixel / 8;
       
   927     int nSetsPerScanline = m_width;
       
   928 
       
   929     RI_ASSERT(nSetsPerScanline);
       
   930     // \todo 1bpp and 4bpp mask formats must be supported. fillPackedPixels should
       
   931     // automatically work, but riMemSet32 path needs a bit more logic.
       
   932     // \note < 8bpp formats are always rounded to 8-bit boundaries at scanline end.
       
   933     // It is assumed that the "padding bits" may be filled.
       
   934         
       
   935     if (m_desc.bitsPerPixel < 8)
       
   936     {
       
   937         pc = logExpand8(packedColor, m_desc.bitsPerPixel);
       
   938         Bpp = 1;
       
   939         nSetsPerScanline = (m_width * m_desc.bitsPerPixel + 7) / 8;
       
   940         //nSetsPerScanline /= (8/m_desc.bitsPerPixel);
       
   941     }
       
   942 
       
   943     RI_ASSERT(Bpp <= 4 && Bpp >= 1);
       
   944 
       
   945     if (m_stride == ((m_desc.bitsPerPixel*m_width+7)/8))
       
   946     {
       
   947         const int nPixels = nSetsPerScanline * m_height;
       
   948         riMemSet32(m_data, pc, nPixels, Bpp);
       
   949     } else
       
   950     {
       
   951         RIuint8 *ptr = (RIuint8*)m_data;
       
   952         // set per-scanline
       
   953         for (int y = 0; y < m_height; y++)
       
   954         {
       
   955             riMemSet32(ptr, pc, nSetsPerScanline, Bpp); 
       
   956             ptr += m_stride;
       
   957         }
       
   958     }
       
   959 }
       
   960 
       
   961 /*-------------------------------------------------------------------*//*!
       
   962 * \brief	Clears a rectangular portion of an image with the given clear color.
       
   963 * \param
       
   964 * \return
       
   965 * \note
       
   966 *//*-------------------------------------------------------------------*/
       
   967 
       
   968 void Image::clear(const Color& clearColor, int x, int y, int w, int h)
       
   969 {
       
   970     RI_ASSERT(m_data);
       
   971     RI_ASSERT(m_referenceCount > 0);
       
   972 
       
   973 
       
   974     //intersect clear region with image bounds
       
   975     Rectangle r(0,0,m_width,m_height);
       
   976     r.intersect(Rectangle(x,y,w,h));
       
   977     if(!r.width || !r.height)
       
   978         return;		//intersection is empty or one of the rectangles is invalid
       
   979 
       
   980     Color col = clearColor;
       
   981     col.clamp();
       
   982     col.convert(getDescriptor().internalFormat);
       
   983 
       
   984     IntegerColor ic = IntegerColor(col);
       
   985     ic.truncateColor(getDescriptor());
       
   986     const RIuint32 c = ic.getPackedColor(getDescriptor());
       
   987 
       
   988     if (r.width == getWidth() && r.height == getHeight() && !m_parent)
       
   989         fillPacked(c);
       
   990     else
       
   991     {
       
   992         fillPackedRectangle(r.x, r.y, r.width, r.height, c);
       
   993     }
       
   994 }
       
   995 
       
   996 #if 0
       
   997 static RIfloat ditherChannel(RIfloat c, int bits, RIfloat m)
       
   998 {
       
   999     RIfloat fc = c * (RIfloat)((1<<bits)-1);
       
  1000     RIfloat ic = (RIfloat)floor(fc);
       
  1001     if(fc - ic > m) ic += 1.0f;
       
  1002     return RI_MIN(ic / (RIfloat)((1<<bits)-1), 1.0f);
       
  1003 }
       
  1004 #endif
       
  1005 
       
  1006 static void computeBlitRegion(int& sx, int& sy, int& dx, int& dy, int& w, int& h, int srcWidth, int srcHeight, int dstWidth, int dstHeight)
       
  1007 {
       
  1008     RI_ASSERT(w > 0 && h > 0);
       
  1009     sx = RI_INT_MIN(RI_INT_MAX(sx, (int)(RI_INT32_MIN>>2)), (int)(RI_INT32_MAX>>2));
       
  1010     sy = RI_INT_MIN(RI_INT_MAX(sy, (int)(RI_INT32_MIN>>2)), (int)(RI_INT32_MAX>>2));
       
  1011     dx = RI_INT_MIN(RI_INT_MAX(dx, (int)(RI_INT32_MIN>>2)), (int)(RI_INT32_MAX>>2));
       
  1012     dy = RI_INT_MIN(RI_INT_MAX(dy, (int)(RI_INT32_MIN>>2)), (int)(RI_INT32_MAX>>2));
       
  1013     w = RI_INT_MIN(w, (int)(RI_INT32_MAX>>2));
       
  1014     h = RI_INT_MIN(h, (int)(RI_INT32_MAX>>2));
       
  1015     int srcsx = sx, srcex = sx + w, dstsx = dx, dstex = dx + w;
       
  1016     if(srcsx < 0)
       
  1017     {
       
  1018         dstsx -= srcsx;
       
  1019         srcsx = 0;
       
  1020     }
       
  1021     if(srcex > srcWidth)
       
  1022     {
       
  1023         dstex -= srcex - srcWidth;
       
  1024         srcex = srcWidth;
       
  1025     }
       
  1026     if(dstsx < 0)
       
  1027     {
       
  1028         srcsx -= dstsx;
       
  1029         dstsx = 0;
       
  1030     }
       
  1031     if(dstex > dstWidth)
       
  1032     {
       
  1033         srcex -= dstex - dstWidth;
       
  1034         dstex = dstWidth;
       
  1035     }
       
  1036     RI_ASSERT(srcsx >= 0 && dstsx >= 0 && srcex <= srcWidth && dstex <= dstWidth);
       
  1037     w = srcex - srcsx;
       
  1038     RI_ASSERT(w == dstex - dstsx);
       
  1039 
       
  1040     int srcsy = sy, srcey = sy + h, dstsy = dy, dstey = dy + h;
       
  1041     if(srcsy < 0)
       
  1042     {
       
  1043         dstsy -= srcsy;
       
  1044         srcsy = 0;
       
  1045     }
       
  1046     if(srcey > srcHeight)
       
  1047     {
       
  1048         dstey -= srcey - srcHeight;
       
  1049         srcey = srcHeight;
       
  1050     }
       
  1051     if(dstsy < 0)
       
  1052     {
       
  1053         srcsy -= dstsy;
       
  1054         dstsy = 0;
       
  1055     }
       
  1056     if(dstey > dstHeight)
       
  1057     {
       
  1058         srcey -= dstey - dstHeight;
       
  1059         dstey = dstHeight;
       
  1060     }
       
  1061     RI_ASSERT(srcsy >= 0 && dstsy >= 0 && srcey <= srcHeight && dstey <= dstHeight);
       
  1062     h = srcey - srcsy;
       
  1063     RI_ASSERT(h == dstey - dstsy);
       
  1064     sx = srcsx;
       
  1065     sy = srcsy;
       
  1066     dx = dstsx;
       
  1067     dy = dstsy;
       
  1068 }
       
  1069 
       
  1070 /*-------------------------------------------------------------------*//*!
       
  1071 * \brief	Blits a source region to destination. Source and destination
       
  1072 *			can overlap.
       
  1073 * \param
       
  1074 * \return
       
  1075 * \note
       
  1076 *//*-------------------------------------------------------------------*/
       
  1077 
       
  1078 // \todo Extract dithering kernel and put it into the blitter
       
  1079 #if 0
       
  1080 void Image::blit(VGContext* context, const Image* src, int sx, int sy, int dx, int dy, int w, int h, bool dither)
       
  1081 {
       
  1082     //img=>img: vgCopyImage
       
  1083     //img=>user: vgGetImageSubData
       
  1084     //user=>img: vgImageSubData
       
  1085     
       
  1086     // \todo Implement dither to blitter.
       
  1087     this->blit(context, src, sx, sy, dx, dy, w, h, NULL, dither);
       
  1088     RI_ASSERT(src.m_data);	//source exists
       
  1089     RI_ASSERT(m_data);	//destination exists
       
  1090     RI_ASSERT(m_referenceCount > 0 && src.m_referenceCount > 0);
       
  1091 
       
  1092     computeBlitRegion(sx, sy, dx, dy, w, h, src.m_width, src.m_height, m_width, m_height);
       
  1093     if(w <= 0 || h <= 0)
       
  1094         return;	//zero area
       
  1095 
       
  1096     Array<Color> tmp;
       
  1097     tmp.resize(w*h);	//throws bad_alloc
       
  1098 
       
  1099     //copy source region to tmp
       
  1100     for(int j=0;j<h;j++)
       
  1101     {
       
  1102         for(int i=0;i<w;i++)
       
  1103         {
       
  1104             Color c = src.readPixel(sx + i, sy + j);
       
  1105             c.convert(m_desc.internalFormat);
       
  1106             tmp[j*w+i] = c;
       
  1107         }
       
  1108     }
       
  1109 
       
  1110     int rbits = m_desc.redBits, gbits = m_desc.greenBits, bbits = m_desc.blueBits, abits = m_desc.alphaBits;
       
  1111     if(m_desc.isLuminance())
       
  1112     {
       
  1113         rbits = gbits = bbits = m_desc.luminanceBits;
       
  1114         abits = 0;
       
  1115     }
       
  1116 
       
  1117     //write tmp to destination region
       
  1118     for(int j=0;j<h;j++)
       
  1119     {
       
  1120         for(int i=0;i<w;i++)
       
  1121         {
       
  1122             Color col = tmp[j*w+i];
       
  1123 
       
  1124             if(dither)
       
  1125             {
       
  1126                 static const int matrix[16] = {
       
  1127                     0,  8,  2,  10,
       
  1128                     12, 4,  14, 6,
       
  1129                     3,  11, 1,  9,
       
  1130                     15, 7,  13, 5};
       
  1131                 int x = i & 3;
       
  1132                 int y = j & 3;
       
  1133                 RIfloat m = matrix[y*4+x] / 16.0f;
       
  1134 
       
  1135                 if(rbits) col.r = ditherChannel(col.r, rbits, m);
       
  1136                 if(gbits) col.g = ditherChannel(col.g, gbits, m);
       
  1137                 if(bbits) col.b = ditherChannel(col.b, bbits, m);
       
  1138                 if(abits) col.a = ditherChannel(col.a, abits, m);
       
  1139             }
       
  1140 
       
  1141             writePixel(dx + i, dy + j, col);
       
  1142         }
       
  1143     }
       
  1144 }
       
  1145 #endif
       
  1146 
       
  1147 /**
       
  1148  * \brief   Common body for drawImage-functions (one is the actual drawImage, and the
       
  1149  *          other one is used for scissored image-set operations.
       
  1150  * \todo    Reorganize all image draw operations to use this function. 
       
  1151  */
       
  1152 static bool drawImageBody(VGContext* context, Image* image, const Matrix3x3& userToSurfaceMatrix,
       
  1153     VGImageQuality imageQuality,
       
  1154     VGBlendMode blendMode,
       
  1155     bool hasMasking,
       
  1156     bool hasColorTransform,
       
  1157     VGImageMode imageMode)
       
  1158 {
       
  1159     Drawable* drawable = context->getCurrentDrawable();
       
  1160     if(!drawable)
       
  1161         return false;   //no EGL surface is current at the moment
       
  1162 
       
  1163     Image* img = (Image*)image;
       
  1164     //transform image corners into the surface space
       
  1165     Vector3 p0(0, 0, 1);
       
  1166     Vector3 p1(0, (RIfloat)img->getHeight(), 1);
       
  1167     Vector3 p2((RIfloat)img->getWidth(), (RIfloat)img->getHeight(), 1);
       
  1168     Vector3 p3((RIfloat)img->getWidth(), 0, 1);
       
  1169 
       
  1170     p0 = userToSurfaceMatrix * p0;
       
  1171     p1 = userToSurfaceMatrix * p1;
       
  1172     p2 = userToSurfaceMatrix * p2;
       
  1173     p3 = userToSurfaceMatrix * p3;
       
  1174     if(p0.z <= 0.0f || p1.z <= 0.0f || p2.z <= 0.0f || p3.z <= 0.0f)
       
  1175         return false;
       
  1176 
       
  1177     //projection
       
  1178     p0 *= 1.0f/p0.z;
       
  1179     p1 *= 1.0f/p1.z;
       
  1180     p2 *= 1.0f/p2.z;
       
  1181     p3 *= 1.0f/p3.z;
       
  1182 
       
  1183     Rasterizer& rasterizer = context->m_rasterizer;
       
  1184     rasterizer.clear();
       
  1185 
       
  1186     if(context->m_scissoring)
       
  1187         rasterizer.setScissor(context->m_scissor);	//throws bad_alloc
       
  1188 
       
  1189     PixelPipe& pixelPipe = context->m_pixelPipe;
       
  1190     pixelPipe.setTileFillColor(context->m_tileFillColor);
       
  1191     pixelPipe.setPaint((Paint*)context->m_fillPaint);
       
  1192     const bool aa = imageQuality == VG_IMAGE_QUALITY_NONANTIALIASED ? false : true;
       
  1193     rasterizer.setAntiAliasing(aa);
       
  1194     pixelPipe.setImageQuality(imageQuality);
       
  1195     pixelPipe.setBlendMode(blendMode);
       
  1196     pixelPipe.setRenderToMask(false);
       
  1197     pixelPipe.setDrawable(drawable);
       
  1198     pixelPipe.setMask(hasMasking);
       
  1199     pixelPipe.setColorTransform(hasColorTransform, context->m_colorTransformValues);
       
  1200 
       
  1201     Matrix3x3 surfaceToImageMatrix = userToSurfaceMatrix;
       
  1202     Matrix3x3 surfaceToPaintMatrix = userToSurfaceMatrix * context->m_fillPaintToUser;
       
  1203     if(surfaceToImageMatrix.invert() && surfaceToPaintMatrix.invert())
       
  1204     {
       
  1205         VGImageMode imode = imageMode;
       
  1206 
       
  1207         if(!surfaceToPaintMatrix.isAffine())
       
  1208             imode = VG_DRAW_IMAGE_NORMAL;	//if paint matrix is not affine, always use normal image mode
       
  1209 
       
  1210         surfaceToPaintMatrix[2].set(0,0,1);	//force affine
       
  1211 
       
  1212         pixelPipe.setImage(img, imode);
       
  1213         pixelPipe.setSurfaceToPaintMatrix(surfaceToPaintMatrix);
       
  1214         pixelPipe.setSurfaceToImageMatrix(surfaceToImageMatrix);
       
  1215         pixelPipe.prepareSpanUniforms(aa);
       
  1216         rasterizer.setup(0, 0, drawable->getWidth(), drawable->getHeight(), VG_EVEN_ODD, &pixelPipe);
       
  1217 
       
  1218         rasterizer.addEdge(Vector2(p0.x,p0.y), Vector2(p1.x,p1.y));	//throws bad_alloc
       
  1219         rasterizer.addEdge(Vector2(p1.x,p1.y), Vector2(p2.x,p2.y));	//throws bad_alloc
       
  1220         rasterizer.addEdge(Vector2(p2.x,p2.y), Vector2(p3.x,p3.y));	//throws bad_alloc
       
  1221         rasterizer.addEdge(Vector2(p3.x,p3.y), Vector2(p0.x,p0.y));	//throws bad_alloc
       
  1222 
       
  1223         rasterizer.fill();	//throws bad_alloc
       
  1224     }
       
  1225 
       
  1226     return true;
       
  1227 }
       
  1228 
       
  1229 /*-------------------------------------------------------------------*//*!
       
  1230 * \brief	Converts from multisampled format to display format.
       
  1231 * \param    unsafeInput     Data may contain incorrect values (user data)     
       
  1232 * \return
       
  1233 * \note     May throw std::bad_alloc on cases where blitting within the
       
  1234 *           same buffer and overlapping regions (this may change in the
       
  1235 *           future).
       
  1236 *//*-------------------------------------------------------------------*/
       
  1237 
       
  1238 void Image::blit(VGContext* context, const Image* src, 
       
  1239     int sx, int sy, int dx, int dy, int w, int h, 
       
  1240     Array<Rectangle>* scissors,
       
  1241     bool dither)
       
  1242 {
       
  1243     bool overlap = false;
       
  1244     (void)dither;
       
  1245     DynamicBlitter& blitter = context->getBlitter();
       
  1246 
       
  1247     //RI_ASSERT(!src->isInUse(this));
       
  1248     //int isx = sx, isy = sy, idx = dx, idy = dy, iw = w, ih = h;
       
  1249 
       
  1250     computeBlitRegion(sx, sy, dx, dy, w, h, src->getWidth(), src->getHeight(), m_width, m_height);
       
  1251 
       
  1252     if(w <= 0 || h <= 0)
       
  1253         return;	//zero area
       
  1254 
       
  1255     if (this->m_data == src->m_data)
       
  1256     {
       
  1257         // The images may overlap.
       
  1258         int minsx = RI_INT_MIN(sx, dx);
       
  1259         int minsy = RI_INT_MIN(sy, dy);
       
  1260         int maxsx = RI_INT_MAX(sx, dx);
       
  1261         int maxsy = RI_INT_MAX(sy, dy);
       
  1262 
       
  1263         if ((maxsx < (minsx + w)) && (maxsy < (minsy + h)))
       
  1264         {
       
  1265             overlap = true;
       
  1266         }
       
  1267     }
       
  1268 
       
  1269     if (!scissors)
       
  1270     {
       
  1271         // Currently the blitter does not support scissors
       
  1272         if (!overlap)
       
  1273         {
       
  1274             blitter.prepareBlit(this, src, sx+src->m_storageOffsetX, sy+src->m_storageOffsetY, 
       
  1275                 dx+m_storageOffsetX, dy+m_storageOffsetY, w, h);
       
  1276             blitter.blit();
       
  1277         } else
       
  1278         {
       
  1279             Image temp(src->getDescriptor(), w, h, VG_IMAGE_QUALITY_NONANTIALIASED);
       
  1280             blitter.prepareBlit(&temp, src, sx+src->m_storageOffsetX, sy+src->m_storageOffsetY, 0, 0, w, h);
       
  1281             blitter.blit();
       
  1282             blitter.prepareBlit(this, &temp, 0, 0, dx+m_storageOffsetX, dy+m_storageOffsetY, w, h);
       
  1283             blitter.blit();
       
  1284         }
       
  1285     } else
       
  1286     {
       
  1287         // For the moment, use the generic poly-rasterizer for scissored images.
       
  1288         if (!overlap)
       
  1289         {
       
  1290             // Create a child image
       
  1291             Image blitImage((Image*)src, sx, sy, w, h);
       
  1292             Matrix3x3 tx;
       
  1293             tx.set(1, 0, dx, 0, 1, dy, 0, 0, 1);
       
  1294 
       
  1295             drawImageBody(context, &blitImage, tx,
       
  1296                         VG_IMAGE_QUALITY_NONANTIALIASED,
       
  1297                         VG_BLEND_SRC,
       
  1298                         false,
       
  1299                         false,
       
  1300                         VG_DRAW_IMAGE_NORMAL);
       
  1301         } else
       
  1302         {
       
  1303             // Create a copy of the source region
       
  1304             Image temp(src->getDescriptor(), w, h, VG_IMAGE_QUALITY_NONANTIALIASED);
       
  1305             blitter.prepareBlit(&temp, src, sx, sy, 0, 0, w, h);
       
  1306             blitter.blit();
       
  1307 
       
  1308             Image blitImage((Image*)src, sx, sy, w, h);
       
  1309             Matrix3x3 tx;
       
  1310             tx.set(1, 0, dx, 0, 1, dy, 0, 0, 1);
       
  1311 
       
  1312             drawImageBody(context, &blitImage, tx,
       
  1313                         VG_IMAGE_QUALITY_NONANTIALIASED,
       
  1314                         VG_BLEND_SRC,
       
  1315                         false,
       
  1316                         false,
       
  1317                         VG_DRAW_IMAGE_NORMAL);
       
  1318         }
       
  1319     }
       
  1320 
       
  1321 }
       
  1322 
       
  1323 /*-------------------------------------------------------------------*//*!
       
  1324 * \brief	Returns the color at pixel (x,y).
       
  1325 * \param
       
  1326 * \return
       
  1327 * \note
       
  1328 *//*-------------------------------------------------------------------*/
       
  1329 
       
  1330 Color Image::readPixel(int x, int y) const
       
  1331 {
       
  1332     const RIuint32 p = readPackedPixel(x, y);
       
  1333 
       
  1334     Color c;
       
  1335     c.unpack(p, m_desc);
       
  1336     return c;
       
  1337 }
       
  1338 
       
  1339 /*-------------------------------------------------------------------*//*!
       
  1340 * \brief	Writes the color to pixel (x,y). Internal color formats must
       
  1341 *			match.
       
  1342 * \param
       
  1343 * \return
       
  1344 * \note
       
  1345 *//*-------------------------------------------------------------------*/
       
  1346 
       
  1347 void Image::writePixel(int x, int y, const Color& c)
       
  1348 {
       
  1349     RI_ASSERT(c.getInternalFormat() == m_desc.internalFormat);
       
  1350 
       
  1351     RIuint32 p = c.pack(m_desc);
       
  1352     writePackedPixel(x, y, p);
       
  1353 }
       
  1354 
       
  1355 /*-------------------------------------------------------------------*//*!
       
  1356 * \brief	Writes a filtered color to destination surface
       
  1357 * \param
       
  1358 * \return
       
  1359 * \note
       
  1360 *//*-------------------------------------------------------------------*/
       
  1361 
       
  1362 void Image::writeFilteredPixel(int i, int j, const Color& color, VGbitfield channelMask)
       
  1363 {
       
  1364     //section 3.4.4: before color space conversion, premultiplied colors are
       
  1365     //clamped to alpha, and the color is converted to nonpremultiplied format
       
  1366     //section 11.2: how to deal with channel mask
       
  1367     //step 1
       
  1368     Color f = color;
       
  1369     f.clamp();			//vgColorMatrix and vgLookups can produce colors that exceed alpha or [0,1] range
       
  1370 
       
  1371     //step 2: color space conversion
       
  1372     f.convert((Color::InternalFormat)(m_desc.internalFormat & (Color::NONLINEAR | Color::LUMINANCE)));
       
  1373 
       
  1374     //step 3: read the destination color and convert it to nonpremultiplied
       
  1375     Color d = readPixel(i,j);
       
  1376     d.unpremultiply();
       
  1377     RI_ASSERT(d.getInternalFormat() == f.getInternalFormat());
       
  1378 
       
  1379     //step 4: replace the destination channels specified by the channelMask (channelmask is ignored for luminance formats)
       
  1380     if(!m_desc.isLuminance())
       
  1381     {   //rgba format => use channelmask
       
  1382         if(channelMask & VG_RED)
       
  1383             d.r = f.r;
       
  1384         if(channelMask & VG_GREEN)
       
  1385             d.g = f.g;
       
  1386         if(channelMask & VG_BLUE)
       
  1387             d.b = f.b;
       
  1388         if(channelMask & VG_ALPHA)
       
  1389             d.a = f.a;
       
  1390     }
       
  1391     else d = f;
       
  1392 
       
  1393     //step 5: if destination is premultiplied, convert to premultiplied format
       
  1394     if(m_desc.isPremultiplied())
       
  1395         d.premultiply();
       
  1396     //write the color to destination
       
  1397     writePixel(i,j,d);
       
  1398 }
       
  1399 
       
  1400 /*-------------------------------------------------------------------*//*!
       
  1401 * \brief	Reads the pixel (x,y) and converts it into an alpha mask value.
       
  1402 * \param
       
  1403 * \return
       
  1404 * \note
       
  1405 *//*-------------------------------------------------------------------*/
       
  1406 
       
  1407 RIfloat Image::readMaskPixel(int x, int y) const
       
  1408 {
       
  1409     RI_ASSERT(m_data);
       
  1410     RI_ASSERT(x >= 0 && x < m_width);
       
  1411     RI_ASSERT(y >= 0 && y < m_height);
       
  1412     RI_ASSERT(m_referenceCount > 0);
       
  1413 
       
  1414     Color c = readPixel(x,y);
       
  1415     if(m_desc.isLuminance())
       
  1416     {
       
  1417         return c.r;
       
  1418     }
       
  1419     else
       
  1420     {	//rgba
       
  1421         if(m_desc.alphaBits)
       
  1422             return c.a;
       
  1423         return c.r;
       
  1424     }
       
  1425 }
       
  1426 
       
  1427 /*-------------------------------------------------------------------*//*!
       
  1428 * \brief	Writes the alpha mask to pixel (x,y).
       
  1429 * \param
       
  1430 * \return
       
  1431 * \note		Overwrites color.
       
  1432 *//*-------------------------------------------------------------------*/
       
  1433 
       
  1434 void Image::writeMaskPixel(int x, int y, RIfloat m)
       
  1435 {
       
  1436     RI_ASSERT(m_data);
       
  1437     RI_ASSERT(x >= 0 && x < m_width);
       
  1438     RI_ASSERT(y >= 0 && y < m_height);
       
  1439     RI_ASSERT(m_referenceCount > 0);
       
  1440 
       
  1441     //if luminance or no alpha, red channel will be used, otherwise alpha channel will be used
       
  1442     writePixel(x, y, Color(m,m,m,m,m_desc.internalFormat));
       
  1443 }
       
  1444 
       
  1445 /*-------------------------------------------------------------------*//*!
       
  1446 * \brief	Reads a texel (u,v) at the given mipmap level. Tiling modes and
       
  1447 *			color space conversion are applied. Outputs color in premultiplied
       
  1448 *			format.
       
  1449 * \param
       
  1450 * \return
       
  1451 * \note
       
  1452 *//*-------------------------------------------------------------------*/
       
  1453 
       
  1454 Color Image::readTexel(int u, int v, int level, VGTilingMode tilingMode, const Color& tileFillColor) const
       
  1455 {
       
  1456     const Image* image = this;
       
  1457     if( level > 0 )
       
  1458     {
       
  1459         RI_ASSERT(false);
       
  1460     }
       
  1461     RI_ASSERT(image);
       
  1462 
       
  1463     Color p;
       
  1464     if(tilingMode == VG_TILE_FILL)
       
  1465     {
       
  1466         if(u < 0 || v < 0 || u >= image->m_width || v >= image->m_height)
       
  1467             p = tileFillColor;
       
  1468         else
       
  1469             p = image->readPixel(u, v);
       
  1470     }
       
  1471     else if(tilingMode == VG_TILE_PAD)
       
  1472     {
       
  1473         u = RI_INT_MIN(RI_INT_MAX(u,0),image->m_width-1);
       
  1474         v = RI_INT_MIN(RI_INT_MAX(v,0),image->m_height-1);
       
  1475         p = image->readPixel(u, v);
       
  1476     }
       
  1477     else if(tilingMode == VG_TILE_REPEAT)
       
  1478     {
       
  1479         u = RI_INT_MOD(u, image->m_width);
       
  1480         v = RI_INT_MOD(v, image->m_height);
       
  1481         p = image->readPixel(u, v);
       
  1482     }
       
  1483     else
       
  1484     {
       
  1485         RI_ASSERT(tilingMode == VG_TILE_REFLECT);
       
  1486 
       
  1487         u = RI_INT_MOD(u, image->m_width*2);
       
  1488         v = RI_INT_MOD(v, image->m_height*2);
       
  1489         if( u >= image->m_width ) u = image->m_width*2-1 - u;
       
  1490         if( v >= image->m_height ) v = image->m_height*2-1 - v;
       
  1491         p = image->readPixel(u, v);
       
  1492     }
       
  1493 
       
  1494     p.premultiply();    //interpolate in premultiplied format
       
  1495     return p;
       
  1496 }
       
  1497 
       
  1498 /*-------------------------------------------------------------------*//*!
       
  1499 * \brief	Maps point (x,y) to an image and returns a filtered,
       
  1500 *			premultiplied color value.
       
  1501 * \param
       
  1502 * \return
       
  1503 * \note
       
  1504 *//*-------------------------------------------------------------------*/
       
  1505 
       
  1506 Color Image::resample(RIfloat x, RIfloat y, const Matrix3x3& surfaceToImage, VGImageQuality quality, VGTilingMode tilingMode, const Color& tileFillColor)	//throws bad_alloc
       
  1507 {
       
  1508     RI_ASSERT(m_referenceCount > 0);
       
  1509 
       
  1510     VGbitfield aq = getAllowedQuality();
       
  1511     aq &= (VGbitfield)quality;
       
  1512 
       
  1513     Vector3 uvw(x,y,1.0f);
       
  1514     uvw = surfaceToImage * uvw;
       
  1515     RIfloat oow = 1.0f / uvw.z;
       
  1516     uvw *= oow;
       
  1517 
       
  1518 #if 0
       
  1519     if(aq & VG_IMAGE_QUALITY_BETTER)
       
  1520     {	//EWA on mipmaps
       
  1521         makeMipMaps();	//throws bad_alloc
       
  1522 
       
  1523         Color::InternalFormat procFormat = (Color::InternalFormat)(m_desc.internalFormat | Color::PREMULTIPLIED);
       
  1524 
       
  1525         RIfloat m_pixelFilterRadius = 1.25f;
       
  1526         RIfloat m_resamplingFilterRadius = 1.25f;
       
  1527 
       
  1528         RIfloat Ux = (surfaceToImage[0][0] - uvw.x * surfaceToImage[2][0]) * oow * m_pixelFilterRadius;
       
  1529         RIfloat Vx = (surfaceToImage[1][0] - uvw.y * surfaceToImage[2][0]) * oow * m_pixelFilterRadius;
       
  1530         RIfloat Uy = (surfaceToImage[0][1] - uvw.x * surfaceToImage[2][1]) * oow * m_pixelFilterRadius;
       
  1531         RIfloat Vy = (surfaceToImage[1][1] - uvw.y * surfaceToImage[2][1]) * oow * m_pixelFilterRadius;
       
  1532         RIfloat U0 = uvw.x;
       
  1533         RIfloat V0 = uvw.y;
       
  1534 
       
  1535         //calculate mip level
       
  1536         int level = 0;
       
  1537         RIfloat axis1sq = Ux*Ux + Vx*Vx;
       
  1538         RIfloat axis2sq = Uy*Uy + Vy*Vy;
       
  1539         RIfloat minorAxissq = RI_MIN(axis1sq,axis2sq);
       
  1540         while(minorAxissq > 9.0f && level < m_mipmaps.size())	//half the minor axis must be at least three texels
       
  1541         {
       
  1542             level++;
       
  1543             minorAxissq *= 0.25f;
       
  1544         }
       
  1545 
       
  1546         RIfloat sx = 1.0f;
       
  1547         RIfloat sy = 1.0f;
       
  1548         if(level > 0)
       
  1549         {
       
  1550             sx = (RIfloat)m_mipmaps[level-1]->m_width / (RIfloat)m_width;
       
  1551             sy = (RIfloat)m_mipmaps[level-1]->m_height / (RIfloat)m_height;
       
  1552         }
       
  1553         Ux *= sx;
       
  1554         Vx *= sx;
       
  1555         U0 *= sx;
       
  1556         Uy *= sy;
       
  1557         Vy *= sy;
       
  1558         V0 *= sy;
       
  1559 
       
  1560         //clamp filter size so that filtering doesn't take excessive amount of time (clamping results in aliasing)
       
  1561         RIfloat lim = 100.0f;
       
  1562         axis1sq = Ux*Ux + Vx*Vx;
       
  1563         axis2sq = Uy*Uy + Vy*Vy;
       
  1564         if( axis1sq > lim*lim )
       
  1565         {
       
  1566             RIfloat s = lim / (RIfloat)sqrt(axis1sq);
       
  1567             Ux *= s;
       
  1568             Vx *= s;
       
  1569         }
       
  1570         if( axis2sq > lim*lim )
       
  1571         {
       
  1572             RIfloat s = lim / (RIfloat)sqrt(axis2sq);
       
  1573             Uy *= s;
       
  1574             Vy *= s;
       
  1575         }
       
  1576 
       
  1577 
       
  1578         //form elliptic filter by combining texel and pixel filters
       
  1579         RIfloat A = Vx*Vx + Vy*Vy + 1.0f;
       
  1580         RIfloat B = -2.0f*(Ux*Vx + Uy*Vy);
       
  1581         RIfloat C = Ux*Ux + Uy*Uy + 1.0f;
       
  1582         //scale by the user-defined size of the kernel
       
  1583         A *= m_resamplingFilterRadius;
       
  1584         B *= m_resamplingFilterRadius;
       
  1585         C *= m_resamplingFilterRadius;
       
  1586 
       
  1587         //calculate bounding box in texture space
       
  1588         RIfloat usize = (RIfloat)sqrt(C);
       
  1589         RIfloat vsize = (RIfloat)sqrt(A);
       
  1590         int u1 = (int)floor(U0 - usize + 0.5f);
       
  1591         int u2 = (int)floor(U0 + usize + 0.5f);
       
  1592         int v1 = (int)floor(V0 - vsize + 0.5f);
       
  1593         int v2 = (int)floor(V0 + vsize + 0.5f);
       
  1594         if( u1 == u2 || v1 == v2 )
       
  1595             return Color(0,0,0,0,procFormat);
       
  1596 
       
  1597         //scale the filter so that Q = 1 at the cutoff radius
       
  1598         RIfloat F = A*C - 0.25f * B*B;
       
  1599         if( F <= 0.0f )
       
  1600             return Color(0,0,0,0,procFormat);	//invalid filter shape due to numerical inaccuracies => return black
       
  1601         RIfloat ooF = 1.0f / F;
       
  1602         A *= ooF;
       
  1603         B *= ooF;
       
  1604         C *= ooF;
       
  1605 
       
  1606         //evaluate filter by using forward differences to calculate Q = A*U^2 + B*U*V + C*V^2
       
  1607         Color color(0,0,0,0,procFormat);
       
  1608         RIfloat sumweight = 0.0f;
       
  1609         RIfloat DDQ = 2.0f * A;
       
  1610         RIfloat U = (RIfloat)u1 - U0 + 0.5f;
       
  1611         for(int v=v1;v<v2;v++)
       
  1612         {
       
  1613             RIfloat V = (RIfloat)v - V0 + 0.5f;
       
  1614             RIfloat DQ = A*(2.0f*U+1.0f) + B*V;
       
  1615             RIfloat Q = (C*V+B*U)*V + A*U*U;
       
  1616             for(int u=u1;u<u2;u++)
       
  1617             {
       
  1618                 if( Q >= 0.0f && Q < 1.0f )
       
  1619                 {	//Q = r^2, fit gaussian to the range [0,1]
       
  1620                     RIfloat weight = (RIfloat)exp(-0.5f * 10.0f * Q);	//gaussian at radius 10 equals 0.0067
       
  1621                     color += weight * readTexel(u, v, level, tilingMode, tileFillColor);
       
  1622                     sumweight += weight;
       
  1623                 }
       
  1624                 Q += DQ;
       
  1625                 DQ += DDQ;
       
  1626             }
       
  1627         }
       
  1628         if( sumweight == 0.0f )
       
  1629             return Color(0,0,0,0,procFormat);
       
  1630         RI_ASSERT(sumweight > 0.0f);
       
  1631         sumweight = 1.0f / sumweight;
       
  1632         return color * sumweight;
       
  1633     }
       
  1634     else
       
  1635 #endif
       
  1636         //if(aq & VG_IMAGE_QUALITY_FASTER)
       
  1637     if(aq & VG_IMAGE_QUALITY_BETTER)
       
  1638     {	//bilinear
       
  1639         uvw.x -= 0.5f;
       
  1640         uvw.y -= 0.5f;
       
  1641         int u = (int)floor(uvw.x);
       
  1642         int v = (int)floor(uvw.y);
       
  1643         Color c00 = readTexel(u,v, 0, tilingMode, tileFillColor);
       
  1644         Color c10 = readTexel(u+1,v, 0, tilingMode, tileFillColor);
       
  1645         Color c01 = readTexel(u,v+1, 0, tilingMode, tileFillColor);
       
  1646         Color c11 = readTexel(u+1,v+1, 0, tilingMode, tileFillColor);
       
  1647         RIfloat fu = uvw.x - (RIfloat)u;
       
  1648         RIfloat fv = uvw.y - (RIfloat)v;
       
  1649         Color c0 = c00 * (1.0f - fu) + c10 * fu;
       
  1650         Color c1 = c01 * (1.0f - fu) + c11 * fu;
       
  1651         return c0 * (1.0f - fv) + c1 * fv;
       
  1652     }
       
  1653     else //VG_IMAGE_QUALITY_FASTER and VG_IMAGE_QUALITY_NONANTIALIASED
       
  1654     {	//point sampling
       
  1655         return readTexel((int)floor(uvw.x), (int)floor(uvw.y), 0, tilingMode, tileFillColor);
       
  1656     }
       
  1657 }
       
  1658 
       
  1659 /*-------------------------------------------------------------------*//*!
       
  1660 * \brief	Applies color matrix filter.
       
  1661 * \param
       
  1662 * \return
       
  1663 * \note
       
  1664 *//*-------------------------------------------------------------------*/
       
  1665 
       
  1666 void Image::colorMatrix(const Image& src, const RIfloat* matrix, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask)
       
  1667 {
       
  1668     RI_ASSERT(src.m_data);	//source exists
       
  1669     RI_ASSERT(m_data);	//destination exists
       
  1670     RI_ASSERT(matrix);
       
  1671     RI_ASSERT(m_referenceCount > 0 && src.m_referenceCount > 0);
       
  1672 
       
  1673     int w = RI_INT_MIN(m_width, src.m_width);
       
  1674     int h = RI_INT_MIN(m_height, src.m_height);
       
  1675     RI_ASSERT(w > 0 && h > 0);
       
  1676 
       
  1677     Color::InternalFormat srcFormat = src.m_desc.internalFormat;
       
  1678     Color::InternalFormat procFormat = (Color::InternalFormat)(srcFormat & ~Color::LUMINANCE);	//process in RGB, not luminance
       
  1679     if(filterFormatLinear)
       
  1680         procFormat = (Color::InternalFormat)(procFormat & ~Color::NONLINEAR);
       
  1681     else
       
  1682         procFormat = (Color::InternalFormat)(procFormat | Color::NONLINEAR);
       
  1683 
       
  1684     if(filterFormatPremultiplied)
       
  1685         procFormat = (Color::InternalFormat)(procFormat | Color::PREMULTIPLIED);
       
  1686     else
       
  1687         procFormat = (Color::InternalFormat)(procFormat & ~Color::PREMULTIPLIED);
       
  1688 
       
  1689     for(int j=0;j<h;j++)
       
  1690     {
       
  1691         for(int i=0;i<w;i++)
       
  1692         {
       
  1693             Color s = src.readPixel(i,j);	//convert to RGBA [0,1]
       
  1694             s.convert(procFormat);
       
  1695 
       
  1696             Color d(0,0,0,0,procFormat);
       
  1697             d.r = matrix[0+4*0] * s.r + matrix[0+4*1] * s.g + matrix[0+4*2] * s.b + matrix[0+4*3] * s.a + matrix[0+4*4];
       
  1698             d.g = matrix[1+4*0] * s.r + matrix[1+4*1] * s.g + matrix[1+4*2] * s.b + matrix[1+4*3] * s.a + matrix[1+4*4];
       
  1699             d.b = matrix[2+4*0] * s.r + matrix[2+4*1] * s.g + matrix[2+4*2] * s.b + matrix[2+4*3] * s.a + matrix[2+4*4];
       
  1700             d.a = matrix[3+4*0] * s.r + matrix[3+4*1] * s.g + matrix[3+4*2] * s.b + matrix[3+4*3] * s.a + matrix[3+4*4];
       
  1701 
       
  1702             writeFilteredPixel(i, j, d, channelMask);
       
  1703         }
       
  1704     }
       
  1705 }
       
  1706 
       
  1707 /*-------------------------------------------------------------------*//*!
       
  1708 * \brief	Reads a pixel from image with tiling mode applied.
       
  1709 * \param
       
  1710 * \return
       
  1711 * \note
       
  1712 *//*-------------------------------------------------------------------*/
       
  1713 
       
  1714 static Color readTiledPixel(int x, int y, int w, int h, VGTilingMode tilingMode, const Array<Color>& image, const Color& edge)
       
  1715 {
       
  1716     Color s;
       
  1717     if(x < 0 || x >= w || y < 0 || y >= h)
       
  1718     {	//apply tiling mode
       
  1719         switch(tilingMode)
       
  1720         {
       
  1721         case VG_TILE_FILL:
       
  1722             s = edge;
       
  1723             break;
       
  1724         case VG_TILE_PAD:
       
  1725             x = RI_INT_MIN(RI_INT_MAX(x, 0), w-1);
       
  1726             y = RI_INT_MIN(RI_INT_MAX(y, 0), h-1);
       
  1727             RI_ASSERT(x >= 0 && x < w && y >= 0 && y < h);
       
  1728             s = image[y*w+x];
       
  1729             break;
       
  1730         case VG_TILE_REPEAT:
       
  1731             x = RI_INT_MOD(x, w);
       
  1732             y = RI_INT_MOD(y, h);
       
  1733             RI_ASSERT(x >= 0 && x < w && y >= 0 && y < h);
       
  1734             s = image[y*w+x];
       
  1735             break;
       
  1736         default:
       
  1737             RI_ASSERT(tilingMode == VG_TILE_REFLECT);
       
  1738             x = RI_INT_MOD(x, w*2);
       
  1739             y = RI_INT_MOD(y, h*2);
       
  1740             if(x >= w) x = w*2-1-x;
       
  1741             if(y >= h) y = h*2-1-y;
       
  1742             RI_ASSERT(x >= 0 && x < w && y >= 0 && y < h);
       
  1743             s = image[y*w+x];
       
  1744             break;
       
  1745         }
       
  1746     }
       
  1747     else
       
  1748     {
       
  1749         RI_ASSERT(x >= 0 && x < w && y >= 0 && y < h);
       
  1750         s = image[y*w+x];
       
  1751     }
       
  1752     return s;
       
  1753 }
       
  1754 
       
  1755 /*-------------------------------------------------------------------*//*!
       
  1756 * \brief	Returns processing format for filtering.
       
  1757 * \param
       
  1758 * \return
       
  1759 * \note
       
  1760 *//*-------------------------------------------------------------------*/
       
  1761 
       
  1762 static Color::InternalFormat getProcessingFormat(Color::InternalFormat srcFormat, bool filterFormatLinear, bool filterFormatPremultiplied)
       
  1763 {
       
  1764     Color::InternalFormat procFormat = (Color::InternalFormat)(srcFormat & ~Color::LUMINANCE);	//process in RGB, not luminance
       
  1765     if(filterFormatLinear)
       
  1766         procFormat = (Color::InternalFormat)(procFormat & ~Color::NONLINEAR);
       
  1767     else
       
  1768         procFormat = (Color::InternalFormat)(procFormat | Color::NONLINEAR);
       
  1769 
       
  1770     if(filterFormatPremultiplied)
       
  1771         procFormat = (Color::InternalFormat)(procFormat | Color::PREMULTIPLIED);
       
  1772     else
       
  1773         procFormat = (Color::InternalFormat)(procFormat & ~Color::PREMULTIPLIED);
       
  1774     return procFormat;
       
  1775 }
       
  1776 
       
  1777 /*-------------------------------------------------------------------*//*!
       
  1778 * \brief	Applies convolution filter.
       
  1779 * \param
       
  1780 * \return
       
  1781 * \note
       
  1782 *//*-------------------------------------------------------------------*/
       
  1783 
       
  1784 void Image::convolve(const Image& src, int kernelWidth, int kernelHeight, int shiftX, int shiftY, const RIint16* kernel, RIfloat scale, RIfloat bias, VGTilingMode tilingMode, const Color& edgeFillColor, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask)
       
  1785 {
       
  1786     RI_ASSERT(src.m_data);	//source exists
       
  1787     RI_ASSERT(m_data);	//destination exists
       
  1788     RI_ASSERT(kernel && kernelWidth > 0 && kernelHeight > 0);
       
  1789     RI_ASSERT(m_referenceCount > 0 && src.m_referenceCount > 0);
       
  1790 
       
  1791     //the area to be written is an intersection of source and destination image areas.
       
  1792     //lower-left corners of the images are aligned.
       
  1793     int w = RI_INT_MIN(m_width, src.m_width);
       
  1794     int h = RI_INT_MIN(m_height, src.m_height);
       
  1795     RI_ASSERT(w > 0 && h > 0);
       
  1796 
       
  1797     Color::InternalFormat procFormat = getProcessingFormat(src.m_desc.internalFormat, filterFormatLinear, filterFormatPremultiplied);
       
  1798 
       
  1799     Color edge = edgeFillColor;
       
  1800     edge.clamp();
       
  1801     edge.convert(procFormat);
       
  1802 
       
  1803     Array<Color> tmp;
       
  1804     tmp.resize(src.m_width*src.m_height);	//throws bad_alloc
       
  1805 
       
  1806     //copy source region to tmp and do conversion
       
  1807     for(int j=0;j<src.m_height;j++)
       
  1808     {
       
  1809         for(int i=0;i<src.m_width;i++)
       
  1810         {
       
  1811             Color s = src.readPixel(i, j);
       
  1812             s.convert(procFormat);
       
  1813             tmp[j*src.m_width+i] = s;
       
  1814         }
       
  1815     }
       
  1816 
       
  1817     for(int j=0;j<h;j++)
       
  1818     {
       
  1819         for(int i=0;i<w;i++)
       
  1820         {
       
  1821             Color sum(0,0,0,0,procFormat);
       
  1822 
       
  1823             for(int kj=0;kj<kernelHeight;kj++)
       
  1824             {
       
  1825                 for(int ki=0;ki<kernelWidth;ki++)
       
  1826                 {
       
  1827                     int x = i+ki-shiftX;
       
  1828                     int y = j+kj-shiftY;
       
  1829                     Color s = readTiledPixel(x, y, src.m_width, src.m_height, tilingMode, tmp, edge);
       
  1830 
       
  1831                     int kx = kernelWidth-ki-1;
       
  1832                     int ky = kernelHeight-kj-1;
       
  1833                     RI_ASSERT(kx >= 0 && kx < kernelWidth && ky >= 0 && ky < kernelHeight);
       
  1834 
       
  1835                     sum += (RIfloat)kernel[kx*kernelHeight+ky] * s;
       
  1836                 }
       
  1837             }
       
  1838 
       
  1839             sum *= scale;
       
  1840             sum.r += bias;
       
  1841             sum.g += bias;
       
  1842             sum.b += bias;
       
  1843             sum.a += bias;
       
  1844 
       
  1845             writeFilteredPixel(i, j, sum, channelMask);
       
  1846         }
       
  1847     }
       
  1848 }
       
  1849 
       
  1850 /*-------------------------------------------------------------------*//*!
       
  1851 * \brief	Applies separable convolution filter.
       
  1852 * \param
       
  1853 * \return
       
  1854 * \note
       
  1855 *//*-------------------------------------------------------------------*/
       
  1856 
       
  1857 void Image::separableConvolve(const Image& src, int kernelWidth, int kernelHeight, int shiftX, int shiftY, const RIint16* kernelX, const RIint16* kernelY, RIfloat scale, RIfloat bias, VGTilingMode tilingMode, const Color& edgeFillColor, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask)
       
  1858 {
       
  1859     RI_ASSERT(src.m_data);	//source exists
       
  1860     RI_ASSERT(m_data);	//destination exists
       
  1861     RI_ASSERT(kernelX && kernelY && kernelWidth > 0 && kernelHeight > 0);
       
  1862     RI_ASSERT(m_referenceCount > 0 && src.m_referenceCount > 0);
       
  1863 
       
  1864     //the area to be written is an intersection of source and destination image areas.
       
  1865     //lower-left corners of the images are aligned.
       
  1866     int w = RI_INT_MIN(m_width, src.m_width);
       
  1867     int h = RI_INT_MIN(m_height, src.m_height);
       
  1868     RI_ASSERT(w > 0 && h > 0);
       
  1869 
       
  1870     Color::InternalFormat procFormat = getProcessingFormat(src.m_desc.internalFormat, filterFormatLinear, filterFormatPremultiplied);
       
  1871 
       
  1872     Color edge = edgeFillColor;
       
  1873     edge.clamp();
       
  1874     edge.convert(procFormat);
       
  1875 
       
  1876     Array<Color> tmp;
       
  1877     tmp.resize(src.m_width*src.m_height);	//throws bad_alloc
       
  1878 
       
  1879     //copy source region to tmp and do conversion
       
  1880     for(int j=0;j<src.m_height;j++)
       
  1881     {
       
  1882         for(int i=0;i<src.m_width;i++)
       
  1883         {
       
  1884             Color s = src.readPixel(i, j);
       
  1885             s.convert(procFormat);
       
  1886             tmp[j*src.m_width+i] = s;
       
  1887         }
       
  1888     }
       
  1889 
       
  1890     Array<Color> tmp2;
       
  1891     tmp2.resize(w*src.m_height);	//throws bad_alloc
       
  1892     for(int j=0;j<src.m_height;j++)
       
  1893     {
       
  1894         for(int i=0;i<w;i++)
       
  1895         {
       
  1896             Color sum(0,0,0,0,procFormat);
       
  1897             for(int ki=0;ki<kernelWidth;ki++)
       
  1898             {
       
  1899                 int x = i+ki-shiftX;
       
  1900                 Color s = readTiledPixel(x, j, src.m_width, src.m_height, tilingMode, tmp, edge);
       
  1901 
       
  1902                 int kx = kernelWidth-ki-1;
       
  1903                 RI_ASSERT(kx >= 0 && kx < kernelWidth);
       
  1904 
       
  1905                 sum += (RIfloat)kernelX[kx] * s;
       
  1906             }
       
  1907             tmp2[j*w+i] = sum;
       
  1908         }
       
  1909     }
       
  1910 
       
  1911     if(tilingMode == VG_TILE_FILL)
       
  1912     {	//convolve the edge color
       
  1913         Color sum(0,0,0,0,procFormat);
       
  1914         for(int ki=0;ki<kernelWidth;ki++)
       
  1915         {
       
  1916             sum += (RIfloat)kernelX[ki] * edge;
       
  1917         }
       
  1918         edge = sum;
       
  1919     }
       
  1920 
       
  1921     for(int j=0;j<h;j++)
       
  1922     {
       
  1923         for(int i=0;i<w;i++)
       
  1924         {
       
  1925             Color sum(0,0,0,0,procFormat);
       
  1926             for(int kj=0;kj<kernelHeight;kj++)
       
  1927             {
       
  1928                 int y = j+kj-shiftY;
       
  1929                 Color s = readTiledPixel(i, y, w, src.m_height, tilingMode, tmp2, edge);
       
  1930 
       
  1931                 int ky = kernelHeight-kj-1;
       
  1932                 RI_ASSERT(ky >= 0 && ky < kernelHeight);
       
  1933 
       
  1934                 sum += (RIfloat)kernelY[ky] * s;
       
  1935             }
       
  1936 
       
  1937             sum *= scale;
       
  1938             sum.r += bias;
       
  1939             sum.g += bias;
       
  1940             sum.b += bias;
       
  1941             sum.a += bias;
       
  1942 
       
  1943             writeFilteredPixel(i, j, sum, channelMask);
       
  1944         }
       
  1945     }
       
  1946 }
       
  1947 
       
  1948 /*-------------------------------------------------------------------*//*!
       
  1949 * \brief	Applies Gaussian blur filter.
       
  1950 * \param
       
  1951 * \return
       
  1952 * \note
       
  1953 *//*-------------------------------------------------------------------*/
       
  1954 
       
  1955 void Image::gaussianBlur(const Image& src, RIfloat stdDeviationX, RIfloat stdDeviationY, VGTilingMode tilingMode, const Color& edgeFillColor, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask)
       
  1956 {
       
  1957     RI_ASSERT(src.m_data);	//source exists
       
  1958     RI_ASSERT(m_data);	//destination exists
       
  1959     RI_ASSERT(stdDeviationX > 0.0f && stdDeviationY > 0.0f);
       
  1960     RI_ASSERT(stdDeviationX <= RI_MAX_GAUSSIAN_STD_DEVIATION && stdDeviationY <= RI_MAX_GAUSSIAN_STD_DEVIATION);
       
  1961     RI_ASSERT(m_referenceCount > 0 && src.m_referenceCount > 0);
       
  1962 
       
  1963     //the area to be written is an intersection of source and destination image areas.
       
  1964     //lower-left corners of the images are aligned.
       
  1965     int w = RI_INT_MIN(m_width, src.m_width);
       
  1966     int h = RI_INT_MIN(m_height, src.m_height);
       
  1967     RI_ASSERT(w > 0 && h > 0);
       
  1968 
       
  1969     Color::InternalFormat procFormat = getProcessingFormat(src.m_desc.internalFormat, filterFormatLinear, filterFormatPremultiplied);
       
  1970 
       
  1971     Color edge = edgeFillColor;
       
  1972     edge.clamp();
       
  1973     edge.convert(procFormat);
       
  1974 
       
  1975     Array<Color> tmp;
       
  1976     tmp.resize(src.m_width*src.m_height);	//throws bad_alloc
       
  1977 
       
  1978     //copy source region to tmp and do conversion
       
  1979     for(int j=0;j<src.m_height;j++)
       
  1980     {
       
  1981         for(int i=0;i<src.m_width;i++)
       
  1982         {
       
  1983             Color s = src.readPixel(i, j);
       
  1984             s.convert(procFormat);
       
  1985             tmp[j*src.m_width+i] = s;
       
  1986         }
       
  1987     }
       
  1988 
       
  1989     RIfloat expScaleX = -1.0f / (2.0f*stdDeviationX*stdDeviationX);
       
  1990     RIfloat expScaleY = -1.0f / (2.0f*stdDeviationY*stdDeviationY);
       
  1991 
       
  1992     int kernelWidth = (int)(stdDeviationX * 4.0f + 1.0f);
       
  1993     int kernelHeight = (int)(stdDeviationY * 4.0f + 1.0f);
       
  1994 
       
  1995     //make a separable kernel
       
  1996     Array<RIfloat> kernelX;
       
  1997     kernelX.resize(kernelWidth*2+1);
       
  1998     int shiftX = kernelWidth;
       
  1999     RIfloat scaleX = 0.0f;
       
  2000     for(int i=0;i<kernelX.size();i++)
       
  2001     {
       
  2002         int x = i-shiftX;
       
  2003         kernelX[i] = (RIfloat)exp((RIfloat)x*(RIfloat)x * expScaleX);
       
  2004         scaleX += kernelX[i];
       
  2005     }
       
  2006     scaleX = 1.0f / scaleX;	//NOTE: using the mathematical definition of the scaling term doesn't work since we cut the filter support early for performance
       
  2007 
       
  2008     Array<RIfloat> kernelY;
       
  2009     kernelY.resize(kernelHeight*2+1);
       
  2010     int shiftY = kernelHeight;
       
  2011     RIfloat scaleY = 0.0f;
       
  2012     for(int i=0;i<kernelY.size();i++)
       
  2013     {
       
  2014         int y = i-shiftY;
       
  2015         kernelY[i] = (RIfloat)exp((RIfloat)y*(RIfloat)y * expScaleY);
       
  2016         scaleY += kernelY[i];
       
  2017     }
       
  2018     scaleY = 1.0f / scaleY;	//NOTE: using the mathematical definition of the scaling term doesn't work since we cut the filter support early for performance
       
  2019 
       
  2020     Array<Color> tmp2;
       
  2021     tmp2.resize(w*src.m_height);	//throws bad_alloc
       
  2022     //horizontal pass
       
  2023     for(int j=0;j<src.m_height;j++)
       
  2024     {
       
  2025         for(int i=0;i<w;i++)
       
  2026         {
       
  2027             Color sum(0,0,0,0,procFormat);
       
  2028             for(int ki=0;ki<kernelX.size();ki++)
       
  2029             {
       
  2030                 int x = i+ki-shiftX;
       
  2031                 sum += kernelX[ki] * readTiledPixel(x, j, src.m_width, src.m_height, tilingMode, tmp, edge);
       
  2032             }
       
  2033             tmp2[j*w+i] = sum * scaleX;
       
  2034         }
       
  2035     }
       
  2036     //vertical pass
       
  2037     for(int j=0;j<h;j++)
       
  2038     {
       
  2039         for(int i=0;i<w;i++)
       
  2040         {
       
  2041             Color sum(0,0,0,0,procFormat);
       
  2042             for(int kj=0;kj<kernelY.size();kj++)
       
  2043             {
       
  2044                 int y = j+kj-shiftY;
       
  2045                 sum += kernelY[kj] * readTiledPixel(i, y, w, src.m_height, tilingMode, tmp2, edge);
       
  2046             }
       
  2047             writeFilteredPixel(i, j, sum * scaleY, channelMask);
       
  2048         }
       
  2049     }
       
  2050 }
       
  2051 
       
  2052 /*-------------------------------------------------------------------*//*!
       
  2053 * \brief	Returns lookup table format for lookup filters.
       
  2054 * \param
       
  2055 * \return
       
  2056 * \note
       
  2057 *//*-------------------------------------------------------------------*/
       
  2058 
       
  2059 static Color::InternalFormat getLUTFormat(bool outputLinear, bool outputPremultiplied)
       
  2060 {
       
  2061     Color::InternalFormat lutFormat = Color::lRGBA;
       
  2062     if(outputLinear && outputPremultiplied)
       
  2063         lutFormat = Color::lRGBA_PRE;
       
  2064     else if(!outputLinear && !outputPremultiplied)
       
  2065         lutFormat = Color::sRGBA;
       
  2066     else if(!outputLinear && outputPremultiplied)
       
  2067         lutFormat = Color::sRGBA_PRE;
       
  2068     return lutFormat;
       
  2069 }
       
  2070 
       
  2071 /*-------------------------------------------------------------------*//*!
       
  2072 * \brief	Applies multi-channel lookup table filter.
       
  2073 * \param
       
  2074 * \return
       
  2075 * \note
       
  2076 *//*-------------------------------------------------------------------*/
       
  2077 
       
  2078 void Image::lookup(const Image& src, const RIuint8 * redLUT, const RIuint8 * greenLUT, const RIuint8 * blueLUT, const RIuint8 * alphaLUT, bool outputLinear, bool outputPremultiplied, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask)
       
  2079 {
       
  2080     RI_ASSERT(src.m_data);	//source exists
       
  2081     RI_ASSERT(m_data);	//destination exists
       
  2082     RI_ASSERT(redLUT && greenLUT && blueLUT && alphaLUT);
       
  2083     RI_ASSERT(m_referenceCount > 0 && src.m_referenceCount > 0);
       
  2084 
       
  2085     //the area to be written is an intersection of source and destination image areas.
       
  2086     //lower-left corners of the images are aligned.
       
  2087     int w = RI_INT_MIN(m_width, src.m_width);
       
  2088     int h = RI_INT_MIN(m_height, src.m_height);
       
  2089     RI_ASSERT(w > 0 && h > 0);
       
  2090 
       
  2091     Color::InternalFormat procFormat = getProcessingFormat(src.m_desc.internalFormat, filterFormatLinear, filterFormatPremultiplied);
       
  2092     Color::InternalFormat lutFormat = getLUTFormat(outputLinear, outputPremultiplied);
       
  2093 
       
  2094     for(int j=0;j<h;j++)
       
  2095     {
       
  2096         for(int i=0;i<w;i++)
       
  2097         {
       
  2098             Color s = src.readPixel(i,j);	//convert to RGBA [0,1]
       
  2099             s.convert(procFormat);
       
  2100 
       
  2101             Color d(0,0,0,0,lutFormat);
       
  2102             d.r = intToColor(  redLUT[colorToInt(s.r, 255)], 255);
       
  2103             d.g = intToColor(greenLUT[colorToInt(s.g, 255)], 255);
       
  2104             d.b = intToColor( blueLUT[colorToInt(s.b, 255)], 255);
       
  2105             d.a = intToColor(alphaLUT[colorToInt(s.a, 255)], 255);
       
  2106 
       
  2107             writeFilteredPixel(i, j, d, channelMask);
       
  2108         }
       
  2109     }
       
  2110 }
       
  2111 
       
  2112 /*-------------------------------------------------------------------*//*!
       
  2113 * \brief	Applies single channel lookup table filter.
       
  2114 * \param
       
  2115 * \return
       
  2116 * \note
       
  2117 *//*-------------------------------------------------------------------*/
       
  2118 
       
  2119 void Image::lookupSingle(const Image& src, const RIuint32 * lookupTable, VGImageChannel sourceChannel, bool outputLinear, bool outputPremultiplied, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask)
       
  2120 {
       
  2121     RI_ASSERT(src.m_data);	//source exists
       
  2122     RI_ASSERT(m_data);	//destination exists
       
  2123     RI_ASSERT(lookupTable);
       
  2124     RI_ASSERT(m_referenceCount > 0 && src.m_referenceCount > 0);
       
  2125 
       
  2126     //the area to be written is an intersection of source and destination image areas.
       
  2127     //lower-left corners of the images are aligned.
       
  2128     int w = RI_INT_MIN(m_width, src.m_width);
       
  2129     int h = RI_INT_MIN(m_height, src.m_height);
       
  2130     RI_ASSERT(w > 0 && h > 0);
       
  2131 
       
  2132     if(src.m_desc.isLuminance())
       
  2133         sourceChannel = VG_RED;
       
  2134     else if(src.m_desc.redBits + src.m_desc.greenBits + src.m_desc.blueBits == 0)
       
  2135     {
       
  2136         RI_ASSERT(src.m_desc.alphaBits);
       
  2137         sourceChannel = VG_ALPHA;
       
  2138     }
       
  2139 
       
  2140     Color::InternalFormat procFormat = getProcessingFormat(src.m_desc.internalFormat, filterFormatLinear, filterFormatPremultiplied);
       
  2141     Color::InternalFormat lutFormat = getLUTFormat(outputLinear, outputPremultiplied);
       
  2142 
       
  2143     for(int j=0;j<h;j++)
       
  2144     {
       
  2145         for(int i=0;i<w;i++)
       
  2146         {
       
  2147             Color s = src.readPixel(i,j);	//convert to RGBA [0,1]
       
  2148             s.convert(procFormat);
       
  2149             int e;
       
  2150             switch(sourceChannel)
       
  2151             {
       
  2152             case VG_RED:
       
  2153                 e = colorToInt(s.r, 255);
       
  2154                 break;
       
  2155             case VG_GREEN:
       
  2156                 e = colorToInt(s.g, 255);
       
  2157                 break;
       
  2158             case VG_BLUE:
       
  2159                 e = colorToInt(s.b, 255);
       
  2160                 break;
       
  2161             default:
       
  2162                 RI_ASSERT(sourceChannel == VG_ALPHA);
       
  2163                 e = colorToInt(s.a, 255);
       
  2164                 break;
       
  2165             }
       
  2166 
       
  2167             RIuint32 l = ((const RIuint32*)lookupTable)[e];
       
  2168             Color d(0,0,0,0,lutFormat);
       
  2169             d.r = intToColor((l>>24), 255);
       
  2170             d.g = intToColor((l>>16), 255);
       
  2171             d.b = intToColor((l>> 8), 255);
       
  2172             d.a = intToColor((l    ), 255);
       
  2173 
       
  2174             writeFilteredPixel(i, j, d, channelMask);
       
  2175         }
       
  2176     }
       
  2177 }
       
  2178 
       
  2179 
       
  2180 /*-------------------------------------------------------------------*//*!
       
  2181 * \brief
       
  2182 * \param
       
  2183 * \return
       
  2184 * \note
       
  2185 *//*-------------------------------------------------------------------*/
       
  2186 
       
  2187 Surface::Surface(const Color::Descriptor& desc, int width, int height, int numSamples) :
       
  2188     m_width(width),
       
  2189     m_height(height),
       
  2190     m_numSamples(numSamples),
       
  2191     m_referenceCount(0),
       
  2192     m_image(NULL)
       
  2193 {
       
  2194     RI_ASSERT(width > 0 && height > 0 && numSamples > 0 && numSamples <= 32);
       
  2195     m_image = RI_NEW(Image, (desc, width*numSamples, height, 0));	//throws bad_alloc
       
  2196     m_image->addReference();
       
  2197 }
       
  2198 
       
  2199 /*-------------------------------------------------------------------*//*!
       
  2200 * \brief
       
  2201 * \param
       
  2202 * \return
       
  2203 * \note
       
  2204 *//*-------------------------------------------------------------------*/
       
  2205 
       
  2206 Surface::Surface(Image* image) :
       
  2207     m_width(0),
       
  2208     m_height(0),
       
  2209     m_numSamples(1),
       
  2210     m_referenceCount(0),
       
  2211     m_image(image)
       
  2212 {
       
  2213     RI_ASSERT(image);
       
  2214     m_width = image->getWidth();
       
  2215     m_height = image->getHeight();
       
  2216     m_image->addReference();
       
  2217 }
       
  2218 
       
  2219 /*-------------------------------------------------------------------*//*!
       
  2220 * \brief
       
  2221 * \param
       
  2222 * \return
       
  2223 * \note
       
  2224 *//*-------------------------------------------------------------------*/
       
  2225 
       
  2226 Surface::Surface(const Color::Descriptor& desc, int width, int height, int stride, RIuint8* data) :
       
  2227     m_width(width),
       
  2228     m_height(height),
       
  2229     m_numSamples(1),
       
  2230     m_referenceCount(0),
       
  2231     m_image(NULL)
       
  2232 {
       
  2233     RI_ASSERT(width > 0 && height > 0);
       
  2234     m_image = RI_NEW(Image, (desc, width, height, stride, data));	//throws bad_alloc
       
  2235     m_image->addReference();
       
  2236 }
       
  2237 
       
  2238 /*-------------------------------------------------------------------*//*!
       
  2239 * \brief
       
  2240 * \param
       
  2241 * \return
       
  2242 * \note
       
  2243 *//*-------------------------------------------------------------------*/
       
  2244 
       
  2245 Surface::~Surface()
       
  2246 {
       
  2247     RI_ASSERT(m_referenceCount == 0);
       
  2248     if(!m_image->removeReference())
       
  2249         RI_DELETE(m_image);
       
  2250 }
       
  2251 
       
  2252 /*-------------------------------------------------------------------*//*!
       
  2253 * \brief
       
  2254 * \param
       
  2255 * \return
       
  2256 * \note
       
  2257 *//*-------------------------------------------------------------------*/
       
  2258 
       
  2259 void Surface::clear(const Color& clearColor, int x, int y, int w, int h, const Array<Rectangle>* scissors)
       
  2260 {
       
  2261     RI_ASSERT(m_numSamples == 1);
       
  2262 
       
  2263     Image* image = m_image;
       
  2264 
       
  2265     Color col = clearColor;
       
  2266     col.clamp();
       
  2267     col.convert(m_image->getDescriptor().internalFormat);
       
  2268 
       
  2269     IntegerColor ic = IntegerColor(col);
       
  2270     ic.truncateColor(m_image->getDescriptor());
       
  2271     const RIuint32 c = ic.getPackedColor(m_image->getDescriptor());
       
  2272 
       
  2273     if (x != 0 || y != 0 || w != image->getWidth() || h != image->getHeight() || scissors)
       
  2274     {
       
  2275         // Simple implementation: intersect with surface and clip rects -> may clear the
       
  2276         // same area several times. Best if scissors are non-overlapping
       
  2277         Rectangle r(0,0,getWidth(),getHeight());
       
  2278         r.intersect(Rectangle(x,y,w,h));
       
  2279 
       
  2280         if (r.isEmpty() || (scissors && scissors->size() == 0))
       
  2281             return;
       
  2282 
       
  2283         if (scissors && scissors->size())
       
  2284         {
       
  2285             for (int i = 0; i < scissors->size(); i++)
       
  2286             {
       
  2287                 Rectangle s = (*scissors)[i];
       
  2288                 s.intersect(r);
       
  2289 
       
  2290                 if (s.isEmpty())
       
  2291                     continue;
       
  2292 
       
  2293                 image->fillPackedRectangle(s.x, s.y, s.width, s.height, c);
       
  2294             }
       
  2295         }
       
  2296         else
       
  2297         {
       
  2298             image->fillPackedRectangle(r.x, r.y, r.width, r.height, c);
       
  2299         }
       
  2300     }
       
  2301     else
       
  2302     {
       
  2303         // Clear the whole buffer
       
  2304 
       
  2305         m_image->fillPacked(c);
       
  2306    }
       
  2307 }
       
  2308 
       
  2309 /*-------------------------------------------------------------------*//*!
       
  2310 * \brief
       
  2311 * \param
       
  2312 * \return
       
  2313 * \note
       
  2314 *//*-------------------------------------------------------------------*/
       
  2315 
       
  2316 #if 0
       
  2317 void Surface::blit(const Image& src, int sx, int sy, int dx, int dy, int w, int h)
       
  2318 {
       
  2319     Rectangle rect;
       
  2320     rect.x = 0;
       
  2321     rect.y = 0;
       
  2322     rect.width = getWidth();
       
  2323     rect.height = getHeight();
       
  2324     Array<Rectangle> scissors;
       
  2325     scissors.push_back(rect);
       
  2326     blit(src, sx, sy, dx, dy, w, h, scissors);
       
  2327 }
       
  2328 #endif
       
  2329 
       
  2330 /*-------------------------------------------------------------------*//*!
       
  2331 * \brief
       
  2332 * \param
       
  2333 * \return
       
  2334 * \note		no overlap is possible. Single sample to single or multisample (replicate)
       
  2335 *//*-------------------------------------------------------------------*/
       
  2336 
       
  2337 #if 0
       
  2338 void Surface::blit(const Image& src, int sx, int sy, int dx, int dy, int w, int h, const Array<Rectangle>& scissors)
       
  2339 {
       
  2340     //img=>fb: vgSetPixels
       
  2341     //user=>fb: vgWritePixels
       
  2342     computeBlitRegion(sx, sy, dx, dy, w, h, src.getWidth(), src.getHeight(), getWidth(), getHeight());
       
  2343     if(w <= 0 || h <= 0)
       
  2344         return;	//zero area
       
  2345 
       
  2346     Array<ScissorEdge> scissorEdges;
       
  2347     for(int i=0;i<scissors.size();i++)
       
  2348     {
       
  2349         if(scissors[i].width > 0 && scissors[i].height > 0)
       
  2350         {
       
  2351             ScissorEdge e;
       
  2352             e.miny = scissors[i].y;
       
  2353             e.maxy = RI_INT_ADDSATURATE(scissors[i].y, scissors[i].height);
       
  2354 
       
  2355             e.x = scissors[i].x;
       
  2356             e.direction = 1;
       
  2357             scissorEdges.push_back(e);	//throws bad_alloc
       
  2358             e.x = RI_INT_ADDSATURATE(scissors[i].x, scissors[i].width);
       
  2359             e.direction = -1;
       
  2360             scissorEdges.push_back(e);	//throws bad_alloc
       
  2361         }
       
  2362     }
       
  2363     if(!scissorEdges.size())
       
  2364         return;	//there are no scissor rectangles => nothing is visible
       
  2365 
       
  2366     //sort scissor edges by edge x
       
  2367     scissorEdges.sort();
       
  2368 
       
  2369     Array<ScissorEdge> scissorAet;
       
  2370     for(int j=0;j<h;j++)
       
  2371     {
       
  2372         //gather scissor edges intersecting this scanline
       
  2373         scissorAet.clear();
       
  2374         for(int e=0;e<scissorEdges.size();e++)
       
  2375         {
       
  2376             const ScissorEdge& se = scissorEdges[e];
       
  2377             if(dy + j >= se.miny && dy + j < se.maxy)
       
  2378                 scissorAet.push_back(scissorEdges[e]);	//throws bad_alloc
       
  2379         }
       
  2380         if(!scissorAet.size())
       
  2381             continue;	//scissoring is on, but there are no scissor rectangles on this scanline
       
  2382 
       
  2383         //blit a scanline
       
  2384         int scissorWinding = 0;
       
  2385         int scissorIndex = 0;
       
  2386         for(int i=0;i<w;i++)
       
  2387         {
       
  2388             while(scissorIndex < scissorAet.size() && scissorAet[scissorIndex].x <= dx + i)
       
  2389                 scissorWinding += scissorAet[scissorIndex++].direction;
       
  2390             RI_ASSERT(scissorWinding >= 0);
       
  2391 
       
  2392             if(scissorWinding)
       
  2393             {
       
  2394                 Color c = src.readPixel(sx + i, sy + j);
       
  2395                 c.convert(getDescriptor().internalFormat);
       
  2396                 for(int s=0;s<m_numSamples;s++)
       
  2397                     writeSample(dx + i, dy + j, s, c);
       
  2398             }
       
  2399         }
       
  2400     }
       
  2401 }
       
  2402 #endif
       
  2403 
       
  2404 /*-------------------------------------------------------------------*//*!
       
  2405 * \brief
       
  2406 * \param
       
  2407 * \return
       
  2408 * \note
       
  2409 *//*-------------------------------------------------------------------*/
       
  2410 
       
  2411 #if 0
       
  2412 void Surface::blit(const Surface* src, int sx, int sy, int dx, int dy, int w, int h)
       
  2413 {
       
  2414     Rectangle rect;
       
  2415     rect.x = 0;
       
  2416     rect.y = 0;
       
  2417     rect.width = getWidth();
       
  2418     rect.height = getHeight();
       
  2419     Array<Rectangle> scissors;
       
  2420     scissors.push_back(rect);
       
  2421     blit(src, sx, sy, dx, dy, w, h, scissors);
       
  2422 }
       
  2423 #endif
       
  2424 
       
  2425 /*-------------------------------------------------------------------*//*!
       
  2426 * \brief
       
  2427 * \param
       
  2428 * \return
       
  2429 * \note
       
  2430 *//*-------------------------------------------------------------------*/
       
  2431 
       
  2432 #if 0
       
  2433 void Surface::blit(const Surface* src, int sx, int sy, int dx, int dy, int w, int h, const Array<Rectangle>& scissors)
       
  2434 {
       
  2435     RI_ASSERT(m_numSamples == src->m_numSamples);
       
  2436 
       
  2437     //fb=>fb: vgCopyPixels
       
  2438     computeBlitRegion(sx, sy, dx, dy, w, h, src->getWidth(), src->getHeight(), getWidth(), getHeight());
       
  2439     if(w <= 0 || h <= 0)
       
  2440         return;	//zero area
       
  2441 
       
  2442     Array<ScissorEdge> scissorEdges;
       
  2443     for(int i=0;i<scissors.size();i++)
       
  2444     {
       
  2445         if(scissors[i].width > 0 && scissors[i].height > 0)
       
  2446         {
       
  2447             ScissorEdge e;
       
  2448             e.miny = scissors[i].y;
       
  2449             e.maxy = RI_INT_ADDSATURATE(scissors[i].y, scissors[i].height);
       
  2450 
       
  2451             e.x = scissors[i].x;
       
  2452             e.direction = 1;
       
  2453             scissorEdges.push_back(e);	//throws bad_alloc
       
  2454             e.x = RI_INT_ADDSATURATE(scissors[i].x, scissors[i].width);
       
  2455             e.direction = -1;
       
  2456             scissorEdges.push_back(e);	//throws bad_alloc
       
  2457         }
       
  2458     }
       
  2459     if(!scissorEdges.size())
       
  2460         return;	//there are no scissor rectangles => nothing is visible
       
  2461 
       
  2462     //sort scissor edges by edge x
       
  2463     scissorEdges.sort();
       
  2464 
       
  2465     Array<Color> tmp;
       
  2466     tmp.resize(w*m_numSamples*h);	//throws bad_alloc
       
  2467 
       
  2468     //copy source region to tmp
       
  2469     for(int j=0;j<h;j++)
       
  2470     {
       
  2471         for(int i=0;i<w;i++)
       
  2472         {
       
  2473             int numSamples = m_numSamples;
       
  2474             for(int s=0;s<numSamples;s++)
       
  2475             {
       
  2476                 Color c = src->m_image->readPixel((sx + i)*m_numSamples+s, sy + j);
       
  2477                 c.convert(m_image->getDescriptor().internalFormat);
       
  2478                 tmp[(j*w+i)*m_numSamples+s] = c;
       
  2479             }
       
  2480         }
       
  2481     }
       
  2482 
       
  2483     Array<ScissorEdge> scissorAet;
       
  2484     for(int j=0;j<h;j++)
       
  2485     {
       
  2486         //gather scissor edges intersecting this scanline
       
  2487         scissorAet.clear();
       
  2488         for(int e=0;e<scissorEdges.size();e++)
       
  2489         {
       
  2490             const ScissorEdge& se = scissorEdges[e];
       
  2491             if(dy + j >= se.miny && dy + j < se.maxy)
       
  2492                 scissorAet.push_back(scissorEdges[e]);	//throws bad_alloc
       
  2493         }
       
  2494         if(!scissorAet.size())
       
  2495             continue;	//scissoring is on, but there are no scissor rectangles on this scanline
       
  2496 
       
  2497         //blit a scanline
       
  2498         int scissorWinding = 0;
       
  2499         int scissorIndex = 0;
       
  2500         for(int i=0;i<w;i++)
       
  2501         {
       
  2502             while(scissorIndex < scissorAet.size() && scissorAet[scissorIndex].x <= dx + i)
       
  2503                 scissorWinding += scissorAet[scissorIndex++].direction;
       
  2504             RI_ASSERT(scissorWinding >= 0);
       
  2505 
       
  2506             if(scissorWinding)
       
  2507             {
       
  2508                 int numSamples = m_numSamples;
       
  2509                 for(int s=0;s<numSamples;s++)
       
  2510                 {
       
  2511                     m_image->writePixel((dx + i)*m_numSamples+s, dy + j, tmp[(j*w+i)*m_numSamples+s]);
       
  2512                 }
       
  2513             }
       
  2514         }
       
  2515     }
       
  2516 }
       
  2517 #endif
       
  2518 
       
  2519 /*-------------------------------------------------------------------*//*!
       
  2520 * \brief
       
  2521 * \param
       
  2522 * \return
       
  2523 * \note
       
  2524 *//*-------------------------------------------------------------------*/
       
  2525 
       
  2526 void Surface::mask(DynamicBlitter& blitter, const Image* src, VGMaskOperation operation, int x, int y, int w, int h)
       
  2527 {
       
  2528     RI_ASSERT(w > 0 && h > 0);
       
  2529     RI_ASSERT(m_numSamples == 1);
       
  2530 
       
  2531     if(operation == VG_CLEAR_MASK || operation == VG_FILL_MASK)
       
  2532     {
       
  2533         //intersect clear region with image bounds
       
  2534         Rectangle r(0,0,getWidth(),getHeight());
       
  2535         r.intersect(Rectangle(x,y,w,h));
       
  2536 
       
  2537         if(!r.width || !r.height)
       
  2538             return;		//intersection is empty or one of the rectangles is invalid
       
  2539 
       
  2540         {
       
  2541             Color mcolor(1.0f, 1.0f, 1.0f, 1.0f, Color::sRGBA_PRE);
       
  2542             if (operation == VG_CLEAR_MASK)
       
  2543                 mcolor = Color(0,0,0,0, Color::sRGBA_PRE);
       
  2544             IntegerColor ic = IntegerColor(mcolor);
       
  2545             RIuint32 p = ic.getPackedMaskColor(m_image->getDescriptor());
       
  2546             m_image->fillPackedRectangle(r.x, r.y, r.width, r.height, p);
       
  2547         }
       
  2548     }
       
  2549     else
       
  2550     {
       
  2551         int sx = 0, sy = 0, dx = x, dy = y;
       
  2552 
       
  2553         computeBlitRegion(sx, sy, dx, dy, w, h, src->getWidth(), src->getHeight(), getWidth(), getHeight());
       
  2554 
       
  2555         if(w <= 0 || h <= 0)
       
  2556             return;	//zero area
       
  2557 
       
  2558         blitter.enableMaskOperation(true);
       
  2559         blitter.setMaskOperation(operation);
       
  2560         blitter.prepareBlit(this->m_image, src, sx, sy, dx, dy, w, h);
       
  2561         blitter.blit();
       
  2562         blitter.enableMaskOperation(false);
       
  2563 #if 0
       
  2564         RI_ASSERT(src);
       
  2565 
       
  2566         int sx = 0, sy = 0, dx = x, dy = y;
       
  2567         computeBlitRegion(sx, sy, dx, dy, w, h, src->getWidth(), src->getHeight(), getWidth(), getHeight());
       
  2568         if(w <= 0 || h <= 0)
       
  2569             return;	//zero area
       
  2570 
       
  2571         {
       
  2572             for(int j=0;j<h;j++)
       
  2573             {
       
  2574                 for(int i=0;i<w;i++)
       
  2575                 {
       
  2576                     RIfloat amask = src->readMaskPixel(sx + i, sy + j);
       
  2577                     if(operation == VG_SET_MASK)
       
  2578                         writeMaskCoverage(dx + i, dy + j, amask);
       
  2579                     else
       
  2580                     {
       
  2581                         RIfloat aprev = readMaskCoverage(dx + i, dy + j);
       
  2582                         RIfloat anew = 0.0f;
       
  2583                         switch(operation)
       
  2584                         {
       
  2585                         case VG_UNION_MASK:		anew = 1.0f - (1.0f - amask)*(1.0f - aprev); break;
       
  2586                         case VG_INTERSECT_MASK:	anew = amask * aprev; break;
       
  2587                         default:				anew = aprev * (1.0f - amask); RI_ASSERT(operation == VG_SUBTRACT_MASK); break;
       
  2588                         }
       
  2589                         writeMaskCoverage(dx + i, dy + j, anew);
       
  2590                     }
       
  2591                 }
       
  2592             }
       
  2593         }
       
  2594 #endif
       
  2595     }
       
  2596 }
       
  2597 
       
  2598 /*-------------------------------------------------------------------*//*!
       
  2599 * \brief
       
  2600 * \param
       
  2601 * \return
       
  2602 * \note
       
  2603 *//*-------------------------------------------------------------------*/
       
  2604 
       
  2605 RIfloat Surface::readMaskCoverage(int x, int y) const
       
  2606 {
       
  2607     RI_ASSERT(x >= 0 && x < m_width && y >= 0 && y < m_height);
       
  2608     RI_ASSERT(m_numSamples == 1);
       
  2609     return m_image->readMaskPixel(x, y);
       
  2610 }
       
  2611 
       
  2612 void Surface::writeMaskCoverage(int x, int y, RIfloat m)
       
  2613 {
       
  2614     RI_ASSERT(x >= 0 && x < m_width && y >= 0 && y < m_height);
       
  2615     RI_ASSERT(m_numSamples == 1);
       
  2616     m_image->writeMaskPixel(x, y, m);    //TODO support other than alpha formats but don't write to color channels?
       
  2617 }
       
  2618 
       
  2619 unsigned int Surface::readMaskMSAA(int x, int y) const
       
  2620 {
       
  2621     RI_ASSERT(x >= 0 && x < m_width && y >= 0 && y < m_height);
       
  2622     RI_ASSERT(m_numSamples > 1);
       
  2623     unsigned int m = 0;
       
  2624     for(int i=0;i<m_numSamples;i++)
       
  2625     {
       
  2626         if(m_image->readMaskPixel(x*m_numSamples+i, y) > 0.5f)   //TODO is this the right formula for converting alpha to bit mask? does it matter?
       
  2627             m |= 1<<i;
       
  2628     }
       
  2629     return m;
       
  2630 }
       
  2631 
       
  2632 void Surface::writeMaskMSAA(int x, int y, unsigned int m)
       
  2633 {
       
  2634     RI_ASSERT(x >= 0 && x < m_width && y >= 0 && y < m_height);
       
  2635     RI_ASSERT(m_numSamples > 1);
       
  2636     for(int i=0;i<m_numSamples;i++)
       
  2637     {
       
  2638         RIfloat a = 0.0f;
       
  2639         if(m & (1<<i))
       
  2640             a = 1.0f;
       
  2641         m_image->writeMaskPixel(x*m_numSamples+i, y, a);    //TODO support other than alpha formats but don't write to color channels?
       
  2642     }
       
  2643 }
       
  2644 
       
  2645 /*-------------------------------------------------------------------*//*!
       
  2646 * \brief
       
  2647 * \param
       
  2648 * \return
       
  2649 * \note
       
  2650 *//*-------------------------------------------------------------------*/
       
  2651 
       
  2652 Color Surface::FSAAResolve(int x, int y) const
       
  2653 {
       
  2654     if(m_numSamples == 1)
       
  2655         return readSample(x, y, 0);
       
  2656 
       
  2657     Color::InternalFormat aaFormat = getDescriptor().isLuminance() ? Color::lLA_PRE : Color::lRGBA_PRE;	//antialias in linear color space
       
  2658     Color r(0.0f, 0.0f, 0.0f, 0.0f, aaFormat);
       
  2659     for(int i=0;i<m_numSamples;i++)
       
  2660     {
       
  2661         Color d = readSample(x, y, i);
       
  2662         d.convert(aaFormat);
       
  2663         r += d;
       
  2664     }
       
  2665     r *= 1.0f/m_numSamples;
       
  2666     return r;
       
  2667 }
       
  2668 
       
  2669 
       
  2670 /**
       
  2671  *	\brief	Return a resolved sample in packed format.
       
  2672  *	\note	Further operations on color may require unpack.
       
  2673  */
       
  2674 RI_INLINE RIuint32 Surface::FSAAResolvePacked(int x, int y) const
       
  2675 {
       
  2676     if (m_numSamples == 1)
       
  2677         return readPackedSample(x, y, 0);
       
  2678 
       
  2679     RI_ASSERT(false); /* Not implemented yet. */
       
  2680     return 0xffffffffu;
       
  2681 }
       
  2682 
       
  2683 /*-------------------------------------------------------------------*//*!
       
  2684 * \brief
       
  2685 * \param
       
  2686 * \return
       
  2687 * \note
       
  2688 *//*-------------------------------------------------------------------*/
       
  2689 
       
  2690 Drawable::Drawable(const Color::Descriptor& desc, int width, int height, int numSamples, int maskBits) :
       
  2691     m_referenceCount(0),
       
  2692     m_color(NULL),
       
  2693     m_mask(NULL)
       
  2694 {
       
  2695     RI_ASSERT(width > 0 && height > 0 && numSamples > 0 && numSamples <= 32);
       
  2696     RI_ASSERT(maskBits == 0 || maskBits == 1 || maskBits == 4 || maskBits == 8);
       
  2697     m_color = RI_NEW(Surface, (desc, width, height, numSamples));	//throws bad_alloc
       
  2698     m_color->addReference();
       
  2699     if(maskBits)
       
  2700     {
       
  2701         VGImageFormat mf = VG_A_1;
       
  2702         if(maskBits == 4)
       
  2703             mf = VG_A_4;
       
  2704         else if(maskBits == 8)
       
  2705             mf = VG_A_8;
       
  2706         m_mask = RI_NEW(Surface, (Color::formatToDescriptor(mf), width, height, numSamples));
       
  2707         m_mask->addReference();
       
  2708         m_mask->clear(Color(1,1,1,1,Color::sRGBA), 0, 0, width, height);
       
  2709     }
       
  2710 }
       
  2711 
       
  2712 /*-------------------------------------------------------------------*//*!
       
  2713 * \brief
       
  2714 * \param
       
  2715 * \return
       
  2716 * \note
       
  2717 *//*-------------------------------------------------------------------*/
       
  2718 
       
  2719 Drawable::Drawable(Image* image, int maskBits) :
       
  2720     m_referenceCount(0),
       
  2721     m_color(NULL),
       
  2722     m_mask(NULL)
       
  2723 {
       
  2724     RI_ASSERT(maskBits == 0 || maskBits == 1 || maskBits == 4 || maskBits == 8);
       
  2725     RI_ASSERT(image);
       
  2726     m_color = RI_NEW(Surface, (image));
       
  2727     m_color->addReference();
       
  2728     if(maskBits)
       
  2729     {
       
  2730         VGImageFormat mf = VG_A_1;
       
  2731         if(maskBits == 4)
       
  2732             mf = VG_A_4;
       
  2733         else if(maskBits == 8)
       
  2734             mf = VG_A_8;
       
  2735         m_mask = RI_NEW(Surface, (Color::formatToDescriptor(mf), image->getWidth(), image->getHeight(), 1));
       
  2736         m_mask->addReference();
       
  2737         m_mask->clear(Color(1,1,1,1,Color::sRGBA), 0, 0, image->getWidth(), image->getHeight());
       
  2738     }
       
  2739 }
       
  2740 
       
  2741 /*-------------------------------------------------------------------*//*!
       
  2742 * \brief
       
  2743 * \param
       
  2744 * \return
       
  2745 * \note
       
  2746 *//*-------------------------------------------------------------------*/
       
  2747 
       
  2748 Drawable::Drawable(const Color::Descriptor& desc, int width, int height, int stride, RIuint8* data, int maskBits) :
       
  2749     m_referenceCount(0),
       
  2750     m_color(NULL),
       
  2751     m_mask(NULL)
       
  2752 {
       
  2753     RI_ASSERT(width > 0 && height > 0);
       
  2754     RI_ASSERT(maskBits == 0 || maskBits == 1 || maskBits == 4 || maskBits == 8);
       
  2755     m_color = RI_NEW(Surface, (desc, width, height, stride, data));	//throws bad_alloc
       
  2756     m_color->addReference();
       
  2757     if(maskBits)
       
  2758     {
       
  2759         VGImageFormat mf = VG_A_1;
       
  2760         if(maskBits == 4)
       
  2761             mf = VG_A_4;
       
  2762         else if(maskBits == 8)
       
  2763             mf = VG_A_8;
       
  2764         m_mask = RI_NEW(Surface, (Color::formatToDescriptor(mf), width, height, 1));
       
  2765         m_mask->addReference();
       
  2766         m_mask->clear(Color(1,1,1,1,Color::sRGBA), 0, 0, width, height);
       
  2767     }
       
  2768 }
       
  2769 
       
  2770 /*-------------------------------------------------------------------*//*!
       
  2771 * \brief
       
  2772 * \param
       
  2773 * \return
       
  2774 * \note
       
  2775 *//*-------------------------------------------------------------------*/
       
  2776 
       
  2777 Drawable::~Drawable()
       
  2778 {
       
  2779     RI_ASSERT(m_referenceCount == 0);
       
  2780     if(!m_color->removeReference())
       
  2781         RI_DELETE(m_color);
       
  2782     if(m_mask)
       
  2783         if(!m_mask->removeReference())
       
  2784             RI_DELETE(m_mask);
       
  2785 }
       
  2786 
       
  2787 /*-------------------------------------------------------------------*//*!
       
  2788 * \brief
       
  2789 * \param
       
  2790 * \return
       
  2791 * \note
       
  2792 *//*-------------------------------------------------------------------*/
       
  2793 
       
  2794 void Drawable::resize(VGContext* context, int newWidth, int newHeight)
       
  2795 {
       
  2796     Surface* oldcolor = m_color;
       
  2797     Surface* oldmask = m_mask;
       
  2798     int oldWidth = m_color->getWidth();
       
  2799     int oldHeight = m_color->getHeight();
       
  2800 
       
  2801     //TODO check that image is not a proxy
       
  2802     m_color = RI_NEW(Surface, (m_color->getDescriptor(), newWidth, newHeight, m_color->getNumSamples()));
       
  2803     m_color->addReference();
       
  2804     if(m_mask)
       
  2805     {
       
  2806         m_mask = RI_NEW(Surface, (m_mask->getDescriptor(), newWidth, newHeight, m_mask->getNumSamples()));
       
  2807         m_mask->addReference();
       
  2808     }
       
  2809 
       
  2810     int wmin = RI_INT_MIN(newWidth,oldWidth);
       
  2811     int hmin = RI_INT_MIN(newHeight,oldHeight);
       
  2812     m_color->clear(Color(0.0f, 0.0f, 0.0f, 0.0f, getDescriptor().internalFormat), 0, 0, m_color->getWidth(), m_color->getHeight());
       
  2813     m_color->m_image->blit(context, oldcolor->m_image, 0, 0, 0, 0, wmin, hmin);
       
  2814     if(m_mask)
       
  2815     {
       
  2816         m_mask->clear(Color(1.0f, 1.0f, 1.0f, 1.0f, getDescriptor().internalFormat), 0, 0, m_mask->getWidth(), m_mask->getHeight());
       
  2817         m_mask->m_image->blit(context, oldmask->m_image, 0, 0, 0, 0, wmin, hmin);
       
  2818     }
       
  2819 
       
  2820     if(!oldcolor->removeReference())
       
  2821         RI_DELETE(oldcolor);
       
  2822     if(oldmask)
       
  2823         if(!oldmask->removeReference())
       
  2824             RI_DELETE(oldmask);
       
  2825 }
       
  2826 
       
  2827 #ifndef RI_COMPILE_LLVM_BYTECODE
       
  2828 
       
  2829 #endif /* RI_COMPILE_LLVM_BYTECODE */
       
  2830 
       
  2831 //==============================================================================================
       
  2832 
       
  2833 }	//namespace OpenVGRI
       
  2834 
       
  2835 //==============================================================================================