hostsupport/hostopenvg/src/src/riImage.h
branchbug235_bringup_0
changeset 53 c2ef9095503a
parent 24 a3f46bb01be2
equal deleted inserted replaced
52:39e5f73667ba 53:c2ef9095503a
       
     1 #ifndef __RIIMAGE_H
       
     2 #define __RIIMAGE_H
       
     3 
       
     4 /*------------------------------------------------------------------------
       
     5  *
       
     6  * OpenVG 1.1 Reference Implementation
       
     7  * -----------------------------------
       
     8  *
       
     9  * Copyright (c) 2007 The Khronos Group Inc.
       
    10  * Portions copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
    11  *
       
    12  * Permission is hereby granted, free of charge, to any person obtaining a
       
    13  * copy of this software and /or associated documentation files
       
    14  * (the "Materials "), to deal in the Materials without restriction,
       
    15  * including without limitation the rights to use, copy, modify, merge,
       
    16  * publish, distribute, sublicense, and/or sell copies of the Materials,
       
    17  * and to permit persons to whom the Materials are furnished to do so,
       
    18  * subject to the following conditions:
       
    19  *
       
    20  * The above copyright notice and this permission notice shall be included
       
    21  * in all copies or substantial portions of the Materials.
       
    22  *
       
    23  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
       
    24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
       
    25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
       
    26  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
       
    27  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
       
    28  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
       
    29  * THE USE OR OTHER DEALINGS IN THE MATERIALS.
       
    30  *
       
    31  *//**
       
    32  * \file
       
    33  * \brief	Color and Image classes.
       
    34  * \note
       
    35  *//*-------------------------------------------------------------------*/
       
    36 
       
    37 #ifndef _OPENVG_H
       
    38 #include "VG/openvg.h"
       
    39 #endif
       
    40 
       
    41 #ifndef __RIMATH_H
       
    42 #include "riMath.h"
       
    43 #endif
       
    44 
       
    45 #ifndef __RIARRAY_H
       
    46 #include "riArray.h"
       
    47 #endif
       
    48 
       
    49 #include "sfAlphaRcp.h"
       
    50 #include "sfGammaLUT.h"
       
    51 #include "riUtils.h"
       
    52 
       
    53 //==============================================================================================
       
    54 
       
    55 namespace OpenVGRI
       
    56 {
       
    57 
       
    58 class VGContext;
       
    59 class DynamicBlitter;
       
    60 
       
    61 /*-------------------------------------------------------------------*//*!
       
    62 * \brief	A class representing rectangles.
       
    63 * \param
       
    64 * \return
       
    65 * \note
       
    66 *//*-------------------------------------------------------------------*/
       
    67 
       
    68 class Rectangle
       
    69 {
       
    70 public:
       
    71     Rectangle() : x(0), y(0), width(0), height(0) {}
       
    72     Rectangle(int rx, int ry, int rw, int rh) : x(rx), y(ry), width(rw), height(rh) {}
       
    73     void		intersect(const Rectangle& r)
       
    74     {
       
    75         if(width >= 0 && r.width >= 0 && height >= 0 && r.height >= 0)
       
    76         {
       
    77             int x1 = RI_INT_MIN(RI_INT_ADDSATURATE(x, width), RI_INT_ADDSATURATE(r.x, r.width));
       
    78             x = RI_INT_MAX(x, r.x);
       
    79             width = RI_INT_MAX(x1 - x, 0);
       
    80 
       
    81             int y1 = RI_INT_MIN(RI_INT_ADDSATURATE(y, height), RI_INT_ADDSATURATE(r.y, r.height));
       
    82             y = RI_INT_MAX(y, r.y);
       
    83             height = RI_INT_MAX(y1 - y, 0);
       
    84         }
       
    85         else
       
    86         {
       
    87             x = 0;
       
    88             y = 0;
       
    89             width = 0;
       
    90             height = 0;
       
    91         }
       
    92     }
       
    93     bool isEmpty() const { return width == 0 || height == 0; }
       
    94 
       
    95     int			x;
       
    96     int			y;
       
    97     int			width;
       
    98     int			height;
       
    99 };
       
   100 
       
   101 /*-------------------------------------------------------------------*//*!
       
   102 * \brief	A class representing color for processing and converting it
       
   103 *			to and from various surface formats.
       
   104 * \param
       
   105 * \return
       
   106 * \note
       
   107 *//*-------------------------------------------------------------------*/
       
   108 
       
   109 class Color
       
   110 {
       
   111 public:
       
   112     enum FormatSize
       
   113     {
       
   114         SIZE_1      = 0,
       
   115         SIZE_4      = 1,
       
   116         SIZE_8      = 2,
       
   117         SIZE_16     = 3,
       
   118         SIZE_24     = 4,
       
   119         SIZE_32     = 5
       
   120     };
       
   121 
       
   122     enum Shape
       
   123     {
       
   124         SHAPE_RGBA            = 0,
       
   125         SHAPE_RGBX            = 1,
       
   126         SHAPE_RGB             = 2,
       
   127         SHAPE_LA              = 3,
       
   128         SHAPE_L               = 4,
       
   129         SHAPE_A               = 5,
       
   130         SHAPE_ARGB            = 6,
       
   131         SHAPE_XRGB            = 7,
       
   132         SHAPE_AL              = 8,
       
   133         SHAPE_BGRA            = 9,
       
   134         SHAPE_BGRX            = 10,
       
   135         SHAPE_BGR             = 11,
       
   136         SHAPE_ABGR            = 12,
       
   137         SHAPE_XBGR            = 13
       
   138     };
       
   139     enum InternalFormat
       
   140     {
       
   141         lRGBA			= 0,
       
   142         sRGBA			= 1,
       
   143         lRGBA_PRE		= 2,
       
   144         sRGBA_PRE		= 3,
       
   145         lLA				= 4,
       
   146         sLA				= 5,
       
   147         lLA_PRE			= 6,
       
   148         sLA_PRE			= 7
       
   149     };
       
   150     enum FormatBits
       
   151     {
       
   152         NONLINEAR		= (1<<0),
       
   153         PREMULTIPLIED	= (1<<1),
       
   154         LUMINANCE		= (1<<2)
       
   155     };
       
   156     struct SmallDescriptor
       
   157     {
       
   158         RIuint32        toUint32()
       
   159         {
       
   160             RIuint32 ret = 0;
       
   161             ret = (RIuint32)size;
       
   162             ret |= (RIuint32)shape << 3;
       
   163             ret |= (RIuint32)internalFormat << (3 + 4);
       
   164             return ret;
       
   165         }
       
   166         FormatSize      size;
       
   167         Shape           shape;
       
   168         InternalFormat  internalFormat;
       
   169     };
       
   170     class Descriptor
       
   171     {
       
   172     public:
       
   173         Descriptor() {};
       
   174         RI_INLINE Descriptor(int dredBits, int dredShift, int dgreenBits, int dgreenShift, int dblueBits, int dblueShift, int dalphaBits, int dalphaShift, int dluminanceBits, int dluminanceShift, InternalFormat dinternalFormat, int dbpp, Shape shape);
       
   175         RI_INLINE bool      isNonlinear() const                                 { return (internalFormat & NONLINEAR) ? true : false; }
       
   176         RI_INLINE void      setNonlinear(bool nonlinear);
       
   177         RI_INLINE bool      isPremultiplied() const                             { return (internalFormat & PREMULTIPLIED) ? true : false; }
       
   178         RI_INLINE bool      isLuminance() const                                 { return (internalFormat & LUMINANCE) ? true : false; }
       
   179         RI_INLINE bool      isAlphaOnly() const                                 { return (alphaBits && (redBits+greenBits+blueBits+luminanceBits) == 0) ? true : false; }
       
   180         RI_INLINE bool      isBW() const { return isLuminance() && (luminanceBits == 1); }
       
   181         RI_INLINE bool      hasAlpha() const { return alphaBits > 0; }
       
   182         RI_INLINE bool      operator==(const Descriptor& rhs) const;
       
   183         RI_INLINE bool      isShiftConversionToLower(const Descriptor& rhs) const;
       
   184         RI_INLINE bool      isShiftConversion(const Descriptor& rhs) const;
       
   185         RI_INLINE bool      isZeroConversion(const Descriptor& rhs) const;
       
   186         RI_INLINE bool      maybeUnsafe() const { return internalFormat & PREMULTIPLIED ? true : false; };
       
   187         static RI_INLINE RIuint32  crossConvertToLower(RIuint32 c, const Descriptor& src, const Descriptor& dst);
       
   188         void                toSmallDescriptor(SmallDescriptor& smallDesc) const;
       
   189         RI_INLINE RIuint32  toIndex() const;
       
   190         static Descriptor   getDummyDescriptor();
       
   191         Shape               getShape() const;
       
   192 
       
   193         int				redBits;
       
   194         int				redShift;
       
   195         int				greenBits;
       
   196         int				greenShift;
       
   197         int				blueBits;
       
   198         int				blueShift;
       
   199         int				alphaBits;
       
   200         int				alphaShift;
       
   201         int				luminanceBits;
       
   202         int				luminanceShift;
       
   203         Shape           shape;
       
   204         VGImageFormat   vgFormat; // \note Storage only
       
   205         InternalFormat	internalFormat;
       
   206         int				bitsPerPixel;
       
   207         // Derived info:
       
   208         int             bytesPerPixel;
       
   209         int             maskBits;
       
   210         int             maskShift;
       
   211     };
       
   212 
       
   213     RI_INLINE Color() : r(0.0f), g(0.0f), b(0.0f), a(0.0f), m_format(sRGBA_PRE)													{}
       
   214     RI_INLINE Color(RIfloat cl, RIfloat ca, InternalFormat cs) : r(cl), g(cl), b(cl), a(ca), m_format(cs)							{ RI_ASSERT(cs == lLA || cs == sLA || cs == lLA_PRE || cs == sLA_PRE); }
       
   215     RI_INLINE Color(RIfloat cr, RIfloat cg, RIfloat cb, RIfloat ca, InternalFormat cs) : r(cr), g(cg), b(cb), a(ca), m_format(cs)	{ RI_ASSERT(cs == lRGBA || cs == sRGBA || cs == lRGBA_PRE || cs == sRGBA_PRE || cs == lLA || cs == sLA || cs == lLA_PRE || cs == sLA_PRE); }
       
   216     RI_INLINE Color(const Color& c) : r(c.r), g(c.g), b(c.b), a(c.a), m_format(c.m_format)									{}
       
   217     RI_INLINE Color& operator=(const Color&c)										{ r = c.r; g = c.g; b = c.b; a = c.a; m_format = c.m_format; return *this; }
       
   218     RI_INLINE void operator*=(RIfloat f)											{ r *= f; g *= f; b *= f; a*= f; }
       
   219     RI_INLINE void operator+=(const Color& c1)										{ RI_ASSERT(m_format == c1.getInternalFormat()); r += c1.r; g += c1.g; b += c1.b; a += c1.a; }
       
   220     RI_INLINE void operator-=(const Color& c1)										{ RI_ASSERT(m_format == c1.getInternalFormat()); r -= c1.r; g -= c1.g; b -= c1.b; a -= c1.a; }
       
   221 
       
   222     void						set(RIfloat cl, RIfloat ca, InternalFormat cs)							{ RI_ASSERT(cs == lLA || cs == sLA || cs == lLA_PRE || cs == sLA_PRE); r = cl; g = cl; b = cl; a = ca; m_format = cs; }
       
   223     void						set(RIfloat cr, RIfloat cg, RIfloat cb, RIfloat ca, InternalFormat cs)	{ RI_ASSERT(cs == lRGBA || cs == sRGBA || cs == lRGBA_PRE || cs == sRGBA_PRE); r = cr; g = cg; b = cb; a = ca; m_format = cs; }
       
   224     void						unpack(unsigned int inputData, const Descriptor& inputDesc);
       
   225     unsigned int				pack(const Descriptor& outputDesc) const;
       
   226     RI_INLINE InternalFormat	getInternalFormat() const							{ return m_format; }
       
   227 
       
   228     //clamps nonpremultiplied colors and alpha to [0,1] range, and premultiplied alpha to [0,1], colors to [0,a]
       
   229     void						clamp()												{ a = RI_CLAMP(a,0.0f,1.0f); RIfloat u = (m_format & PREMULTIPLIED) ? a : (RIfloat)1.0f; r = RI_CLAMP(r,0.0f,u); g = RI_CLAMP(g,0.0f,u); b = RI_CLAMP(b,0.0f,u); }
       
   230     void						convert(InternalFormat outputFormat);
       
   231     void						premultiply()										{ if(!(m_format & PREMULTIPLIED)) { r *= a; g *= a; b *= a; m_format = (InternalFormat)(m_format | PREMULTIPLIED); } }
       
   232     void						unpremultiply()										{ if(m_format & PREMULTIPLIED) { RIfloat ooa = (a != 0.0f) ? 1.0f/a : (RIfloat)0.0f; r *= ooa; g *= ooa; b *= ooa; m_format = (InternalFormat)(m_format & ~PREMULTIPLIED); } }
       
   233     void                        luminanceToRGB()                                    { if(m_format & LUMINANCE) { RI_ASSERT(r == g && g == b); m_format = (InternalFormat)(m_format & ~LUMINANCE); } }
       
   234 
       
   235     bool                        isNonlinear() const                                 { return (m_format & NONLINEAR) ? true : false; }
       
   236     bool                        isPremultiplied() const                             { return (m_format & PREMULTIPLIED) ? true : false; }
       
   237     bool                        isLuminance() const                                 { return (m_format & LUMINANCE) ? true : false; }
       
   238 
       
   239     RI_INLINE void              assertConsistency() const;
       
   240 
       
   241     // \note Why are these in the color class instead of descriptor?
       
   242     static VGImageFormat        descriptorToVGImageFormat(const Descriptor& desc);
       
   243     RI_INLINE static Descriptor formatToDescriptorConst(VGImageFormat format);
       
   244     static Descriptor			formatToDescriptor(VGImageFormat format);
       
   245     static bool					isValidDescriptor(const Descriptor& desc);
       
   246 
       
   247     RIfloat		r;
       
   248     RIfloat		g;
       
   249     RIfloat		b;
       
   250     RIfloat		a;
       
   251 private:
       
   252     InternalFormat	m_format;
       
   253 };
       
   254 
       
   255 RI_INLINE Color::Descriptor::Descriptor(int dredBits, int dredShift, int dgreenBits, int dgreenShift, int dblueBits, int dblueShift, int dalphaBits, int dalphaShift, int dluminanceBits, int dluminanceShift, InternalFormat dinternalFormat, int dbpp, Shape shape) :
       
   256     redBits(dredBits),
       
   257     redShift(dredShift),
       
   258     greenBits(dgreenBits),
       
   259     greenShift(dgreenShift),
       
   260     blueBits(dblueBits),
       
   261     blueShift(dblueShift),
       
   262     alphaBits(dalphaBits),
       
   263     alphaShift(dalphaShift),
       
   264     luminanceBits(dluminanceBits),
       
   265     luminanceShift(dluminanceShift),
       
   266     shape(shape),
       
   267     internalFormat(dinternalFormat),
       
   268     bitsPerPixel(dbpp)
       
   269 {
       
   270     bytesPerPixel = bitsPerPixel / 8;
       
   271 
       
   272     if (alphaBits)
       
   273     {
       
   274         maskBits = alphaBits;
       
   275         maskShift = alphaShift;
       
   276     }
       
   277     else if (!this->isLuminance())
       
   278     {
       
   279         maskBits = redBits;
       
   280         maskShift = redShift;
       
   281     }
       
   282     else
       
   283     {
       
   284         maskBits = luminanceBits;
       
   285         maskShift = luminanceShift;
       
   286     }
       
   287     RI_ASSERT(getShape() == shape);
       
   288 }
       
   289 
       
   290 RI_INLINE void Color::Descriptor::setNonlinear(bool nonlinear)
       
   291 {
       
   292     if (nonlinear)
       
   293         internalFormat = (InternalFormat)(((RIuint32)internalFormat)|NONLINEAR);
       
   294     else
       
   295         internalFormat = (InternalFormat)(((RIuint32)internalFormat)&(~NONLINEAR));
       
   296 }
       
   297 
       
   298 /**
       
   299  * \brief	Creates a pixel format descriptor out of VGImageFormat
       
   300  * \todo    The formats without alpha were non-premultiplied in the reference
       
   301  *          implementation, but wouldn't it make more sense to consider them
       
   302  *          premultiplied? This would make sense at least when blitting to
       
   303  *          windows, etc., where the output color should have the alpha
       
   304  *          multiplied "in".
       
   305  */
       
   306 RI_INLINE Color::Descriptor Color::formatToDescriptorConst(VGImageFormat format)
       
   307 {
       
   308     switch(format)
       
   309     {
       
   310     case VG_sRGBX_8888:
       
   311         return Color::Descriptor(8, 24, 8, 16, 8, 8, 0, 0, 0, 0, Color::sRGBA, 32, SHAPE_RGBX);
       
   312     case VG_sRGBA_8888:
       
   313         return Color::Descriptor(8, 24, 8, 16, 8, 8, 8, 0, 0, 0, Color::sRGBA, 32, SHAPE_RGBA);
       
   314     case VG_sRGBA_8888_PRE:
       
   315         return Color::Descriptor(8, 24, 8, 16, 8, 8, 8, 0, 0, 0, Color::sRGBA_PRE, 32, SHAPE_RGBA);
       
   316     case VG_sRGB_565:
       
   317         return Color::Descriptor(5, 11, 6, 5, 5, 0, 0, 0, 0, 0, Color::sRGBA, 16, SHAPE_RGB);
       
   318     case VG_sRGBA_5551:
       
   319         return Color::Descriptor(5, 11, 5, 6, 5, 1, 1, 0, 0, 0, Color::sRGBA, 16, SHAPE_RGBA);
       
   320     case VG_sRGBA_4444:
       
   321         return Color::Descriptor(4, 12, 4, 8, 4, 4, 4, 0, 0, 0, Color::sRGBA, 16, SHAPE_RGBA);
       
   322     case VG_sL_8:
       
   323         return Color::Descriptor(0, 0, 0, 0, 0, 0, 0, 0, 8, 0, Color::sLA, 8, SHAPE_L);
       
   324     case VG_lRGBX_8888:
       
   325         return Color::Descriptor(8, 24, 8, 16, 8, 8, 0, 0, 0, 0, Color::lRGBA, 32, SHAPE_RGBX);
       
   326     case VG_lRGBA_8888:
       
   327         return Color::Descriptor(8, 24, 8, 16, 8, 8, 8, 0, 0, 0, Color::lRGBA, 32, SHAPE_RGBA);
       
   328     case VG_lRGBA_8888_PRE:
       
   329         return Color::Descriptor(8, 24, 8, 16, 8, 8, 8, 0, 0, 0, Color::lRGBA_PRE, 32, SHAPE_RGBA);
       
   330     case VG_lL_8:
       
   331         return Color::Descriptor(0, 0, 0, 0, 0, 0, 0, 0, 8, 0, Color::lLA, 8, SHAPE_L);
       
   332     case VG_A_8:
       
   333         return Color::Descriptor(0, 0, 0, 0, 0, 0, 8, 0, 0, 0, Color::lRGBA, 8, SHAPE_A);
       
   334     case VG_BW_1:
       
   335         return Color::Descriptor(0, 0, 0, 0, 0, 0, 0, 0, 1, 0, Color::lLA, 1, SHAPE_L);
       
   336     case VG_A_1:
       
   337         return Color::Descriptor(0, 0, 0, 0, 0, 0, 1, 0, 0, 0, Color::lRGBA, 1, SHAPE_A);
       
   338     case VG_A_4:
       
   339         return Color::Descriptor(0, 0, 0, 0, 0, 0, 4, 0, 0, 0, Color::lRGBA, 4, SHAPE_A);
       
   340 
       
   341   /* {A,X}RGB channel ordering */
       
   342     case VG_sXRGB_8888:
       
   343         return Color::Descriptor(8, 16, 8, 8, 8, 0, 0, 0, 0, 0, Color::sRGBA, 32, SHAPE_XRGB);
       
   344     case VG_sARGB_8888:
       
   345         return Color::Descriptor(8, 16, 8, 8, 8, 0, 8, 24, 0, 0, Color::sRGBA, 32, SHAPE_ARGB);
       
   346     case VG_sARGB_8888_PRE:
       
   347         return Color::Descriptor(8, 16, 8, 8, 8, 0, 8, 24, 0, 0, Color::sRGBA_PRE, 32, SHAPE_ARGB);
       
   348     case VG_sARGB_1555:
       
   349         return Color::Descriptor(5, 10, 5, 5, 5, 0, 1, 15, 0, 0, Color::sRGBA, 16, SHAPE_ARGB);
       
   350     case VG_sARGB_4444:
       
   351         return Color::Descriptor(4, 8, 4, 4, 4, 0, 4, 12, 0, 0, Color::sRGBA, 16, SHAPE_ARGB);
       
   352     case VG_lXRGB_8888:
       
   353         return Color::Descriptor(8, 16, 8, 8, 8, 0, 0, 0, 0, 0, Color::lRGBA, 32, SHAPE_XRGB);
       
   354     case VG_lARGB_8888:
       
   355         return Color::Descriptor(8, 16, 8, 8, 8, 0, 8, 24, 0, 0, Color::lRGBA, 32, SHAPE_ARGB);
       
   356     case VG_lARGB_8888_PRE:
       
   357         return Color::Descriptor(8, 16, 8, 8, 8, 0, 8, 24, 0, 0, Color::lRGBA_PRE, 32, SHAPE_ARGB);
       
   358 
       
   359   /* BGR{A,X} channel ordering */
       
   360     case VG_sBGRX_8888:
       
   361         return Color::Descriptor(8, 8, 8, 16, 8, 24, 0, 0, 0, 0, Color::sRGBA, 32, SHAPE_BGRX);
       
   362     case VG_sBGRA_8888:
       
   363         return Color::Descriptor(8, 8, 8, 16, 8, 24, 8, 0, 0, 0, Color::sRGBA, 32, SHAPE_BGRA);
       
   364     case VG_sBGRA_8888_PRE:
       
   365         return Color::Descriptor(8, 8, 8, 16, 8, 24, 8, 0, 0, 0, Color::sRGBA_PRE, 32, SHAPE_BGRA);
       
   366     case VG_sBGR_565:
       
   367         return Color::Descriptor(5, 0, 6, 5, 5, 11, 0, 0, 0, 0, Color::sRGBA, 16, SHAPE_BGR);
       
   368     case VG_sBGRA_5551:
       
   369         return Color::Descriptor(5, 1, 5, 6, 5, 11, 1, 0, 0, 0, Color::sRGBA, 16, SHAPE_BGRA);
       
   370     case VG_sBGRA_4444:
       
   371         return Color::Descriptor(4, 4, 4, 8, 4, 12, 4, 0, 0, 0, Color::sRGBA, 16, SHAPE_BGRA);
       
   372     case VG_lBGRX_8888:
       
   373         return Color::Descriptor(8, 8, 8, 16, 8, 24, 0, 0, 0, 0, Color::lRGBA, 32, SHAPE_BGRX);
       
   374     case VG_lBGRA_8888:
       
   375         return Color::Descriptor(8, 8, 8, 16, 8, 24, 8, 0, 0, 0, Color::lRGBA, 32, SHAPE_BGRA);
       
   376     case VG_lBGRA_8888_PRE:
       
   377         return Color::Descriptor(8, 8, 8, 16, 8, 24, 8, 0, 0, 0, Color::lRGBA_PRE, 32, SHAPE_BGRA);
       
   378 
       
   379   /* {A,X}BGR channel ordering */
       
   380     case VG_sXBGR_8888:
       
   381         return Color::Descriptor(8, 0, 8, 8, 8, 16, 0, 0, 0, 0, Color::sRGBA, 32, SHAPE_XBGR);
       
   382     case VG_sABGR_8888:
       
   383         return Color::Descriptor(8, 0, 8, 8, 8, 16, 8, 24, 0, 0, Color::sRGBA, 32, SHAPE_ABGR);
       
   384     case VG_sABGR_8888_PRE:
       
   385         return Color::Descriptor(8, 0, 8, 8, 8, 16, 8, 24, 0, 0, Color::sRGBA_PRE, 32, SHAPE_ABGR);
       
   386     case VG_sABGR_1555:
       
   387         return Color::Descriptor(5, 0, 5, 5, 5, 10, 1, 15, 0, 0, Color::sRGBA, 16, SHAPE_ABGR);
       
   388     case VG_sABGR_4444:
       
   389         return Color::Descriptor(4, 0, 4, 4, 4, 8, 4, 12, 0, 0, Color::sRGBA, 16, SHAPE_ABGR);
       
   390     case VG_lXBGR_8888:
       
   391         return Color::Descriptor(8, 0, 8, 8, 8, 16, 0, 0, 0, 0, Color::lRGBA, 32, SHAPE_XBGR);
       
   392     case VG_lABGR_8888:
       
   393         return Color::Descriptor(8, 0, 8, 8, 8, 16, 8, 24, 0, 0, Color::lRGBA, 32, SHAPE_ABGR);
       
   394     default:
       
   395     //case VG_lABGR_8888_PRE:
       
   396         RI_ASSERT(format == VG_lABGR_8888_PRE);
       
   397         return Color::Descriptor(8, 0, 8, 8, 8, 16, 8, 24, 0, 0, Color::lRGBA_PRE, 32, SHAPE_ABGR);
       
   398     }
       
   399 }
       
   400 
       
   401 RI_INLINE bool 	Color::Descriptor::operator==(const Descriptor& rhs) const
       
   402 {
       
   403     return memcmp(this, &rhs, sizeof(Descriptor)) ? false : true;
       
   404 }
       
   405 
       
   406 RI_INLINE bool Color::Descriptor::isZeroConversion(const Descriptor& rhs) const
       
   407 {
       
   408     return (shape == rhs.shape) &&
       
   409         (internalFormat == rhs.internalFormat) &&
       
   410         (redBits == rhs.redBits) &&
       
   411         (greenBits == rhs.greenBits) &&
       
   412         (blueBits == rhs.blueBits) &&
       
   413         (alphaBits == rhs.alphaBits) &&
       
   414         (luminanceBits == rhs.luminanceBits);
       
   415 }
       
   416 
       
   417 RI_INLINE bool Color::Descriptor::isShiftConversion(const Descriptor& rhs) const
       
   418 {
       
   419     // \note BW conversion is always forced to full at the moment.
       
   420     if (isBW() != rhs.isBW()) 
       
   421         return false;
       
   422 
       
   423     return (isPremultiplied() == rhs.isPremultiplied())
       
   424             && (isNonlinear() == rhs.isNonlinear())
       
   425             && (isLuminance() == rhs.isLuminance());
       
   426 }
       
   427 
       
   428 RI_INLINE bool Color::Descriptor::isShiftConversionToLower(const Descriptor& rhs) const
       
   429 {
       
   430     // \note BW conversion is always forced to full at the moment.
       
   431     if (isBW() != rhs.isBW()) 
       
   432         return false;
       
   433     // \note Mask bits are not checked because they are derived information.
       
   434     return (isShiftConversion(rhs)
       
   435             && (rhs.redBits <= redBits)
       
   436             && (rhs.greenBits <= greenBits)
       
   437             && (rhs.blueBits <= blueBits)
       
   438             && (rhs.alphaBits <= alphaBits)
       
   439             && (rhs.luminanceBits <= luminanceBits));
       
   440 
       
   441 }
       
   442 
       
   443 /**
       
   444  * \brief   In-place conversion of packed color to lower bit-depth
       
   445  * \param   c   Input packed color
       
   446  * \param   src Source color descriptor
       
   447  * \param   dst Destination color descriptor
       
   448  */
       
   449 RI_INLINE RIuint32  Color::Descriptor::crossConvertToLower(RIuint32 c, const Descriptor& src, const Descriptor& dst)
       
   450 {
       
   451     RIuint32 r = 0;
       
   452 
       
   453     RI_ASSERT(dst.redBits <= src.redBits);
       
   454     RI_ASSERT(dst.greenBits <= src.greenBits);
       
   455     RI_ASSERT(dst.blueBits <= src.blueBits);
       
   456     RI_ASSERT(dst.alphaBits <= src.alphaBits);
       
   457 
       
   458     if (src.isLuminance())
       
   459     {
       
   460         RI_ASSERT(dst.isLuminance());
       
   461         r = ((c >> (src.luminanceShift + src.luminanceBits - dst.luminanceBits)) & ((1u<<dst.luminanceBits)-1)) << dst.luminanceShift;
       
   462     } else
       
   463     {
       
   464         r = ((c >> (src.redShift + src.redBits - dst.redBits)) & ((1u<<dst.redBits)-1)) << dst.redShift;
       
   465         r |= ((c >> (src.greenShift + src.greenBits - dst.greenBits)) & ((1u<<dst.greenBits)-1)) << dst.greenShift;
       
   466         r |= ((c >> (src.blueShift + src.blueBits - dst.blueBits)) & ((1u<<dst.blueBits)-1)) << dst.blueShift;
       
   467     }
       
   468 
       
   469     if (src.hasAlpha())
       
   470     {
       
   471         if (dst.hasAlpha())
       
   472             r |= ((c >> (src.alphaShift + src.alphaBits - dst.alphaBits)) & ((1u<<dst.alphaBits)-1)) << dst.alphaShift;
       
   473         else
       
   474         {
       
   475             // Make sure that the alpha is applied to the color if doing only a shift conversion.
       
   476             RI_ASSERT(src.isPremultiplied() == dst.isPremultiplied());
       
   477         }
       
   478     }
       
   479 
       
   480     return r;
       
   481 }
       
   482 
       
   483 RI_INLINE RIuint32 Color::Descriptor::toIndex() const
       
   484 {
       
   485     SmallDescriptor smallDesc;
       
   486     toSmallDescriptor(smallDesc);
       
   487     return smallDesc.toUint32();
       
   488 }
       
   489 
       
   490 RI_INLINE Color operator*(const Color& c, RIfloat f)			{ return Color(c.r*f, c.g*f, c.b*f, c.a*f, c.getInternalFormat()); }
       
   491 RI_INLINE Color operator*(RIfloat f, const Color& c)			{ return Color(c.r*f, c.g*f, c.b*f, c.a*f, c.getInternalFormat()); }
       
   492 RI_INLINE Color operator+(const Color& c0, const Color& c1)		{ RI_ASSERT(c0.getInternalFormat() == c1.getInternalFormat()); return Color(c0.r+c1.r, c0.g+c1.g, c0.b+c1.b, c0.a+c1.a, c0.getInternalFormat()); }
       
   493 RI_INLINE Color operator-(const Color& c0, const Color& c1)		{ RI_ASSERT(c0.getInternalFormat() == c1.getInternalFormat()); return Color(c0.r-c1.r, c0.g-c1.g, c0.b-c1.b, c0.a-c1.a, c0.getInternalFormat()); }
       
   494 RI_INLINE void  Color::assertConsistency() const
       
   495 {
       
   496     RI_ASSERT(r >= 0.0f && r <= 1.0f);
       
   497     RI_ASSERT(g >= 0.0f && g <= 1.0f);
       
   498     RI_ASSERT(b >= 0.0f && b <= 1.0f);
       
   499     RI_ASSERT(a >= 0.0f && a <= 1.0f);
       
   500     RI_ASSERT(!isPremultiplied() || (r <= a && g <= a && b <= a));	//premultiplied colors must have color channels less than or equal to alpha
       
   501     RI_ASSERT((isLuminance() && r == g && r == b) || !isLuminance());	//if luminance, r=g=b
       
   502 }
       
   503 
       
   504 class IntegerColor
       
   505 {
       
   506 public:
       
   507 
       
   508     IntegerColor() {r = g = b = a = 0;}
       
   509     IntegerColor(const Color& color);
       
   510 
       
   511     RI_INLINE           IntegerColor(RIuint32 packedColor, const Color::Descriptor& desc) { fromPackedColor(packedColor, desc); }
       
   512     RI_INLINE           IntegerColor(RIuint32 cr, RIuint32 cg, RIuint32 cb, RIuint32 ca) { r = cr; g = cg; b = cb; a = ca; }
       
   513     RI_INLINE void      asFixedPoint(const Color& color);
       
   514     RI_INLINE void      fromPackedColor(RIuint32 packedColor, const Color::Descriptor& desc);
       
   515     RI_INLINE void      expandColor(const Color::Descriptor& desc);
       
   516     RI_INLINE void      truncateColor(const Color::Descriptor& desc);
       
   517     RI_INLINE void      clampToAlpha();
       
   518     RI_INLINE RIuint32  getPackedColor(const Color::Descriptor& desc) const;
       
   519     RI_INLINE RIuint32  getPackedMaskColor(const Color::Descriptor& desc) const;
       
   520     RI_INLINE void      premultiply(bool luminance = false);
       
   521     RI_INLINE void      unpremultiply(bool luminance = false);
       
   522     //RI_INLINE void      linearToGamma(bool luminance, bool premultipliedIn, bool premultipliedOut);
       
   523     RI_INLINE void      linearToGamma(bool luminance = false);
       
   524     RI_INLINE void      gammaToLinear(bool luminance = false);
       
   525     RI_INLINE void      fromPackedMask(RIuint32 packedColor, const Color::Descriptor& desc);
       
   526     RI_INLINE void      expandMask(const Color::Descriptor& desc);
       
   527     RI_INLINE void      truncateMask(const Color::Descriptor& desc);
       
   528     RI_INLINE void      fullLuminanceToRGB(bool premultipliedIn, bool gammaIn, bool premultipliedOut, bool gammaOut);
       
   529     RI_INLINE void      fullRGBToLuminance(bool premultipliedIn, bool gammaIn, bool premultipliedOut, bool gammaOut);
       
   530     RI_INLINE void      luminanceToRGB();
       
   531     RI_INLINE void      rgbToLuminance();
       
   532     RI_INLINE void      convertToFrom(const Color::Descriptor& dst, const Color::Descriptor& src, bool srcIsMask);
       
   533 
       
   534     RI_INLINE static IntegerColor linearBlendNS(const IntegerColor& c0, const IntegerColor& c1, int k);
       
   535 
       
   536     RIuint32 r;
       
   537     RIuint32 g;
       
   538     RIuint32 b;
       
   539     RIuint32 a;
       
   540 
       
   541 };
       
   542 
       
   543 /**
       
   544  * \brief   Blend two colors linearly. The output will not be scaled into original range.
       
   545  * \param   k   Blend coefficient. Must be [0..255] for correct results.
       
   546  * \todo    Parameterize against bits in k? To perform well, that setup must be compiled rt.
       
   547  */
       
   548 RI_INLINE IntegerColor IntegerColor::linearBlendNS(const IntegerColor& c0, const IntegerColor& c1, int k)
       
   549 {
       
   550     RI_ASSERT(k >= 0 && k <= 255);
       
   551     IntegerColor ret;
       
   552     RIuint32 ik = 255 - k;
       
   553 
       
   554     ret.r = ik * c0.r + k * c1.r;
       
   555     ret.g = ik * c0.g + k * c1.g;
       
   556     ret.b = ik * c0.b + k * c1.b;
       
   557     ret.a = ik * c0.a + k * c1.a;
       
   558 
       
   559     return ret;
       
   560 }
       
   561 
       
   562 /**
       
   563  *	\note 	Assumes that each individual component is in proper range (usually indicated by the
       
   564  *			corresponding shift).
       
   565  */
       
   566 RI_INLINE RIuint32 packRGBAInteger(RIuint32 cr, int rs, RIuint32 cg, int gs, RIuint32 cb, int bs, RIuint32 ca, int as)
       
   567 {
       
   568     return (cr << rs) | (cg << gs) | (cb << bs) | (ca << as);
       
   569 }
       
   570 
       
   571 /**
       
   572  * \brief   Packs a color into RIuint32.
       
   573  * \note    The color must have been truncated to contain correct amount of bits per channel
       
   574  * \note    This function is efficient only if runtime compilation is used.
       
   575  */
       
   576 RI_INLINE RIuint32 IntegerColor::getPackedColor(const Color::Descriptor& desc) const
       
   577 {
       
   578     RIuint32 res = 0;
       
   579     if (desc.luminanceBits)
       
   580     {
       
   581         RI_ASSERT(desc.redBits == 0 && desc.greenBits == 0 && desc.blueBits == 0);
       
   582         RI_ASSERT(r < (1u<<desc.luminanceBits));
       
   583         res = r << desc.luminanceShift;
       
   584     }
       
   585     else if (desc.redBits)
       
   586     {
       
   587         RI_ASSERT(r < (1u<<desc.redBits));
       
   588         res = r << desc.redShift;
       
   589         if (desc.greenBits)
       
   590         {
       
   591             RI_ASSERT(desc.blueBits);
       
   592             RI_ASSERT(g < (1u<<desc.greenBits));
       
   593             RI_ASSERT(b < (1u<<desc.blueBits));
       
   594             res |= g << desc.greenShift;
       
   595             res |= b << desc.blueShift;
       
   596         }
       
   597     }
       
   598 
       
   599     if (desc.alphaBits)
       
   600     {
       
   601         RI_ASSERT(a < (1u<<desc.alphaBits));
       
   602         res |= a << desc.alphaShift;
       
   603     }
       
   604 
       
   605     return res;
       
   606 }
       
   607 
       
   608 RI_INLINE RIuint32 IntegerColor::getPackedMaskColor(const Color::Descriptor& desc) const
       
   609 {
       
   610     if (desc.alphaBits)
       
   611         return packRGBAInteger(0, desc.redShift, 0, desc.greenShift, 0, desc.blueShift, a, desc.alphaShift);
       
   612     else if(desc.redBits)
       
   613         return packRGBAInteger(a, desc.redShift, 0, desc.greenShift, 0, desc.blueShift, 0, desc.alphaShift);
       
   614     else
       
   615     {
       
   616         RI_ASSERT(desc.luminanceBits);
       
   617         return packRGBAInteger(a, desc.luminanceBits, 0, desc.greenShift, 0, desc.blueShift, 0, desc.alphaShift);
       
   618     }
       
   619 
       
   620 }
       
   621 
       
   622 RI_INLINE void IntegerColor::premultiply(bool luminance)
       
   623 {
       
   624     // \todo Check the round!!!
       
   625     RIuint32 fxa = a + (a>>7);
       
   626     r = (r * fxa); r = (r + (1<<7))>>8;
       
   627 
       
   628     if (!luminance)
       
   629     {
       
   630         g = (g * fxa); g = (g + (1<<7))>>8;
       
   631         b = (b * fxa); b = (b + (1<<7))>>8;
       
   632     }
       
   633 }
       
   634 
       
   635 RI_INLINE void IntegerColor::unpremultiply(bool luminance)
       
   636 {
       
   637     RI_ASSERT(a <= 255);
       
   638 
       
   639     RIuint32 rcp = sc_alphaRcp[a];
       
   640     r = (r * rcp) >> 8;
       
   641 
       
   642     if (!luminance)
       
   643     {
       
   644         g = (g * rcp) >> 8;
       
   645         b = (b * rcp) >> 8;
       
   646     }
       
   647 }
       
   648 
       
   649 RI_INLINE void IntegerColor::linearToGamma(bool luminance)
       
   650 {
       
   651     RI_ASSERT(r <= 255 && g <= 255 && b <= 255 && a <= 255);
       
   652 
       
   653     r = sc_lRGB_to_sRGB[r];
       
   654 
       
   655     if (!luminance)
       
   656     {
       
   657         g = sc_lRGB_to_sRGB[g];
       
   658         b = sc_lRGB_to_sRGB[b];
       
   659     }
       
   660 
       
   661     // \note Alpha is _not_ converted and it must be considered linear always
       
   662 }
       
   663 
       
   664 RI_INLINE void IntegerColor::gammaToLinear(bool luminance)
       
   665 {
       
   666     RI_ASSERT(r <= 255 && g <= 255 && b <= 255 && a <= 255);
       
   667 
       
   668     r = sc_sRGB_to_lRGB[r];
       
   669     if (!luminance)
       
   670     {
       
   671         g = sc_sRGB_to_lRGB[g];
       
   672         b = sc_sRGB_to_lRGB[b];
       
   673     }
       
   674 
       
   675     // \note Alpha is _not_ converted and it must be considered linear always
       
   676 }
       
   677 
       
   678 RI_INLINE void IntegerColor::asFixedPoint(const Color& color)
       
   679 {
       
   680     r = (RIuint32)(color.r * 256.0f + 0.5f);
       
   681     g = (RIuint32)(color.g * 256.0f + 0.5f);
       
   682     b = (RIuint32)(color.b * 256.0f + 0.5f);
       
   683     a = (RIuint32)(color.a * 256.0f + 0.5f);
       
   684 }
       
   685 
       
   686 RI_INLINE void IntegerColor::fromPackedColor(RIuint32 packedColor, const Color::Descriptor& desc)
       
   687 {
       
   688     /* \note Expand MUST be done separately! */
       
   689 
       
   690     if (desc.luminanceBits)
       
   691     {
       
   692         r = (packedColor >> desc.luminanceShift) & ((1u << desc.luminanceBits)-1);
       
   693         g = b = r;
       
   694     }
       
   695     else
       
   696     {
       
   697         r = (packedColor >> desc.redShift) & ((1u << desc.redBits)-1);
       
   698         g = (packedColor >> desc.greenShift) & ((1u << desc.greenBits)-1);
       
   699         b = (packedColor >> desc.blueShift) & ((1u << desc.blueBits)-1);
       
   700     }
       
   701 
       
   702     if (desc.alphaBits)
       
   703         a = (packedColor >> desc.alphaShift) & ((1u << desc.alphaBits)-1);
       
   704     else
       
   705         a = 255;
       
   706 }
       
   707 
       
   708 /**
       
   709  * \brief   Expand color to larger (or same) bit depth as in the OpenVG specification.
       
   710  * \todo    1 and 2 bpp!
       
   711  */
       
   712 RI_INLINE RIuint32 expandComponent(RIuint32 c, RIuint32 srcBits)
       
   713 {
       
   714     const RIuint32 destBits = 8;
       
   715     RI_ASSERT(destBits >= srcBits);
       
   716 
       
   717     if (!srcBits) return 0;
       
   718 
       
   719     if (srcBits == destBits) return c;
       
   720 
       
   721     switch (srcBits)
       
   722     {
       
   723     case 6:
       
   724         return (c << 2) | (c >> 4);
       
   725     case 5:
       
   726         return (c << 3) | (c >> 2);
       
   727     case 4:
       
   728         return (c << 4) | c;
       
   729     case 2:
       
   730         return c | (c << 2) | (c << 4) | (c << 6);
       
   731     default:
       
   732         RI_ASSERT(srcBits == 1);
       
   733         if (c) return 0xff;
       
   734         return 0;
       
   735     }
       
   736 }
       
   737 
       
   738 /**
       
   739  * \brief   Expands integer color representation to internal format (8-bits per component atm.).
       
   740  * \todo    Do nothing when bits == 8.
       
   741  */
       
   742 RI_INLINE void IntegerColor::expandColor(const Color::Descriptor& desc)
       
   743 {
       
   744     if (desc.luminanceBits)
       
   745     {
       
   746         r = expandComponent(r, desc.luminanceBits);
       
   747         g = b = r;
       
   748         a = 255;
       
   749     } else
       
   750     {
       
   751         if (desc.redBits < 8 || desc.luminanceBits < 8)
       
   752             r = expandComponent(r, desc.redBits);
       
   753         if (desc.greenBits < 8)
       
   754             g = expandComponent(g, desc.greenBits);
       
   755         if (desc.blueBits < 8)
       
   756             b = expandComponent(b, desc.blueBits);
       
   757     }
       
   758 
       
   759     if (desc.alphaBits && desc.alphaBits < 8)
       
   760         a = expandComponent(a, desc.alphaBits);
       
   761 
       
   762     if (desc.isAlphaOnly())
       
   763     {
       
   764         if (!desc.isPremultiplied())
       
   765             r = g = b = 255;
       
   766         else
       
   767             r = g = b = a;
       
   768     }
       
   769 }
       
   770 
       
   771 /**
       
   772  * \brief   Convert IntegerColor components to destination bitdepth (from internal) by
       
   773  *          shifting. Rounding does not take place.
       
   774  */
       
   775 RI_INLINE void IntegerColor::truncateColor(const Color::Descriptor& desc)
       
   776 {
       
   777     if (desc.luminanceBits)
       
   778     {
       
   779         RI_ASSERT(desc.redBits == 0 && desc.greenBits == 0 && desc.blueBits == 0);
       
   780         if (desc.luminanceBits == 1)
       
   781         {
       
   782             // Round the 1-bit case a bit better?
       
   783             r = (r + 128)>>8;
       
   784         } else if (desc.luminanceBits < 8)
       
   785             r >>= (8 - desc.luminanceBits);
       
   786     }
       
   787     else
       
   788     {
       
   789         if (desc.redBits < 8)
       
   790             r >>= (8 - desc.redBits);
       
   791         if (desc.greenBits < 8)
       
   792             g >>= (8 - desc.greenBits);
       
   793         if (desc.blueBits < 8)
       
   794             b >>= (8 - desc.blueBits);
       
   795     }
       
   796 
       
   797     if (desc.alphaBits < 8)
       
   798     {
       
   799         if (desc.alphaBits == 1)
       
   800             a = (a+128)>>8;
       
   801         else
       
   802             a >>= (8 - desc.alphaBits);
       
   803     }
       
   804 }
       
   805 
       
   806 RI_INLINE void IntegerColor::truncateMask(const Color::Descriptor& desc)
       
   807 {
       
   808     if (desc.redBits < 8 || desc.luminanceBits < 8)
       
   809         r >>= (8 - desc.maskBits);
       
   810     if (desc.greenBits < 8)
       
   811         g >>= (8 - desc.maskBits);
       
   812     if (desc.blueBits < 8)
       
   813         b >>= (8 - desc.maskBits);
       
   814     if (desc.alphaBits < 8)
       
   815         a >>= (8 - desc.maskBits);
       
   816 }
       
   817 
       
   818 RI_INLINE void IntegerColor::clampToAlpha()
       
   819 {
       
   820     if (r > a) r = a;
       
   821     if (g > a) g = a;
       
   822     if (b > a) b = a;
       
   823 }
       
   824 
       
   825 RI_INLINE void IntegerColor::fromPackedMask(RIuint32 packedMask, const Color::Descriptor& desc)
       
   826 {
       
   827     RI_ASSERT(desc.maskBits);
       
   828     a = (packedMask >> desc.maskShift) & ((1u << desc.maskBits)-1);
       
   829 }
       
   830 
       
   831 RI_INLINE void IntegerColor::expandMask(const Color::Descriptor& desc)
       
   832 {
       
   833     a = expandComponent(a, desc.maskBits);
       
   834     r = g = b = a;
       
   835 }
       
   836 
       
   837 #if 0
       
   838 RI_INLINE void IntegerColor::truncateMask(const Color::Descriptor& desc)
       
   839 {
       
   840     a >>= (8 - desc.maskBits);
       
   841 }
       
   842 #endif
       
   843 
       
   844 RI_INLINE void IntegerColor::fullLuminanceToRGB(bool premultipliedIn, bool gammaIn, bool premultipliedOut, bool gammaOut)
       
   845 {
       
   846     if (premultipliedIn)
       
   847         unpremultiply();
       
   848 
       
   849     luminanceToRGB();
       
   850 
       
   851     if (gammaIn != gammaOut)
       
   852     {
       
   853         if (gammaIn)
       
   854             gammaToLinear();
       
   855         else
       
   856             linearToGamma();
       
   857     }
       
   858 
       
   859     if (premultipliedOut)
       
   860         premultiply();
       
   861 
       
   862 }
       
   863 
       
   864 RI_INLINE void IntegerColor::fullRGBToLuminance(bool premultipliedIn, bool gammaIn, bool premultipliedOut, bool gammaOut)
       
   865 {
       
   866     if (premultipliedIn)
       
   867         unpremultiply();
       
   868 
       
   869     if (gammaIn)
       
   870         gammaToLinear();
       
   871 
       
   872     rgbToLuminance();
       
   873 
       
   874     if (gammaOut)
       
   875         linearToGamma();
       
   876 
       
   877     if (premultipliedOut)
       
   878         premultiply();
       
   879 
       
   880 }
       
   881 
       
   882 
       
   883 // \todo This should not be needed (only r-channel is used anyway)
       
   884 RI_INLINE void IntegerColor::luminanceToRGB()
       
   885 {
       
   886     g = b = r;
       
   887 }
       
   888 
       
   889 // \todo Only write to R!
       
   890 RI_INLINE void IntegerColor::rgbToLuminance()
       
   891 {
       
   892     enum { Rx = 871, Gx = 2929, Bx = 296, Bits = 12 };
       
   893     //enum { Rx = 54, Gx = 183, Bx = 18, Bits = 8 };
       
   894     RIuint32 l = Rx * r + Gx * g + Bx * b;
       
   895     r = g = b = l >> Bits;
       
   896 }
       
   897 
       
   898 #if 0
       
   899 RI_INLINE void IntegerColor::convertFromInternal(const Color::Descriptor& dst)
       
   900 {
       
   901 }
       
   902 #endif
       
   903 
       
   904 /**
       
   905  * \brief   Convert color from one format to another using integer operations.
       
   906  * \note    Currently expands the color to intermediate format first (8 bits
       
   907  *          per component.
       
   908  */
       
   909 RI_INLINE void IntegerColor::convertToFrom(const Color::Descriptor& dst, const Color::Descriptor& src, bool srcIsMask)
       
   910 {
       
   911     if (src.isZeroConversion(dst))
       
   912         return;
       
   913 
       
   914     if (src.isShiftConversionToLower(dst))
       
   915     {
       
   916         if (dst.luminanceBits)
       
   917         {
       
   918             if (dst.luminanceBits == 1)
       
   919             {
       
   920                 RI_ASSERT(src.luminanceBits == 8);
       
   921                 r = (r + 128)>>8;
       
   922             }
       
   923             else
       
   924                 r = r >> (src.luminanceBits - dst.luminanceBits);
       
   925         } else
       
   926         {
       
   927             r = r >> (src.redBits - dst.redBits);
       
   928             g = g >> (src.greenBits - dst.greenBits);
       
   929             b = b >> (src.blueBits - dst.blueBits);
       
   930         }
       
   931         if (dst.alphaBits)
       
   932         {
       
   933                 //a = (a+128)>>8;
       
   934             if (dst.alphaBits == 1)
       
   935                 a = (a+(1<<(src.alphaBits-1)))>>src.alphaBits;
       
   936             else
       
   937                 a = a >> (src.alphaBits - dst.alphaBits);
       
   938         }
       
   939 
       
   940         return;
       
   941     }
       
   942 
       
   943     if (!srcIsMask)
       
   944         expandColor(src);
       
   945     else
       
   946         expandMask(src);
       
   947 
       
   948 
       
   949     if (dst.isLuminance() != src.isLuminance())
       
   950     {
       
   951         if (src.isLuminance())
       
   952             fullLuminanceToRGB(src.isPremultiplied(), src.isNonlinear(), dst.isPremultiplied(), dst.isNonlinear());
       
   953         else
       
   954             fullRGBToLuminance(src.isPremultiplied(), src.isNonlinear(), dst.isPremultiplied(), dst.isNonlinear());
       
   955     }
       
   956     else if (dst.isNonlinear() != src.isNonlinear())
       
   957     {
       
   958         // No luminance/rgb change.
       
   959         // Change of gamma requires unpremultiplication:
       
   960         if (src.isPremultiplied() && !(src.isAlphaOnly()))
       
   961             unpremultiply();
       
   962 
       
   963         if (src.isNonlinear())
       
   964             gammaToLinear(src.isLuminance());
       
   965         else
       
   966             linearToGamma(src.isLuminance());
       
   967 
       
   968         if (dst.isPremultiplied() && !(dst.isAlphaOnly()))
       
   969             premultiply();
       
   970     }
       
   971     else
       
   972     if ((dst.isPremultiplied() != src.isPremultiplied()) && !(dst.isAlphaOnly() || dst.isAlphaOnly()))
       
   973     {
       
   974         // \todo Make sure non-alpha formats are properly handled.
       
   975         if (src.isPremultiplied())
       
   976             unpremultiply(dst.isLuminance());
       
   977         else
       
   978             premultiply(dst.isLuminance());
       
   979     }
       
   980 
       
   981     truncateColor(dst);
       
   982 }
       
   983 
       
   984 //==============================================================================================
       
   985 
       
   986 /*-------------------------------------------------------------------*//*!
       
   987 * \brief	Storage and operations for VGImage.
       
   988 * \param
       
   989 * \return
       
   990 * \note
       
   991 *//*-------------------------------------------------------------------*/
       
   992 
       
   993 class Surface;
       
   994 class Image
       
   995 {
       
   996 public:
       
   997     Image(const Color::Descriptor& desc, int width, int height, VGbitfield allowedQuality);	//throws bad_alloc
       
   998     //use data from a memory buffer. NOTE: data is not copied, so it is user's responsibility to make sure the data remains valid while the Image is in use.
       
   999     Image(const Color::Descriptor& desc, int width, int height, int stride, RIuint8* data);	//throws bad_alloc
       
  1000     //child image constructor
       
  1001     Image(Image* parent, int x, int y, int width, int height);	//throws bad_alloc
       
  1002     ~Image();
       
  1003 
       
  1004     const Color::Descriptor&	getDescriptor() const		{ return m_desc; }
       
  1005     int					getWidth() const					{ return m_width; }
       
  1006     int					getHeight() const					{ return m_height; }
       
  1007     int					getStride() const					{ return m_stride; }
       
  1008     Image*				getParent() const					{ return m_parent; }
       
  1009     VGbitfield			getAllowedQuality() const			{ return m_allowedQuality; }
       
  1010     void				addInUse()							{ m_inUse++; }
       
  1011     void				removeInUse()						{ RI_ASSERT(m_inUse > 0); m_inUse--; }
       
  1012     int					isInUse() const						{ return m_inUse; }
       
  1013     RIuint8*			getData() const						{ return m_data; }
       
  1014     void				addReference()						{ m_referenceCount++; }
       
  1015     int					removeReference()					{ m_referenceCount--; RI_ASSERT(m_referenceCount >= 0); return m_referenceCount; }
       
  1016     bool				overlaps(const Image* src) const;
       
  1017     void                setUnsafe(bool unsafe) { if (unsafe && m_desc.maybeUnsafe()) m_unsafeData = unsafe; else m_unsafeData = false; }
       
  1018     bool                isUnsafe() const { return m_unsafeData; }
       
  1019 
       
  1020     void				clear(const Color& clearColor, int x, int y, int w, int h);
       
  1021     void				blit(VGContext* context, const Image* src, int sx, int sy, int dx, int dy, int w, int h, Array<Rectangle>* scissors = NULL, bool dither = false);	//throws bad_alloc
       
  1022 
       
  1023     RI_INLINE static const void* incrementPointer(const void* ptr, int bpp, RIint32 x);
       
  1024     RI_INLINE static void* calculateAddress(const void* basePtr, int bpp, int x, int y, int stride);
       
  1025 
       
  1026     static RI_INLINE RIuint32   readPackedPixelFromAddress(const void *ptr, int bpp, int x);
       
  1027     static RI_INLINE void       writePackedPixelToAddress(void* ptr, int bpp, int x, RIuint32 packedColor);
       
  1028 
       
  1029     RI_INLINE RIuint32 			readPackedPixel(int x, int y) const;
       
  1030     Color				readPixel(int x, int y) const;
       
  1031     RI_INLINE void      writePackedPixelToAddress(void* ptr, int x, RIuint32 packedColor);
       
  1032     void				writePackedPixel(int x, int y, RIuint32 packedColor);
       
  1033     void				writePixel(int x, int y, const Color& c);
       
  1034 
       
  1035     void                fillPacked(RIuint32 packedColor);
       
  1036 
       
  1037     static RI_INLINE void   fillPackedPixels(void* data, int bpp, int x, int y, int stride, int nPixels, RIuint32 packedColor);
       
  1038     RI_INLINE void		    fillPackedPixels(int x, int y, int nPixels, RIuint32 packedColor);
       
  1039     RI_INLINE void          fillPackedRectangle(int x0, int y0, int width, int height, RIuint32 packedColor);
       
  1040 
       
  1041     void				writeFilteredPixel(int x, int y, const Color& c, VGbitfield channelMask);
       
  1042 
       
  1043     RIfloat				readMaskPixel(int x, int y) const;		//can read any image format
       
  1044     void				writeMaskPixel(int x, int y, RIfloat m);	//can write only to VG_A_x
       
  1045 
       
  1046     Color				resample(RIfloat x, RIfloat y, const Matrix3x3& surfaceToImage, VGImageQuality quality, VGTilingMode tilingMode, const Color& tileFillColor);	//throws bad_alloc
       
  1047     void				makeMipMaps();	//throws bad_alloc
       
  1048 
       
  1049     void				colorMatrix(const Image& src, const RIfloat* matrix, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask);
       
  1050     void				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);
       
  1051     void				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);
       
  1052     void				gaussianBlur(const Image& src, RIfloat stdDeviationX, RIfloat stdDeviationY, VGTilingMode tilingMode, const Color& edgeFillColor, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask);
       
  1053     void				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);
       
  1054     void				lookupSingle(const Image& src, const RIuint32 * lookupTable, VGImageChannel sourceChannel, bool outputLinear, bool outputPremultiplied, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask);
       
  1055 
       
  1056     RI_INLINE static int descriptorToStride(const Color::Descriptor& desc, int width) { return (width*desc.bitsPerPixel+7)/8; };
       
  1057 
       
  1058     void getStorageOffset(int& x, int& y) const { x = m_storageOffsetX; y = m_storageOffsetY; }
       
  1059 
       
  1060 private:
       
  1061     Image(const Image&);					//!< Not allowed.
       
  1062     void operator=(const Image&);			//!< Not allowed.
       
  1063 
       
  1064 #if defined(RI_DEBUG)
       
  1065     bool                ptrInImage(const void* ptr) const;
       
  1066 #endif
       
  1067     Color				readTexel(int u, int v, int level, VGTilingMode tilingMode, const Color& tileFillColor) const;
       
  1068 
       
  1069     Color::Descriptor	m_desc;
       
  1070     int					m_width;
       
  1071     int					m_height;
       
  1072     VGbitfield			m_allowedQuality;
       
  1073     int					m_inUse;
       
  1074     int					m_stride;
       
  1075     RIuint8*			m_data;
       
  1076     int					m_referenceCount;
       
  1077     bool				m_ownsData;
       
  1078     Image*				m_parent;
       
  1079     int					m_storageOffsetX;
       
  1080     int					m_storageOffsetY;
       
  1081     bool                m_unsafeData; // Data may contain incorrect pixel data
       
  1082 
       
  1083 #ifndef RI_COMPILE_LLVM_BYTECODE
       
  1084 
       
  1085 #endif /* RI_COMPILE_LLVM_BYTECODE */
       
  1086 };
       
  1087 
       
  1088 #if defined(RI_DEBUG)
       
  1089 RI_INLINE bool Image::ptrInImage(const void* ptr) const
       
  1090 {
       
  1091     RIuint8* p = (RIuint8*)ptr;
       
  1092 
       
  1093     if (p < m_data) return false;
       
  1094     if (p >= (m_data + m_height * m_stride)) return false;
       
  1095     return true;
       
  1096 }
       
  1097 #endif
       
  1098 
       
  1099 RI_INLINE const void* Image::incrementPointer(const void* ptr, int bpp, int x)
       
  1100 {
       
  1101     if (bpp >= 8)
       
  1102         return (((RIuint8*)ptr) + (bpp >> 3));
       
  1103     // Increment the pointer only when the byte is actually about to change.
       
  1104     int mask;
       
  1105     if (bpp == 4)
       
  1106         mask = 1;
       
  1107     else if (bpp == 2)
       
  1108         mask = 3;
       
  1109     else
       
  1110         mask = 7;
       
  1111     if ((x & mask) == mask)
       
  1112         return ((RIuint8*)ptr + 1);
       
  1113     return ptr;
       
  1114 }
       
  1115 
       
  1116 RI_INLINE void* Image::calculateAddress(const void* basePtr, int bpp, int x, int y, int stride)
       
  1117 {
       
  1118     if (bpp >= 8)
       
  1119     {
       
  1120         return (void*)((RIuint8*)basePtr + y * stride + x * (bpp >> 3));
       
  1121     } else
       
  1122     {
       
  1123         // 4, 2, or 1 bits per pixel
       
  1124         RI_ASSERT(bpp == 4 || bpp == 2 || bpp == 1);
       
  1125         return (void*)((RIuint8*)basePtr + y * stride + ((x * bpp) >> 3));
       
  1126     }
       
  1127 }
       
  1128 
       
  1129 RI_INLINE RIuint32 Image::readPackedPixel(int x, int y) const
       
  1130 {
       
  1131     RI_ASSERT(m_data);
       
  1132     RI_ASSERT(x >= 0 && x < m_width);
       
  1133     RI_ASSERT(y >= 0 && y < m_height);
       
  1134     RI_ASSERT(m_referenceCount > 0);
       
  1135 
       
  1136     RIuint32 p = 0;
       
  1137 
       
  1138     void* ptr = Image::calculateAddress(m_data, m_desc.bitsPerPixel, x+m_storageOffsetX, y+m_storageOffsetY, m_stride);
       
  1139     p = readPackedPixelFromAddress(ptr, m_desc.bitsPerPixel, x+m_storageOffsetX);
       
  1140 
       
  1141     return p;
       
  1142 }
       
  1143 
       
  1144 
       
  1145 RI_INLINE void Image::writePackedPixelToAddress(void* ptr, int bpp, int x, RIuint32 packedColor)
       
  1146 {
       
  1147     // \note packedColor must contain the whole data (including < 8 bpp data)?
       
  1148     switch(bpp)
       
  1149     {
       
  1150     case 32:
       
  1151     {
       
  1152         RIuint32* s = ((RIuint32*)ptr);
       
  1153         *s = (RIuint32)packedColor;
       
  1154         break;
       
  1155     }
       
  1156 
       
  1157     case 16:
       
  1158     {
       
  1159         RIuint16* s = ((RIuint16*)ptr);
       
  1160         *s = (RIuint16)packedColor;
       
  1161         break;
       
  1162     }
       
  1163 
       
  1164     case 8:
       
  1165     {
       
  1166         RIuint8* s = ((RIuint8*)ptr);
       
  1167         *s = (RIuint8)packedColor;
       
  1168         break;
       
  1169     }
       
  1170     case 4:
       
  1171     {
       
  1172         RIuint8* s = ((RIuint8*)ptr);
       
  1173         *s = (RIuint8)((packedColor << ((x&1)<<2)) | ((unsigned int)*s & ~(0xf << ((x&1)<<2))));
       
  1174         break;
       
  1175     }
       
  1176 
       
  1177     case 2:
       
  1178     {
       
  1179         RIuint8* s = ((RIuint8*)ptr);
       
  1180         *s = (RIuint8)((packedColor << ((x&3)<<1)) | ((unsigned int)*s & ~(0x3 << ((x&3)<<1))));
       
  1181         break;
       
  1182     }
       
  1183 
       
  1184     default:
       
  1185     {
       
  1186         RI_ASSERT(bpp == 1);
       
  1187         RIuint8* s = ((RIuint8*)ptr);
       
  1188         *s = (RIuint8)((packedColor << (x&7)) | ((unsigned int)*s & ~(0x1 << (x&7))));
       
  1189         break;
       
  1190     }
       
  1191     }
       
  1192     // m_mipmapsValid = false; // \note Will never do this, must be handled outside this class somehow!
       
  1193 }
       
  1194 
       
  1195 /**
       
  1196  * \brief   Write packed pixel into address.
       
  1197  * \param   x   Which x-coordinate (starting from the start of the scanline
       
  1198  *              pointed to) is addressed? This is only required for formats
       
  1199  *              that have less than 8 bpp.
       
  1200  */
       
  1201 void Image::writePackedPixelToAddress(void* address, int x, RIuint32 packedColor)
       
  1202 {
       
  1203     writePackedPixelToAddress(address, m_desc.bitsPerPixel, x, packedColor);
       
  1204 }
       
  1205 
       
  1206 /**
       
  1207  * \brief   Read a packed pixel from a given address. Notice the use of param x!
       
  1208  * \param   x   Check which part of byte to return if bpp < 8
       
  1209  */
       
  1210 RI_INLINE RIuint32 Image::readPackedPixelFromAddress(const void *ptr, int bpp, int x)
       
  1211 {
       
  1212     switch(bpp)
       
  1213     {
       
  1214     case 32:
       
  1215     {
       
  1216         RIuint32* s = (RIuint32*)ptr;
       
  1217         return *s;
       
  1218     }
       
  1219 
       
  1220     case 16:
       
  1221     {
       
  1222         RIuint16* s = (RIuint16*)ptr;
       
  1223         return (RIuint32)*s;
       
  1224     }
       
  1225 
       
  1226     case 8:
       
  1227     {
       
  1228         RIuint8* s = (RIuint8*)ptr;
       
  1229         return (RIuint32)*s;
       
  1230     }
       
  1231     case 4:
       
  1232     {
       
  1233         RIuint8* s = ((RIuint8*)ptr);
       
  1234         return (RIuint32)(*s >> ((x&1)<<2)) & 0xf;
       
  1235     }
       
  1236 
       
  1237     case 2:
       
  1238     {
       
  1239         RIuint8* s = ((RIuint8*)ptr);
       
  1240         return (RIuint32)(*s >> ((x&3)<<1)) & 0x3;
       
  1241     }
       
  1242 
       
  1243     default:
       
  1244     {
       
  1245         RI_ASSERT(bpp == 1);
       
  1246         RIuint8* s = ((RIuint8*)ptr);
       
  1247         return (RIuint32)(*s >> (x&7)) & 0x1;
       
  1248     }
       
  1249     }
       
  1250 }
       
  1251 
       
  1252 RI_INLINE void Image::writePackedPixel(int x, int y, RIuint32 packedColor)
       
  1253 {
       
  1254     RI_ASSERT(m_data);
       
  1255     RI_ASSERT(x >= 0 && x < m_width);
       
  1256     RI_ASSERT(y >= 0 && y < m_height);
       
  1257     RI_ASSERT(m_referenceCount > 0);
       
  1258 
       
  1259     x += m_storageOffsetX;
       
  1260     y += m_storageOffsetY;
       
  1261 
       
  1262     RIuint8* scanline = m_data + y * m_stride;
       
  1263     switch(m_desc.bitsPerPixel)
       
  1264     {
       
  1265     case 32:
       
  1266     {
       
  1267         RIuint32* s = ((RIuint32*)scanline) + x;
       
  1268         *s = (RIuint32)packedColor;
       
  1269         break;
       
  1270     }
       
  1271 
       
  1272     case 16:
       
  1273     {
       
  1274         RIuint16* s = ((RIuint16*)scanline) + x;
       
  1275         *s = (RIuint16)packedColor;
       
  1276         break;
       
  1277     }
       
  1278 
       
  1279     case 8:
       
  1280     {
       
  1281         RIuint8* s = ((RIuint8*)scanline) + x;
       
  1282         *s = (RIuint8)packedColor;
       
  1283         break;
       
  1284     }
       
  1285     case 4:
       
  1286     {
       
  1287         RIuint8* s = ((RIuint8*)scanline) + (x>>1);
       
  1288         *s = (RIuint8)((packedColor << ((x&1)<<2)) | ((unsigned int)*s & ~(0xf << ((x&1)<<2))));
       
  1289         break;
       
  1290     }
       
  1291 
       
  1292     case 2:
       
  1293     {
       
  1294         RIuint8* s = ((RIuint8*)scanline) + (x>>2);
       
  1295         *s = (RIuint8)((packedColor << ((x&3)<<1)) | ((unsigned int)*s & ~(0x3 << ((x&3)<<1))));
       
  1296         break;
       
  1297     }
       
  1298 
       
  1299     default:
       
  1300     {
       
  1301         RI_ASSERT(m_desc.bitsPerPixel == 1);
       
  1302         RIuint8* s = ((RIuint8*)scanline) + (x>>3);
       
  1303         *s = (RIuint8)((packedColor << (x&7)) | ((unsigned int)*s & ~(0x1 << (x&7))));
       
  1304         break;
       
  1305     }
       
  1306     }
       
  1307     //m_mipmapsValid = false;
       
  1308 }
       
  1309 
       
  1310 
       
  1311 /**
       
  1312  * \brief   Unsafe static method for setting image pixels
       
  1313  */
       
  1314 RI_INLINE void Image::fillPackedPixels(void* data, int bpp, int x, int y, int stride, int nPixels, RIuint32 packedColor)
       
  1315 {
       
  1316     RI_ASSERT(nPixels > 0);
       
  1317     RI_ASSERT(data);
       
  1318 
       
  1319     RIuint8* scanline = (RIuint8*)data + y * stride;
       
  1320 
       
  1321     switch(bpp)
       
  1322     {
       
  1323     case 32:
       
  1324     {
       
  1325         RIuint32* s = ((RIuint32*)scanline) + x;
       
  1326 
       
  1327         for (int i = 0; i < nPixels; i++)
       
  1328             s[i] = packedColor;
       
  1329 
       
  1330         break;
       
  1331     }
       
  1332 
       
  1333     case 16:
       
  1334     {
       
  1335         RIuint16* s = ((RIuint16*)scanline) + x;
       
  1336 
       
  1337         for (int i = 0; i < nPixels; i++)
       
  1338             s[i] = (RIuint16)packedColor;
       
  1339 
       
  1340         break;
       
  1341     }
       
  1342 
       
  1343     case 8:
       
  1344     {
       
  1345         RIuint8* s = ((RIuint8*)scanline) + x;
       
  1346 
       
  1347         for (int i = 0; i < nPixels; i++)
       
  1348             s[i] = (RIuint8)packedColor;
       
  1349 
       
  1350         break;
       
  1351     }
       
  1352     case 4:
       
  1353     {
       
  1354         //RI_ASSERT((packedColor & 0xf) == 0);
       
  1355         //packedColor &= 0xf;
       
  1356         RIuint8* s = ((RIuint8*)scanline) + (x>>1);
       
  1357         if (x & 1)
       
  1358         {
       
  1359             *s = (RIuint8)((packedColor << ((x&1)<<2)) | ((unsigned int)*s & ~(0xf << ((x&1)<<2))));
       
  1360             s++;
       
  1361             x++;
       
  1362             nPixels--;
       
  1363         }
       
  1364         RI_ASSERT(!(x&1));
       
  1365 
       
  1366         int c = nPixels / 2;
       
  1367         RIuint8 bytePacked = packedColor | (packedColor << 4);
       
  1368         while (c)
       
  1369         {
       
  1370             *s++ = bytePacked;
       
  1371             c--;
       
  1372             x+=2;
       
  1373         }
       
  1374         nPixels &= 1;
       
  1375 
       
  1376         if (nPixels)
       
  1377         {
       
  1378             *s = (RIuint8)((packedColor << ((x&1)<<2)) | ((unsigned int)*s & ~(0xf << ((x&1)<<2))));
       
  1379             s++;
       
  1380             x++;
       
  1381             nPixels--;
       
  1382         }
       
  1383         RI_ASSERT(nPixels == 0);
       
  1384         break;
       
  1385     }
       
  1386 
       
  1387     case 2:
       
  1388     {
       
  1389         // This case should not be needed!
       
  1390         RI_ASSERT(false);
       
  1391         RIuint8* s = ((RIuint8*)scanline) + (x>>2);
       
  1392         *s = (RIuint8)((packedColor << ((x&3)<<1)) | ((unsigned int)*s & ~(0x3 << ((x&3)<<1))));
       
  1393         break;
       
  1394     }
       
  1395 
       
  1396     default:
       
  1397     {
       
  1398         RI_ASSERT(bpp == 1);
       
  1399         RIuint8* s = ((RIuint8*)scanline) + (x>>3);
       
  1400         // \todo Get this as input instead?
       
  1401         RI_ASSERT(packedColor == 1 || packedColor == 0);
       
  1402         RIuint8 fullyPacked = (RIuint8)(-(RIint8)packedColor);
       
  1403 
       
  1404         if (x & 7)
       
  1405         {
       
  1406             // Handle the first byte:
       
  1407             RIuint8 o = *s;
       
  1408             int a = x&7;
       
  1409             RI_ASSERT(a>=1);
       
  1410             int b = RI_INT_MIN(a + nPixels, 8);
       
  1411             RI_ASSERT(b > a);
       
  1412             RIuint8 emask = (1u << b)-1;
       
  1413             RIuint8 mask = (0xffu<<a) & emask;
       
  1414             RI_ASSERT(mask>0);
       
  1415             RI_ASSERT(mask<=254);
       
  1416             *s++ = (o&(~mask))|(fullyPacked & mask);
       
  1417             nPixels -= 8-(x&7);
       
  1418             x += 8-(x&7);
       
  1419         }
       
  1420 
       
  1421         if (nPixels < 0)
       
  1422             return;
       
  1423 
       
  1424         RI_ASSERT(!(x&1));
       
  1425 
       
  1426         int c = nPixels/8;
       
  1427         while (c)
       
  1428         {
       
  1429             *s++ = fullyPacked;
       
  1430             c--;
       
  1431             x+=8;
       
  1432         }
       
  1433         nPixels -= ((nPixels/8) * 8);
       
  1434 
       
  1435 
       
  1436         if (nPixels)
       
  1437         {
       
  1438             RI_ASSERT((x&7) == 0);
       
  1439 
       
  1440             RIuint8 o = *s;
       
  1441             int b = nPixels;
       
  1442             RI_ASSERT(b<=7);
       
  1443             RIuint8 mask = (1u<<b)-1;
       
  1444             RI_ASSERT(mask <= 127);
       
  1445             *s++ = (o&(~mask))|(fullyPacked & mask);
       
  1446         }
       
  1447         break;
       
  1448     }
       
  1449     }
       
  1450     //m_mipmapsValid = false;
       
  1451 }
       
  1452 RI_INLINE void Image::fillPackedPixels(int x, int y, int nPixels, RIuint32 packedColor)
       
  1453 {
       
  1454     fillPackedPixels((void*)m_data, m_desc.bitsPerPixel, x + m_storageOffsetX, y + m_storageOffsetY, m_stride, nPixels, packedColor);
       
  1455 }
       
  1456 
       
  1457 RI_INLINE void Image::fillPackedRectangle(int x0, int y0, int width, int height, RIuint32 packedColor)
       
  1458 {
       
  1459     int y = y0;
       
  1460     while (height)
       
  1461     {
       
  1462         fillPackedPixels(x0, y, width, packedColor);
       
  1463         y++;
       
  1464         height--;
       
  1465     }
       
  1466 }
       
  1467 
       
  1468 /*-------------------------------------------------------------------*//*!
       
  1469 * \brief	Surface class abstracting multisampled rendering surface.
       
  1470 * \param
       
  1471 * \return
       
  1472 * \note
       
  1473 *//*-------------------------------------------------------------------*/
       
  1474 
       
  1475 class Surface
       
  1476 {
       
  1477 public:
       
  1478     Surface(const Color::Descriptor& desc, int width, int height, int numSamples);	//throws bad_alloc
       
  1479     Surface(Image* image);	//throws bad_alloc
       
  1480     Surface(const Color::Descriptor& desc, int width, int height, int stride, RIuint8* data);	//throws bad_alloc
       
  1481     ~Surface();
       
  1482 
       
  1483     RI_INLINE const Image* getImage() const {return m_image;}
       
  1484     RI_INLINE const Color::Descriptor&	getDescriptor() const		{ return m_image->getDescriptor(); }
       
  1485     RI_INLINE int		getWidth() const							{ return m_width; }
       
  1486     RI_INLINE int		getHeight() const							{ return m_height; }
       
  1487     RI_INLINE int		getNumSamples() const						{ return m_numSamples; }
       
  1488     RI_INLINE void		addReference()								{ m_referenceCount++; }
       
  1489     RI_INLINE int		removeReference()							{ m_referenceCount--; RI_ASSERT(m_referenceCount >= 0); return m_referenceCount; }
       
  1490     RI_INLINE int		isInUse() const								{ return m_image->isInUse(); }
       
  1491     RI_INLINE bool		isInUse(Image* image) const					{ return image == m_image ? true : false; }
       
  1492 
       
  1493     void				clear(const Color& clearColor, int x, int y, int w, int h, const Array<Rectangle>* scissors = NULL);
       
  1494 #if 0
       
  1495     // Currently does not support msaa surfaces
       
  1496     void				blit(const Image& src, int sx, int sy, int dx, int dy, int w, int h);	//throws bad_alloc
       
  1497     void				blit(const Image& src, int sx, int sy, int dx, int dy, int w, int h, const Array<Rectangle>& scissors);	//throws bad_alloc
       
  1498     void				blit(const Surface* src, int sx, int sy, int dx, int dy, int w, int h);	//throws bad_alloc
       
  1499     void				blit(const Surface* src, int sx, int sy, int dx, int dy, int w, int h, const Array<Rectangle>& scissors);	//throws bad_alloc
       
  1500 #endif
       
  1501     void				mask(DynamicBlitter& blitter, const Image* src, VGMaskOperation operation, int x, int y, int w, int h);
       
  1502 
       
  1503     RI_INLINE void      writePackedPixelToAddress(void* address, int x, RIuint32 p)        { m_image->writePackedPixelToAddress(address, x, p); }
       
  1504    RI_INLINE RIuint32 	readPackedSample(int x, int y, int sample) const			 { return m_image->readPackedPixel(x*m_numSamples+sample, y); }
       
  1505     RI_INLINE Color		readSample(int x, int y, int sample) const                   { return m_image->readPixel(x*m_numSamples+sample, y); }
       
  1506     RI_INLINE void		writePackedSample(int x, int y, int sample, RIuint32 p)		 { m_image->writePackedPixel(x*m_numSamples+sample, y, p); }
       
  1507     RI_INLINE void		writeSample(int x, int y, int sample, const Color& c)        { m_image->writePixel(x*m_numSamples+sample, y, c); }
       
  1508     RI_INLINE void		fillPackedSamples(int x, int y, int nPixels, RIuint32 p);
       
  1509 
       
  1510     RIfloat				readMaskCoverage(int x, int y) const;
       
  1511     void				writeMaskCoverage(int x, int y, RIfloat m);
       
  1512     unsigned int		readMaskMSAA(int x, int y) const;
       
  1513     void				writeMaskMSAA(int x, int y, unsigned int m);
       
  1514 
       
  1515     RIuint32 			FSAAResolvePacked(int x, int y) const;
       
  1516     Color				FSAAResolve(int x, int y) const;	//for fb=>img: vgGetPixels, vgReadPixels
       
  1517 
       
  1518 private:
       
  1519     Surface(const Surface&);			//!< Not allowed.
       
  1520     void operator=(const Surface&);			//!< Not allowed.
       
  1521 
       
  1522     struct ScissorEdge
       
  1523     {
       
  1524         ScissorEdge() : x(0), miny(0), maxy(0), direction(0) {}
       
  1525         bool operator<(const ScissorEdge& e) const	{ return x < e.x; }
       
  1526         int			x;
       
  1527         int			miny;
       
  1528         int			maxy;
       
  1529         int			direction;		//1 start, -1 end
       
  1530     };
       
  1531 
       
  1532     int				m_width;
       
  1533     int				m_height;
       
  1534     int				m_numSamples;
       
  1535     int				m_referenceCount;
       
  1536 
       
  1537 public:
       
  1538     // \todo TERO: Broke the design of this by making it public, make proper
       
  1539     // friend/etc. C++ accessor for optimized pixel-pipelines. Combine with the
       
  1540     // removal of (remnants of) the FSAA support.
       
  1541     Image*			m_image;
       
  1542 };
       
  1543 
       
  1544 RI_INLINE void Surface::fillPackedSamples(int x, int y, int nPixels, RIuint32 p)
       
  1545 {
       
  1546     m_image->fillPackedPixels(x, y, nPixels, p);
       
  1547 }
       
  1548 
       
  1549 
       
  1550 /*-------------------------------------------------------------------*//*!
       
  1551 * \brief	Drawable class for encapsulating color and mask buffers.
       
  1552 * \param
       
  1553 * \return
       
  1554 * \note
       
  1555 *//*-------------------------------------------------------------------*/
       
  1556 
       
  1557 class Drawable
       
  1558 {
       
  1559 public:
       
  1560     Drawable(const Color::Descriptor& desc, int width, int height, int numSamples, int maskBits);	//throws bad_alloc
       
  1561     Drawable(Image* image, int maskBits);	//throws bad_alloc
       
  1562     Drawable(const Color::Descriptor& desc, int width, int height, int stride, RIuint8* data, int maskBits);	//throws bad_alloc
       
  1563     ~Drawable();
       
  1564 
       
  1565     RI_INLINE const Color::Descriptor&	getDescriptor() const		{ return m_color->getDescriptor(); }
       
  1566     RI_INLINE int       getNumMaskBits() const                      { if(!m_mask) return 0; return m_mask->getDescriptor().alphaBits; }
       
  1567     RI_INLINE int		getWidth() const							{ return m_color->getWidth(); }
       
  1568     RI_INLINE int		getHeight() const							{ return m_color->getHeight(); }
       
  1569     RI_INLINE int		getNumSamples() const						{ return m_color->getNumSamples(); }
       
  1570     RI_INLINE void		addReference()								{ m_referenceCount++; }
       
  1571     RI_INLINE int		removeReference()							{ m_referenceCount--; RI_ASSERT(m_referenceCount >= 0); return m_referenceCount; }
       
  1572     RI_INLINE int		isInUse() const								{ return m_color->isInUse() || (m_mask && m_mask->isInUse()); }
       
  1573     RI_INLINE bool		isInUse(Image* image) const					{ return m_color->isInUse(image) || (m_mask && m_mask->isInUse(image)); }
       
  1574     RI_INLINE Surface*  getColorBuffer() const                      { return m_color; }
       
  1575     RI_INLINE Surface*  getMaskBuffer() const                       { return m_mask; }
       
  1576 
       
  1577     void				resize(VGContext* context, int newWidth, int newHeight);	//throws bad_alloc
       
  1578 private:
       
  1579     Drawable(const Drawable&);			//!< Not allowed.
       
  1580     void operator=(const Drawable&);	//!< Not allowed.
       
  1581 
       
  1582     int                 m_referenceCount;
       
  1583     Surface*			m_color;
       
  1584     Surface*            m_mask;
       
  1585 };
       
  1586 
       
  1587 //==============================================================================================
       
  1588 
       
  1589 }	//namespace OpenVGRI
       
  1590 
       
  1591 //==============================================================================================
       
  1592 
       
  1593 #endif /* __RIIMAGE_H */