|
1 /*------------------------------------------------------------------------ |
|
2 * |
|
3 * OpenVG 1.1 Reference Implementation |
|
4 * ----------------------------------- |
|
5 * |
|
6 * Copyright (c) 2007 The Khronos Group Inc. |
|
7 * Portions copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
8 * |
|
9 * Permission is hereby granted, free of charge, to any person obtaining a |
|
10 * copy of this software and /or associated documentation files |
|
11 * (the "Materials "), to deal in the Materials without restriction, |
|
12 * including without limitation the rights to use, copy, modify, merge, |
|
13 * publish, distribute, sublicense, and/or sell copies of the Materials, |
|
14 * and to permit persons to whom the Materials are furnished to do so, |
|
15 * subject to the following conditions: |
|
16 * |
|
17 * The above copyright notice and this permission notice shall be included |
|
18 * in all copies or substantial portions of the Materials. |
|
19 * |
|
20 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
23 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
24 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
25 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR |
|
26 * THE USE OR OTHER DEALINGS IN THE MATERIALS. |
|
27 * |
|
28 *//** |
|
29 * \file |
|
30 * \brief Implementation of Paint and pixel pipe functionality. |
|
31 * \note |
|
32 *//*-------------------------------------------------------------------*/ |
|
33 |
|
34 #ifndef __RIPIXELPIPE_H |
|
35 # include "riPixelPipe.h" |
|
36 #endif |
|
37 #ifndef __RIRASTERIZER_H |
|
38 # include "riRasterizer.h" |
|
39 #endif |
|
40 #ifndef __SFDYNAMICPIXELPIPE_H |
|
41 # include "sfDynamicPixelPipe.h" |
|
42 #endif |
|
43 #ifndef __SFCOMPILER_H |
|
44 # include "sfCompiler.h" |
|
45 #endif |
|
46 |
|
47 //============================================================================================== |
|
48 |
|
49 namespace OpenVGRI |
|
50 { |
|
51 |
|
52 /*-------------------------------------------------------------------*//*! |
|
53 * \brief Paint constructor. |
|
54 * \param |
|
55 * \return |
|
56 * \note |
|
57 *//*-------------------------------------------------------------------*/ |
|
58 |
|
59 Paint::Paint() : |
|
60 m_paintType(VG_PAINT_TYPE_COLOR), |
|
61 m_paintColor(0,0,0,1,Color::sRGBA_PRE), |
|
62 m_inputPaintColor(0,0,0,1,Color::sRGBA), |
|
63 m_colorRampSpreadMode(VG_COLOR_RAMP_SPREAD_PAD), |
|
64 m_colorRampStops(), |
|
65 m_inputColorRampStops(), |
|
66 m_colorRampPremultiplied(VG_TRUE), |
|
67 m_inputLinearGradientPoint0(0,0), |
|
68 m_inputLinearGradientPoint1(1,0), |
|
69 m_inputRadialGradientCenter(0,0), |
|
70 m_inputRadialGradientFocalPoint(0,0), |
|
71 m_inputRadialGradientRadius(1.0f), |
|
72 m_linearGradientPoint0(0,0), |
|
73 m_linearGradientPoint1(1,0), |
|
74 m_radialGradientCenter(0,0), |
|
75 m_radialGradientFocalPoint(0,0), |
|
76 m_radialGradientRadius(1.0f), |
|
77 m_patternTilingMode(VG_TILE_FILL), |
|
78 m_pattern(NULL), |
|
79 m_referenceCount(0), |
|
80 m_lutFormat((VGImageFormat)-1), |
|
81 m_gradientStopsChanged(true) |
|
82 { |
|
83 Paint::GradientStop gs; |
|
84 gs.offset = 0.0f; |
|
85 gs.color.set(0,0,0,1,Color::sRGBA); |
|
86 m_colorRampStops.push_back(gs); //throws bad_alloc |
|
87 gs.offset = 1.0f; |
|
88 gs.color.set(1,1,1,1,Color::sRGBA); |
|
89 m_colorRampStops.push_back(gs); //throws bad_alloc |
|
90 } |
|
91 |
|
92 /*-------------------------------------------------------------------*//*! |
|
93 * \brief Paint destructor. |
|
94 * \param |
|
95 * \return |
|
96 * \note |
|
97 *//*-------------------------------------------------------------------*/ |
|
98 |
|
99 Paint::~Paint() |
|
100 { |
|
101 RI_ASSERT(m_referenceCount == 0); |
|
102 if(m_pattern) |
|
103 { |
|
104 m_pattern->removeInUse(); |
|
105 if(!m_pattern->removeReference()) |
|
106 RI_DELETE(m_pattern); |
|
107 } |
|
108 } |
|
109 |
|
110 static Color readStopColor(const Array<Paint::GradientStop>& colorRampStops, int i, VGboolean colorRampPremultiplied) |
|
111 { |
|
112 RI_ASSERT(i >= 0 && i < colorRampStops.size()); |
|
113 Color c = colorRampStops[i].color; |
|
114 RI_ASSERT(c.getInternalFormat() == Color::sRGBA); |
|
115 if(colorRampPremultiplied) |
|
116 c.premultiply(); |
|
117 return c; |
|
118 } |
|
119 |
|
120 void Paint::setGradientStops(Array<GradientStop>& inputStops, Array<GradientStop>& stops) |
|
121 { |
|
122 m_colorRampStops.swap(stops); |
|
123 m_inputColorRampStops.swap(inputStops); |
|
124 m_gradientStopsChanged = true; |
|
125 } |
|
126 |
|
127 void Paint::setLinearGradient(const Vector2& p0, const Vector2& p1) |
|
128 { |
|
129 m_linearGradientPoint0 = p0; |
|
130 m_linearGradientPoint1 = p1; |
|
131 } |
|
132 |
|
133 void Paint::setRadialGradient(const Vector2& c, const Vector2& f, VGfloat r) |
|
134 { |
|
135 m_radialGradientCenter = c; |
|
136 m_radialGradientFocalPoint = f; |
|
137 m_radialGradientRadius = r; |
|
138 } |
|
139 |
|
140 bool Paint::linearDegenerate() const |
|
141 { |
|
142 return m_linearGradientPoint0 == m_linearGradientPoint1 ? true : false; |
|
143 } |
|
144 |
|
145 bool Paint::radialDegenerate() const |
|
146 { |
|
147 return m_radialGradientRadius == 0.0f ? true : false; |
|
148 } |
|
149 |
|
150 /** |
|
151 * \brief Returns either the VG_PAINT_COLOR, or evaluated gradient value when the |
|
152 * gradient is degenerate. |
|
153 */ |
|
154 Color Paint::getSolidColor() const |
|
155 { |
|
156 if (m_paintType == VG_PAINT_TYPE_PATTERN) |
|
157 { |
|
158 RI_ASSERT(m_pattern == NULL); |
|
159 return m_paintColor; |
|
160 } |
|
161 |
|
162 if (m_paintType == VG_PAINT_TYPE_COLOR) |
|
163 return m_paintColor; |
|
164 |
|
165 RI_ASSERT(linearDegenerate() || radialDegenerate()); |
|
166 |
|
167 // Determine the color at the end of the gradient |
|
168 RIfloat gs, ge; |
|
169 if (m_colorRampSpreadMode == VG_COLOR_RAMP_SPREAD_PAD) |
|
170 { |
|
171 gs = 1.0f - 1/256.0f; |
|
172 ge = 1.0f; |
|
173 } else if (m_colorRampSpreadMode == VG_COLOR_RAMP_SPREAD_REPEAT) |
|
174 { |
|
175 gs = 0.0f; |
|
176 ge = 1/256.0f; |
|
177 } else |
|
178 { |
|
179 gs = 1.0f - 1/256.0f; |
|
180 ge = 1.0f; |
|
181 } |
|
182 Color c = integrateColorRamp(gs, ge); |
|
183 return c * 256.0f; |
|
184 } |
|
185 |
|
186 /*-------------------------------------------------------------------*//*! |
|
187 * \brief Returns the average color within an offset range in the color ramp. |
|
188 * \param |
|
189 * \return |
|
190 * \note |
|
191 *//*-------------------------------------------------------------------*/ |
|
192 |
|
193 Color Paint::integrateColorRamp(RIfloat gmin, RIfloat gmax) const |
|
194 { |
|
195 RI_ASSERT(gmin <= gmax); |
|
196 RI_ASSERT(gmin >= 0.0f && gmin <= 1.0f); |
|
197 RI_ASSERT(gmax >= 0.0f && gmax <= 1.0f); |
|
198 RI_ASSERT(m_colorRampStops.size() >= 2); //there are at least two stops |
|
199 |
|
200 Color currC(0,0,0,0,m_colorRampPremultiplied ? Color::sRGBA_PRE : Color::sRGBA); |
|
201 |
|
202 if(gmin == 1.0f || gmax == 0.0f) |
|
203 return currC; |
|
204 |
|
205 int i = 0; |
|
206 |
|
207 for(; i < m_colorRampStops.size()-1; i++) |
|
208 { |
|
209 if(gmin >= m_colorRampStops[i].offset && gmin < m_colorRampStops[i+1].offset) |
|
210 { |
|
211 RIfloat s = m_colorRampStops[i].offset; |
|
212 RIfloat e = m_colorRampStops[i+1].offset; |
|
213 RI_ASSERT(s < e); |
|
214 RIfloat g = (gmin - s) / (e - s); |
|
215 |
|
216 Color sc = readStopColor(m_colorRampStops, i, m_colorRampPremultiplied); |
|
217 Color ec = readStopColor(m_colorRampStops, i+1, m_colorRampPremultiplied); |
|
218 Color rc = (1.0f-g) * sc + g * ec; |
|
219 |
|
220 //subtract the average color from the start of the stop to gmin |
|
221 Color dc = 0.5f*(gmin - s)*(sc + rc); |
|
222 currC -= dc; |
|
223 break; |
|
224 } |
|
225 } |
|
226 |
|
227 for(;i < m_colorRampStops.size()-1; i++) |
|
228 { |
|
229 RIfloat s = m_colorRampStops[i].offset; |
|
230 RIfloat e = m_colorRampStops[i+1].offset; |
|
231 RI_ASSERT(s <= e); |
|
232 |
|
233 Color sc = readStopColor(m_colorRampStops, i, m_colorRampPremultiplied); |
|
234 Color ec = readStopColor(m_colorRampStops, i+1, m_colorRampPremultiplied); |
|
235 |
|
236 //average of the stop |
|
237 Color dc = 0.5f*(e-s)*(sc + ec); |
|
238 currC += dc; |
|
239 |
|
240 if(gmax >= m_colorRampStops[i].offset && gmax < m_colorRampStops[i+1].offset) |
|
241 { |
|
242 RIfloat g = (gmax - s) / (e - s); |
|
243 Color rc = (1.0f-g) * sc + g * ec; |
|
244 |
|
245 //subtract the average color from gmax to the end of the stop |
|
246 dc = 0.5f*(e - gmax)*(rc + ec); |
|
247 currC -= dc; |
|
248 break; |
|
249 } |
|
250 } |
|
251 |
|
252 return currC; |
|
253 } |
|
254 |
|
255 /** |
|
256 * \brief Generates gradient color-ramp lookup values. |
|
257 * |
|
258 * \param targetFormat Destination or image format to associate LUT with. |
|
259 * \patam drawImage true if paint is evaluated along drawImage. |
|
260 * |
|
261 * \note Must be called prior to rendering, and after the destination |
|
262 * format is known. The destination format is either destination |
|
263 * surface format, or the image format in case of image rendering |
|
264 * operation. |
|
265 */ |
|
266 void Paint::generateLUT(PixelPipe& pipe, VGImageFormat preferredFormat) |
|
267 { |
|
268 const RIfloat gstep = 1.0f / (GRADIENT_LUT_COUNT); |
|
269 const RIfloat rcp = (RIfloat)(GRADIENT_LUT_COUNT); |
|
270 RIfloat gsx; |
|
271 gsx = 0.0f; |
|
272 |
|
273 if (!pipe.colorTransformChanged() && !m_gradientStopsChanged && (preferredFormat == m_lutFormat)) |
|
274 return; // Already in correct format |
|
275 |
|
276 const bool inputPremultiplied = m_colorRampPremultiplied == VG_TRUE ? true : false; |
|
277 |
|
278 // Colortransform premultiplies color. |
|
279 const Color::Descriptor srcDesc = Color::formatToDescriptorConst( |
|
280 inputPremultiplied || pipe.hasColorTransform() ? VG_sRGBA_8888_PRE : VG_sRGBA_8888); |
|
281 |
|
282 const Color::Descriptor dstDesc = Color::formatToDescriptorConst(preferredFormat); |
|
283 |
|
284 // Create a pre-calculated LUT. |
|
285 for (int i = 0; i < GRADIENT_LUT_COUNT; i++) |
|
286 { |
|
287 // \todo Open up the integrator and/or use also integers. |
|
288 Color c = integrateColorRamp(gsx, gsx + gstep); |
|
289 c *= rcp; |
|
290 |
|
291 // \todo Changing the mode must be tracked somehow! |
|
292 if (pipe.getImageMode() != VG_DRAW_IMAGE_MULTIPLY) |
|
293 pipe.colorTransform(c); |
|
294 |
|
295 IntegerColor ic = IntegerColor(c); |
|
296 ic.convertToFrom(dstDesc, srcDesc, false); |
|
297 m_gradientLUT[i] = ic; |
|
298 |
|
299 gsx += gstep; |
|
300 } |
|
301 |
|
302 m_gradientStopsChanged = false; |
|
303 m_lutFormat = Color::descriptorToVGImageFormat(dstDesc); |
|
304 pipe.setColorTransformChanged(false); |
|
305 |
|
306 RI_ASSERT(m_lutFormat == preferredFormat); |
|
307 } |
|
308 |
|
309 /*-------------------------------------------------------------------*//*! |
|
310 * \brief PixelPipe constructor. |
|
311 * \param |
|
312 * \return |
|
313 * \note |
|
314 *//*-------------------------------------------------------------------*/ |
|
315 |
|
316 PixelPipe::PixelPipe() : |
|
317 m_drawable(NULL), |
|
318 m_image(NULL), |
|
319 m_paint(NULL), |
|
320 m_defaultPaint(), |
|
321 m_blendMode(VG_BLEND_SRC_OVER), |
|
322 m_imageMode(VG_DRAW_IMAGE_NORMAL), |
|
323 m_imageQuality(VG_IMAGE_QUALITY_FASTER), |
|
324 m_tileFillColor(0,0,0,0,Color::sRGBA), |
|
325 m_colorTransform(false), |
|
326 m_colorTransformValues(), |
|
327 m_iColorTransformValues(), |
|
328 m_surfaceToPaintMatrix(), |
|
329 m_surfaceToImageMatrix(), |
|
330 m_paintToSurfaceMatrix(), |
|
331 m_maskOperation(VG_SET_MASK), |
|
332 m_renderToMask(false), |
|
333 m_colorTransformChanged(true) |
|
334 { |
|
335 for(int i=0;i<8;i++) |
|
336 { |
|
337 m_colorTransformValues[i] = (i < 4) ? 1.0f : 0.0f; |
|
338 m_iColorTransformValues[i] = (i < 4) ? (COLOR_TRANSFORM_ONE) : 0; |
|
339 } |
|
340 } |
|
341 |
|
342 |
|
343 /*-------------------------------------------------------------------*//*! |
|
344 * \brief PixelPipe destructor. |
|
345 * \param |
|
346 * \return |
|
347 * \note |
|
348 *//*-------------------------------------------------------------------*/ |
|
349 |
|
350 PixelPipe::~PixelPipe() |
|
351 { |
|
352 } |
|
353 |
|
354 /*-------------------------------------------------------------------*//*! |
|
355 * \brief Sets the rendering surface. |
|
356 * \param |
|
357 * \return |
|
358 * \note |
|
359 *//*-------------------------------------------------------------------*/ |
|
360 |
|
361 void PixelPipe::setDrawable(Drawable* drawable) |
|
362 { |
|
363 RI_ASSERT(drawable); |
|
364 m_drawable = drawable; |
|
365 } |
|
366 |
|
367 /*-------------------------------------------------------------------*//*! |
|
368 * \brief Sets the blend mode. |
|
369 * \param |
|
370 * \return |
|
371 * \note |
|
372 *//*-------------------------------------------------------------------*/ |
|
373 |
|
374 void PixelPipe::setBlendMode(VGBlendMode blendMode) |
|
375 { |
|
376 RI_ASSERT(blendMode >= VG_BLEND_SRC && blendMode <= VG_BLEND_ADDITIVE); |
|
377 m_blendMode = blendMode; |
|
378 } |
|
379 |
|
380 /*-------------------------------------------------------------------*//*! |
|
381 * \brief Sets the mask image. NULL disables masking. |
|
382 * \param |
|
383 * \return |
|
384 * \note |
|
385 *//*-------------------------------------------------------------------*/ |
|
386 |
|
387 void PixelPipe::setMask(bool masking) |
|
388 { |
|
389 m_masking = masking; |
|
390 } |
|
391 |
|
392 /*-------------------------------------------------------------------*//*! |
|
393 * \brief Sets the image to be drawn. NULL disables image drawing. |
|
394 * \param |
|
395 * \return |
|
396 * \note |
|
397 *//*-------------------------------------------------------------------*/ |
|
398 |
|
399 void PixelPipe::setImage(Image* image, VGImageMode imageMode) |
|
400 { |
|
401 RI_ASSERT(imageMode == VG_DRAW_IMAGE_NORMAL || imageMode == VG_DRAW_IMAGE_MULTIPLY || imageMode == VG_DRAW_IMAGE_STENCIL); |
|
402 m_image = image; |
|
403 m_imageMode = imageMode; |
|
404 } |
|
405 |
|
406 /*-------------------------------------------------------------------*//*! |
|
407 * \brief Sets the surface-to-paint matrix. |
|
408 * \param |
|
409 * \return |
|
410 * \note |
|
411 *//*-------------------------------------------------------------------*/ |
|
412 |
|
413 void PixelPipe::setSurfaceToPaintMatrix(const Matrix3x3& surfaceToPaintMatrix) |
|
414 { |
|
415 m_surfaceToPaintMatrix = surfaceToPaintMatrix; |
|
416 } |
|
417 |
|
418 /*-------------------------------------------------------------------*//*! |
|
419 * \brief Sets the surface-to-image matrix. |
|
420 * \param |
|
421 * \return |
|
422 * \note |
|
423 *//*-------------------------------------------------------------------*/ |
|
424 |
|
425 void PixelPipe::setSurfaceToImageMatrix(const Matrix3x3& surfaceToImageMatrix) |
|
426 { |
|
427 m_surfaceToImageMatrix = surfaceToImageMatrix; |
|
428 } |
|
429 |
|
430 /*-------------------------------------------------------------------*//*! |
|
431 * \brief Sets image quality. |
|
432 * \param |
|
433 * \return |
|
434 * \note |
|
435 *//*-------------------------------------------------------------------*/ |
|
436 |
|
437 void PixelPipe::setImageQuality(VGImageQuality imageQuality) |
|
438 { |
|
439 RI_ASSERT(imageQuality == VG_IMAGE_QUALITY_NONANTIALIASED || imageQuality == VG_IMAGE_QUALITY_FASTER || imageQuality == VG_IMAGE_QUALITY_BETTER); |
|
440 m_imageQuality = imageQuality; |
|
441 } |
|
442 |
|
443 /*-------------------------------------------------------------------*//*! |
|
444 * \brief Sets fill color for VG_TILE_FILL tiling mode (pattern only). |
|
445 * \param |
|
446 * \return |
|
447 * \note |
|
448 *//*-------------------------------------------------------------------*/ |
|
449 |
|
450 void PixelPipe::setTileFillColor(const Color& c) |
|
451 { |
|
452 m_tileFillColor = c; |
|
453 m_tileFillColor.clamp(); |
|
454 } |
|
455 |
|
456 /*-------------------------------------------------------------------*//*! |
|
457 * \brief Sets paint. |
|
458 * \param |
|
459 * \return |
|
460 * \note |
|
461 *//*-------------------------------------------------------------------*/ |
|
462 |
|
463 void PixelPipe::setPaint(Paint* paint) |
|
464 { |
|
465 // \temp Only call this right before filling a polygon. |
|
466 m_paint = paint; |
|
467 |
|
468 if(!m_paint) |
|
469 m_paint = &m_defaultPaint; |
|
470 |
|
471 if(m_paint->m_pattern) |
|
472 m_tileFillColor.convert(m_paint->m_pattern->getDescriptor().internalFormat); |
|
473 |
|
474 } |
|
475 |
|
476 /*-------------------------------------------------------------------*//*! |
|
477 * \brief Color transform. |
|
478 * \param |
|
479 * \return |
|
480 * \note |
|
481 *//*-------------------------------------------------------------------*/ |
|
482 |
|
483 void PixelPipe::setColorTransform(bool enable, RIfloat values[8]) |
|
484 { |
|
485 m_colorTransform = enable; |
|
486 for(int i=0;i<4;i++) |
|
487 { |
|
488 m_colorTransformValues[i] = RI_CLAMP(values[i], -127.0f, 127.0f); |
|
489 m_colorTransformValues[i+4] = RI_CLAMP(values[i+4], -1.0f, 1.0f); |
|
490 m_iColorTransformValues[i] = RI_ROUND_TO_INT(m_colorTransformValues[i]*(RIfloat)COLOR_TRANSFORM_ONE); |
|
491 m_iColorTransformValues[i+4] = RI_ROUND_TO_INT(m_colorTransformValues[i+4]*255.0f); |
|
492 } |
|
493 m_colorTransformChanged = true; |
|
494 } |
|
495 |
|
496 const Image* PixelPipe::getRenderTargetImage() const |
|
497 { |
|
498 if (m_renderToMask) |
|
499 return m_drawable->getMaskBuffer()->getImage(); |
|
500 |
|
501 return m_drawable->getColorBuffer()->getImage(); |
|
502 } |
|
503 |
|
504 /** |
|
505 * \brief Determine an appropriate VGImageFormat to use for lookup tables. |
|
506 * \todo Should return descriptor instead? |
|
507 */ |
|
508 VGImageFormat PixelPipe::getPreferredLUTFormat() const |
|
509 { |
|
510 const Image* target = getRenderTargetImage(); |
|
511 const Color::Descriptor& targetDesc = target->getDescriptor(); |
|
512 |
|
513 if (m_renderToMask) |
|
514 { |
|
515 RI_ASSERT(!m_image); |
|
516 if (targetDesc.isNonlinear()) |
|
517 return VG_sRGBA_8888_PRE; |
|
518 else |
|
519 return VG_lRGBA_8888_PRE; |
|
520 } |
|
521 |
|
522 if (m_image && m_imageMode == VG_DRAW_IMAGE_MULTIPLY) |
|
523 return VG_sRGBA_8888_PRE; // ? |
|
524 |
|
525 // Prefer premultiplied formats |
|
526 // \note Can also generate non-premultiplied if no sampling/other operation and destination |
|
527 // is in linear format. |
|
528 // \note Do not use VGImageFormat, because using (s/l)LA88 is possible with |
|
529 // luminance destination formats. |
|
530 if (targetDesc.isNonlinear()) |
|
531 return VG_sRGBA_8888_PRE; |
|
532 else |
|
533 return VG_lRGBA_8888_PRE; |
|
534 } |
|
535 |
|
536 void PixelPipe::prepareSolidFill() |
|
537 { |
|
538 if (!(m_drawable && m_paint)) |
|
539 return; |
|
540 |
|
541 Color c = m_paint->getSolidColor(); |
|
542 //Color c = m_paint->m_paintColor; |
|
543 |
|
544 if (!m_image || m_imageMode != VG_DRAW_IMAGE_MULTIPLY) |
|
545 colorTransform(c); // Output will be premultiplied |
|
546 // Generate internal color |
|
547 Color::Descriptor blendDesc = getRenderTargetImage()->getDescriptor(); |
|
548 |
|
549 // MULTIPLY uses the color as-is. |
|
550 if (m_imageMode != VG_DRAW_IMAGE_MULTIPLY) c.convert(blendDesc.internalFormat); |
|
551 |
|
552 IntegerColor ic = IntegerColor(c); |
|
553 blendDesc.internalFormat = (Color::InternalFormat)(blendDesc.internalFormat | (Color::PREMULTIPLIED)); |
|
554 |
|
555 if (m_imageMode != VG_DRAW_IMAGE_MULTIPLY) c.convert(blendDesc.internalFormat); |
|
556 |
|
557 IntegerColor blendColor = IntegerColor(c); |
|
558 |
|
559 if (m_imageMode == VG_DRAW_IMAGE_STENCIL) |
|
560 blendColor.asFixedPoint(c); // Enhance the precision a bit |
|
561 |
|
562 // \todo No need to pack the color if solid fill is not possible |
|
563 if (!m_renderToMask) |
|
564 ic.truncateColor(getRenderTargetImage()->getDescriptor()); |
|
565 else |
|
566 ic.truncateMask(getRenderTargetImage()->getDescriptor()); |
|
567 |
|
568 RIuint32 p = ic.getPackedColor(getRenderTargetImage()->getDescriptor()); |
|
569 |
|
570 m_spanUniforms.solidColor = blendColor; // This must be premultiplied |
|
571 m_spanUniforms.packedSolidColor = p; // This must be exactly the dst color |
|
572 } |
|
573 |
|
574 void PixelPipe::prepareCoverageFill() |
|
575 { |
|
576 IntegerColor ic = IntegerColor(255, 255, 255, 255); |
|
577 RIuint32 p = ic.getPackedColor(m_drawable->getMaskBuffer()->getDescriptor()); |
|
578 |
|
579 m_spanUniforms.solidColor = ic; |
|
580 m_spanUniforms.packedSolidColor = p; |
|
581 } |
|
582 |
|
583 void PixelPipe::prepareLinearGradient() |
|
584 { |
|
585 const Matrix3x3& s2p = m_surfaceToPaintMatrix; |
|
586 |
|
587 Vector2 zero(0,0); |
|
588 Vector2 p0 = m_paint->m_linearGradientPoint0; |
|
589 Vector2 p1 = m_paint->m_linearGradientPoint1; |
|
590 Vector2 delta = p1 - p0; |
|
591 |
|
592 zero = affineTransform(s2p, zero); |
|
593 |
|
594 RIfloat d = (delta.x * delta.x) + (delta.y * delta.y); |
|
595 RIfloat gdx = (s2p[0][0] * delta.x + s2p[1][0] * delta.y) / d; |
|
596 RIfloat gdy = (s2p[0][1] * delta.x + s2p[1][1] * delta.y) / d; |
|
597 RIfloat cx = (zero.x-p0.x) * (delta.x); |
|
598 RIfloat cy = (zero.y-p0.y) * (delta.y); |
|
599 RIfloat c = (cx + cy) / d; |
|
600 |
|
601 m_spanUniforms.dgdx = RI_FLOAT_TO_FX(gdx, PixelPipe::GRADIENT_BITS); |
|
602 m_spanUniforms.dgdy = RI_FLOAT_TO_FX(gdy, PixelPipe::GRADIENT_BITS); |
|
603 m_spanUniforms.lgc = RI_FLOAT_TO_FX(c + 0.5*(gdx + gdy), PixelPipe::GRADIENT_BITS); |
|
604 |
|
605 m_spanUniforms.gradientLookup = m_paint->getGradientLUT(); |
|
606 } |
|
607 |
|
608 void PixelPipe::prepareRadialGradient() |
|
609 { |
|
610 const Matrix3x3& s2p = m_surfaceToPaintMatrix; |
|
611 |
|
612 Vector2 c = m_paint->m_radialGradientCenter; |
|
613 Vector2 f = m_paint->m_radialGradientFocalPoint; |
|
614 RGScalar r = m_paint->m_radialGradientRadius; |
|
615 |
|
616 Vector2 zero(0,0); |
|
617 Vector2 pzero = affineTransform(s2p, zero); |
|
618 |
|
619 Vector2 fp = f - c; |
|
620 |
|
621 RGScalar q = fp.length(); |
|
622 |
|
623 if (q > r) |
|
624 { |
|
625 const RIfloat scale = 0.99f; |
|
626 fp.normalize(); |
|
627 fp *= r * scale; |
|
628 f = fp + c; |
|
629 } |
|
630 |
|
631 RGScalar r1sqr = RI_SQR(r); |
|
632 RGScalar d = r1sqr - dot(fp, fp); |
|
633 |
|
634 m_spanUniforms.rdxdx = s2p[0][0]; |
|
635 m_spanUniforms.rdxdy = s2p[0][1]; |
|
636 m_spanUniforms.rdydx = s2p[1][0]; |
|
637 m_spanUniforms.rdydy = s2p[1][1]; |
|
638 |
|
639 m_spanUniforms.rsqrp = r1sqr / RI_SQR(d); |
|
640 m_spanUniforms.rfxp = fp.x / d; |
|
641 m_spanUniforms.rfyp = fp.y / d; |
|
642 m_spanUniforms.rx0 = pzero.x - f.x + 0.5f*(m_spanUniforms.rdxdx + m_spanUniforms.rdxdy); |
|
643 m_spanUniforms.ry0 = pzero.y - f.y + 0.5f*(m_spanUniforms.rdydy + m_spanUniforms.rdydx); |
|
644 |
|
645 m_spanUniforms.gradientLookup = m_paint->getGradientLUT(); |
|
646 } |
|
647 |
|
648 void PixelPipe::preparePattern() |
|
649 { |
|
650 // Patterns only support affine transforms |
|
651 const Matrix3x3& s2p = m_surfaceToPaintMatrix; |
|
652 const RIfloat patternWidth = (RIfloat)m_paint->m_pattern->getWidth(); |
|
653 const RIfloat patternHeight = (RIfloat)m_paint->m_pattern->getHeight(); |
|
654 const Vector2 zero(0, 0); |
|
655 Vector2 pzero = affineTransform(s2p, zero); |
|
656 |
|
657 m_spanUniforms.paint_x0 = RI_ROUND_TO_INT((pzero.x/patternWidth)*(1<<GRADIENT_BITS)); |
|
658 m_spanUniforms.paint_y0 = RI_ROUND_TO_INT((pzero.y/patternHeight)*(1<<GRADIENT_BITS)); |
|
659 m_spanUniforms.paint_dxdx = RI_ROUND_TO_INT((s2p[0][0]/patternWidth)*(1<<GRADIENT_BITS)); |
|
660 m_spanUniforms.paint_dxdy = RI_ROUND_TO_INT((s2p[0][1]/patternHeight)*(1<<GRADIENT_BITS)); |
|
661 m_spanUniforms.paint_dydx = RI_ROUND_TO_INT((s2p[1][0]/patternWidth)*(1<<GRADIENT_BITS)); |
|
662 m_spanUniforms.paint_dydy = RI_ROUND_TO_INT((s2p[1][1]/patternHeight)*(1<<GRADIENT_BITS)); |
|
663 |
|
664 m_spanUniforms.paint_x0 += (m_spanUniforms.paint_dxdx + m_spanUniforms.paint_dxdy) / 2; |
|
665 m_spanUniforms.paint_y0 += (m_spanUniforms.paint_dydy + m_spanUniforms.paint_dydx) / 2; |
|
666 |
|
667 m_spanUniforms.patternPtr = m_paint->m_pattern->getData(); |
|
668 m_spanUniforms.patternStride = m_paint->m_pattern->getStride(); |
|
669 m_spanUniforms.paint_width = m_paint->m_pattern->getWidth(); |
|
670 m_spanUniforms.paint_height = m_paint->m_pattern->getHeight(); |
|
671 |
|
672 m_signatureState.patternDesc = m_paint->m_pattern->getDescriptor(); |
|
673 |
|
674 m_spanUniforms.tileFillColor = IntegerColor(m_tileFillColor); |
|
675 // The tile fill-color must be shifted down to same bit-depth (see integer samplers) |
|
676 m_spanUniforms.tileFillColor.truncateColor(m_signatureState.patternDesc); |
|
677 |
|
678 } |
|
679 |
|
680 RI_INLINE static RIfloat floatEqu(RIfloat a, RIfloat b, RIfloat e) |
|
681 { |
|
682 // \note This should be sufficient for our use-cases; |
|
683 return (RI_ABS(a - b) < e); |
|
684 } |
|
685 |
|
686 RI_INLINE static RIfloat distToInt(RIfloat f) |
|
687 { |
|
688 const RIfloat intF = RI_ROUND_TO_INT(f); |
|
689 return RI_ABS(intF - f); |
|
690 } |
|
691 |
|
692 /** |
|
693 * \brief Check if transform is 90 degree rotation, or flip and nothing else. |
|
694 */ |
|
695 RI_INLINE static bool orthoNormalCoAxialTransform(const Matrix3x3& t, bool aa) |
|
696 { |
|
697 const RIfloat epsilonCoord = 1/255.0f; // 1/127.0f; |
|
698 const RIfloat epsilonGradient = epsilonCoord * epsilonCoord; // \todo Too strict? |
|
699 const RIfloat absPatterns[2][4] = { |
|
700 {1.0f, 0.0f, 0.0f, 1.0f}, |
|
701 {0.0f, 1.0f, 1.0f, 0.0f} }; |
|
702 |
|
703 if (!t.isAffine()) |
|
704 return false; |
|
705 |
|
706 // \todo This rule only applies if filtering is in use? |
|
707 if (aa) |
|
708 if (!floatEqu(distToInt(t[0][2]), 0.0f, epsilonCoord) || !floatEqu(distToInt(t[1][2]), 0.0f, epsilonCoord)) |
|
709 return false; |
|
710 |
|
711 Matrix3x3 u = t; |
|
712 |
|
713 for (int j = 0; j < 2; j++) |
|
714 for (int i = 0; i < 2; i++) |
|
715 u[j][i] = RI_ABS(u[j][i]); |
|
716 |
|
717 bool found; |
|
718 |
|
719 for (int m = 0; m < 2; m++) |
|
720 { |
|
721 found = true; |
|
722 for (int j = 0; j < 2; j++) |
|
723 { |
|
724 for (int i = 0; i < 2; i++) |
|
725 { |
|
726 //if (u[j][i] != absPatterns[m][i+j*2]) |
|
727 if (!floatEqu(u[j][i], absPatterns[m][i+j*2], epsilonGradient)) |
|
728 { |
|
729 found = false; |
|
730 break; |
|
731 } |
|
732 } |
|
733 if (!found) break; |
|
734 } |
|
735 if (found) break; |
|
736 } |
|
737 |
|
738 return found; |
|
739 } |
|
740 |
|
741 void PixelPipe::prepareImage(bool aa) |
|
742 { |
|
743 if (!m_image) |
|
744 { |
|
745 m_signatureState.imageGradientType = GRADIENT_TYPE_INTEGER; |
|
746 return; |
|
747 } |
|
748 |
|
749 RI_ASSERT(m_image); |
|
750 m_spanUniforms.imagePtr = m_image->getData(); |
|
751 m_spanUniforms.imageStride = m_image->getStride(); |
|
752 |
|
753 if (m_image->getParent() != NULL) |
|
754 { |
|
755 // Adjust the pointer. |
|
756 int x, y; |
|
757 m_image->getStorageOffset(x, y); |
|
758 m_spanUniforms.imagePtr = Image::calculateAddress( |
|
759 m_spanUniforms.imagePtr, m_image->getDescriptor().bitsPerPixel, x, y, m_spanUniforms.imageStride); |
|
760 } |
|
761 |
|
762 // \todo This function writes to derived state also. |
|
763 // \todo Plenty of fast-paths possible! |
|
764 const Matrix3x3& s2i = m_surfaceToImageMatrix; |
|
765 |
|
766 Vector3 zero(0,0,1); |
|
767 Vector3 pzero; |
|
768 |
|
769 bool fastImage = orthoNormalCoAxialTransform(s2i, aa); |
|
770 |
|
771 pzero = s2i * zero; |
|
772 |
|
773 if (fastImage) |
|
774 { |
|
775 RI_ASSERT(pzero.z == 1.0f); |
|
776 m_spanUniforms.image_idxdx = RI_ROUND_TO_INT(s2i[0][0]); |
|
777 m_spanUniforms.image_idxdy = RI_ROUND_TO_INT(s2i[0][1]); |
|
778 m_spanUniforms.image_idydx = RI_ROUND_TO_INT(s2i[1][0]); |
|
779 m_spanUniforms.image_idydy = RI_ROUND_TO_INT(s2i[1][1]); |
|
780 m_spanUniforms.image_ix0 = RI_FLOOR(pzero.x + 0.5f*(s2i[0][0]+s2i[0][1])); |
|
781 m_spanUniforms.image_iy0 = RI_FLOOR(pzero.y + 0.5f*(s2i[1][1]+s2i[1][0])); |
|
782 |
|
783 // Adjust sample-center when using (exactly) integer coordinates. |
|
784 |
|
785 #if 0 |
|
786 if (m_spanUniforms.image_idxdx < 0 || m_spanUniforms.image_idxdy < 0) |
|
787 m_spanUniforms.image_ix0--; |
|
788 |
|
789 if (m_spanUniforms.image_idydy < 0 || m_spanUniforms.image_idydx < 0) |
|
790 m_spanUniforms.image_iy0--; |
|
791 #endif |
|
792 |
|
793 m_signatureState.imageGradientType = GRADIENT_TYPE_INTEGER; |
|
794 } |
|
795 else if (s2i.isAffine()) |
|
796 { |
|
797 RI_ASSERT(pzero.z == 1.0f); |
|
798 const RIfloat imageWidth = m_image->getWidth(); |
|
799 const RIfloat imageHeight = m_image->getHeight(); |
|
800 |
|
801 m_spanUniforms.image_idxdx = RI_ROUND_TO_INT((s2i[0][0]/imageWidth)*(1<<GRADIENT_BITS)); |
|
802 m_spanUniforms.image_idxdy = RI_ROUND_TO_INT((s2i[0][1]/imageHeight)*(1<<GRADIENT_BITS)); |
|
803 m_spanUniforms.image_idydx = RI_ROUND_TO_INT((s2i[1][0]/imageWidth)*(1<<GRADIENT_BITS)); |
|
804 m_spanUniforms.image_idydy = RI_ROUND_TO_INT((s2i[1][1]/imageHeight)*(1<<GRADIENT_BITS)); |
|
805 m_spanUniforms.image_ix0 = RI_ROUND_TO_INT((pzero.x/imageWidth)*(1<<GRADIENT_BITS)); |
|
806 m_spanUniforms.image_iy0 = RI_ROUND_TO_INT((pzero.y/imageHeight)*(1<<GRADIENT_BITS)); |
|
807 |
|
808 m_spanUniforms.image_ix0 += (m_spanUniforms.image_idxdx + m_spanUniforms.image_idxdy)/2; |
|
809 m_spanUniforms.image_iy0 += (m_spanUniforms.image_idydy + m_spanUniforms.image_idydx)/2; |
|
810 |
|
811 m_spanUniforms.image_iWidth = (RIint32)imageWidth; |
|
812 m_spanUniforms.image_iHeight = (RIint32)imageHeight; |
|
813 |
|
814 m_signatureState.imageGradientType = GRADIENT_TYPE_FIXED; |
|
815 } |
|
816 else |
|
817 { |
|
818 // Use floats. |
|
819 m_spanUniforms.image_fx0 = pzero.x; |
|
820 m_spanUniforms.image_fy0 = pzero.y; |
|
821 m_spanUniforms.image_fw0 = pzero.z; |
|
822 m_spanUniforms.image_fdxdx = s2i[0][0]; |
|
823 m_spanUniforms.image_fdxdy = s2i[0][1]; |
|
824 m_spanUniforms.image_fdydx = s2i[1][0]; |
|
825 m_spanUniforms.image_fdydy = s2i[1][1]; |
|
826 m_spanUniforms.image_fdwdx = s2i[2][0]; |
|
827 m_spanUniforms.image_fdwdy = s2i[2][1]; |
|
828 |
|
829 m_spanUniforms.image_fx0 += 0.5f * (m_spanUniforms.image_fdxdx + m_spanUniforms.image_fdxdy); |
|
830 m_spanUniforms.image_fy0 += 0.5f * (m_spanUniforms.image_fdydy + m_spanUniforms.image_fdydx); |
|
831 m_spanUniforms.image_fw0 += 0.5f * (m_spanUniforms.image_fdwdx + m_spanUniforms.image_fdwdy); |
|
832 |
|
833 m_spanUniforms.image_fWidth = (RIfloat)m_image->getWidth(); |
|
834 m_spanUniforms.image_fHeight = (RIfloat)m_image->getHeight(); |
|
835 |
|
836 m_signatureState.imageGradientType = GRADIENT_TYPE_FLOAT; |
|
837 } |
|
838 |
|
839 m_signatureState.imageDesc = m_image->getDescriptor(); |
|
840 } |
|
841 |
|
842 static PixelPipe::TilingMode tilingModeOfImageTilingMode(VGTilingMode it) |
|
843 { |
|
844 switch(it) |
|
845 { |
|
846 case VG_TILE_PAD: |
|
847 return PixelPipe::TILING_MODE_PAD; |
|
848 case VG_TILE_REPEAT: |
|
849 return PixelPipe::TILING_MODE_REPEAT; |
|
850 case VG_TILE_REFLECT: |
|
851 return PixelPipe::TILING_MODE_REFLECT; |
|
852 default: |
|
853 RI_ASSERT(it == VG_TILE_FILL); |
|
854 return PixelPipe::TILING_MODE_FILL; |
|
855 } |
|
856 } |
|
857 |
|
858 static PixelPipe::TilingMode tilingModeOfSpreadMode(VGColorRampSpreadMode sm) |
|
859 { |
|
860 switch(sm) |
|
861 { |
|
862 case VG_COLOR_RAMP_SPREAD_PAD: |
|
863 return PixelPipe::TILING_MODE_PAD; |
|
864 case VG_COLOR_RAMP_SPREAD_REPEAT: |
|
865 return PixelPipe::TILING_MODE_REPEAT; |
|
866 default: |
|
867 RI_ASSERT(sm == VG_COLOR_RAMP_SPREAD_REFLECT); |
|
868 return PixelPipe::TILING_MODE_REFLECT; |
|
869 } |
|
870 } |
|
871 |
|
872 static PixelPipe::TilingMode tilingModeOfPaint(const Paint* paint) |
|
873 { |
|
874 switch(paint->m_paintType) |
|
875 { |
|
876 case VG_PAINT_TYPE_COLOR: |
|
877 return PixelPipe::TILING_MODE_PAD; |
|
878 case VG_PAINT_TYPE_LINEAR_GRADIENT: |
|
879 case VG_PAINT_TYPE_RADIAL_GRADIENT: |
|
880 return tilingModeOfSpreadMode(paint->m_colorRampSpreadMode); |
|
881 default: |
|
882 RI_ASSERT(paint->m_paintType == VG_PAINT_TYPE_PATTERN); |
|
883 return tilingModeOfImageTilingMode(paint->m_patternTilingMode); |
|
884 } |
|
885 } |
|
886 |
|
887 void PixelPipe::prepareRenderToMask() |
|
888 { |
|
889 RI_ASSERT(m_drawable->getMaskBuffer()); |
|
890 |
|
891 m_signatureState.dstDesc = m_drawable->getMaskBuffer()->getDescriptor(); |
|
892 //RI_ASSERT(m_signatureState.dstFormat >= 0 && m_signatureState.dstFormat <= VG_lABGR_8888_PRE); |
|
893 |
|
894 m_signatureState.maskOperation = m_maskOperation; |
|
895 } |
|
896 |
|
897 void PixelPipe::prepareSignatureState() |
|
898 { |
|
899 m_signatureState.isRenderToMask = m_renderToMask; |
|
900 |
|
901 if (m_signatureState.isRenderToMask) |
|
902 { |
|
903 prepareRenderToMask(); |
|
904 return; |
|
905 } |
|
906 |
|
907 m_signatureState.blendMode = getBlendMode(); |
|
908 |
|
909 m_signatureState.hasColorTransform = this->m_colorTransform; |
|
910 |
|
911 m_signatureState.paintType = getPaintType(); |
|
912 |
|
913 m_signatureState.paintTilingMode = tilingModeOfPaint(m_paint); |
|
914 // \todo Derive these from the quality settings somehow. |
|
915 // Linear and nearest should work atm. |
|
916 m_signatureState.paintSampler = SAMPLER_TYPE_NEAREST; |
|
917 m_signatureState.imageSampler = SAMPLER_TYPE_NEAREST; |
|
918 |
|
919 m_signatureState.hasMasking = isMasking() && (m_drawable->getMaskBuffer() != NULL); |
|
920 |
|
921 m_signatureState.hasImage = m_image ? true : false; |
|
922 m_signatureState.unsafeImageInput = !m_image ? false : m_image->isUnsafe(); |
|
923 m_signatureState.imageMode = m_imageMode; |
|
924 |
|
925 // Formats. Note that fields that are not filled in / used get set to a derived state in a |
|
926 // separate function! |
|
927 |
|
928 if (m_signatureState.paintType == (RIuint32)VG_PAINT_TYPE_COLOR) |
|
929 { |
|
930 RI_ASSERT(m_paint); |
|
931 if (m_paint->getSolidColor().a == 1.0) |
|
932 m_signatureState.fillColorTransparent = false; |
|
933 else |
|
934 m_signatureState.fillColorTransparent = true; |
|
935 } |
|
936 |
|
937 m_signatureState.dstDesc = m_drawable->getColorBuffer()->getDescriptor(); |
|
938 |
|
939 // \todo Why isn't the imagedescriptor set here? |
|
940 if (m_signatureState.hasMasking) |
|
941 { |
|
942 m_signatureState.maskDesc = m_drawable->getMaskBuffer()->getDescriptor(); |
|
943 } |
|
944 |
|
945 } |
|
946 |
|
947 /** |
|
948 * \brief Remove redundancy from the pixel-pipeline state so that less |
|
949 * pipelines are generated. |
|
950 */ |
|
951 static void determineDerivedState(PixelPipe::SignatureState& derivedState, const PixelPipe::SignatureState& originalState) |
|
952 { |
|
953 derivedState = originalState; |
|
954 |
|
955 if (derivedState.isRenderToMask) |
|
956 { |
|
957 // Set a lot of defaults: |
|
958 derivedState.blendMode = VG_BLEND_SRC; |
|
959 derivedState.imageMode = VG_DRAW_IMAGE_NORMAL; |
|
960 derivedState.paintType = VG_PAINT_TYPE_COLOR; |
|
961 |
|
962 derivedState.hasImage = false; |
|
963 derivedState.hasMasking = false; |
|
964 derivedState.hasColorTransform = false; |
|
965 } |
|
966 |
|
967 if (derivedState.paintType == VG_PAINT_TYPE_COLOR) |
|
968 { |
|
969 derivedState.paintTilingMode = PixelPipe::TILING_MODE_PAD; |
|
970 derivedState.paintSampler = PixelPipe::SAMPLER_TYPE_NEAREST; |
|
971 // \todo Opaque solid colors can benefit from simpler coverage-blending |
|
972 // becase SRC_OVER == SRC. This information has to be present in |
|
973 // the derivedState (and not just uniform). |
|
974 } |
|
975 |
|
976 if (!derivedState.hasImage) |
|
977 { |
|
978 derivedState.imageMode = VG_DRAW_IMAGE_NORMAL; |
|
979 derivedState.imageSampler = PixelPipe::SAMPLER_TYPE_NEAREST; |
|
980 derivedState.imageGradientType = PixelPipe::GRADIENT_TYPE_INTEGER; |
|
981 derivedState.imageDesc = Color::Descriptor::getDummyDescriptor(); |
|
982 } else if (derivedState.imageMode == VG_DRAW_IMAGE_NORMAL) |
|
983 { |
|
984 // If paint is not generated, use a common enum |
|
985 derivedState.paintType = VG_PAINT_TYPE_COLOR; |
|
986 } |
|
987 |
|
988 if (derivedState.paintType != VG_PAINT_TYPE_PATTERN) |
|
989 { |
|
990 derivedState.patternDesc = Color::Descriptor::getDummyDescriptor(); |
|
991 } |
|
992 |
|
993 if (!derivedState.isRenderToMask) |
|
994 derivedState.maskOperation = VG_CLEAR_MASK; |
|
995 |
|
996 if (!derivedState.hasMasking) |
|
997 { |
|
998 derivedState.maskDesc = Color::Descriptor::getDummyDescriptor(); |
|
999 } |
|
1000 } |
|
1001 |
|
1002 |
|
1003 /** |
|
1004 * \brief Determine per-scanconversion constant state. |
|
1005 * \todo NOTE! This also prepares the derived state at the moment. |
|
1006 */ |
|
1007 void PixelPipe::prepareSpanUniforms(bool aa) |
|
1008 { |
|
1009 prepareSignatureState(); |
|
1010 |
|
1011 if (m_signatureState.hasColorTransform) |
|
1012 m_spanUniforms.colorTransformValues = m_iColorTransformValues; |
|
1013 |
|
1014 RI_ASSERT(m_drawable->getColorBuffer()); |
|
1015 |
|
1016 const Image* dst; |
|
1017 |
|
1018 if (!m_signatureState.isRenderToMask) |
|
1019 dst = m_drawable->getColorBuffer()->getImage(); |
|
1020 else |
|
1021 dst = m_drawable->getMaskBuffer()->getImage(); |
|
1022 |
|
1023 m_spanUniforms.dstPtr = dst->getData(); |
|
1024 m_spanUniforms.dstStride = dst->getStride(); |
|
1025 |
|
1026 if (m_drawable->getMaskBuffer()) |
|
1027 { |
|
1028 m_spanUniforms.maskPtr = m_drawable->getMaskBuffer()->m_image->getData(); |
|
1029 m_spanUniforms.maskStride = m_drawable->getMaskBuffer()->m_image->getStride(); |
|
1030 } |
|
1031 else |
|
1032 { |
|
1033 m_spanUniforms.maskPtr = NULL; |
|
1034 m_spanUniforms.maskStride = 0; |
|
1035 } |
|
1036 |
|
1037 if (!m_renderToMask) |
|
1038 { |
|
1039 VGImageFormat prefPaintFormat = getPreferredLUTFormat(); |
|
1040 |
|
1041 switch (getPaintType()) |
|
1042 { |
|
1043 case VG_PAINT_TYPE_COLOR: |
|
1044 prepareSolidFill(); |
|
1045 break; |
|
1046 case VG_PAINT_TYPE_LINEAR_GRADIENT: |
|
1047 m_paint->generateLUT(*this, prefPaintFormat); |
|
1048 prepareLinearGradient(); |
|
1049 break; |
|
1050 case VG_PAINT_TYPE_RADIAL_GRADIENT: |
|
1051 m_paint->generateLUT(*this, prefPaintFormat); |
|
1052 prepareRadialGradient(); |
|
1053 break; |
|
1054 default: |
|
1055 RI_ASSERT(getPaintType() == VG_PAINT_TYPE_PATTERN); |
|
1056 preparePattern(); |
|
1057 break; |
|
1058 } |
|
1059 } |
|
1060 else |
|
1061 { |
|
1062 prepareCoverageFill(); |
|
1063 } |
|
1064 |
|
1065 prepareImage(aa); |
|
1066 |
|
1067 // Must be done last: |
|
1068 determineDerivedState(m_derivedState, m_signatureState); |
|
1069 } |
|
1070 |
|
1071 |
|
1072 /*-------------------------------------------------------------------*//*! |
|
1073 * \brief Computes the linear gradient function at (x,y). |
|
1074 * \param |
|
1075 * \return |
|
1076 * \note |
|
1077 *//*-------------------------------------------------------------------*/ |
|
1078 void PixelPipe::linearGradient(RIfloat& g, RIfloat& rho, RIfloat x, RIfloat y) const |
|
1079 { |
|
1080 RI_ASSERT(m_paint); |
|
1081 Vector2 u = m_paint->m_linearGradientPoint1 - m_paint->m_linearGradientPoint0; |
|
1082 RIfloat usq = dot(u,u); |
|
1083 if( usq <= 0.0f ) |
|
1084 { //points are equal, gradient is always 1.0f |
|
1085 g = 1.0f; |
|
1086 rho = 0.0f; |
|
1087 return; |
|
1088 } |
|
1089 RIfloat oou = 1.0f / usq; |
|
1090 |
|
1091 Vector2 p(x, y); |
|
1092 p = affineTransform(m_surfaceToPaintMatrix, p); |
|
1093 p -= m_paint->m_linearGradientPoint0; |
|
1094 RI_ASSERT(usq >= 0.0f); |
|
1095 g = dot(p, u) * oou; |
|
1096 RIfloat dgdx = oou * u.x * m_surfaceToPaintMatrix[0][0] + oou * u.y * m_surfaceToPaintMatrix[1][0]; |
|
1097 RIfloat dgdy = oou * u.x * m_surfaceToPaintMatrix[0][1] + oou * u.y * m_surfaceToPaintMatrix[1][1]; |
|
1098 rho = (RIfloat)sqrt(dgdx*dgdx + dgdy*dgdy); |
|
1099 RI_ASSERT(rho >= 0.0f); |
|
1100 } |
|
1101 |
|
1102 /*-------------------------------------------------------------------*//*! |
|
1103 * \brief Computes the radial gradient function at (x,y). |
|
1104 * \param |
|
1105 * \return |
|
1106 * \note |
|
1107 *//*-------------------------------------------------------------------*/ |
|
1108 |
|
1109 void PixelPipe::radialGradient(RIfloat &g, RIfloat &rho, RIfloat x, RIfloat y) const |
|
1110 { |
|
1111 RI_ASSERT(m_paint); |
|
1112 if( m_paint->m_radialGradientRadius <= 0.0f ) |
|
1113 { |
|
1114 g = 1.0f; |
|
1115 rho = 0.0f; |
|
1116 return; |
|
1117 } |
|
1118 |
|
1119 RIfloat r = m_paint->m_radialGradientRadius; |
|
1120 Vector2 c = m_paint->m_radialGradientCenter; |
|
1121 Vector2 f = m_paint->m_radialGradientFocalPoint; |
|
1122 Vector2 gx(m_surfaceToPaintMatrix[0][0], m_surfaceToPaintMatrix[1][0]); |
|
1123 Vector2 gy(m_surfaceToPaintMatrix[0][1], m_surfaceToPaintMatrix[1][1]); |
|
1124 |
|
1125 Vector2 fp = f - c; |
|
1126 |
|
1127 //clamp the focal point inside the gradient circle |
|
1128 RIfloat fpLen = fp.length(); |
|
1129 if( fpLen > 0.999f * r ) |
|
1130 fp *= 0.999f * r / fpLen; |
|
1131 |
|
1132 RIfloat D = -1.0f / (dot(fp,fp) - r*r); |
|
1133 Vector2 p(x, y); |
|
1134 p = affineTransform(m_surfaceToPaintMatrix, p) - c; |
|
1135 Vector2 d = p - fp; |
|
1136 RIfloat s = (RIfloat)sqrt(r*r*dot(d,d) - RI_SQR(p.x*fp.y - p.y*fp.x)); |
|
1137 g = (dot(fp,d) + s) * D; |
|
1138 if(RI_ISNAN(g)) |
|
1139 g = 0.0f; |
|
1140 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); |
|
1141 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); |
|
1142 rho = (RIfloat)sqrt(dgdx*dgdx + dgdy*dgdy); |
|
1143 if(RI_ISNAN(rho)) |
|
1144 rho = 0.0f; |
|
1145 RI_ASSERT(rho >= 0.0f); |
|
1146 } |
|
1147 |
|
1148 /*-------------------------------------------------------------------*//*! |
|
1149 * \brief Maps a gradient function value to a color. |
|
1150 * \param |
|
1151 * \return |
|
1152 * \note |
|
1153 *//*-------------------------------------------------------------------*/ |
|
1154 |
|
1155 Color PixelPipe::colorRamp(RIfloat gradient, RIfloat rho) const |
|
1156 { |
|
1157 RI_ASSERT(m_paint); |
|
1158 RI_ASSERT(rho >= 0.0f); |
|
1159 |
|
1160 Color c(0,0,0,0,m_paint->m_colorRampPremultiplied ? Color::sRGBA_PRE : Color::sRGBA); |
|
1161 Color avg; |
|
1162 |
|
1163 if(rho == 0.0f) |
|
1164 { //filter size is zero or gradient is degenerate |
|
1165 switch(m_paint->m_colorRampSpreadMode) |
|
1166 { |
|
1167 case VG_COLOR_RAMP_SPREAD_PAD: |
|
1168 gradient = RI_CLAMP(gradient, 0.0f, 1.0f); |
|
1169 break; |
|
1170 case VG_COLOR_RAMP_SPREAD_REFLECT: |
|
1171 { |
|
1172 RIfloat g = RI_MOD(gradient, 2.0f); |
|
1173 gradient = (g < 1.0f) ? g : 2.0f - g; |
|
1174 break; |
|
1175 } |
|
1176 default: |
|
1177 RI_ASSERT(m_paint->m_colorRampSpreadMode == VG_COLOR_RAMP_SPREAD_REPEAT); |
|
1178 gradient = gradient - (RIfloat)floor(gradient); |
|
1179 break; |
|
1180 } |
|
1181 RI_ASSERT(gradient >= 0.0f && gradient <= 1.0f); |
|
1182 |
|
1183 for(int i=0;i<m_paint->m_colorRampStops.size()-1;i++) |
|
1184 { |
|
1185 if(gradient >= m_paint->m_colorRampStops[i].offset && gradient < m_paint->m_colorRampStops[i+1].offset) |
|
1186 { |
|
1187 RIfloat s = m_paint->m_colorRampStops[i].offset; |
|
1188 RIfloat e = m_paint->m_colorRampStops[i+1].offset; |
|
1189 RI_ASSERT(s < e); |
|
1190 RIfloat g = RI_CLAMP((gradient - s) / (e - s), 0.0f, 1.0f); //clamp needed due to numerical inaccuracies |
|
1191 |
|
1192 Color sc = readStopColor(m_paint->m_colorRampStops, i, m_paint->m_colorRampPremultiplied); |
|
1193 Color ec = readStopColor(m_paint->m_colorRampStops, i+1, m_paint->m_colorRampPremultiplied); |
|
1194 return (1.0f-g) * sc + g * ec; //return interpolated value |
|
1195 } |
|
1196 } |
|
1197 return readStopColor(m_paint->m_colorRampStops, m_paint->m_colorRampStops.size()-1, m_paint->m_colorRampPremultiplied); |
|
1198 } |
|
1199 |
|
1200 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) |
|
1201 RIfloat gmax = gradient + rho*0.5f; |
|
1202 |
|
1203 switch(m_paint->m_colorRampSpreadMode) |
|
1204 { |
|
1205 case VG_COLOR_RAMP_SPREAD_PAD: |
|
1206 { |
|
1207 if(gmin < 0.0f) |
|
1208 c += (RI_MIN(gmax, 0.0f) - gmin) * readStopColor(m_paint->m_colorRampStops, 0, m_paint->m_colorRampPremultiplied); |
|
1209 if(gmax > 1.0f) |
|
1210 c += (gmax - RI_MAX(gmin, 1.0f)) * readStopColor(m_paint->m_colorRampStops, m_paint->m_colorRampStops.size()-1, m_paint->m_colorRampPremultiplied); |
|
1211 gmin = RI_CLAMP(gmin, 0.0f, 1.0f); |
|
1212 gmax = RI_CLAMP(gmax, 0.0f, 1.0f); |
|
1213 c += m_paint->integrateColorRamp(gmin, gmax); |
|
1214 c *= 1.0f/rho; |
|
1215 c.clamp(); //clamp needed due to numerical inaccuracies |
|
1216 return c; |
|
1217 } |
|
1218 |
|
1219 case VG_COLOR_RAMP_SPREAD_REFLECT: |
|
1220 { |
|
1221 avg = m_paint->integrateColorRamp(0.0f, 1.0f); |
|
1222 RIfloat gmini = (RIfloat)floor(gmin); |
|
1223 RIfloat gmaxi = (RIfloat)floor(gmax); |
|
1224 c = (gmaxi + 1.0f - gmini) * avg; //full ramps |
|
1225 |
|
1226 //subtract beginning |
|
1227 if(((int)gmini) & 1) |
|
1228 c -= m_paint->integrateColorRamp(RI_CLAMP(1.0f - (gmin - gmini), 0.0f, 1.0f), 1.0f); |
|
1229 else |
|
1230 c -= m_paint->integrateColorRamp(0.0f, RI_CLAMP(gmin - gmini, 0.0f, 1.0f)); |
|
1231 |
|
1232 //subtract end |
|
1233 if(((int)gmaxi) & 1) |
|
1234 c -= m_paint->integrateColorRamp(0.0f, RI_CLAMP(1.0f - (gmax - gmaxi), 0.0f, 1.0f)); |
|
1235 else |
|
1236 c -= m_paint->integrateColorRamp(RI_CLAMP(gmax - gmaxi, 0.0f, 1.0f), 1.0f); |
|
1237 break; |
|
1238 } |
|
1239 |
|
1240 default: |
|
1241 { |
|
1242 RI_ASSERT(m_paint->m_colorRampSpreadMode == VG_COLOR_RAMP_SPREAD_REPEAT); |
|
1243 avg = m_paint->integrateColorRamp(0.0f, 1.0f); |
|
1244 RIfloat gmini = (RIfloat)floor(gmin); |
|
1245 RIfloat gmaxi = (RIfloat)floor(gmax); |
|
1246 c = (gmaxi + 1.0f - gmini) * avg; //full ramps |
|
1247 c -= m_paint->integrateColorRamp(0.0f, RI_CLAMP(gmin - gmini, 0.0f, 1.0f)); //subtract beginning |
|
1248 c -= m_paint->integrateColorRamp(RI_CLAMP(gmax - gmaxi, 0.0f, 1.0f), 1.0f); //subtract end |
|
1249 break; |
|
1250 } |
|
1251 } |
|
1252 |
|
1253 //divide color by the length of the range |
|
1254 c *= 1.0f / rho; |
|
1255 c.clamp(); //clamp needed due to numerical inaccuracies |
|
1256 |
|
1257 //hide aliasing by fading to the average color |
|
1258 const RIfloat fadeStart = 0.5f; |
|
1259 const RIfloat fadeMultiplier = 2.0f; //the larger, the earlier fade to average is done |
|
1260 |
|
1261 if(rho < fadeStart) |
|
1262 return c; |
|
1263 |
|
1264 RIfloat ratio = RI_MIN((rho - fadeStart) * fadeMultiplier, 1.0f); |
|
1265 return ratio * avg + (1.0f - ratio) * c; |
|
1266 } |
|
1267 |
|
1268 /*-------------------------------------------------------------------*//*! |
|
1269 * \brief Computes blend. |
|
1270 * \param |
|
1271 * \return |
|
1272 * \note premultiplied blending formulas |
|
1273 //src |
|
1274 a = asrc |
|
1275 r = rsrc |
|
1276 //src over |
|
1277 a = asrc + adst * (1-asrc) |
|
1278 r = rsrc + rdst * (1-asrc) |
|
1279 //dst over |
|
1280 a = asrc * (1-adst) + adst |
|
1281 r = rsrc * (1-adst) + adst |
|
1282 //src in |
|
1283 a = asrc * adst |
|
1284 r = rsrc * adst |
|
1285 //dst in |
|
1286 a = adst * asrc |
|
1287 r = rdst * asrc |
|
1288 //multiply |
|
1289 a = asrc + adst * (1-asrc) |
|
1290 r = rsrc * (1-adst) + rdst * (1-asrc) + rsrc * rdst |
|
1291 //screen |
|
1292 a = asrc + adst * (1-asrc) |
|
1293 r = rsrc + rdst - rsrc * rdst |
|
1294 //darken |
|
1295 a = asrc + adst * (1-asrc) |
|
1296 r = MIN(rsrc + rdst * (1-asrc), rdst + rsrc * (1-adst)) |
|
1297 //lighten |
|
1298 a = asrc + adst * (1-asrc) |
|
1299 r = MAX(rsrc + rdst * (1-asrc), rdst + rsrc * (1-adst)) |
|
1300 //additive |
|
1301 a = MIN(asrc+adst,1) |
|
1302 r = rsrc + rdst |
|
1303 *//*-------------------------------------------------------------------*/ |
|
1304 |
|
1305 |
|
1306 |
|
1307 Color PixelPipe::blend(const Color& s, RIfloat ar, RIfloat ag, RIfloat ab, const Color& d, VGBlendMode blendMode) const |
|
1308 { |
|
1309 //apply blending in the premultiplied format |
|
1310 Color r(0,0,0,0,d.getInternalFormat()); |
|
1311 RI_ASSERT(s.a >= 0.0f && s.a <= 1.0f); |
|
1312 RI_ASSERT(s.r >= 0.0f && s.r <= s.a && s.r <= ar); |
|
1313 RI_ASSERT(s.g >= 0.0f && s.g <= s.a && s.g <= ag); |
|
1314 RI_ASSERT(s.b >= 0.0f && s.b <= s.a && s.b <= ab); |
|
1315 RI_ASSERT(d.a >= 0.0f && d.a <= 1.0f); |
|
1316 RI_ASSERT(d.r >= 0.0f && d.r <= d.a); |
|
1317 RI_ASSERT(d.g >= 0.0f && d.g <= d.a); |
|
1318 RI_ASSERT(d.b >= 0.0f && d.b <= d.a); |
|
1319 switch(blendMode) |
|
1320 { |
|
1321 case VG_BLEND_SRC: |
|
1322 r = s; |
|
1323 break; |
|
1324 |
|
1325 case VG_BLEND_SRC_OVER: |
|
1326 r.r = s.r + d.r * (1.0f - ar); |
|
1327 r.g = s.g + d.g * (1.0f - ag); |
|
1328 r.b = s.b + d.b * (1.0f - ab); |
|
1329 r.a = s.a + d.a * (1.0f - s.a); |
|
1330 break; |
|
1331 |
|
1332 case VG_BLEND_DST_OVER: |
|
1333 r.r = s.r * (1.0f - d.a) + d.r; |
|
1334 r.g = s.g * (1.0f - d.a) + d.g; |
|
1335 r.b = s.b * (1.0f - d.a) + d.b; |
|
1336 r.a = s.a * (1.0f - d.a) + d.a; |
|
1337 break; |
|
1338 |
|
1339 case VG_BLEND_SRC_IN: |
|
1340 r.r = s.r * d.a; |
|
1341 r.g = s.g * d.a; |
|
1342 r.b = s.b * d.a; |
|
1343 r.a = s.a * d.a; |
|
1344 break; |
|
1345 |
|
1346 case VG_BLEND_DST_IN: |
|
1347 r.r = d.r * ar; |
|
1348 r.g = d.g * ag; |
|
1349 r.b = d.b * ab; |
|
1350 r.a = d.a * s.a; |
|
1351 break; |
|
1352 |
|
1353 case VG_BLEND_MULTIPLY: |
|
1354 r.r = s.r * (1.0f - d.a + d.r) + d.r * (1.0f - ar); |
|
1355 r.g = s.g * (1.0f - d.a + d.g) + d.g * (1.0f - ag); |
|
1356 r.b = s.b * (1.0f - d.a + d.b) + d.b * (1.0f - ab); |
|
1357 r.a = s.a + d.a * (1.0f - s.a); |
|
1358 break; |
|
1359 |
|
1360 case VG_BLEND_SCREEN: |
|
1361 r.r = s.r + d.r * (1.0f - s.r); |
|
1362 r.g = s.g + d.g * (1.0f - s.g); |
|
1363 r.b = s.b + d.b * (1.0f - s.b); |
|
1364 r.a = s.a + d.a * (1.0f - s.a); |
|
1365 break; |
|
1366 |
|
1367 case VG_BLEND_DARKEN: |
|
1368 r.r = RI_MIN(s.r + d.r * (1.0f - ar), d.r + s.r * (1.0f - d.a)); |
|
1369 r.g = RI_MIN(s.g + d.g * (1.0f - ag), d.g + s.g * (1.0f - d.a)); |
|
1370 r.b = RI_MIN(s.b + d.b * (1.0f - ab), d.b + s.b * (1.0f - d.a)); |
|
1371 r.a = s.a + d.a * (1.0f - s.a); |
|
1372 break; |
|
1373 |
|
1374 case VG_BLEND_LIGHTEN: |
|
1375 r.r = RI_MAX(s.r + d.r * (1.0f - ar), d.r + s.r * (1.0f - d.a)); |
|
1376 r.g = RI_MAX(s.g + d.g * (1.0f - ag), d.g + s.g * (1.0f - d.a)); |
|
1377 r.b = RI_MAX(s.b + d.b * (1.0f - ab), d.b + s.b * (1.0f - d.a)); |
|
1378 //although the statement below is equivalent to r.a = s.a + d.a * (1.0f - s.a) |
|
1379 //in practice there can be a very slight difference because |
|
1380 //of the max operation in the blending formula that may cause color to exceed alpha. |
|
1381 //Because of this, we compute the result both ways and return the maximum. |
|
1382 r.a = RI_MAX(s.a + d.a * (1.0f - s.a), d.a + s.a * (1.0f - d.a)); |
|
1383 break; |
|
1384 |
|
1385 default: |
|
1386 RI_ASSERT(blendMode == VG_BLEND_ADDITIVE); |
|
1387 r.r = RI_MIN(s.r + d.r, 1.0f); |
|
1388 r.g = RI_MIN(s.g + d.g, 1.0f); |
|
1389 r.b = RI_MIN(s.b + d.b, 1.0f); |
|
1390 r.a = RI_MIN(s.a + d.a, 1.0f); |
|
1391 break; |
|
1392 } |
|
1393 return r; |
|
1394 } |
|
1395 |
|
1396 /*-------------------------------------------------------------------*//*! |
|
1397 * \brief Applies color transform. |
|
1398 * \param |
|
1399 * \return |
|
1400 * \note |
|
1401 *//*-------------------------------------------------------------------*/ |
|
1402 |
|
1403 void PixelPipe::colorTransform(Color& c) const |
|
1404 { |
|
1405 if(m_colorTransform) |
|
1406 { |
|
1407 c.unpremultiply(); |
|
1408 c.luminanceToRGB(); |
|
1409 c.r = c.r * m_colorTransformValues[0] + m_colorTransformValues[4]; |
|
1410 c.g = c.g * m_colorTransformValues[1] + m_colorTransformValues[5]; |
|
1411 c.b = c.b * m_colorTransformValues[2] + m_colorTransformValues[6]; |
|
1412 c.a = c.a * m_colorTransformValues[3] + m_colorTransformValues[7]; |
|
1413 c.clamp(); |
|
1414 c.premultiply(); |
|
1415 } |
|
1416 } |
|
1417 |
|
1418 void PixelPipe::fillSpans(PPVariants& variants, const Span* spans, int nSpans) const |
|
1419 { |
|
1420 #if 1 |
|
1421 PPCompiler& compiler = PPCompiler::getCompiler(); |
|
1422 |
|
1423 PPCompiler::PixelPipeHandle handle = compiler.compilePixelPipeline(m_derivedState); |
|
1424 if (handle) |
|
1425 { |
|
1426 PixelPipeFunction func = compiler.getPixelPipePtr(handle); |
|
1427 RI_ASSERT(func); |
|
1428 func(m_spanUniforms, variants, spans, nSpans); |
|
1429 compiler.releasePixelPipeline(handle); |
|
1430 } else |
|
1431 #endif |
|
1432 { |
|
1433 executePixelPipeline(m_derivedState, m_spanUniforms, variants, spans, nSpans); |
|
1434 } |
|
1435 } |
|
1436 |
|
1437 //======================================================================= |
|
1438 |
|
1439 } //namespace OpenVGRI |
|
1440 |