xref: /haiku/src/tests/servers/app/newerClipping/drawing/DrawingEngine.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
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
13 DrawingEngine::DrawingEngine(AccelerantHWInterface* interface,
14 							 DirectWindowBuffer* buffer)
15 	: fHWInterface(interface),
16 	  fBuffer(buffer),
17 	  fCurrentClipping()
18 {
19 }
20 
21 // destructor
22 DrawingEngine::~DrawingEngine()
23 {
24 }
25 
26 // Lock
27 bool
28 DrawingEngine::Lock()
29 {
30 	return fHWInterface->Lock();
31 }
32 
33 // Unlock
34 void
35 DrawingEngine::Unlock()
36 {
37 	fHWInterface->Unlock();
38 }
39 
40 // ConstrainClipping
41 void
42 DrawingEngine::ConstrainClipping(BRegion* region)
43 {
44 	if (region)
45 		fCurrentClipping = *region;
46 	else
47 		fCurrentClipping.MakeEmpty();
48 }
49 
50 // StraightLine
51 bool
52 DrawingEngine::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
116 void
117 DrawingEngine::StrokeLine(BPoint a, BPoint b, const rgb_color& color)
118 {
119 	if (!StraightLine(a, b, color)) {
120 		// ...
121 	}
122 }
123 
124 // StrokeRect
125 void
126 DrawingEngine::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
135 void
136 DrawingEngine::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
147 void
148 DrawingEngine::DrawString(const char* string, BPoint baseLine,
149 						  const rgb_color& color)
150 {
151 }
152 
153 
154 
155 
156 struct 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 
200 bool
201 is_left_of(const BRect& a, const BRect& b)
202 {
203 	return (a.right < b.left);
204 }
205 bool
206 is_above(const BRect& a, const BRect& b)
207 {
208 	return (a.bottom < b.top);
209 }
210 
211 void
212 DrawingEngine::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