Make UEFI boot-platform build again
[haiku.git] / src / libs / icon / IconRenderer.cpp
blob2b12cad1b19fa2a49b449b30fa75b02463989fd8
1 /*
2 * Copyright 2006-2007, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Stephan Aßmus <superstippi@gmx.de>
7 */
9 #include "IconRenderer.h"
11 #include <new>
12 #include <stdio.h>
14 #include <Bitmap.h>
15 #include <List.h>
17 #include <agg_span_gradient.h>
18 #include <agg_span_interpolator_linear.h>
20 #include "GradientTransformable.h"
21 #include "Icon.h"
22 #include "Shape.h"
23 #include "ShapeContainer.h"
24 #include "Style.h"
25 #include "VectorPath.h"
27 using std::nothrow;
29 class IconRenderer::StyleHandler {
30 struct StyleItem {
31 Style* style;
32 Transformation transformation;
35 public:
36 StyleHandler(::GammaTable& gammaTable)
37 : fStyles(20),
38 fGammaTable(gammaTable),
39 fTransparent(0, 0, 0, 0),
40 fColor(0, 0, 0, 0)
43 ~StyleHandler()
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);
53 if (!styleItem)
54 return true;
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)
66 if (!style)
67 return false;
68 StyleItem* item = new (nothrow) StyleItem;
69 if (!item)
70 return false;
71 item->style = style;
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);
77 } else {
78 item->transformation = transformation;
80 item->transformation.invert();
81 return fStyles.AddItem((void*)item);
84 private:
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);
90 BList fStyles;
91 ::GammaTable& fGammaTable;
92 agg::rgba8 fTransparent;
93 agg::rgba8 fColor;
96 // color
97 const agg::rgba8&
98 IconRenderer::StyleHandler::color(unsigned styleIndex)
100 StyleItem* styleItem = (StyleItem*)fStyles.ItemAt(styleIndex);
101 if (!styleItem) {
102 printf("no style at index: %u!\n", styleIndex);
103 return fTransparent;
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();
110 return fColor;
113 // generate_span
114 void
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?
122 return;
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);
134 break;
136 case GRADIENT_CIRCULAR: {
137 agg::gradient_radial function;
138 _GenerateGradient(span, x, y, len, function, 0, 64, colors,
139 styleItem->transformation);
140 break;
142 case GRADIENT_DIAMOND: {
143 agg::gradient_diamond function;
144 _GenerateGradient(span, x, y, len, function, 0, 64, colors,
145 styleItem->transformation);
146 break;
148 case GRADIENT_CONIC: {
149 agg::gradient_conic function;
150 _GenerateGradient(span, x, y, len, function, 0, 64, colors,
151 styleItem->transformation);
152 break;
154 case GRADIENT_XY: {
155 agg::gradient_xy function;
156 _GenerateGradient(span, x, y, len, function, 0, 64, colors,
157 styleItem->transformation);
158 break;
160 case GRADIENT_SQRT_XY: {
161 agg::gradient_sqrt_xy function;
162 _GenerateGradient(span, x, y, len, function, 0, 64, colors,
163 styleItem->transformation);
164 break;
169 // _GenerateGradient
170 template<class GradientFunction>
171 void
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,
179 Interpolator,
180 GradientFunction,
181 ColorArray> GradientGenerator;
183 Interpolator interpolator(gradientTransform);
185 ColorArray array(gradientColors);
186 GradientGenerator gradientGenerator(interpolator, function, array,
187 start, end);
189 gradientGenerator.generate(span, x, y, len);
192 // #pragma mark -
194 class HintingTransformer {
195 public:
197 void transform(double* x, double* y) const
199 *x = floor(*x + 0.5);
200 *y = floor(*y + 0.5);
205 // #pragma mark -
207 // constructor
208 IconRenderer::IconRenderer(BBitmap* bitmap)
209 : fBitmap(bitmap),
210 fBackground(NULL),
211 fBackgroundColor(0, 0, 0, 0),
212 fIcon(NULL),
214 fGammaTable(2.2),
216 fRenderingBuffer(),
217 fPixelFormat(fRenderingBuffer),
218 fPixelFormatPre(fRenderingBuffer),
219 fBaseRenderer(fPixelFormat),
220 fBaseRendererPre(fPixelFormatPre),
222 fScanline(),
223 fBinaryScanline(),
224 fSpanAllocator(),
226 fRasterizer(),
228 fGlobalTransform()
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());
239 // destructor
240 IconRenderer::~IconRenderer()
244 // SetIcon
245 void
246 IconRenderer::SetIcon(const Icon* icon)
248 if (fIcon == icon)
249 return;
251 fIcon = icon;
252 // TODO: ... ?
255 // Render
256 void
257 IconRenderer::Render()
259 _Render(fBitmap->Bounds());
262 // Render
263 void
264 IconRenderer::Render(const BRect& area)
266 _Render(fBitmap->Bounds() & area);
269 //SetScale
270 void
271 IconRenderer::SetScale(double scale)
273 fGlobalTransform.reset();
274 fGlobalTransform.multiply(agg::trans_affine_scaling(scale));
277 //SetBackground
278 void
279 IconRenderer::SetBackground(const BBitmap* background)
281 fBackground = background;
284 //SetBackground
285 void
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;
294 // Demultiply
295 void
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++) {
304 uint8* b = bits;
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]);
311 b += 4;
313 bits += bpr;
317 // #pragma mark -
319 typedef agg::conv_transform<VertexSource, Transformation> ScaledPath;
320 typedef agg::conv_transform<ScaledPath, HintingTransformer> HintedPath;
322 // _Render
323 void
324 IconRenderer::_Render(const BRect& r)
326 if (!fIcon)
327 return;
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));
333 if (fBackground)
334 memcpy(fBitmap->Bits(), fBackground->Bits(), fBitmap->BitsLength());
335 else
336 fBaseRendererPre.clear(fBackgroundColor);
338 //bigtime_t start = system_time();
339 StyleHandler styleHandler(fGammaTable);
341 fRasterizer.reset();
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)) {
356 continue;
359 Transformation transform(*shape);
360 transform.multiply(fGlobalTransform);
361 // NOTE: this works only because "agg::trans_affine",
362 // "Transformable" and "Transformation" are all the
363 // same thing
365 Style* style = shape->Style();
366 if (!style)
367 continue;
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(),
376 fGlobalTransform);
377 } else {
378 styleAdded = styleHandler.AddStyle(shape->Style(), transform);
381 if (!styleAdded) {
382 printf("IconRenderer::_Render() - out of memory\n");
383 break;
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);
392 styleIndex++;
394 // global scale
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);
402 } else {
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);
416 // _CommitRenderPass
417 void
418 IconRenderer::_CommitRenderPass(StyleHandler& styleHandler, bool reset)
420 agg::render_scanlines_compound(fRasterizer, fScanline, fBinaryScanline,
421 fBaseRendererPre, fSpanAllocator, styleHandler);
423 if (reset)
424 fRasterizer.reset();