#include <stdio.h>
#include <stack.h>
#include <Region.h>
#include "AccelerantHWInterface.h"
#include "DirectWindowBuffer.h"
#include "DrawingEngine.h"
DrawingEngine::DrawingEngine(AccelerantHWInterface* interface,
DirectWindowBuffer* buffer)
: fHWInterface(interface),
fBuffer(buffer),
fCurrentClipping()
{
}
DrawingEngine::~DrawingEngine()
{
}
bool
DrawingEngine::Lock()
{
return fHWInterface->Lock();
}
void
DrawingEngine::Unlock()
{
fHWInterface->Unlock();
}
void
DrawingEngine::ConstrainClipping(BRegion* region)
{
if (region)
fCurrentClipping = *region;
else
fCurrentClipping.MakeEmpty();
}
bool
DrawingEngine::StraightLine(BPoint a, BPoint b, const rgb_color& c)
{
uint8* dst = (uint8*)fBuffer->Bits();
uint32 bpr = fBuffer->BytesPerRow();
if (dst && fCurrentClipping.Frame().IsValid()) {
int32 clipBoxCount = fCurrentClipping.CountRects();
uint32 color;
color = (255 << 24) | (c.red << 16) | (c.green << 8) | (c.blue);
if (a.x == b.x) {
int32 x = (int32)a.x;
dst += x * 4;
int32 y1 = (int32)min_c(a.y, b.y);
int32 y2 = (int32)max_c(a.y, b.y);
for (int32 i = 0; i < clipBoxCount; i++) {
clipping_rect rect = fCurrentClipping.RectAtInt(i);
if (rect.left <= x &&
rect.right >= x) {
int32 i = max_c(rect.top, y1);
int32 end = min_c(rect.bottom, y2);
uint8* handle = dst + i * bpr;
for (; i <= end; i++) {
*(uint32*)handle = color;
handle += bpr;
}
}
}
return true;
} else if (a.y == b.y) {
int32 y = (int32)a.y;
dst += y * bpr;
int32 x1 = (int32)min_c(a.x, b.x);
int32 x2 = (int32)max_c(a.x, b.x);
for (int32 i = 0; i < clipBoxCount; i++) {
clipping_rect rect = fCurrentClipping.RectAtInt(i);
if (rect.top <= y &&
rect.bottom >= y) {
int32 i = max_c(rect.left, x1);
int32 end = min_c(rect.right, x2);
uint32* handle = (uint32*)(dst + i * 4);
for (; i <= end; i++) {
*handle++ = color;
}
}
}
return true;
}
}
return false;
}
void
DrawingEngine::StrokeLine(BPoint a, BPoint b, const rgb_color& color)
{
if (!StraightLine(a, b, color)) {
}
}
void
DrawingEngine::StrokeRect(BRect r, const rgb_color& color)
{
StrokeLine(r.LeftTop(), r.RightTop(), color);
StrokeLine(r.RightTop(), r.RightBottom(), color);
StrokeLine(r.RightBottom(), r.LeftBottom(), color);
StrokeLine(r.LeftBottom(), r.LeftTop(), color);
}
void
DrawingEngine::FillRegion(BRegion *region, const rgb_color& color)
{
if (Lock()) {
fHWInterface->FillRegion(*region, color);
Unlock();
}
}
void
DrawingEngine::DrawString(const char* string, BPoint baseLine,
const rgb_color& color)
{
}
struct node {
node()
{
pointers = NULL;
}
node(const BRect& r, int32 maxPointers)
{
init(r, maxPointers);
}
~node()
{
delete [] pointers;
}
void init(const BRect& r, int32 maxPointers)
{
rect = r;
pointers = new node*[maxPointers];
in_degree = 0;
next_pointer = 0;
}
void push(node* node)
{
pointers[next_pointer] = node;
next_pointer++;
}
node* top()
{
return pointers[next_pointer];
}
node* pop()
{
node* ret = top();
next_pointer--;
return ret;
}
BRect rect;
int32 in_degree;
node** pointers;
int32 next_pointer;
};
bool
is_left_of(const BRect& a, const BRect& b)
{
return (a.right < b.left);
}
bool
is_above(const BRect& a, const BRect& b)
{
return (a.bottom < b.top);
}
void
DrawingEngine::CopyRegion(BRegion* region, int32 xOffset, int32 yOffset)
{
if (Lock()) {
int32 count = region->CountRects();
node nodes[count];
for (int32 i= 0; i < count; i++) {
nodes[i].init(region->RectAt(i), count);
}
for (int32 i = 0; i < count; i++) {
BRect a = region->RectAt(i);
for (int32 k = i + 1; k < count; k++) {
BRect b = region->RectAt(k);
int cmp = 0;
if (xOffset > 0) {
if (is_left_of(a, b)) {
cmp -= 1;
} else if (is_left_of(b, a)) {
cmp += 1;
}
} else if (xOffset < 0) {
if (is_left_of(a, b)) {
cmp += 1;
} else if (is_left_of(b, a)) {
cmp -= 1;
}
}
if (yOffset > 0) {
if (is_above(a, b)) {
cmp -= 1;
} else if (is_above(b, a)) {
cmp += 1;
}
} else if (yOffset < 0) {
if (is_above(a, b)) {
cmp += 1;
} else if (is_above(b, a)) {
cmp -= 1;
}
}
if (cmp > 0) {
nodes[i].push(&nodes[k]);
nodes[k].in_degree++;
} else if (cmp < 0) {
nodes[k].push(&nodes[i]);
nodes[i].in_degree++;
}
}
}
stack<node*> inDegreeZeroNodes;
for (int32 i = 0; i < count; i++) {
if (nodes[i].in_degree == 0) {
inDegreeZeroNodes.push(&nodes[i]);
}
}
clipping_rect* sortedRectList = new clipping_rect[count];
int32 nextSortedIndex = 0;
while (!inDegreeZeroNodes.empty()) {
node* n = inDegreeZeroNodes.top();
inDegreeZeroNodes.pop();
sortedRectList[nextSortedIndex].left = (int32)n->rect.left;
sortedRectList[nextSortedIndex].top = (int32)n->rect.top;
sortedRectList[nextSortedIndex].right = (int32)n->rect.right;
sortedRectList[nextSortedIndex].bottom = (int32)n->rect.bottom;
nextSortedIndex++;
for (int32 k = 0; k < n->next_pointer; k++) {
n->pointers[k]->in_degree--;
if (n->pointers[k]->in_degree == 0)
inDegreeZeroNodes.push(n->pointers[k]);
}
}
fHWInterface->CopyRegion(sortedRectList, count, xOffset, yOffset);
delete[] sortedRectList;
Unlock();
}
}