⛏️ index : haiku.git


#include <stdio.h>
#include <stack.h>

#include <Region.h>

#include "AccelerantHWInterface.h"
#include "DirectWindowBuffer.h"

#include "DrawingEngine.h"

// constructor
DrawingEngine::DrawingEngine(AccelerantHWInterface* interface,
							 DirectWindowBuffer* buffer)
	: fHWInterface(interface),
	  fBuffer(buffer),
	  fCurrentClipping()
{
}

// destructor
DrawingEngine::~DrawingEngine()
{
}

// Lock
bool
DrawingEngine::Lock()
{
	return fHWInterface->Lock();
}

// Unlock
void
DrawingEngine::Unlock()
{
	fHWInterface->Unlock();
}

// ConstrainClipping
void
DrawingEngine::ConstrainClipping(BRegion* region)
{
	if (region)
		fCurrentClipping = *region;
	else
		fCurrentClipping.MakeEmpty();
}

// StraightLine
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) {
			// vertical
			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);
			// draw a line, iterate over clipping boxes
			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) {
			// horizontal
			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);
			// draw a line, iterate over clipping boxes
			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;
}

// StrokeLine
void
DrawingEngine::StrokeLine(BPoint a, BPoint b, const rgb_color& color)
{
	if (!StraightLine(a, b, color)) {
		// ...
	}
}

// StrokeRect
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);
}

// FillRegion
void
DrawingEngine::FillRegion(BRegion *region, const rgb_color& color)
{
	if (Lock()) {
		// for speed reasons, expected to be already clipped
		fHWInterface->FillRegion(*region, color);

		Unlock();
	}
}

// DrawString
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();
	
		// TODO: make this step unnecessary
		// (by using different stack impl inside node)
		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;
				// compare horizontally
				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;
					}
				}
				// compare vertically
				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;
					}
				}
				// add appropriate node as successor
				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++;
				}
			}
		}
		// put all nodes onto a stack that have an "indegree" count of zero
		stack<node*> inDegreeZeroNodes;
		for (int32 i = 0; i < count; i++) {
			if (nodes[i].in_degree == 0) {
				inDegreeZeroNodes.push(&nodes[i]);
			}
		}
		// pop the rects from the stack, do the actual copy operation
		// and decrease the "indegree" count of the other rects not
		// currently on the stack and to which the current rect pointed
		// to. If their "indegree" count reaches zero, put them onto the
		// stack as well.

		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]);
			}
		}

		// trigger the HW accelerated blit
		fHWInterface->CopyRegion(sortedRectList, count, xOffset, yOffset);

		delete[] sortedRectList;

		Unlock();
	}
}