2 * Copyright 2006-2007, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Stephan Aßmus <superstippi@gmx.de>
9 #include "IconRenderer.h"
17 #include <agg_span_gradient.h>
18 #include <agg_span_interpolator_linear.h>
20 #include "GradientTransformable.h"
23 #include "ShapeContainer.h"
25 #include "VectorPath.h"
29 class IconRenderer::StyleHandler
{
32 Transformation transformation
;
36 StyleHandler(::GammaTable
& gammaTable
)
38 fGammaTable(gammaTable
),
39 fTransparent(0, 0, 0, 0),
45 int32 count
= fStyles
.CountItems();
46 for (int32 i
= 0; i
< count
; i
++)
47 delete (StyleItem
*)fStyles
.ItemAtFast(i
);
50 bool is_solid(unsigned styleIndex
) const
52 StyleItem
* styleItem
= (StyleItem
*)fStyles
.ItemAt(styleIndex
);
56 return styleItem
->style
->Gradient() == NULL
;
59 const agg::rgba8
& color(unsigned styleIndex
);
61 void generate_span(agg::rgba8
* span
, int x
, int y
,
62 unsigned len
, unsigned styleIndex
);
64 bool AddStyle(Style
* style
, const Transformation
& transformation
)
68 StyleItem
* item
= new (nothrow
) StyleItem
;
72 // if the style uses a gradient, the transformation
73 // is based on the gradient transformation
74 if (Gradient
* gradient
= style
->Gradient()) {
75 item
->transformation
= *gradient
;
76 item
->transformation
.multiply(transformation
);
78 item
->transformation
= transformation
;
80 item
->transformation
.invert();
81 return fStyles
.AddItem((void*)item
);
85 template<class GradientFunction
>
86 void _GenerateGradient(agg::rgba8
* span
, int x
, int y
, unsigned len
,
87 GradientFunction function
, int32 start
, int32 end
,
88 const agg::rgba8
* gradientColors
, Transformation
& gradientTransform
);
91 ::GammaTable
& fGammaTable
;
92 agg::rgba8 fTransparent
;
98 IconRenderer::StyleHandler::color(unsigned styleIndex
)
100 StyleItem
* styleItem
= (StyleItem
*)fStyles
.ItemAt(styleIndex
);
102 printf("no style at index: %u!\n", styleIndex
);
106 const rgb_color
& c
= styleItem
->style
->Color();
107 fColor
= agg::rgba8(fGammaTable
.dir(c
.red
), fGammaTable
.dir(c
.green
),
108 fGammaTable
.dir(c
.blue
), c
.alpha
);
109 fColor
.premultiply();
115 IconRenderer::StyleHandler::generate_span(agg::rgba8
* span
, int x
, int y
,
116 unsigned len
, unsigned styleIndex
)
118 StyleItem
* styleItem
= (StyleItem
*)fStyles
.ItemAt(styleIndex
);
119 if (!styleItem
|| !styleItem
->style
->Gradient()) {
120 printf("no style/gradient at index: %u!\n", styleIndex
);
121 // TODO: memset() span?
125 Style
* style
= styleItem
->style
;
126 Gradient
* gradient
= style
->Gradient();
127 const agg::rgba8
* colors
= style
->GammaCorrectedColors(fGammaTable
);
129 switch (gradient
->Type()) {
130 case GRADIENT_LINEAR
: {
131 agg::gradient_x function
;
132 _GenerateGradient(span
, x
, y
, len
, function
, -64, 64, colors
,
133 styleItem
->transformation
);
136 case GRADIENT_CIRCULAR
: {
137 agg::gradient_radial function
;
138 _GenerateGradient(span
, x
, y
, len
, function
, 0, 64, colors
,
139 styleItem
->transformation
);
142 case GRADIENT_DIAMOND
: {
143 agg::gradient_diamond function
;
144 _GenerateGradient(span
, x
, y
, len
, function
, 0, 64, colors
,
145 styleItem
->transformation
);
148 case GRADIENT_CONIC
: {
149 agg::gradient_conic function
;
150 _GenerateGradient(span
, x
, y
, len
, function
, 0, 64, colors
,
151 styleItem
->transformation
);
155 agg::gradient_xy function
;
156 _GenerateGradient(span
, x
, y
, len
, function
, 0, 64, colors
,
157 styleItem
->transformation
);
160 case GRADIENT_SQRT_XY
: {
161 agg::gradient_sqrt_xy function
;
162 _GenerateGradient(span
, x
, y
, len
, function
, 0, 64, colors
,
163 styleItem
->transformation
);
170 template<class GradientFunction
>
172 IconRenderer::StyleHandler::_GenerateGradient(agg::rgba8
* span
, int x
, int y
,
173 unsigned len
, GradientFunction function
, int32 start
, int32 end
,
174 const agg::rgba8
* gradientColors
, Transformation
& gradientTransform
)
176 typedef agg::pod_auto_array
<agg::rgba8
, 256> ColorArray
;
177 typedef agg::span_interpolator_linear
<> Interpolator
;
178 typedef agg::span_gradient
<agg::rgba8
,
181 ColorArray
> GradientGenerator
;
183 Interpolator
interpolator(gradientTransform
);
185 ColorArray
array(gradientColors
);
186 GradientGenerator
gradientGenerator(interpolator
, function
, array
,
189 gradientGenerator
.generate(span
, x
, y
, len
);
194 class HintingTransformer
{
197 void transform(double* x
, double* y
) const
199 *x
= floor(*x
+ 0.5);
200 *y
= floor(*y
+ 0.5);
208 IconRenderer::IconRenderer(BBitmap
* bitmap
)
211 fBackgroundColor(0, 0, 0, 0),
217 fPixelFormat(fRenderingBuffer
),
218 fPixelFormatPre(fRenderingBuffer
),
219 fBaseRenderer(fPixelFormat
),
220 fBaseRendererPre(fPixelFormatPre
),
230 // attach rendering buffer to bitmap
231 fRenderingBuffer
.attach((uint8
*)bitmap
->Bits(),
232 bitmap
->Bounds().IntegerWidth() + 1,
233 bitmap
->Bounds().IntegerHeight() + 1, bitmap
->BytesPerRow());
235 fBaseRendererPre
.clip_box(0, 0, bitmap
->Bounds().IntegerWidth(),
236 bitmap
->Bounds().IntegerHeight());
240 IconRenderer::~IconRenderer()
246 IconRenderer::SetIcon(const Icon
* icon
)
257 IconRenderer::Render()
259 _Render(fBitmap
->Bounds());
264 IconRenderer::Render(const BRect
& area
)
266 _Render(fBitmap
->Bounds() & area
);
271 IconRenderer::SetScale(double scale
)
273 fGlobalTransform
.reset();
274 fGlobalTransform
.multiply(agg::trans_affine_scaling(scale
));
279 IconRenderer::SetBackground(const BBitmap
* background
)
281 fBackground
= background
;
286 IconRenderer::SetBackground(const agg::rgba8
& background
)
288 fBackgroundColor
.r
= fGammaTable
.dir(background
.r
);
289 fBackgroundColor
.g
= fGammaTable
.dir(background
.g
);
290 fBackgroundColor
.b
= fGammaTable
.dir(background
.b
);
291 fBackgroundColor
.a
= background
.a
;
296 IconRenderer::Demultiply()
298 uint8
* bits
= (uint8
*)fBitmap
->Bits();
299 uint32 bpr
= fBitmap
->BytesPerRow();
300 uint32 width
= fBitmap
->Bounds().IntegerWidth() + 1;
301 uint32 height
= fBitmap
->Bounds().IntegerHeight() + 1;
303 for (uint32 y
= 0; y
< height
; y
++) {
305 for (uint32 x
= 0; x
< width
; x
++) {
306 if (b
[3] < 255 && b
[3] > 0) {
307 b
[0] = (uint8
)((int)b
[0] * 255 / b
[3]);
308 b
[1] = (uint8
)((int)b
[1] * 255 / b
[3]);
309 b
[2] = (uint8
)((int)b
[2] * 255 / b
[3]);
319 typedef agg::conv_transform
<VertexSource
, Transformation
> ScaledPath
;
320 typedef agg::conv_transform
<ScaledPath
, HintingTransformer
> HintedPath
;
324 IconRenderer::_Render(const BRect
& r
)
329 // TODO: fix clip box for "clear" and "apply_gamma_inv"
330 // fBaseRendererPre.clip_box((int)floorf(r.left), (int)floorf(r.top),
331 // (int)ceilf(r.right), (int)ceilf(r.bottom));
334 memcpy(fBitmap
->Bits(), fBackground
->Bits(), fBitmap
->BitsLength());
336 fBaseRendererPre
.clear(fBackgroundColor
);
338 //bigtime_t start = system_time();
339 StyleHandler
styleHandler(fGammaTable
);
342 // iterate over the shapes in the icon,
343 // add the vector paths to the rasterizer
344 // and associate each shapes style
345 int32 shapeCount
= fIcon
->Shapes()->CountShapes();
346 int32 styleIndex
= 0;
347 for (int32 i
= 0; i
< shapeCount
; i
++) {
348 Shape
* shape
= fIcon
->Shapes()->ShapeAtFast(i
);
350 // Don't render shape if the Level Of Detail falls out of range.
351 // That's unless the scale is bigger than the maximum
352 // MaxVisibilityScale of 4.0f.
353 if (fGlobalTransform
.scale() < shape
->MinVisibilityScale()
354 || (fGlobalTransform
.scale() > shape
->MaxVisibilityScale()
355 && shape
->MaxVisibilityScale() < 4.0f
)) {
359 Transformation
transform(*shape
);
360 transform
.multiply(fGlobalTransform
);
361 // NOTE: this works only because "agg::trans_affine",
362 // "Transformable" and "Transformation" are all the
365 Style
* style
= shape
->Style();
369 // add the style either with global transformation or with
370 // the shapes transformation, depending on whether there
371 // is a gradient and its settings
372 Gradient
* gradient
= style
->Gradient();
373 bool styleAdded
= false;
374 if (gradient
&& !gradient
->InheritTransformation()) {
375 styleAdded
= styleHandler
.AddStyle(shape
->Style(),
378 styleAdded
= styleHandler
.AddStyle(shape
->Style(), transform
);
382 printf("IconRenderer::_Render() - out of memory\n");
386 // if this is not the first shape, and the style contains
387 // transparency, commit a render pass of previous shapes
388 if (i
> 0 && style
->HasTransparency())
389 _CommitRenderPass(styleHandler
);
391 fRasterizer
.styles(styleIndex
, -1);
395 shape
->SetGlobalScale(max_c(1.0, transform
.scale()));
396 ScaledPath
scaledPath(shape
->VertexSource(), transform
);
397 if (shape
->Hinting()) {
398 // additional hinting
399 HintingTransformer hinter
;
400 HintedPath
hintedPath(scaledPath
, hinter
);
401 fRasterizer
.add_path(hintedPath
);
403 fRasterizer
.add_path(scaledPath
);
407 _CommitRenderPass(styleHandler
, false);
409 if (fGammaTable
.gamma() != 1.0)
410 fPixelFormat
.apply_gamma_inv(fGammaTable
);
412 //if (fRenderingBuffer.width() == 64)
413 //printf("rendering 64x64: %lld\n", system_time() - start);
418 IconRenderer::_CommitRenderPass(StyleHandler
& styleHandler
, bool reset
)
420 agg::render_scanlines_compound(fRasterizer
, fScanline
, fBinaryScanline
,
421 fBaseRendererPre
, fSpanAllocator
, styleHandler
);