/*
 * svgalib.c
 *
 * svgalib interface.
 */


#include <stdlib.h>
#include <stdio.h>

#include <vga.h>
#include <vgakeyboard.h>
#include <vgamouse.h>

#include "fb.h"
#include "input.h"
#include "rc.h"



struct fb fb;




static int vmode[3] = { 0, 0, 8 };
static int svga_mode;
static int svga_vsync = 1;

rcvar_t vid_exports[] =
{
	RCV_VECTOR("vmode", vmode, 3),
	RCV_INT("vsync", &svga_vsync),
	RCV_INT("svga_mode", &svga_mode),
	RCV_END
};



/* keymap - mappings of the form { scancode, localcode } - from pc/keymap.c */
extern int keymap[][2];

static int mapscancode(int scan)
{
	int i;
	for (i = 0; keymap[i][0]; i++)
		if (keymap[i][0] == scan)
			return keymap[i][1];
	return 0;
}

static void kbhandler(int scan, int state)
{
	event_t ev;
	ev.type = state ? EV_PRESS : EV_RELEASE;
	ev.code = mapscancode(scan);
	ev_postevent(&ev);
}

int *rc_getvec();

static int selectmode()
{
	int i;
	int stop;
	vga_modeinfo *mi;
	int best = -1;
	int besterr = 1<<24;
	int err;
	int *vd;

	vd = vmode;
	
	stop = vga_lastmodenumber();
	for (i = 0; i <= stop; i++)
	{
		if (!vga_hasmode(i)) continue;
		mi = vga_getmodeinfo(i);
		
		/* modex is too crappy to deal with */
		if (!mi->bytesperpixel) continue;

		/* so are banked modes */
		if (mi->width * mi->height * mi->bytesperpixel > 65536)
			if (!(mi->flags & (IS_LINEAR))) continue;

		/* we can't use modes that are too small */
		if (mi->colors < 256) continue;
		if (mi->width < vd[0]) continue;
		if (mi->height < vd[1]) continue;

		/* perfect matches always win */
		if (mi->width == vd[0] && mi->height == vd[1]
			&& (mi->bytesperpixel<<3) == vd[2])
		{
			best = i;
			break;
		}

		/* compare error */
		err = mi->width * mi->height - vd[0] * vd[1]
			+ abs((mi->bytesperpixel<<3)-vd[2]);
		if (err < besterr)
		{
			best = i;
			besterr = err;
		}
	}
	if (best < 0)
		die("no suitable modes available\n");

	return best;
}



void vid_preinit()
{
	vga_init();
}

void vid_init()
{
	int m;
	vga_modeinfo *mi;

	if (!vmode[0] || !vmode[1])
	{
		int scale = rc_getint("scale");
		if (scale < 1) scale = 1;
		vmode[0] = 160 * scale;
		vmode[1] = 144 * scale;
	}
	
	m = svga_mode;
	if (!m) m = selectmode();
	
	if (!vga_hasmode(m))
		die("no such video mode: %d\n", m);

	vga_setmode(m);
	mi = vga_getmodeinfo(m);
	fb.w = mi->width;
	fb.h = mi->height;
	fb.pelsize = mi->bytesperpixel;
	fb.pitch = mi->linewidth;
	fb.ptr = vga_getgraphmem();
	fb.enabled = 1;
	fb.dirty = 0;

	switch (mi->colors)
	{
	case 256:
		fb.indexed = 1;
		fb.cc[0].r = fb.cc[1].r = fb.cc[2].r = 8;
		fb.cc[0].l = fb.cc[1].l = fb.cc[2].l = 0;
		break;
	case 32768:
		fb.indexed = 0;
		fb.cc[0].r = fb.cc[1].r = fb.cc[2].r = 3;
		fb.cc[0].l = 10;
		fb.cc[1].l = 5;
		fb.cc[2].l = 0;
		break;
	case 65536:
		fb.indexed = 0;
		fb.cc[0].r = fb.cc[2].r = 3;
		fb.cc[1].r = 2;
		fb.cc[0].l = 11;
		fb.cc[1].l = 5;
		fb.cc[2].l = 0;
		break;
	case 16384*1024:
		fb.indexed = 0;
		fb.cc[0].r = fb.cc[1].r = fb.cc[2].r = 0;
		fb.cc[0].l = 16;
		fb.cc[1].l = 8;
		fb.cc[2].l = 0;
		break;
	}
	
	keyboard_init();
	keyboard_seteventhandler(kbhandler);

	joy_init();
}


void vid_close()
{
	if (!fb.ptr) return;
	memset(&fb, 0, sizeof fb);
	joy_close();
	keyboard_close();
	vga_setmode(TEXT);
}

void vid_settitle(char *title)
{
}

void vid_setpal(int i, int r, int g, int b)
{
	vga_setpalette(i, r>>2, g>>2, b>>2);
}

void vid_begin()
{
	if (svga_vsync) vga_waitretrace();
}

void vid_end()
{
}

void kb_init()
{
}

void kb_close()
{
}

void kb_poll()
{
	keyboard_update();
}

void ev_poll()
{
	kb_poll();
	joy_poll();
}














