|
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 * |
|
11 * Permission is hereby granted, free of charge, to any person obtaining a |
|
12 * copy of this software and /or associated documentation files |
|
13 * (the "Materials "), to deal in the Materials without restriction, |
|
14 * including without limitation the rights to use, copy, modify, merge, |
|
15 * publish, distribute, sublicense, and/or sell copies of the Materials, |
|
16 * and to permit persons to whom the Materials are furnished to do so, |
|
17 * subject to the following conditions: |
|
18 * |
|
19 * The above copyright notice and this permission notice shall be included |
|
20 * in all copies or substantial portions of the Materials. |
|
21 * |
|
22 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
23 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
25 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
26 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
27 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR |
|
28 * THE USE OR OTHER DEALINGS IN THE MATERIALS. |
|
29 * |
|
30 *//** |
|
31 * \file |
|
32 * \brief Color and Image classes. |
|
33 * \note |
|
34 *//*-------------------------------------------------------------------*/ |
|
35 |
|
36 #ifndef OPENVG_H |
|
37 #include "openvg.h" |
|
38 #endif |
|
39 |
|
40 #ifndef __RIMATH_H |
|
41 #include "riMath.h" |
|
42 #endif |
|
43 |
|
44 #ifndef __RIARRAY_H |
|
45 #include "riArray.h" |
|
46 #endif |
|
47 |
|
48 //============================================================================================== |
|
49 |
|
50 namespace OpenVGRI |
|
51 { |
|
52 |
|
53 /*-------------------------------------------------------------------*//*! |
|
54 * \brief A class representing rectangles. |
|
55 * \param |
|
56 * \return |
|
57 * \note |
|
58 *//*-------------------------------------------------------------------*/ |
|
59 |
|
60 class Rectangle |
|
61 { |
|
62 public: |
|
63 Rectangle() : x(0), y(0), width(0), height(0) {} |
|
64 Rectangle(int rx, int ry, int rw, int rh) : x(rx), y(ry), width(rw), height(rh) {} |
|
65 void intersect(const Rectangle& r) |
|
66 { |
|
67 if(width >= 0 && r.width >= 0 && height >= 0 && r.height >= 0) |
|
68 { |
|
69 int x1 = RI_INT_MIN(RI_INT_ADDSATURATE(x, width), RI_INT_ADDSATURATE(r.x, r.width)); |
|
70 x = RI_INT_MAX(x, r.x); |
|
71 width = RI_INT_MAX(x1 - x, 0); |
|
72 |
|
73 int y1 = RI_INT_MIN(RI_INT_ADDSATURATE(y, height), RI_INT_ADDSATURATE(r.y, r.height)); |
|
74 y = RI_INT_MAX(y, r.y); |
|
75 height = RI_INT_MAX(y1 - y, 0); |
|
76 } |
|
77 else |
|
78 { |
|
79 x = 0; |
|
80 y = 0; |
|
81 width = 0; |
|
82 height = 0; |
|
83 } |
|
84 } |
|
85 |
|
86 int x; |
|
87 int y; |
|
88 int width; |
|
89 int height; |
|
90 }; |
|
91 |
|
92 /*-------------------------------------------------------------------*//*! |
|
93 * \brief A class representing color for processing and converting it |
|
94 * to and from various surface formats. |
|
95 * \param |
|
96 * \return |
|
97 * \note |
|
98 *//*-------------------------------------------------------------------*/ |
|
99 |
|
100 class Color |
|
101 { |
|
102 public: |
|
103 enum InternalFormat |
|
104 { |
|
105 lRGBA = 0, |
|
106 sRGBA = 1, |
|
107 lRGBA_PRE = 2, |
|
108 sRGBA_PRE = 3, |
|
109 lLA = 4, |
|
110 sLA = 5, |
|
111 lLA_PRE = 6, |
|
112 sLA_PRE = 7 |
|
113 }; |
|
114 enum FormatBits |
|
115 { |
|
116 NONLINEAR = (1<<0), |
|
117 PREMULTIPLIED = (1<<1), |
|
118 LUMINANCE = (1<<2) |
|
119 }; |
|
120 class Descriptor |
|
121 { |
|
122 public: |
|
123 bool isNonlinear() const { return (internalFormat & NONLINEAR) ? true : false; } |
|
124 bool isPremultiplied() const { return (internalFormat & PREMULTIPLIED) ? true : false; } |
|
125 bool isLuminance() const { return (internalFormat & LUMINANCE) ? true : false; } |
|
126 bool isAlphaOnly() const { return (alphaBits && (redBits+greenBits+blueBits+luminanceBits) == 0) ? true : false; } |
|
127 |
|
128 int redBits; |
|
129 int redShift; |
|
130 int greenBits; |
|
131 int greenShift; |
|
132 int blueBits; |
|
133 int blueShift; |
|
134 int alphaBits; |
|
135 int alphaShift; |
|
136 int luminanceBits; |
|
137 int luminanceShift; |
|
138 VGImageFormat format; |
|
139 InternalFormat internalFormat; |
|
140 int bitsPerPixel; |
|
141 }; |
|
142 |
|
143 RI_INLINE Color() : r(0.0f), g(0.0f), b(0.0f), a(0.0f), m_format(lRGBA) {} |
|
144 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); } |
|
145 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); } |
|
146 RI_INLINE Color(const Color& c) : r(c.r), g(c.g), b(c.b), a(c.a), m_format(c.m_format) {} |
|
147 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; } |
|
148 RI_INLINE void operator*=(RIfloat f) { r *= f; g *= f; b *= f; a*= f; } |
|
149 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; } |
|
150 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; } |
|
151 |
|
152 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; } |
|
153 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; } |
|
154 void unpack(unsigned int inputData, const Descriptor& inputDesc); |
|
155 unsigned int pack(const Descriptor& outputDesc) const; |
|
156 RI_INLINE InternalFormat getInternalFormat() const { return m_format; } |
|
157 |
|
158 //clamps nonpremultiplied colors and alpha to [0,1] range, and premultiplied alpha to [0,1], colors to [0,a] |
|
159 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); } |
|
160 void convert(InternalFormat outputFormat); |
|
161 void premultiply() { if(!(m_format & PREMULTIPLIED)) { r *= a; g *= a; b *= a; m_format = (InternalFormat)(m_format | PREMULTIPLIED); } } |
|
162 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); } } |
|
163 void luminanceToRGB() { if(m_format & LUMINANCE) { RI_ASSERT(r == g && g == b); m_format = (InternalFormat)(m_format & ~LUMINANCE); } } |
|
164 |
|
165 bool isNonlinear() const { return (m_format & NONLINEAR) ? true : false; } |
|
166 bool isPremultiplied() const { return (m_format & PREMULTIPLIED) ? true : false; } |
|
167 bool isLuminance() const { return (m_format & LUMINANCE) ? true : false; } |
|
168 |
|
169 RI_INLINE void assertConsistency() const; |
|
170 |
|
171 static Descriptor formatToDescriptor(VGImageFormat format); |
|
172 static bool isValidDescriptor(const Descriptor& desc); |
|
173 |
|
174 RIfloat r; |
|
175 RIfloat g; |
|
176 RIfloat b; |
|
177 RIfloat a; |
|
178 private: |
|
179 InternalFormat m_format; |
|
180 }; |
|
181 |
|
182 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()); } |
|
183 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()); } |
|
184 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()); } |
|
185 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()); } |
|
186 RI_INLINE void Color::assertConsistency() const |
|
187 { |
|
188 RI_ASSERT(r >= 0.0f && r <= 1.0f); |
|
189 RI_ASSERT(g >= 0.0f && g <= 1.0f); |
|
190 RI_ASSERT(b >= 0.0f && b <= 1.0f); |
|
191 RI_ASSERT(a >= 0.0f && a <= 1.0f); |
|
192 RI_ASSERT(!isPremultiplied() || (r <= a && g <= a && b <= a)); //premultiplied colors must have color channels less than or equal to alpha |
|
193 RI_ASSERT((isLuminance() && r == g && r == b) || !isLuminance()); //if luminance, r=g=b |
|
194 } |
|
195 |
|
196 //============================================================================================== |
|
197 |
|
198 /*-------------------------------------------------------------------*//*! |
|
199 * \brief Storage and operations for VGImage. |
|
200 * \param |
|
201 * \return |
|
202 * \note |
|
203 *//*-------------------------------------------------------------------*/ |
|
204 |
|
205 class Surface; |
|
206 class Image |
|
207 { |
|
208 public: |
|
209 Image(const Color::Descriptor& desc, int width, int height, VGbitfield allowedQuality); //throws bad_alloc |
|
210 //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. |
|
211 Image(const Color::Descriptor& desc, int width, int height, int stride, RIuint8* data); //throws bad_alloc |
|
212 //child image constructor |
|
213 Image(Image* parent, int x, int y, int width, int height); //throws bad_alloc |
|
214 ~Image(); |
|
215 |
|
216 const Color::Descriptor& getDescriptor() const { return m_desc; } |
|
217 int getWidth() const { return m_width; } |
|
218 int getHeight() const { return m_height; } |
|
219 int getStride() const { return m_stride; } |
|
220 Image* getParent() const { return m_parent; } |
|
221 VGbitfield getAllowedQuality() const { return m_allowedQuality; } |
|
222 void addInUse() { m_inUse++; } |
|
223 void removeInUse() { RI_ASSERT(m_inUse > 0); m_inUse--; } |
|
224 int isInUse() const { return m_inUse; } |
|
225 RIuint8* getData() const { return m_data; } |
|
226 void addReference() { m_referenceCount++; } |
|
227 int removeReference() { m_referenceCount--; RI_ASSERT(m_referenceCount >= 0); return m_referenceCount; } |
|
228 bool overlaps(const Image* src) const; |
|
229 |
|
230 void clear(const Color& clearColor, int x, int y, int w, int h); |
|
231 void blit(const Image& src, int sx, int sy, int dx, int dy, int w, int h, bool dither); //throws bad_alloc |
|
232 void blit(const Surface* src, int sx, int sy, int dx, int dy, int w, int h); //throws bad_alloc |
|
233 |
|
234 Color readPixel(int x, int y) const; |
|
235 void writePixel(int x, int y, const Color& c); |
|
236 void writeFilteredPixel(int x, int y, const Color& c, VGbitfield channelMask); |
|
237 |
|
238 RIfloat readMaskPixel(int x, int y) const; //can read any image format |
|
239 void writeMaskPixel(int x, int y, RIfloat m); //can write only to VG_A_x |
|
240 |
|
241 Color resample(RIfloat x, RIfloat y, const Matrix3x3& surfaceToImage, VGImageQuality quality, VGTilingMode tilingMode, const Color& tileFillColor); //throws bad_alloc |
|
242 void makeMipMaps(); //throws bad_alloc |
|
243 |
|
244 void colorMatrix(const Image& src, const RIfloat* matrix, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask); |
|
245 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); |
|
246 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); |
|
247 void gaussianBlur(const Image& src, RIfloat stdDeviationX, RIfloat stdDeviationY, VGTilingMode tilingMode, const Color& edgeFillColor, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask); |
|
248 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); |
|
249 void lookupSingle(const Image& src, const RIuint32 * lookupTable, VGImageChannel sourceChannel, bool outputLinear, bool outputPremultiplied, bool filterFormatLinear, bool filterFormatPremultiplied, VGbitfield channelMask); |
|
250 private: |
|
251 Image(const Image&); //!< Not allowed. |
|
252 void operator=(const Image&); //!< Not allowed. |
|
253 |
|
254 Color readTexel(int u, int v, int level, VGTilingMode tilingMode, const Color& tileFillColor) const; |
|
255 |
|
256 Color::Descriptor m_desc; |
|
257 int m_width; |
|
258 int m_height; |
|
259 VGbitfield m_allowedQuality; |
|
260 int m_inUse; |
|
261 int m_stride; |
|
262 RIuint8* m_data; |
|
263 int m_referenceCount; |
|
264 bool m_ownsData; |
|
265 Image* m_parent; |
|
266 int m_storageOffsetX; |
|
267 int m_storageOffsetY; |
|
268 |
|
269 bool m_mipmapsValid; |
|
270 Array<Image*> m_mipmaps; |
|
271 }; |
|
272 |
|
273 /*-------------------------------------------------------------------*//*! |
|
274 * \brief Surface class abstracting multisampled rendering surface. |
|
275 * \param |
|
276 * \return |
|
277 * \note |
|
278 *//*-------------------------------------------------------------------*/ |
|
279 |
|
280 class Surface |
|
281 { |
|
282 public: |
|
283 Surface(const Color::Descriptor& desc, int width, int height, int numSamples); //throws bad_alloc |
|
284 Surface(Image* image); //throws bad_alloc |
|
285 Surface(const Color::Descriptor& desc, int width, int height, int stride, RIuint8* data); //throws bad_alloc |
|
286 ~Surface(); |
|
287 |
|
288 RI_INLINE const Color::Descriptor& getDescriptor() const { return m_image->getDescriptor(); } |
|
289 RI_INLINE int getWidth() const { return m_width; } |
|
290 RI_INLINE int getHeight() const { return m_height; } |
|
291 RI_INLINE int getNumSamples() const { return m_numSamples; } |
|
292 RI_INLINE void addReference() { m_referenceCount++; } |
|
293 RI_INLINE int removeReference() { m_referenceCount--; RI_ASSERT(m_referenceCount >= 0); return m_referenceCount; } |
|
294 RI_INLINE int isInUse() const { return m_image->isInUse(); } |
|
295 RI_INLINE bool isInUse(Image* image) const { return image == m_image ? true : false; } |
|
296 |
|
297 void clear(const Color& clearColor, int x, int y, int w, int h); |
|
298 void clear(const Color& clearColor, int x, int y, int w, int h, const Array<Rectangle>& scissors); |
|
299 void blit(const Image& src, int sx, int sy, int dx, int dy, int w, int h); //throws bad_alloc |
|
300 void blit(const Image& src, int sx, int sy, int dx, int dy, int w, int h, const Array<Rectangle>& scissors); //throws bad_alloc |
|
301 void blit(const Surface* src, int sx, int sy, int dx, int dy, int w, int h); //throws bad_alloc |
|
302 void blit(const Surface* src, int sx, int sy, int dx, int dy, int w, int h, const Array<Rectangle>& scissors); //throws bad_alloc |
|
303 void mask(const Image* src, VGMaskOperation operation, int x, int y, int w, int h); |
|
304 void mask(const Surface* src, VGMaskOperation operation, int x, int y, int w, int h); |
|
305 |
|
306 RI_INLINE Color readSample(int x, int y, int sample) const { return m_image->readPixel(x*m_numSamples+sample, y); } |
|
307 RI_INLINE void writeSample(int x, int y, int sample, const Color& c) { m_image->writePixel(x*m_numSamples+sample, y, c); } |
|
308 |
|
309 RIfloat readMaskCoverage(int x, int y) const; |
|
310 void writeMaskCoverage(int x, int y, RIfloat m); |
|
311 unsigned int readMaskMSAA(int x, int y) const; |
|
312 void writeMaskMSAA(int x, int y, unsigned int m); |
|
313 |
|
314 Color FSAAResolve(int x, int y) const; //for fb=>img: vgGetPixels, vgReadPixels |
|
315 private: |
|
316 Surface(const Surface&); //!< Not allowed. |
|
317 void operator=(const Surface&); //!< Not allowed. |
|
318 |
|
319 struct ScissorEdge |
|
320 { |
|
321 ScissorEdge() : x(0), miny(0), maxy(0), direction(0) {} |
|
322 bool operator<(const ScissorEdge& e) const { return x < e.x; } |
|
323 int x; |
|
324 int miny; |
|
325 int maxy; |
|
326 int direction; //1 start, -1 end |
|
327 }; |
|
328 |
|
329 int m_width; |
|
330 int m_height; |
|
331 int m_numSamples; |
|
332 int m_referenceCount; |
|
333 Image* m_image; |
|
334 }; |
|
335 |
|
336 /*-------------------------------------------------------------------*//*! |
|
337 * \brief Drawable class for encapsulating color and mask buffers. |
|
338 * \param |
|
339 * \return |
|
340 * \note |
|
341 *//*-------------------------------------------------------------------*/ |
|
342 |
|
343 class Drawable |
|
344 { |
|
345 public: |
|
346 Drawable(const Color::Descriptor& desc, int width, int height, int numSamples, int maskBits); //throws bad_alloc |
|
347 Drawable(Image* image, int maskBits); //throws bad_alloc |
|
348 Drawable(const Color::Descriptor& desc, int width, int height, int stride, RIuint8* data, int maskBits); //throws bad_alloc |
|
349 ~Drawable(); |
|
350 |
|
351 RI_INLINE const Color::Descriptor& getDescriptor() const { return m_color->getDescriptor(); } |
|
352 RI_INLINE int getNumMaskBits() const { if(!m_mask) return 0; return m_mask->getDescriptor().alphaBits; } |
|
353 RI_INLINE int getWidth() const { return m_color->getWidth(); } |
|
354 RI_INLINE int getHeight() const { return m_color->getHeight(); } |
|
355 RI_INLINE int getNumSamples() const { return m_color->getNumSamples(); } |
|
356 RI_INLINE void addReference() { m_referenceCount++; } |
|
357 RI_INLINE int removeReference() { m_referenceCount--; RI_ASSERT(m_referenceCount >= 0); return m_referenceCount; } |
|
358 RI_INLINE int isInUse() const { return m_color->isInUse() || (m_mask && m_mask->isInUse()); } |
|
359 RI_INLINE bool isInUse(Image* image) const { return m_color->isInUse(image) || (m_mask && m_mask->isInUse(image)); } |
|
360 RI_INLINE Surface* getColorBuffer() const { return m_color; } |
|
361 RI_INLINE Surface* getMaskBuffer() const { return m_mask; } |
|
362 |
|
363 void resize(int newWidth, int newHeight); //throws bad_alloc |
|
364 private: |
|
365 Drawable(const Drawable&); //!< Not allowed. |
|
366 void operator=(const Drawable&); //!< Not allowed. |
|
367 |
|
368 int m_referenceCount; |
|
369 Surface* m_color; |
|
370 Surface* m_mask; |
|
371 }; |
|
372 |
|
373 //============================================================================================== |
|
374 |
|
375 } //namespace OpenVGRI |
|
376 |
|
377 //============================================================================================== |
|
378 |
|
379 #endif /* __RIIMAGE_H */ |