1
2#include <stdio.h>
3#include <stack.h>
4
5#include <Region.h>
6
7#include "AccelerantHWInterface.h"
8#include "DirectWindowBuffer.h"
9
10#include "DrawingEngine.h"
11
12// constructor
13DrawingEngine::DrawingEngine(AccelerantHWInterface* interface,
14							 DirectWindowBuffer* buffer)
15	: fHWInterface(interface),
16	  fBuffer(buffer),
17	  fCurrentClipping()
18{
19}
20
21// destructor
22DrawingEngine::~DrawingEngine()
23{
24}
25
26// Lock
27bool
28DrawingEngine::Lock()
29{
30	return fHWInterface->Lock();
31}
32
33// Unlock
34void
35DrawingEngine::Unlock()
36{
37	fHWInterface->Unlock();
38}
39
40// ConstrainClipping
41void
42DrawingEngine::ConstrainClipping(BRegion* region)
43{
44	if (region)
45		fCurrentClipping = *region;
46	else
47		fCurrentClipping.MakeEmpty();
48}
49
50// StraightLine
51bool
52DrawingEngine::StraightLine(BPoint a, BPoint b, const rgb_color& c)
53{
54	uint8* dst = (uint8*)fBuffer->Bits();
55	uint32 bpr = fBuffer->BytesPerRow();
56
57	if (dst && fCurrentClipping.Frame().IsValid()) {
58
59		int32 clipBoxCount = fCurrentClipping.CountRects();
60
61		uint32 color;
62		color = (255 << 24) | (c.red << 16) | (c.green << 8) | (c.blue);
63
64		if (a.x == b.x) {
65			// vertical
66			int32 x = (int32)a.x;
67			dst += x * 4;
68			int32 y1 = (int32)min_c(a.y, b.y);
69			int32 y2 = (int32)max_c(a.y, b.y);
70			// draw a line, iterate over clipping boxes
71			for (int32 i = 0; i < clipBoxCount; i++) {
72				clipping_rect rect = fCurrentClipping.RectAtInt(i);
73
74				if (rect.left <= x &&
75					rect.right >= x) {
76					int32 i = max_c(rect.top, y1);
77					int32 end = min_c(rect.bottom, y2);
78					uint8* handle = dst + i * bpr;
79					for (; i <= end; i++) {
80						*(uint32*)handle = color;
81						handle += bpr;
82					}
83				}
84			}
85
86			return true;
87
88		} else if (a.y == b.y) {
89			// horizontal
90			int32 y = (int32)a.y;
91			dst += y * bpr;
92			int32 x1 = (int32)min_c(a.x, b.x);
93			int32 x2 = (int32)max_c(a.x, b.x);
94			// draw a line, iterate over clipping boxes
95			for (int32 i = 0; i < clipBoxCount; i++) {
96				clipping_rect rect = fCurrentClipping.RectAtInt(i);
97
98				if (rect.top <= y &&
99					rect.bottom >= y) {
100					int32 i = max_c(rect.left, x1);
101					int32 end = min_c(rect.right, x2);
102					uint32* handle = (uint32*)(dst + i * 4);
103					for (; i <= end; i++) {
104						*handle++ = color;
105					}
106				}
107			}
108
109			return true;
110		}
111	}
112	return false;
113}
114
115// StrokeLine
116void
117DrawingEngine::StrokeLine(BPoint a, BPoint b, const rgb_color& color)
118{
119	if (!StraightLine(a, b, color)) {
120		// ...
121	}
122}
123
124// StrokeRect
125void
126DrawingEngine::StrokeRect(BRect r, const rgb_color& color)
127{
128	StrokeLine(r.LeftTop(), r.RightTop(), color);
129	StrokeLine(r.RightTop(), r.RightBottom(), color);
130	StrokeLine(r.RightBottom(), r.LeftBottom(), color);
131	StrokeLine(r.LeftBottom(), r.LeftTop(), color);
132}
133
134// FillRegion
135void
136DrawingEngine::FillRegion(BRegion *region, const rgb_color& color)
137{
138	if (Lock()) {
139		// for speed reasons, expected to be already clipped
140		fHWInterface->FillRegion(*region, color);
141
142		Unlock();
143	}
144}
145
146// DrawString
147void
148DrawingEngine::DrawString(const char* string, BPoint baseLine,
149						  const rgb_color& color)
150{
151}
152
153
154
155
156struct node {
157			node()
158			{
159				pointers = NULL;
160			}
161			node(const BRect& r, int32 maxPointers)
162			{
163				init(r, maxPointers);
164			}
165			~node()
166			{
167				delete [] pointers;
168			}
169
170	void	init(const BRect& r, int32 maxPointers)
171			{
172				rect = r;
173				pointers = new node*[maxPointers];
174				in_degree = 0;
175				next_pointer = 0;
176			}
177
178	void	push(node* node)
179			{
180				pointers[next_pointer] = node;
181				next_pointer++;
182			}
183	node*	top()
184			{
185				return pointers[next_pointer];
186			}
187	node*	pop()
188			{
189				node* ret = top();
190				next_pointer--;
191				return ret;
192			}
193
194	BRect	rect;
195	int32	in_degree;
196	node**	pointers;
197	int32	next_pointer;
198};
199
200bool
201is_left_of(const BRect& a, const BRect& b)
202{
203	return (a.right < b.left);
204}
205bool
206is_above(const BRect& a, const BRect& b)
207{
208	return (a.bottom < b.top);
209}
210
211void
212DrawingEngine::CopyRegion(BRegion* region, int32 xOffset, int32 yOffset)
213{
214	if (Lock()) {
215
216		int32 count = region->CountRects();
217
218		// TODO: make this step unnecessary
219		// (by using different stack impl inside node)
220		node nodes[count];
221		for (int32 i= 0; i < count; i++) {
222			nodes[i].init(region->RectAt(i), count);
223		}
224
225		for (int32 i = 0; i < count; i++) {
226			BRect a = region->RectAt(i);
227			for (int32 k = i + 1; k < count; k++) {
228				BRect b = region->RectAt(k);
229				int cmp = 0;
230				// compare horizontally
231				if (xOffset > 0) {
232					if (is_left_of(a, b)) {
233						cmp -= 1;
234					} else if (is_left_of(b, a)) {
235						cmp += 1;
236					}
237				} else if (xOffset < 0) {
238					if (is_left_of(a, b)) {
239						cmp += 1;
240					} else if (is_left_of(b, a)) {
241						cmp -= 1;
242					}
243				}
244				// compare vertically
245				if (yOffset > 0) {
246					if (is_above(a, b)) {
247						cmp -= 1;
248					} else if (is_above(b, a)) {
249						cmp += 1;
250					}
251				} else if (yOffset < 0) {
252					if (is_above(a, b)) {
253						cmp += 1;
254					} else if (is_above(b, a)) {
255						cmp -= 1;
256					}
257				}
258				// add appropriate node as successor
259				if (cmp > 0) {
260					nodes[i].push(&nodes[k]);
261					nodes[k].in_degree++;
262				} else if (cmp < 0) {
263					nodes[k].push(&nodes[i]);
264					nodes[i].in_degree++;
265				}
266			}
267		}
268		// put all nodes onto a stack that have an "indegree" count of zero
269		stack<node*> inDegreeZeroNodes;
270		for (int32 i = 0; i < count; i++) {
271			if (nodes[i].in_degree == 0) {
272				inDegreeZeroNodes.push(&nodes[i]);
273			}
274		}
275		// pop the rects from the stack, do the actual copy operation
276		// and decrease the "indegree" count of the other rects not
277		// currently on the stack and to which the current rect pointed
278		// to. If their "indegree" count reaches zero, put them onto the
279		// stack as well.
280
281		clipping_rect* sortedRectList = new clipping_rect[count];
282		int32 nextSortedIndex = 0;
283
284		while (!inDegreeZeroNodes.empty()) {
285			node* n = inDegreeZeroNodes.top();
286			inDegreeZeroNodes.pop();
287
288			sortedRectList[nextSortedIndex].left	= (int32)n->rect.left;
289			sortedRectList[nextSortedIndex].top		= (int32)n->rect.top;
290			sortedRectList[nextSortedIndex].right	= (int32)n->rect.right;
291			sortedRectList[nextSortedIndex].bottom	= (int32)n->rect.bottom;
292			nextSortedIndex++;
293
294			for (int32 k = 0; k < n->next_pointer; k++) {
295				n->pointers[k]->in_degree--;
296				if (n->pointers[k]->in_degree == 0)
297					inDegreeZeroNodes.push(n->pointers[k]);
298			}
299		}
300
301		// trigger the HW accelerated blit
302		fHWInterface->CopyRegion(sortedRectList, count, xOffset, yOffset);
303
304		delete[] sortedRectList;
305
306		Unlock();
307	}
308}
309