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