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_NEAREST_NEIGHBOR_H
9#define DRAW_BITMAP_NEAREST_NEIGHBOR_H
10
11#include "Painter.h"
12
13
14struct DrawBitmapNearestNeighborCopy {
15	static void
16	Draw(const Painter* painter, PainterAggInterface& aggInterface,
17		agg::rendering_buffer& bitmap, BPoint offset,
18		double scaleX, double scaleY, BRect destinationRect)
19	{
20		//bigtime_t now = system_time();
21		uint32 dstWidth = destinationRect.IntegerWidth() + 1;
22		uint32 dstHeight = destinationRect.IntegerHeight() + 1;
23		uint32 srcWidth = bitmap.width();
24		uint32 srcHeight = bitmap.height();
25
26		// Do not calculate more filter weights than necessary and also
27		// keep the stack based allocations reasonably sized
28		const BRegion& clippingRegion = *painter->ClippingRegion();
29		if (clippingRegion.Frame().IntegerWidth() + 1 < (int32)dstWidth)
30			dstWidth = clippingRegion.Frame().IntegerWidth() + 1;
31		if (clippingRegion.Frame().IntegerHeight() + 1 < (int32)dstHeight)
32			dstHeight = clippingRegion.Frame().IntegerHeight() + 1;
33
34		// When calculating less filter weights than specified by
35		// destinationRect, we need to compensate the offset.
36		uint32 filterWeightXIndexOffset = 0;
37		uint32 filterWeightYIndexOffset = 0;
38		if (clippingRegion.Frame().left > destinationRect.left) {
39			filterWeightXIndexOffset = (int32)(clippingRegion.Frame().left
40				- destinationRect.left);
41		}
42		if (clippingRegion.Frame().top > destinationRect.top) {
43			filterWeightYIndexOffset = (int32)(clippingRegion.Frame().top
44				- destinationRect.top);
45		}
46
47		// should not pose a problem with stack overflows
48		// (needs around 6Kb for 1920x1200)
49		uint16 xIndices[dstWidth];
50		uint16 yIndices[dstHeight];
51
52		// Extract the cropping information for the source bitmap,
53		// If only a part of the source bitmap is to be drawn with scale,
54		// the offset will be different from the destinationRect left top
55		// corner.
56		const int32 xBitmapShift = (int32)(destinationRect.left - offset.x);
57		const int32 yBitmapShift = (int32)(destinationRect.top - offset.y);
58
59		for (uint32 i = 0; i < dstWidth; i++) {
60			// index into source
61			uint16 index = (uint16)((i + filterWeightXIndexOffset) * srcWidth
62				/ (srcWidth * scaleX));
63			// round down to get the left pixel
64			xIndices[i] = index;
65			// handle cropped source bitmap
66			xIndices[i] += xBitmapShift;
67			// precompute index for 32 bit pixels
68			xIndices[i] *= 4;
69		}
70
71		for (uint32 i = 0; i < dstHeight; i++) {
72			// index into source
73			uint16 index = (uint16)((i + filterWeightYIndexOffset) * srcHeight
74				/ (srcHeight * scaleY));
75			// round down to get the top pixel
76			yIndices[i] = index;
77			// handle cropped source bitmap
78			yIndices[i] += yBitmapShift;
79		}
80		//printf("X: %d ... %d, %d (%ld or %f)\n",
81		//	xIndices[0], xIndices[dstWidth - 2], xIndices[dstWidth - 1],
82		//	dstWidth, srcWidth * scaleX);
83		//printf("Y: %d ... %d, %d (%ld or %f)\n",
84		//	yIndices[0], yIndices[dstHeight - 2], yIndices[dstHeight - 1],
85		//	dstHeight, srcHeight * scaleY);
86
87		const int32 left = (int32)destinationRect.left;
88		const int32 top = (int32)destinationRect.top;
89		const int32 right = (int32)destinationRect.right;
90		const int32 bottom = (int32)destinationRect.bottom;
91
92		const uint32 dstBPR = aggInterface.fBuffer.stride();
93
94		renderer_base& baseRenderer = aggInterface.fBaseRenderer;
95
96		// iterate over clipping boxes
97		baseRenderer.first_clip_box();
98		do {
99			const int32 x1 = max_c(baseRenderer.xmin(), left);
100			const int32 x2 = min_c(baseRenderer.xmax(), right);
101			if (x1 > x2)
102				continue;
103
104			int32 y1 = max_c(baseRenderer.ymin(), top);
105			int32 y2 = min_c(baseRenderer.ymax(), bottom);
106			if (y1 > y2)
107				continue;
108
109			// buffer offset into destination
110			uint8* dst = aggInterface.fBuffer.row_ptr(y1) + x1 * 4;
111
112			// x and y are needed as indeces into the wheight arrays, so the
113			// offset into the target buffer needs to be compensated
114			const int32 xIndexL = x1 - left - filterWeightXIndexOffset;
115			const int32 xIndexR = x2 - left - filterWeightXIndexOffset;
116			y1 -= top + filterWeightYIndexOffset;
117			y2 -= top + filterWeightYIndexOffset;
118
119		//printf("x: %ld - %ld\n", xIndexL, xIndexR);
120		//printf("y: %ld - %ld\n", y1, y2);
121
122			for (; y1 <= y2; y1++) {
123				// buffer offset into source (top row)
124				const uint8* src = bitmap.row_ptr(yIndices[y1]);
125				// buffer handle for destination to be incremented per pixel
126				uint32* d = (uint32*)dst;
127
128				for (int32 x = xIndexL; x <= xIndexR; x++) {
129					*d = *(uint32*)(src + xIndices[x]);
130					d++;
131				}
132				dst += dstBPR;
133			}
134		} while (baseRenderer.next_clip_box());
135
136		//printf("draw bitmap %.5fx%.5f: %lld\n", xScale, yScale,
137		//	system_time() - now);
138	}
139};
140
141
142
143#endif // DRAW_BITMAP_NEAREST_NEIGHBOR_H
144