/******************************************************************************

Copyright (c) 2005 Analog Devices.  All Rights Reserved.

This software is proprietary and confidential.  By using this software you agree
to the terms of the associated Analog Devices License Agreement.  

******************************************************************************/



/******************************************************************************

$File:		gfx.c $
$Revision: 1.3 $
$Date: 2008/06/06 07:19:20 $


Description:
   This is the primary source file for GFX

Modification History:
====================
Revision 1.0
Revision 1.1 - BJ (13/12/2005)
	- Made str[4096] array static in gfx_printf to stop stack overflow
	- Added support for NTSC
Revision 1.2 - BJ (09/04/2006)
	- Added YUV colour conversion and added getcolour function
Revision 1.3 - BJ (12/04/2006)
	- Fixed gfx_clear for VGA mode
Revision 2.0 - BJ (2006/07/09)
	- Re-wrote functions to support canvas structure. This allows for a more
	modular interface to graphisc functions


Note:
	YUV to RGB Conversion
	R=1.164(Y-16)+1.596(Cr-128)
	G=1.164(Y-16)-0.813(Cr-128)-0.391(Cb-128)
	B=1.164(Y-16)+2.018(Cb-128)
	
	RGB to YUV Conversion
	Y' = + 0.299    * R' + 0.587    * G' + 0.114    * B'
	Cb = - 0.168736 * R' - 0.331264 * G' + 0.5      * B'
	Cr = + 0.5      * R' - 0.418688 * G' - 0.081312 * B'
	YCbCr 4:2:2

	Y range=[16-235]
	Cr/Cb range=[16-240]
	RGB range=[0-255]
	
	SAV/EAV
	Bit 7 - 1
	Bit 6(F) - Field bit (1st Field: F=0, 2st Field: F=1)
	Bit 5(V) - Vertical blanking (VBI: V=1, Active video: V=0)
	Bit 4(H) - H=0 in SAV H=0, EAV H=1
	
******************************************************************************/



/******************************************************************************

Include files

******************************************************************************/

#include <services/services.h>	// system services
#include <drivers/adi_dev.h>

#include <ada_gfx/gfx.h>

#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <device.h>
#include <device_int.h>

#include <mutex.h>
#include <..\lib\src\libio\_stdio.h>

#include "font_5x5.c"
#include "font_3x7.c"
#include "font_5x7.c"
#include "font_7x7.c"
#include "font_9x12.c"




/******************************************************************************

Function definitions

******************************************************************************/

u32 gfx_preamble(GFX_MODE mode,u32 line,bool fmt);

int _sprintfputchar(FargT , char );




/******************************************************************************

Static data definitions

******************************************************************************/
//section ("sdram0_bank3_app")
u8 *gfx_fonttable[]=
{
	(u8 *)font_5x5,
	(u8 *)font_3x7,
	(u8 *)font_5x7,
	(u8 *)font_7x7,
	(u8 *)font_9x12,
	0,
};



/*********************************************************************
	
	Function: gfx_init
	
	Description: Initialise a canvas
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_init(
	GFX_CANVAS *Canvas,
	GFX_MODE Mode, 
	u16 *Data,
	long Left, long Top,
	long Width, long Height)
{
	if (Mode==GFX_MODE_UNKNOWN) return ADI_DEV_RESULT_FAILED;
	Canvas->Mode=Mode;
	Canvas->Data=Data;
	gfx_setjustify(Canvas,GFX_JUSTIFY_LEFT);
	gfx_setfont(Canvas,0);
	
	Canvas->x=Canvas->y=0;
	Canvas->sx=Canvas->sy=0;
	Canvas->Top=Top>0?Top:Top<0?gfx_getheight(Canvas)+Top:0;
	Canvas->Left=Left>0?Left:Top<0?gfx_getwidth(Canvas)+Left:0;
	Canvas->Height=Height>0?Height:gfx_getheight(Canvas)+(Height<0?Height:0);
	Canvas->Width=Width>0?Width:gfx_getwidth(Canvas)+(Width<0?Width:0);
	
	Canvas->Colour=gfx_getcolour(Canvas,255,255,255);
	
	return ADI_DEV_RESULT_SUCCESS;
}



/*********************************************************************
	
	Function: gfx_frame
	
	Description: Frame a buffer, also initialises blanking
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_frame(GFX_CANVAS *Canvas, u32 Colour)
{
	u32 x,y,Blank,Val;
	u32 *Data=(u32 *)Canvas->Data;
	
	u8 *Data8;
		
	if (!Canvas||!Data) return ADI_DEV_RESULT_FAILED;
	switch (Canvas->Mode)
	{
		case GFX_MODE_VGA_24bit:
			Blank=0;
			Data8=(u8 *)Canvas->Data;
			for (y=0;y<GFX_VGA_24bit_FRAME_HEIGHT;y++)
				for (x=0;x<GFX_VGA_24bit_FRAME_WIDTH;x++) 
				{
					*Data8++=(Colour>>16)&0x000000FF;
					*Data8++=(Colour>>8)&0x000000FF;
					*Data8++=Colour&0x000000FF;
					
				}
			break;
			
		case GFX_MODE_QVGA_24bit:
			Blank=0;
			Data8=(u8 *)Canvas->Data;
			for (y=0;y<GFX_QVGA_24bit_FRAME_HEIGHT;y++)
				for (x=0;x<GFX_QVGA_24bit_FRAME_WIDTH;x++) 
				{
					*Data8++=(Colour>>16)&0x000000FF;
					*Data8++=(Colour>>8)&0x000000FF;
					*Data8++=Colour&0x000000FF;
					
				}
			break;	
		
		case GFX_MODE_VGA:
			Blank=0;
			Colour=(Colour<<16)|Colour;
			for (y=0;y<GFX_VGA_TOP;y++)
				for (x=0;x<GFX_VGA_FRAME_WIDTH/2;x++) {*Data++=Blank; asm("nop;");}
			for (;y<GFX_VGA_FRAME_HEIGHT-GFX_VGA_BOTTOM;y++)
				for (x=0;x<GFX_VGA_FRAME_WIDTH/2;x++) {*Data++=Colour; asm("nop;");}
			for (;y<GFX_VGA_FRAME_HEIGHT;y++)
				for (x=0;x<GFX_VGA_FRAME_WIDTH/2;x++) {*Data++=Blank; asm("nop;");}
			break;		
			
		case GFX_MODE_NTSC:
		case GFX_MODE_NTSCI:
			Blank=0x10801080;
			for (y=0;y<GFX_NTSC_FRAME_HEIGHT;y++)
			{
				u32 Start=gfx_preamble(Canvas->Mode,y,0),End=gfx_preamble(Canvas->Mode,y,1);
				for (x=0,Val=Start;x<(GFX_NTSC_WIDTH+GFX_NTSC_LEFT)/2;x++,Val=Start&0x20000000?Blank:Colour) *Data++=Val;
				for (Val=End;x<GFX_NTSC_FRAME_WIDTH/2;x++,Val=Blank) *Data++=Val;
			}
			break;
			
			
		case GFX_MODE_PAL:
		case GFX_MODE_PALI:
			Blank=0x10801080;
			for (y=0;y<GFX_PAL_FRAME_HEIGHT;y++)
			{
				u32 Start=gfx_preamble(Canvas->Mode,y,0),End=gfx_preamble(Canvas->Mode,y,1);
				for (x=0,Val=Start;x<(GFX_PAL_WIDTH+GFX_PAL_LEFT)/2;x++,Val=Start&0x20000000?Blank:Colour) *Data++=Val;
				for (Val=End;x<GFX_PAL_FRAME_WIDTH/2;x++,Val=Blank) *Data++=Val;
			}
			break;
	}
	return ADI_DEV_RESULT_SUCCESS;
}




/*********************************************************************
	
	Function: gfx_getmode
	
	Description: Get the graphics mode set by gfx_setmode
	
*********************************************************************/
//section ("sdram0_bank3_app")
GFX_MODE gfx_getmode(GFX_CANVAS *Canvas)
{
	return Canvas->Mode;
}




/*********************************************************************
	
	Function: gfx_getframewidth
	
	Description: Get the frame width based on GFX_MODE
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_getframewidth(GFX_CANVAS *Canvas)
{
	switch (Canvas->Mode)
	{
		case GFX_MODE_VGA: 
			return GFX_VGA_FRAME_WIDTH;
		case GFX_MODE_VGA_24bit: 
			return GFX_VGA_24bit_FRAME_WIDTH;
	case GFX_MODE_QVGA_24bit: 
			return GFX_QVGA_24bit_FRAME_WIDTH;	
		case GFX_MODE_NTSC:
		case GFX_MODE_NTSCI: 
			return GFX_NTSC_FRAME_WIDTH;
	
		case GFX_MODE_PAL:
		case GFX_MODE_PALI: 
			return GFX_PAL_FRAME_WIDTH;
	}
	return 0;
}




/*********************************************************************
	
	Function: gfx_getframeheight
	
	Description: Get the frame height based on GFX_MODE
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_getframeheight(GFX_CANVAS *Canvas)
{
	switch (Canvas->Mode)
	{
		case GFX_MODE_VGA: 
			return GFX_VGA_FRAME_HEIGHT;
		case GFX_MODE_VGA_24bit: 
			return GFX_VGA_24bit_FRAME_HEIGHT;
		case GFX_MODE_QVGA_24bit: 
			return GFX_QVGA_24bit_FRAME_HEIGHT;			
		case GFX_MODE_NTSC:
		case GFX_MODE_NTSCI: 
			return GFX_NTSC_FRAME_HEIGHT;
		case GFX_MODE_PAL:
		case GFX_MODE_PALI: 
			return GFX_PAL_FRAME_HEIGHT;
	}
	return 0;
}




/*********************************************************************
	
	Function: gfx_getwidth
	
	Description: Get the canvas width based on GFX_MODE
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_getwidth(GFX_CANVAS *Canvas)
{
	switch (Canvas->Mode)
	{
		case GFX_MODE_VGA: 			
			return GFX_VGA_WIDTH;
		case GFX_MODE_VGA_24bit: 	
			return GFX_VGA_24bit_WIDTH;
		case GFX_MODE_QVGA_24bit: 	
			return GFX_QVGA_24bit_WIDTH;			
		case GFX_MODE_NTSC:
		case GFX_MODE_NTSCI: 		
			return GFX_NTSC_WIDTH/2;
		case GFX_MODE_PAL:
		case GFX_MODE_PALI: 		
			return GFX_PAL_WIDTH/2;
	}
	return 0;
}




/*********************************************************************
	
	Function: gfx_getheight
	
	Description: Get the canvas height based on GFX_MODE
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_getheight(GFX_CANVAS *Canvas)
{
	switch (Canvas->Mode)
	{
		case GFX_MODE_VGA: 			
			return GFX_VGA_HEIGHT;
		case GFX_MODE_VGA_24bit: 	
			return GFX_VGA_24bit_HEIGHT;
		case GFX_MODE_QVGA_24bit: 	
			return GFX_QVGA_24bit_HEIGHT;			
		case GFX_MODE_NTSC:
		case GFX_MODE_NTSCI: 		
			return GFX_NTSC_HEIGHT/2;
	
		case GFX_MODE_PAL:
		case GFX_MODE_PALI: 		
			return GFX_PAL_HEIGHT/2;
	}
	return 0;
}




/*********************************************************************
	
	Function: gfx_setfont
	
	Description: Updates the x and y position
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_setfont(GFX_CANVAS *Canvas, u32 Font)
{
	if (Font>=sizeof(gfx_fonttable)/sizeof(u8 *)) return ADI_DEV_RESULT_FAILED;
	Canvas->Font=Font;
	return ADI_DEV_RESULT_SUCCESS;
}




/*********************************************************************
	
	Function: gfx_setjustify
	
	Description: Set the text justify
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_setjustify(GFX_CANVAS *Canvas, GFX_JUSTIFY Value)
{
	Canvas->Justify=Value;
	return ADI_DEV_RESULT_SUCCESS;
}




/*********************************************************************

	Function: gfx_settab
	
	Description: Set the tab width
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_settab(GFX_CANVAS *Canvas, u32 Value)
{
	Canvas->Tab=Value;
	return ADI_DEV_RESULT_SUCCESS;
}




/*********************************************************************
	
	Function: gfx_getcolour
	
	Description: Return colour depending on graphics mode
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_getcolour(GFX_CANVAS *Canvas, u8 r,u8 g,u8 b)
{
	unsigned char y,u,v;
	
	
	switch (Canvas->Mode)
	{
		case GFX_MODE_VGA:
			return (((r>>3)&0x001F)|((g<<3)&0x07E0)|((b<<8)&0xF800));
		
		case GFX_MODE_VGA_24bit:
		case GFX_MODE_QVGA_24bit:
			return b|(g<<8)|(r<<16);
					
		case GFX_MODE_NTSC:
		case GFX_MODE_NTSCI:
		case GFX_MODE_PAL:
		case GFX_MODE_PALI:
			y=((77*r)+(150*g)+(29*b))>>8;
			u=(-(42*r)-(85*g)+(128*b)+32768)>>8;
			v=((128*r)-(108*g)-(19*b)+32768)>>8;
			return (y<<24)|(v<<16)|(y<<8)|u;
	}
	return 0;
}




/*********************************************************************
	
	Function: gfx_setcolour
	
	Description: Update the colour
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_setcolour(GFX_CANVAS *Canvas, u32 Colour)
{
	Canvas->Colour=Colour;
	return ADI_DEV_RESULT_SUCCESS;
}




/*********************************************************************
	
	Function: gfx_goto
	
	Description: Updates the x and y position
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_goto(GFX_CANVAS *Canvas, u32 x, u32 y)
{
	Canvas->sx=Canvas->x=x;
	Canvas->sy=Canvas->y=y;
	return ADI_DEV_RESULT_SUCCESS;
}




/*********************************************************************
	
	Function: gfx_moveto
	
	Description: Move the x and y position with respect to current 
		position
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_moveto(GFX_CANVAS *Canvas, u32 x, u32 y)
{
	Canvas->x+=x;
	Canvas->y+=y;
	return ADI_DEV_RESULT_SUCCESS;
}




/*********************************************************************
	
	Function: gfx_printf
	
	Description: Write text out to a graphical buffer
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_printf(GFX_CANVAS *Canvas, u8 *Format,...)
{
	u32 Code=ADI_DEV_RESULT_SUCCESS;
	va_list ap; 
	u32 outsize;
	static u8 str[1024];
	u8 *buf=str;
	
	_Lockfileatomic(NULL);
	va_start(ap,Format);
	outsize=_doprnt((char *)Format,ap,_sprintfputchar,&buf);
	va_end(ap);
	*buf=0;
	_Unlockfileatomic(NULL);
	
	buf=str;
	
	while (*buf)
	{
		u8 *tmp=buf,*tmpw=NULL;
		long width=0;
		while (*tmp&&*tmp!=13&&(tmpw==NULL||Canvas->x-width<=Canvas->Width))
		{
			u8 *font_table=gfx_fonttable[Canvas->Font],
				*font=font_table+7+(*tmp-font_table[5])*(1+(font_table[0]?((font_table[2]+7)/8)*font_table[1]:((font_table[1]+7)/8)*font_table[2]));
			
			width-=(u32)((*tmp<font_table[5]||*tmp>=font_table[5]+font_table[6])?0:font[0]+font_table[3]);
			if ((tmp[-1]!=' '||tmp[-1]!=9)&&(tmp[0]==' '||tmp[0]==9)) tmpw=tmp+1;
			tmp++;
		}
		if (tmpw!=NULL&&Canvas->x-width>Canvas->Width) {tmp=tmpw; tmpw=0;}
		if (width) width+=gfx_fonttable[Canvas->Font][3];
		switch (Canvas->Justify)
		{
			case GFX_JUSTIFY_CENTER: Canvas->x+=width/2; break;
			case GFX_JUSTIFY_RIGHT: Canvas->x+=width; break;
		}
		if (*tmp==13) tmp++;
		while (buf!=tmp&&Code==ADI_DEV_RESULT_SUCCESS) Code=gfx_putc(Canvas,*buf++);
		if (!tmpw) {gfx_putc(Canvas,13); gfx_putc(Canvas,10); while (*buf&&(*buf==' '||*buf==9)) buf++;}
	}
	
	return Code;
}




/*********************************************************************
	
	Function: gfx_pixel
	
	Description: Draw a single pixel on the canvas
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_pixel(GFX_CANVAS *Canvas, u32 x, u32 y, u32 Colour)
{
 	if (!Canvas) return ADI_DEV_RESULT_FAILED;
	if (x>Canvas->Width||y>Canvas->Height) return ADI_DEV_RESULT_SUCCESS;
	x+=Canvas->Left;
	y+=Canvas->Top;
	switch (Canvas->Mode)
	{
		case GFX_MODE_VGA:
			if (x<GFX_VGA_WIDTH&&y<GFX_VGA_HEIGHT) ((u16 *)Canvas->Data)[x+((y+GFX_VGA_TOP)*GFX_VGA_WIDTH)]=Colour;
			return ADI_DEV_RESULT_SUCCESS;
			
		case GFX_MODE_VGA_24bit:
			if (x<GFX_VGA_WIDTH&&y<GFX_VGA_HEIGHT) 
			{
				((u8 *)Canvas->Data)[x*3+(y*GFX_VGA_24bit_WIDTH*3)]=(Colour>>16)&0x000000FF;
				((u8 *)Canvas->Data)[x*3+(y*GFX_VGA_24bit_WIDTH*3)+1]=(Colour>>8)&0x000000FF;
				((u8 *)Canvas->Data)[x*3+(y*GFX_VGA_24bit_WIDTH*3)+2]=Colour&0x000000FF;
				
			}	
			return ADI_DEV_RESULT_SUCCESS;		

		case GFX_MODE_QVGA_24bit:
			if (x<GFX_QVGA_24bit_WIDTH&&y<GFX_QVGA_24bit_HEIGHT) 
			{
				((u8 *)Canvas->Data)[x*3+(y*GFX_QVGA_24bit_WIDTH*3)]=(Colour>>16)&0x000000FF;
				((u8 *)Canvas->Data)[x*3+(y*GFX_QVGA_24bit_WIDTH*3)+1]=(Colour>>8)&0x000000FF;
				((u8 *)Canvas->Data)[x*3+(y*GFX_QVGA_24bit_WIDTH*3)+2]=Colour&0x000000FF;
				
			}	
			return ADI_DEV_RESULT_SUCCESS;			
		
		case GFX_MODE_NTSC:
			if (x<GFX_NTSC_WIDTH/2&&y<GFX_NTSC_HEIGHT/2)
			{
				((u32 *)Canvas->Data)[(GFX_NTSC_LEFT/2)+x+((y+GFX_NTSC_TOP)*GFX_NTSC_FRAME_WIDTH)]=Colour;
				((u32 *)Canvas->Data)[(GFX_NTSC_LEFT/2)+x+((y+GFX_NTSC_TOP)*GFX_NTSC_FRAME_WIDTH)+(GFX_NTSC_FRAME_WIDTH/2)]=Colour;
			}
			return ADI_DEV_RESULT_SUCCESS;
		
		
		case GFX_MODE_NTSCI:
			if (x<GFX_NTSC_WIDTH/2&&y<GFX_NTSC_HEIGHT/2)
			{
				((u32 *)Canvas->Data)[(GFX_NTSC_LEFT/2)+x+((y+GFX_NTSC_TOP)*(GFX_NTSC_FRAME_WIDTH/2))]=Colour;
				((u32 *)Canvas->Data)[(GFX_NTSC_LEFT/2)+x+((y+GFX_NTSC_TOP+(GFX_NTSC_HEIGHT/2)+GFX_NTSC_BOTTOM)*(GFX_NTSC_FRAME_WIDTH/2))]=Colour;
			}
			return ADI_DEV_RESULT_SUCCESS;
		
		
		case GFX_MODE_PAL:
			if (x<GFX_PAL_WIDTH/2&&y<GFX_PAL_HEIGHT/2)
			{
				((u32 *)Canvas->Data)[(GFX_PAL_LEFT/2)+x+((y+GFX_PAL_TOP)*GFX_PAL_FRAME_WIDTH)]=Colour;
				((u32 *)Canvas->Data)[(GFX_PAL_LEFT/2)+x+((y+GFX_PAL_TOP)*GFX_PAL_FRAME_WIDTH)+(GFX_PAL_FRAME_WIDTH/2)]=Colour;
			}
			return ADI_DEV_RESULT_SUCCESS;
		
		
		case GFX_MODE_PALI:
			if (x<GFX_PAL_WIDTH/2&&y<GFX_PAL_HEIGHT/2)
			{
				((u32 *)Canvas->Data)[(GFX_PAL_LEFT/2)+x+((y+GFX_PAL_TOP)*(GFX_PAL_FRAME_WIDTH/2))]=Colour;
				((u32 *)Canvas->Data)[(GFX_PAL_LEFT/2)+x+((y+GFX_PAL_TOP+(GFX_PAL_HEIGHT/2)+GFX_PAL_BOTTOM)*(GFX_PAL_FRAME_WIDTH/2))]=Colour;
			}
			return ADI_DEV_RESULT_SUCCESS;
	}
	return ADI_DEV_RESULT_NOT_SUPPORTED;
}




/*********************************************************************
	
	Function: gfx_putc
	
	Description: Draw a single character onto the buffer
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_putc(GFX_CANVAS *Canvas, u8 Value)
{
	u8 *f,m,
		*font_table=gfx_fonttable[Canvas->Font],
		*font=font_table+7+(Value-font_table[5])*(1+(font_table[0]?((font_table[2]+7)/8)*font_table[1]:((font_table[1]+7)/8)*font_table[2]));
	u32 i,j,x,y,code;
	
	// if buffer is null just return the font width + space
	//if (!Flag) return (u32)((Value<font_table[5]||Value>=font_table[5]+font_table[6])?0:font[0]+font_table[3]);
	
	if (Value==13) Canvas->x=Canvas->sx;
	if (Value==10) Canvas->y+=font_table[2]+font_table[4];
	if (Value==9) Canvas->x+=(Canvas->Tab-((Canvas->x-Canvas->sx)%Canvas->Tab));
	
	if (Value<font_table[5]||Value>=font_table[5]+font_table[6]) return ADI_DEV_RESULT_SUCCESS;
	
	if (*font_table)
	{
		for (i=0,x=Canvas->x,f=font;i<*font;i++,x++)
			for (j=0,y=Canvas->y,m=0;j<font_table[2];j++,y++,m<<=1)
			{
				if (!m) {f++; m=0x01;}
				if (*f&m) gfx_pixel(Canvas,x,y,Canvas->Colour);
			}
	} else
	{
		for (j=0,y=Canvas->y,f=font;i<font_table[2];j++,y++)
			for (i=0,x=Canvas->x,m=0;i<*font;i++,x++,m<<=1)
			{
				if (!m) {f++; m=0x01;}
				if (*f&m) gfx_pixel(Canvas,x,y,Canvas->Colour);
			}
	}
	
	Canvas->x+=font[0]+font_table[3];
	return ADI_DEV_RESULT_SUCCESS;
}




/*********************************************************************
	
	Function: gfx_fill
	
	Description: Fill the entire canvas in Colour
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_fill(GFX_CANVAS *Canvas, u32 Colour)
{
	return gfx_boxf(Canvas,0,0,Canvas->Width,Canvas->Height,Colour,Colour);
}




/*********************************************************************
	
	Function: gfx_line
	
	Description: Draw a single line on the canvas
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_line(GFX_CANVAS *Canvas, u32 x1, u32 y1, u32 x2, u32 y2, u32 Colour)
{
	u32 i,dx,dy;
	
	if (x1>x2) {i=x1; x1=x2; x2=i;}
	if (y1>y2) {i=y1; y1=y2; y2=i;}
	
	dx=x2-x1;
	dy=y2-y1;

	if (dx>dy) for (i=0;i<=dx;i++) gfx_pixel(Canvas,x1+i,y1+((i*dy)/dx),Colour);
	else for (i=0;i<=dy;i++) gfx_pixel(Canvas,x1+((i*dx)/dy),y1+i,Colour);		

	Canvas->x=x2;
	Canvas->y=y2;
	
	return ADI_DEV_RESULT_SUCCESS;
}




/*********************************************************************
	
	Function: gfx_lineto
	
	Description: Draw a single line on the buffer from the current
		position
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_lineto(GFX_CANVAS *Canvas, u32 x, u32 y, u32 Colour)
{
	u32 i,dx,dy;
	
	dx=x>0?x:-x;
	dy=y>0?y:-y;
	
	x=x>0?Canvas->x:Canvas->x+x;
	y=y>0?Canvas->y:Canvas->y+y;
	
	if (dx>dy) for (i=0;i<=dx;i++) gfx_pixel(Canvas,x+i,y+((i*dy)/dx),Colour);
	else for (i=0;i<=dy;i++) gfx_pixel(Canvas,x+((i*dx)/dy),y+i,Colour);
	return ADI_DEV_RESULT_SUCCESS;
}




/*********************************************************************
	
	Function: gfx_box
	
	Description: Draw a box
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_box(GFX_CANVAS *Canvas, u32 x1, u32 y1, u32 x2, u32 y2, u32 Colour)
{
	gfx_line(Canvas,x1,y1,x2,y1,Colour);
	gfx_line(Canvas,x2,y1,x2,y2,Colour);
	gfx_line(Canvas,x1,y2,x2,y2,Colour);
	gfx_line(Canvas,x1,y1,x1,y2,Colour);
	return ADI_DEV_RESULT_SUCCESS;
}




/*********************************************************************
	
	Function: gfx_boxf
	
	Description: Draw a filled in box
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_boxf(GFX_CANVAS *Canvas, u32 x1, u32 y1, u32 x2, u32 y2, u32 Colour, u32 Fill)
{
	u32 x,y;
	
	if (x1>x2) {x=x1; x1=x2; x2=x;}
	if (y1>y2) {y=y1; y1=y2; y2=y;}
	
//	for (y=y1+1;y<y2-1;y++)
//		for (x=x1+1;x<x2-1;x++)
	for (y=y1+1;y<y2;y++)
		for (x=x1+1;x<x2;x++)
			gfx_pixel(Canvas,x,y,Fill);
	gfx_box(Canvas,x1,y1,x2,y2,Colour);
	return ADI_DEV_RESULT_SUCCESS;
}




/*********************************************************************

	Function: gfx_preamble
	
	Description:
	
*********************************************************************/
//section ("sdram0_bank3_app")
u32 gfx_preamble(GFX_MODE mode,u32 line,bool fmt)
{
	struct Preamble {u16 Row,Flag;};
	static struct Preamble ntsc[]=
	{
		{GFX_NTSC_TOP,0x20},
		{GFX_NTSC_TOP+GFX_NTSC_HEIGHT,0x00},
		{GFX_NTSC_TOP+GFX_NTSC_HEIGHT+GFX_NTSC_BOTTOM,0x20},
		{0xFFFF,0},
	};
	static struct Preamble ntsci[]={
		{3,0x60},
		{GFX_NTSC_TOP,0x20},
		{GFX_NTSC_TOP+(GFX_NTSC_HEIGHT/2),0x00},
		{GFX_NTSC_TOP+(GFX_NTSC_HEIGHT/2)+3,0x20},
		{GFX_NTSC_TOP+(GFX_NTSC_HEIGHT/2)+GFX_NTSC_BOTTOM,0x60},
		{GFX_NTSC_TOP+GFX_NTSC_HEIGHT+GFX_NTSC_BOTTOM,0x40},
		{0xFFFF,0},
	};
	static struct Preamble pal[]=
	{
		{GFX_PAL_TOP,0x20},
		{GFX_PAL_TOP+GFX_PAL_HEIGHT,0x00},
		{GFX_PAL_TOP+GFX_PAL_HEIGHT+GFX_PAL_BOTTOM,0x20},
		{0xFFFF,0},
	};
	static struct Preamble pali[]={
		{3,0x60},
		{GFX_PAL_TOP,0x20},
		{GFX_PAL_TOP+(GFX_PAL_HEIGHT/2),0x00},
		{GFX_PAL_TOP+(GFX_PAL_HEIGHT/2)+3,0x20},
		{GFX_PAL_TOP+(GFX_PAL_HEIGHT/2)+GFX_PAL_BOTTOM,0x60},
		{GFX_PAL_TOP+GFX_PAL_HEIGHT+GFX_PAL_BOTTOM,0x40},
		{0xFFFF,0},
	};
	struct Preamble *Table=NULL;
	u32 rv=0x800000FF;
	
	switch (mode)
	{
		case GFX_MODE_NTSC: Table=ntsc; break;
		case GFX_MODE_NTSCI: Table=ntsci; break;
		
		// todo: provide support for PAL
		case GFX_MODE_PAL: Table=pal; break;
		case GFX_MODE_PALI: Table=pali; break;
	}
	
	if (Table)
	{
		while (Table->Row!=0xFFFF&&line>=Table->Row) Table++;
		if (Table->Row!=0xFFFF) rv|=Table->Flag<<24;
	}
	return rv^(fmt?0x10000000:0);
}

/*******************************************************************************/

