gnuboy-for-dfi/sys/svga/svgalib.c

247 lines
3.5 KiB
C

/*
* svgalib.c
*
* svgalib interface.
*/
#include <stdlib.h>
#include <stdio.h>
#include <vga.h>
#include <vgakeyboard.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();
}