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