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_NO_SCALE_H
9#define DRAW_BITMAP_NO_SCALE_H
10
11#include "IntPoint.h"
12#include "IntRect.h"
13#include "Painter.h"
14#include "SystemPalette.h"
15
16
17template<class BlendType>
18struct DrawBitmapNoScale {
19public:
20	void
21	Draw(PainterAggInterface& aggInterface, agg::rendering_buffer& bitmap,
22		uint32 bytesPerSourcePixel, IntPoint offset, BRect destinationRect)
23	{
24		// NOTE: this would crash if destinationRect was large enough to read
25		// outside the bitmap, so make sure this is not the case before calling
26		// this function!
27		uint8* dst = aggInterface.fBuffer.row_ptr(0);
28		const uint32 dstBPR = aggInterface.fBuffer.stride();
29
30		const uint8* src = bitmap.row_ptr(0);
31		const uint32 srcBPR = bitmap.stride();
32
33		const int32 left = (int32)destinationRect.left;
34		const int32 top = (int32)destinationRect.top;
35		const int32 right = (int32)destinationRect.right;
36		const int32 bottom = (int32)destinationRect.bottom;
37
38#if DEBUG_DRAW_BITMAP
39	if (left - offset.x < 0
40		|| left  - offset.x >= (int32)bitmap.width()
41		|| right - offset.x >= (int32)srcBuffer.width()
42		|| top - offset.y < 0
43		|| top - offset.y >= (int32)bitmap.height()
44		|| bottom - offset.y >= (int32)bitmap.height()) {
45		char message[256];
46		sprintf(message, "reading outside of bitmap (%ld, %ld, %ld, %ld) "
47				"(%d, %d) (%ld, %ld)",
48			left - offset.x, top - offset.y,
49			right - offset.x, bottom - offset.y,
50			bitmap.width(), bitmap.height(), offset.x, offset.y);
51		debugger(message);
52	}
53#endif
54
55		fColorMap = SystemPalette();
56		fAlphaMask = aggInterface.fClippedAlphaMask;
57		renderer_base& baseRenderer = aggInterface.fBaseRenderer;
58
59		// copy rects, iterate over clipping boxes
60		baseRenderer.first_clip_box();
61		do {
62			fRect.left  = max_c(baseRenderer.xmin(), left);
63			fRect.right = min_c(baseRenderer.xmax(), right);
64			if (fRect.left <= fRect.right) {
65				fRect.top    = max_c(baseRenderer.ymin(), top);
66				fRect.bottom = min_c(baseRenderer.ymax(), bottom);
67				if (fRect.top <= fRect.bottom) {
68					uint8* dstHandle = dst + fRect.top * dstBPR
69						+ fRect.left * 4;
70					const uint8* srcHandle = src
71						+ (fRect.top  - offset.y) * srcBPR
72						+ (fRect.left - offset.x) * bytesPerSourcePixel;
73
74					for (; fRect.top <= fRect.bottom; fRect.top++) {
75						static_cast<BlendType*>(this)->BlendRow(dstHandle,
76							srcHandle, fRect.right - fRect.left + 1);
77
78						dstHandle += dstBPR;
79						srcHandle += srcBPR;
80					}
81				}
82			}
83		} while (baseRenderer.next_clip_box());
84	}
85
86protected:
87	IntRect fRect;
88	const rgb_color* fColorMap;
89	const agg::clipped_alpha_mask* fAlphaMask;
90};
91
92
93struct CMap8Copy : public DrawBitmapNoScale<CMap8Copy>
94{
95	void BlendRow(uint8* dst, const uint8* src, int32 numPixels)
96	{
97		uint32* d = (uint32*)dst;
98		const uint8* s = src;
99		while (numPixels--) {
100			const rgb_color c = fColorMap[*s++];
101			*d++ = (c.alpha << 24) | (c.red << 16) | (c.green << 8) | (c.blue);
102		}
103	}
104};
105
106
107struct CMap8Over : public DrawBitmapNoScale<CMap8Over>
108{
109	void BlendRow(uint8* dst, const uint8* src, int32 numPixels)
110	{
111		uint32* d = (uint32*)dst;
112		const uint8* s = src;
113		while (numPixels--) {
114			const rgb_color c = fColorMap[*s++];
115			if (c.alpha)
116				*d = (c.alpha << 24) | (c.red << 16)
117					| (c.green << 8) | (c.blue);
118			d++;
119		}
120	}
121};
122
123
124struct Bgr32Copy : public DrawBitmapNoScale<Bgr32Copy>
125{
126	void BlendRow(uint8* dst, const uint8* src, int32 numPixels)
127	{
128		memcpy(dst, src, numPixels * 4);
129	}
130};
131
132
133struct Bgr32Over : public DrawBitmapNoScale<Bgr32Over>
134{
135	void BlendRow(uint8* dst, const uint8* src, int32 numPixels)
136	{
137		uint32* d = (uint32*)dst;
138		uint32* s = (uint32*)src;
139		while (numPixels--) {
140			if (*s != B_TRANSPARENT_MAGIC_RGBA32)
141				*(uint32*)d = *(uint32*)s;
142			d++;
143			s++;
144		}
145	}
146};
147
148
149struct Bgr32Alpha : public DrawBitmapNoScale<Bgr32Alpha>
150{
151	void BlendRow(uint8* dst, const uint8* src, int32 numPixels)
152	{
153		uint32* d = (uint32*)dst;
154		int32 bytes = numPixels * 4;
155		uint8 buffer[bytes];
156		uint8* b = buffer;
157		while (numPixels--) {
158			if (src[3] == 255) {
159				*(uint32*)b = *(uint32*)src;
160			} else {
161				*(uint32*)b = *d;
162				b[0] = ((src[0] - b[0]) * src[3] + (b[0] << 8)) >> 8;
163				b[1] = ((src[1] - b[1]) * src[3] + (b[1] << 8)) >> 8;
164				b[2] = ((src[2] - b[2]) * src[3] + (b[2] << 8)) >> 8;
165			}
166			d++;
167			b += 4;
168			src += 4;
169		}
170		memcpy(dst, buffer, bytes);
171	}
172};
173
174
175struct Bgr32CopyMasked : public DrawBitmapNoScale<Bgr32CopyMasked>
176{
177	void BlendRow(uint8* dst, const uint8* src, int32 numPixels)
178	{
179		uint8 covers[numPixels];
180		fAlphaMask->get_hspan(fRect.left, fRect.top, covers, numPixels);
181
182		uint32* destination = (uint32*)dst;
183		uint32* source = (uint32*)src;
184		uint8* mask = (uint8*)&covers[0];
185
186		while (numPixels--) {
187			if (*mask != 0)
188				*destination = *source;
189			destination++;
190			source++;
191			mask++;
192		}
193	}
194};
195
196
197#endif // DRAW_BITMAP_NO_SCALE_H
198