/*
	File	:	spanbuffer.cpp
	Author	:	Richard Flower (c) 1998 Core Design
	----------------------------------------------------------------------------------
	Functions
	----------------------------------------------------------------------------------

	SBAllocate		-	Allocate Memory For Span Buffer
	SBFree			-	Free Memory 

		
	----------------------------------------------------------------------------------
*/


#include "standard.h"
#include "global.h"
#include "spanbuffer.h"
#include "drawprimitive.h"
#include "winmain.h"


SEDGE **EdgeTableY;
SEDGE *EdgePool;
int   NextEdgePool;
int	  MaxY,MaxX;
SEDGE *NewEdge;
SURFACE *SurfaceList;
SURFACE *Head;
SURFACE *Tail;
SURFACE *NewSurface;
POLYGON *PolygonList;
int nPolygon;
int NextList;
POLYGON *CurrentPoly;
int XLeft,XRight;
int ScanLine;
POLYGON BackPoly;


int SpanInsCnt[480];



/*
	Function	:	SBAllocate
	Useage		:	Allocate Memory For Span Buffer
*/

bool SBAllocate(int maxx,int maxy)
{
	

	EdgeTableY   = NULL;
	EdgePool     = NULL;
	SurfaceList  = NULL;
	PolygonList  = NULL;
	

	EdgeTableY   = (SEDGE**)  malloc(maxy*sizeof(SEDGE*));
	EdgePool     = (SEDGE*)	  malloc(MAX_EDGES*sizeof(SEDGE));
	SurfaceList  = (SURFACE*) malloc(MAX_SURFACES*sizeof(SURFACE));
	PolygonList  = (POLYGON*) malloc(MAX_POLYGONS*sizeof(POLYGON));

	MaxX		= maxx;
	MaxY		= maxy;

	return true;
}

// EOF : SBAllocate


/*
	Function	:	SBFree
	Useage		:	Free Span Buffer Memory
*/

void SBFree()
{

	if(EdgeTableY  != NULL) free(EdgeTableY);
	if(EdgePool    != NULL) free(EdgePool);
	if(SurfaceList != NULL) free(SurfaceList);
	if(PolygonList != NULL) free(PolygonList);


	EdgeTableY   = NULL;
	EdgePool     = NULL;
	SurfaceList  = NULL;
	PolygonList  = NULL;
}

// EOF : SBFree



/*
	Function	:	SBInit
	Useage		:	Initialise Span Buffer (Call Every Frame)
*/

void SBInit()
{
	int n;
	NextEdgePool = 0;
	nPolygon = 0;

	for(n=0;n<MaxY;n++)
		EdgeTableY[n] = 0;

	Head = &SurfaceList[0];
	Tail = &SurfaceList[1];
	
	memset(&BackPoly,0,sizeof(POLYGON));

	BackPoly.ooz = -999.0f;

}

// EOF : SBInit





void SBAddPolygon(float ooz,float rf,float gf,float bf)
{
	if(nPolygon < MAX_POLYGONS)
	{
		int r,g,b;
		
		r = FTOL(rf);
		g = FTOL(gf);
		b = FTOL(bf);
		
		r >>= 3;
		g >>= 2;
		b >>= 3;

		PolygonList[nPolygon].ooz = ooz;
		PolygonList[nPolygon].rgb = r<<11|g<<5|b;
		PolygonList[nPolygon].StackStatus = 0;

		CurrentPoly = &PolygonList[nPolygon];

		nPolygon++;
	
	}
}






/*
	Function	:	SBAddEdge
	Useage		:	Add Edge To Buffer

*/

int cy;

void SBAddEdge(int x,int y)
{
	SEDGE* eptr;
	
	if(NextEdgePool < MAX_EDGES)
	{
		
		EdgePool[NextEdgePool].Poly = CurrentPoly;
		EdgePool[NextEdgePool].x    = x;
		EdgePool[NextEdgePool].Left = 0;
		EdgePool[NextEdgePool].Right= 0;

		eptr = EdgeTableY[y];

		cy = y;

		if(eptr == 0)
			EdgeTableY[y] = &EdgePool[NextEdgePool];
		else
			SBInsert(eptr,&EdgePool[NextEdgePool]);
	
	    NextEdgePool++;
		
	}
}

// EOF : SBAddEdge




/*
	Function	:	SBInsert
	Useage		:	Insert Span Into Edge Table
*/

void SBInsert(SEDGE *ptr,SEDGE* NewEdge)
{
	while(1)
	{
		if(NewEdge->x <= ptr->x)
		{
			if(ptr->Left != 0)
				ptr = ptr->Left;
			else
			{
				ptr->Left = NewEdge;
				break;
			}
		}
		else
		{
			if(ptr->Right != 0)
				ptr = ptr->Right;
			else
			{
				ptr->Right = NewEdge;
				break;
			}
		}

	}
}

// EOF : SBInsert

int SpanPixels;
unsigned short *spanout;

inline void DrawScanLine(int x1,int x2,int rgb)
{
	int width;
	unsigned short* pDestination;
	width = x2-x1;
	
	SpanPixels += width;

	pDestination = spanout+x1;

	while(width--)
		*(pDestination++) = rgb;
}



/*
	Function	:	SBDrawSpans
	Useage		:	Output The Spans
*/

void SBDrawSpans()
{

	for(ScanLine=0;ScanLine<MaxY;ScanLine++)
	{
		spanout = Output+(ScanLine*pitch);
				
		XLeft = 0;
		Head->Next = &SurfaceList[2];
		SurfaceList[2].Poly = &BackPoly;
		SurfaceList[2].Next = Tail;
		Tail->Next = 0;
		NextList = 3;
		
		if(EdgeTableY[ScanLine] != 0)
			SBTraverse(EdgeTableY[ScanLine]);

	    if (XLeft < MaxX-1)
			DrawScanLine(XLeft,MaxX,0);
	}
}


// EOF : SBDrawSpans



/*
	Function	:	SBTraverse
	Useage		:
*/

void SBTraverse(SEDGE* Edge)
{
	if(Edge->Left != 0)
		SBTraverse(Edge->Left);

	SBEdgeEvent(Edge);
	
	if(Edge->Right != 0)
		SBTraverse(Edge->Right);
}

// EOF : SBTraverse



/*
	Function	:	SBEdgeEvent
	Useage		:
*/

void SBEdgeEvent(SEDGE* Edge)
{
	SURFACE* ptr;
	float z;

	if(Edge->Poly->StackStatus)
	{
		if(Head->Next->Poly == Edge->Poly)
		{
			XRight = Edge->x;
				
			if(XLeft != XRight)
				DrawScanLine(XLeft,XRight,CurrentPoly->rgb);
			
			XLeft = XRight;

			CurrentPoly = Head->Next->Next->Poly;
		}

		Edge->Poly->StackStatus--;

		ptr = Head;

		while((ptr->Next) && (ptr->Next->Poly != Edge->Poly))
			ptr = ptr->Next;

		if(ptr->Next)
			ptr->Next = ptr->Next->Next;

	}
	else
	{
		z = Edge->Poly->ooz;

		if(z >= Head->Next->Poly->ooz)
		{
			XRight = Edge->x;

			if(XLeft != XRight)
				DrawScanLine(XLeft,XRight,CurrentPoly->rgb);

			XLeft = XRight;

			CurrentPoly = Edge->Poly;
		}
	
		if(NextList < MAX_SURFACES)
		{
			Edge->Poly->StackStatus++;
			ptr = Head;

			while(ptr->Next->Poly->ooz>= z)
				ptr = ptr->Next;

			NewSurface			= &SurfaceList[NextList++];
			NewSurface->Poly	= Edge->Poly;
			NewSurface->Next	= ptr->Next;
			ptr->Next			= NewSurface;
		}

	}
	
}


// EOF : SBEdgeEvent

















