xref: /haiku/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapGeneric.h (revision c67dde0f2ccb45d550af410cf6d73fee39d10504)
1 /*
2  * Copyright 2009, Christian Packmann.
3  * Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
4  * Copyright 2005-2014, Stephan Aßmus <superstippi@gmx.de>.
5  * Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de>
6  * All rights reserved. Distributed under the terms of the MIT License.
7  */
8 #ifndef DRAW_BITMAP_GENERIC_H
9 #define DRAW_BITMAP_GENERIC_H
10 
11 #include "Painter.h"
12 
13 
14 struct Fill {};
15 struct Tile {};
16 
17 template<typename PixFmt, typename Mode>
18 struct ImageAccessor {};
19 
20 template<typename PixFmt>
21 struct ImageAccessor<PixFmt, Fill> {
22 	typedef agg::image_accessor_clone<PixFmt> type;
23 };
24 
25 template<typename PixFmt>
26 struct ImageAccessor<PixFmt, Tile> {
27 	typedef agg::image_accessor_wrap<PixFmt,
28 		agg::wrap_mode_repeat, agg::wrap_mode_repeat> type;
29 };
30 
31 
32 template<typename FillMode>
33 struct DrawBitmapGeneric {
34 	static void
35 	Draw(const Painter* painter, PainterAggInterface& aggInterface,
36 		agg::rendering_buffer& bitmap, BPoint offset,
37 		double scaleX, double scaleY, BRect destinationRect, uint32 options)
38 	{
39 		// pixel format attached to bitmap
40 		typedef agg::pixfmt_bgra32 pixfmt_image;
41 		pixfmt_image pixf_img(bitmap);
42 
43 		agg::trans_affine srcMatrix;
44 		// NOTE: R5 seems to ignore this offset when drawing bitmaps
45 		//	srcMatrix *= agg::trans_affine_translation(-actualBitmapRect.left,
46 		//		-actualBitmapRect.top);
47 		srcMatrix *= painter->Transform();
48 
49 		agg::trans_affine imgMatrix;
50 		imgMatrix *= agg::trans_affine_translation(
51 			offset.x - destinationRect.left, offset.y - destinationRect.top);
52 		imgMatrix *= agg::trans_affine_scaling(scaleX, scaleY);
53 		imgMatrix *= agg::trans_affine_translation(destinationRect.left,
54 			destinationRect.top);
55 		imgMatrix *= painter->Transform();
56 		imgMatrix.invert();
57 
58 		// image interpolator
59 		typedef agg::span_interpolator_linear<> interpolator_type;
60 		interpolator_type interpolator(imgMatrix);
61 
62 		// scanline allocator
63 		agg::span_allocator<pixfmt_image::color_type> spanAllocator;
64 
65 		// image accessor attached to pixel format of bitmap
66 		typedef
67 			typename ImageAccessor<pixfmt_image, FillMode>::type source_type;
68 		source_type source(pixf_img);
69 
70 		// clip to the current clipping region's frame
71 		if (painter->IsIdentityTransform()) {
72 			destinationRect = destinationRect
73 				& painter->ClippingRegion()->Frame();
74 		}
75 		// convert to pixel coords (versus pixel indices)
76 		destinationRect.right++;
77 		destinationRect.bottom++;
78 
79 		// path enclosing the bitmap
80 		agg::path_storage& path = aggInterface.fPath;
81 		rasterizer_type& rasterizer = aggInterface.fRasterizer;
82 
83 		path.remove_all();
84 		path.move_to(destinationRect.left, destinationRect.top);
85 		path.line_to(destinationRect.right, destinationRect.top);
86 		path.line_to(destinationRect.right, destinationRect.bottom);
87 		path.line_to(destinationRect.left, destinationRect.bottom);
88 		path.close_polygon();
89 
90 		agg::conv_transform<agg::path_storage> transformedPath(path,
91 			srcMatrix);
92 		rasterizer.reset();
93 		rasterizer.add_path(transformedPath);
94 
95 		if ((options & B_FILTER_BITMAP_BILINEAR) != 0) {
96 			// image filter (bilinear)
97 			typedef agg::span_image_filter_rgba_bilinear<
98 				source_type, interpolator_type> span_gen_type;
99 			span_gen_type spanGenerator(source, interpolator);
100 
101 			// render the path with the bitmap as scanline fill
102 			if (aggInterface.fMaskedUnpackedScanline != NULL) {
103 				agg::render_scanlines_aa(rasterizer,
104 					*aggInterface.fMaskedUnpackedScanline,
105 					aggInterface.fBaseRenderer, spanAllocator, spanGenerator);
106 			} else {
107 				agg::render_scanlines_aa(rasterizer,
108 					aggInterface.fUnpackedScanline,
109 					aggInterface.fBaseRenderer, spanAllocator, spanGenerator);
110 			}
111 		} else {
112 			// image filter (nearest neighbor)
113 			typedef agg::span_image_filter_rgba_nn<
114 				source_type, interpolator_type> span_gen_type;
115 			span_gen_type spanGenerator(source, interpolator);
116 
117 			// render the path with the bitmap as scanline fill
118 			if (aggInterface.fMaskedUnpackedScanline != NULL) {
119 				agg::render_scanlines_aa(rasterizer,
120 					*aggInterface.fMaskedUnpackedScanline,
121 					aggInterface.fBaseRenderer, spanAllocator, spanGenerator);
122 			} else {
123 				agg::render_scanlines_aa(rasterizer,
124 					aggInterface.fUnpackedScanline,
125 					aggInterface.fBaseRenderer, spanAllocator, spanGenerator);
126 			}
127 		}
128 	}
129 };
130 
131 
132 #endif // DRAW_BITMAP_GENERIC_H
133