/*
 * Copyright (c) 1999, 2000 Greg Haerr <greg@censoft.com>
 *
 * Microwindows Screen Driver using TVGA Library
 *
 * This driver requires the following TVGA entry points:
 * 	vga_init, vga_setmode,
 * 	vga_drawpixel, vga_getpixel,
 * 	vga_setegacolor, vga_drawline,
 *	vga_getscansegment, vga_drawscansegment
 *
 * All graphics drawing primitives are based on top of these functions.
 */
/*#define NDEBUG*/
#include <assert.h>
#include <stdio.h>
#include <cyg/io/tvga/tvga.h>
#include "device.h"
#include "genfont.h"
#include "genmem.h"

#define MAXLINELEN	800	/* max line byte/pixel length*/

/* specific driver entry points*/
static PSD  TVGA_open(PSD psd);
static void TVGA_close(PSD psd);
static void TVGA_getscreeninfo(PSD psd,PMWSCREENINFO psi);
static void TVGA_setpalette(PSD psd,int first,int count,MWPALENTRY *pal);
static void TVGA_drawpixel(PSD psd,MWCOORD x, MWCOORD y, MWPIXELVAL c);
static MWPIXELVAL TVGA_readpixel(PSD psd,MWCOORD x, MWCOORD y);
static void TVGA_drawhline(PSD psd,MWCOORD x1, MWCOORD x2, MWCOORD y, MWPIXELVAL c);
static void TVGA_drawvline(PSD psd,MWCOORD x, MWCOORD y1, MWCOORD y2, MWPIXELVAL c);
static void TVGA_fillrect(PSD psd,MWCOORD x1, MWCOORD y1, MWCOORD x2,
		MWCOORD y2, MWPIXELVAL c);
//static void TVGA_blit(PSD dstpsd, MWCOORD dstx, MWCOORD dsty, MWCOORD w,
//		MWCOORD h, PSD srcpsd, MWCOORD srcx, MWCOORD srcy, long op);

SCREENDEVICE	scrdev = {
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL,
	TVGA_open,
	TVGA_close,
	TVGA_getscreeninfo,
	TVGA_setpalette,
	TVGA_drawpixel,
	TVGA_readpixel,
	TVGA_drawhline,
	TVGA_drawvline,
	TVGA_fillrect,
	gen_fonts,           /* gen_fonts,*/
	NULL,           /* TVGA_blit,*/
	NULL,			/* PreSelect*/
	NULL,			/* DrawArea subdriver*/
	NULL,			/* SetIOPermissions*/
	NULL,           /* del by lh*/
	NULL,			/* MapMemGC*/
	NULL			/* FreeMemGC*/
};

extern int gr_mode;	/* temp kluge*/

static PSD
TVGA_open(PSD psd)
{
	int		mode;
	//vga_modeinfo *	modeinfo;
    
	mode = G360x480x256;
	
	if(vga_setmode(mode) == -1)
		return NULL;
	psd->xres = psd->xvirtres = 360;//modeinfo->width;
	psd->yres = psd->yvirtres = 480;//modeinfo->height;
	psd->linelen = 360;//modeinfo->linewidth;
	psd->ncolors = 256;//modeinfo->colors;
	if(psd->ncolors == 256) {
		psd->planes = 1;
		psd->bpp = 8;
	} else {
		psd->planes = 4;
		psd->bpp = 4;
	}
	/* note: must change psd->pixtype here for truecolor systems*/
	psd->pixtype = MWPF_PALETTE;
	psd->flags = PSF_SCREEN;
	psd->size = 0;
	psd->addr = NULL;

	/*DPRINTF("mode: %dx%dx%d bpp %d\n", psd->xres, psd->yres,
	 	psd->ncolors, psd->bpp);*/

	return psd;
}

static void
TVGA_close(PSD psd)
{
	vga_setmode(TEXT);
}

static void
TVGA_getscreeninfo(PSD psd,PMWSCREENINFO psi)
{
	psi->rows = psd->yvirtres;
	psi->cols = psd->xvirtres;
	psi->planes = psd->planes;
	psi->bpp = psd->bpp;
	psi->ncolors = psd->ncolors;
	psi->pixtype = psd->pixtype;
	psi->fonts = NUMBER_FONTS;

	if(psd->yvirtres > 480) {
		/* TVGA 800x600*/
		psi->xdpcm = 33;	/* assumes screen width of 24 cm*/
		psi->ydpcm = 33;	/* assumes screen height of 18 cm*/
	} else if(psd->yvirtres > 350) {
		/* VGA 640x480*/
		psi->xdpcm = 27;	/* assumes screen width of 24 cm*/
		psi->ydpcm = 27;	/* assumes screen height of 18 cm*/
	} else {
		/* EGA 640x350*/
		psi->xdpcm = 27;	/* assumes screen width of 24 cm*/
		psi->ydpcm = 19;	/* assumes screen height of 18 cm*/
	}
}

static void
TVGA_setpalette(PSD psd,int first,int count,MWPALENTRY *pal)
{
	while(first < 256 && count-- > 0) {
		vga_setpalette(first++, pal->r>>2, pal->g>>2, pal->b>>2);
		++pal;
	}
}

static void
TVGA_drawpixel(PSD psd,MWCOORD x, MWCOORD y, MWPIXELVAL c)
{
	unsigned char gline, line = c;

	if(gr_mode == MWMODE_SET) {
		/* vga_drawpixel apparently doesn't work with 256 colors...
		 * vga_setegacolor(c);
		 * vga_drawpixel(x, y);
		 */
		vga_setcolor(c);
		vga_drawpixel(x, y);
		//vga_drawscansegment(&line, x, y, 1);
		return;
	}
	/*
	 * This fishery is required because vgalib doesn't support
	 * xor drawing mode without acceleration.
	 */
	//vga_getscansegment(&gline, x, y, 1);
	//line ^= gline;
	//vga_drawscansegment(&line, x, y, 1);
}

static MWPIXELVAL
TVGA_readpixel(PSD psd,MWCOORD x, MWCOORD y)
{
	return vga_readpixel(x, y);//vga_getpixel(x, y);
}

static void
TVGA_drawhline(PSD psd,MWCOORD x1, MWCOORD x2, MWCOORD y, MWPIXELVAL c)
{
	int 	i, width;
	unsigned char getline[MAXLINELEN];
	static int lastcolor = -1;
	static int lastwidth = -1;
	static unsigned char line[MAXLINELEN];

	/*
	 * All this fishery is required for two reasons:
	 * one, vga_drawline is way too slow to be called to fill
	 * rectangles, so vga_drawscansegment is used instead.  In
	 * addition, vgalib doesn't support xor drawing mode
	 * without acceleration!!, so we've got to do it ourselves
	 * with vga_getscansegment...
	 */
	width = x2-x1+1;

	/* this is faster than calling vga_drawline !!!*/
/*	if(width != lastwidth || c != lastcolor) {
		lastwidth = width;
		lastcolor = c;
		for(i=0; i<width; ++i)
			line[i] = c;
	}
	if(gr_mode == MWMODE_XOR) {
		vga_getscansegment(getline, x1, y, width);
		for(i=0; i<width; ++i)
			line[i] ^= getline[i];
		lastwidth = -1;
	}
	vga_drawscansegment(line, x1, y, width);
*/
	/*
	 * Non-fishery version is *slow* and doesn't support XOR.*/
	vga_setcolor(c);
	vga_drawline(x1, y, x2, y);
	 
}

static void
TVGA_drawvline(PSD psd,MWCOORD x, MWCOORD y1, MWCOORD y2, MWPIXELVAL c)
{
//	if(gr_mode == MWMODE_SET) {
		vga_setcolor(c);
		vga_drawline(x, y1, x, y2);
//	}

	/* slower version required for XOR drawing support*/
//	while(y1 <= y2)
//		TVGA_drawpixel(psd, x, y1++, c);
}

static void
TVGA_fillrect(PSD psd,MWCOORD x1, MWCOORD y1, MWCOORD x2, MWCOORD y2, MWPIXELVAL c)
{
	while(y1 <= y2)
		TVGA_drawhline(psd, x1, x2, y1++, c);
}

/* only screen-to-screen blit implemented, op ignored*/
/* FIXME*/
#if (0)
{

static void
TVGA_blit(PSD dstpsd, MWCOORD dstx, MWCOORD dsty, MWCOORD w, MWCOORD h,
	PSD srcpsd, MWCOORD srcx, MWCOORD srcy, long op)
{
	#if (0)
	{
	
	unsigned char line[MAXLINELEN];

	assert (dstx >= 0 && dstx < dstpsd->xres);
	assert (dsty >= 0 && dsty < dstpsd->yres);
	assert (w > 0);
	assert (h > 0);
	assert (srcx >= 0 && srcx < srcpsd->xres);
	assert (srcy >= 0 && srcy < srcpsd->yres);
	assert (dstx+w <= dstpsd->xres);
	assert (dsty+h <= dstpsd->yres);
	assert (srcx+w <= srcpsd->xres);
	assert (srcy+h <= srcpsd->yres);

	if(!(srcpsd->flags & PSF_SCREEN) || !(dstpsd->flags & PSF_SCREEN))
		return;

	while(--h >= 0) {
		vga_getscansegment(line, srcx, srcy, w);
		vga_drawscansegment(line, dstx, dsty, w);
		++dsty;
		++srcy;
	}
	}
	#endif
}

static int fade = 100;
/* experimental palette animation*/
void
setfadelevel(PSD psd, int f)
{
	int 		i;
	extern MWPALENTRY gr_palette[256];
	MWPALENTRY local_palette[256];

	if(psd->pixtype != MWPF_PALETTE)
		return;

	fade = f;
	if(fade > 100)
		fade = 100;
	for(i=0; i<256; ++i) {

		local_palette[i].r = (gr_palette[i].r * fade / 100);
		local_palette[i].g = (gr_palette[i].g * fade / 100);
		local_palette[i].b = (gr_palette[i].b * fade / 100);
	}
   TVGA_setpalette( psd, 0,256,local_palette );
}

}
#endif