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