#include <vga.h>
#include "lin_vga.h"

#define	SCREEN_MAGIC	0xBEDA0BED

typedef struct screen_settings_s
{
	unsigned int	magic;
	int				shift, pitch, width, height;
	unsigned int	cur_color, cur_x, cur_y;
	void			*backbuffer;
	void			**vtab;
}	screen_settings_t;

static	screen_settings_t sset;

int		graphInitSvgalib(int width,int height,int bpp)
{
	char mode_name[64];
	int	mode_num;
	int size, i;
	memset(&sset,0,sizeof(screen_settings_t));
	if(bpp!=8 && bpp!=16 && bpp!=32)
	{
		printf("graphInitSvgalib(%d,%d,%d): wrong bpp value '%d'.\n",
			width,height,bpp,bpp);
		return 0;
	}
	if(vga_init())
	{
		printf("graphInitSvgalib(%d,%d,%d): vga_init() failed.\n",width,
			height,bpp);
		return 0;
	}
	switch(bpp)
	{
		case 8:
			sprintf(mode_name,"G%dx%dx256",width,height);
			sset.shift=0;
			sset.pitch=width;
			break;
		case 16:
			sprintf(mode_name,"G%dx%dx64K",width,height);
			sset.shift=1;
			sset.pitch=width<<1;
			break;
		default:
			sprintf(mode_name,"G%dx%dx16M",width,height);
			sset.shift=2;
			sset.pitch=width<<2;
			break;
	}
	mode_num=vga_getmodenumber(mode_name);
	if(mode_num==-1)
	{
		printf("graphInitSvgalib(%d,%d,%d): no such video mode.\n",
			width,height,bpp);
		return 0;
	}
	if(vga_setmode(mode_num))
	{
		printf("graphInitSvgalib(%d,%d,%d): vga_setmode() failed.\n",
			width,height,bpp);
		return 0;
	}
	sset.width=width;
	sset.height=height;
	size=sset.pitch * sset.height;
	if(!(sset.backbuffer=(void*)malloc(size)))
	{
		printf("graphInitSvgalib(%d,%d,%d): can't allocate memory for "
			"backbuffer.\n",width,height,bpp);
		vga_setmode(TEXT);
		memset(&sset,0,sizeof(screen_settings_t));
		return 0;
	}
	if(!(sset.vtab=(void**)malloc(sset.height*sizeof(void*))))
	{
		printf("graphInitSvgalib(%d,%d,%d): can't allocate memory for "
			"vtab.\n",width,height,bpp);
		free(sset.backbuffer);
		vga_setmode(TEXT);
		memset(&sset,0,sizeof(screen_settings_t));
		return 0;
	}
	sset.vtab[0]=sset.backbuffer;
	for(i=1;i<sset.height;i++)
		sset.vtab[i]=(unsigned char*)sset.vtab[i-1]+sset.pitch;
	sset.magic=SCREEN_MAGIC;
	return 1;
}	

void	graphShutdownSvgalib(void)
{
	if(sset.magic!=SCREEN_MAGIC)
	{
		printf("svgalibShutdown(): settings.magic(==%X)!=SCREEN_MAGIC.\n",
			sset.magic);
		return;
	}
	vga_setmode(TEXT);
	if(sset.backbuffer)
		free(sset.backbuffer);
	if(sset.vtab)
		free(sset.vtab);
	memset(&sset,0,sizeof(screen_settings_t));
}

/*
 *	Takes 256 entrties in form RRGGBB (768 bytes total).
 *	Color values are in range 0-255. 
 */
void	graphSetPalette(unsigned char *pal)
{
	int i;
	for(i=0;i<256;i++)
		vga_setpalette(i,pal[3*i]>>2,pal[3*i+1]>>2,pal[3*i+2]>>2);
}
		
void	**graphLockBackbuffer(void)
{
	return sset.vtab;
}

void	graphUnlockBackbuffer(void)
{
}

void	graphSetPixel8(int x,int y,unsigned char color)
{
	*((unsigned char*)sset.vtab[y]+x)=color;
}

void	graphSetPixel16(int x,int y,unsigned short color)
{
	*((unsigned short*)sset.vtab[y]+x)=color;
}

void	graphSetPixel32(int x,int y,unsigned int color)
{
	*((unsigned int*)sset.vtab[y]+x)=color;
}

void	graphClear(unsigned int color)
{
	if(!sset.shift)
	{
		memset(sset.backbuffer,color,sset.height*sset.pitch);
	}
	else if(sset.shift==1)
	{
		int i,j;
		for(i=0;i<sset.height;i++)
			for(j=0;j<sset.width;j++)
				*((unsigned short*)sset.vtab[i]+j)=color;
	}
	else if(sset.shift==2)
	{
		int i,j;
		for(i=0;i<sset.height;i++)
			for(j=0;j<sset.width;j++)
				*((unsigned int*)sset.vtab[i]+j)=color;
	}
}

void	graphSwapBuffers(void)
{
	int i;
	for(i=0;i<sset.height;i++)
		vga_drawscansegment((unsigned char*)sset.vtab[i],0,i,sset.pitch);
}
