links/grx.c

578 lines
15 KiB
C

#include "cfg.h"
#ifdef GRDRV_GRX
#include "links.h"
#include <grx20.h>
#include "arrow.inc"
#define NUMBER_OF_DEVICES 12
static void grx_mouse_init(void);
static void grx_mouse_terminate(void);
void _GrCloseVideoDriver(void);
extern struct graphics_driver grx_driver;
static struct itrm *svgalib_kbd;
static unsigned char *grx_driver_param = NULL;
static struct graphics_device *grx_old_vd;
static unsigned char in_graphics_mode = 0;
#define TEST_INACTIVITY if (dev != current_virtual_device || !dev->clip.x2) return;
#define TEST_INACTIVITY_0 if (dev != current_virtual_device || !dev->clip.x2) return 0;
static void grx_set_palette(void)
{
unsigned i, colors;
if (grx_driver.depth == 33)
colors = 16;
else if (grx_driver.depth == (65 | 0x300))
colors = 216;
else if (grx_driver.depth == 65)
colors = 256;
else
return;
GrResetColors();
for (i = 0; i < colors; i++) {
unsigned rgb[3];
q_palette(colors, i, 255, rgb);
GrSetColor(i, rgb[0], rgb[1], rgb[2]);
}
return;
}
static void grx_update_palette(void)
{
int new_depth;
if (!grx_driver.param->palette_mode)
new_depth = grx_driver.depth | 0x300;
else
new_depth = grx_driver.depth & ~0x300;
if (new_depth == grx_driver.depth)
return;
grx_driver.depth = new_depth;
grx_driver.get_color = get_color_fn(new_depth);
if (!grx_driver.get_color) internal_error("Unknown bit depth %x", new_depth);
grx_mouse_terminate();
grx_set_palette();
grx_mouse_init();
}
static void grx_set_text(void)
{
if (in_graphics_mode) {
GrSetMode(GR_default_text);
in_graphics_mode = 0;
_GrCloseVideoDriver();
restore_terminal();
}
}
static void grx_restore(void)
{
if (grx_driver_param) mem_free(grx_driver_param), grx_driver_param = NULL;
grx_set_text();
}
static void grx_set_clip(void)
{
GrSetClipBox(
current_virtual_device->clip.x1,
current_virtual_device->clip.y1,
current_virtual_device->clip.x2 - 1,
current_virtual_device->clip.y2 - 1
);
}
static void grx_key_in(struct itrm *p, unsigned char *ev_, int size)
{
int vd;
struct links_event *ev = (struct links_event *)(void *)ev_;
if (size != sizeof(struct links_event)) return;
if (ev->ev == EV_ABORT) terminate_loop = 1;
if (ev->ev != EV_KBD) return;
if (ev->y & KBD_PASTING) goto skip;
if (((ev->y & (KBD_CTRL | KBD_ALT)) == KBD_ALT) && ev->x >= '0' && ev->x <= '9') {
vd = (ev->x - '1' + 10) % 10;
goto switch_vd;
}
if (((ev->y & (KBD_CTRL | KBD_ALT)) == KBD_ALT) && ev->x == '-') {
vd = 10;
goto switch_vd;
}
if (((ev->y & (KBD_CTRL | KBD_ALT)) == KBD_ALT) && ev->x == '=') {
vd = 11;
goto switch_vd;
}
if (((ev->y & (KBD_CTRL | KBD_ALT)) == KBD_ALT) && ev->x <= KBD_F1 && ev->x >= KBD_F12) {
vd = KBD_F1 - ev->x;
goto switch_vd;
}
skip:
if (g_kbd_codepage(&grx_driver) != utf8_table && ev->x >= 128 && ev->x <= 255)
if ((ev->x = cp2u(ev->x, g_kbd_codepage(&grx_driver))) == -1) return;
if (current_virtual_device && current_virtual_device->keyboard_handler) current_virtual_device->keyboard_handler(current_virtual_device, ev->x, ev->y);
return;
switch_vd:
switch_virtual_device(vd);
grx_set_clip();
}
int grx_mouse_initialized = 0;
static GrCursor *grx_mouse_cursor;
static void grx_mouse_init(void)
{
int x, y;
static unsigned char cursor[arrow_area];
static GrColor table[3];
if (!GrMouseDetect()) return;
grx_mouse_initialized = 1;
GrMouseInit();
GrMouseEventEnable(0, 1);
memset(&table, 0, sizeof table);
table[0] = 2;
table[1] = grx_driver.get_color(0);
table[2] = grx_driver.get_color(0xffffff);
for (y = 0; y < arrow_height; y++)
for (x = 0; x < arrow_width; x++)
cursor[y * arrow_width + x] =
(arrow[2 * y] >> (arrow_width - x - 1)) & 1 ? 1 :
(arrow[2 * y + 1] >> (arrow_width - x - 1)) & 1 ? 2 :
0;
grx_mouse_cursor = GrBuildCursor(cast_char cursor, arrow_width, arrow_width, arrow_height, 0, 0, table);
if (!grx_mouse_cursor) GrMouseSetColors(grx_driver.get_color(0xffffff), grx_driver.get_color(0x000000));
else GrMouseSetCursor(grx_mouse_cursor);
GrMouseDisplayCursor();
}
static void grx_mouse_terminate(void)
{
if (!grx_mouse_initialized) return;
GrMouseEraseCursor();
GrMouseUnInit();
if (grx_mouse_cursor) GrDestroyCursor(grx_mouse_cursor);
grx_mouse_initialized = 0;
}
void grx_mouse_poll(void)
{
int x = GrMousePendingEvent();
x = x;
}
static void grx_do_event(GrMouseEvent *ev, int b)
{
if (!current_virtual_device) return;
if (current_virtual_device->mouse_handler) current_virtual_device->mouse_handler(current_virtual_device, ev->x, ev->y, b);
}
int grx_mouse_event(void)
{
int e;
GrMouseEvent ev;
e = 0;
get_another:
GrMouseGetEvent(GR_M_MOTION | GR_M_BUTTON_CHANGE | GR_M_POLL, &ev);
if (ev.flags & GR_M_LEFT_DOWN) grx_do_event(&ev, B_LEFT | B_DOWN), e = 1;
if (ev.flags & GR_M_LEFT_UP) grx_do_event(&ev, B_LEFT | B_UP), e = 1;
if (ev.flags & GR_M_RIGHT_DOWN) grx_do_event(&ev, B_RIGHT | B_DOWN), e = 1;
if (ev.flags & GR_M_RIGHT_UP) grx_do_event(&ev, B_RIGHT | B_UP), e = 1;
if (ev.flags & GR_M_MIDDLE_DOWN) grx_do_event(&ev, B_MIDDLE | B_DOWN), e = 1;
if (ev.flags & GR_M_MIDDLE_UP) grx_do_event(&ev, B_MIDDLE | B_UP), e = 1;
if (ev.flags & GR_M_P4_DOWN) grx_do_event(&ev, B_WHEELUP | B_MOVE), e = 1;
if (ev.flags & GR_M_P5_DOWN) grx_do_event(&ev, B_WHEELDOWN | B_MOVE), e = 1;
if (!e && ev.flags & GR_M_MOTION) {
if (GrMousePendingEvent())
goto get_another;
grx_do_event(&ev,
ev.buttons & GR_M_LEFT ? B_LEFT | B_DRAG :
ev.buttons & GR_M_RIGHT ? B_RIGHT | B_DRAG :
ev.buttons & GR_M_MIDDLE ? B_DRAG | B_MIDDLE : B_MOVE), e = 1;
}
return e;
}
static unsigned char *set_mode_according_to_param(unsigned char *param)
{
unsigned char e[MAX_STR_LEN];
save_terminal();
if (!param || !*param) {
return stracpy(cast_uchar "There is no default videomode.\nUse the switch \"-mode WIDTHxHEIGHTxCOLORS\" to select video mode.\nThe COLORS argument may be 16, 256, 32k, 64k, 16M.\n");
#if 0
if (!GrSetMode(GR_default_graphics))
return stracpy(cast_uchar "GrSetMode failed.\n");
in_graphics_mode = 1;
#endif
} else {
unsigned long x, y;
int pl;
unsigned char *ptr = param;
char *end;
x = strtoul(cast_const_char ptr, &end, 10);
if (cast_uchar end == ptr || *end != 'x' || x >= MAXINT)
goto bad_param;
ptr = cast_uchar end + 1;
y = strtoul(cast_const_char ptr, &end, 10);
if (cast_uchar end == ptr || *end != 'x' || y >= MAXINT)
goto bad_param;
ptr = cast_uchar end + 1;
if (!strcmp(cast_const_char ptr, "16")) pl = 4;
else if (!strcmp(cast_const_char ptr, "256")) pl = 8;
else if (!casestrcmp(ptr, cast_uchar "32k") || !strcmp(cast_const_char ptr, "32768")) pl = 15;
else if (!casestrcmp(ptr, cast_uchar "64k") || !strcmp(cast_const_char ptr, "65536")) pl = 16;
else if (!casestrcmp(ptr, cast_uchar "16M") || !casestrcmp(ptr, cast_uchar "16M32") || !strcmp(cast_const_char ptr, "16777216")) pl = 24;
else goto bad_param;
if (x == 800 && y == 600 && pl == 4) y = 599; /* a bug in GRX */
if (!GrSetMode(GR_width_height_bpp_graphics, (int)x, (int)y, pl)) {
snprintf(cast_char e, MAX_STR_LEN, "GrSetMode(%lu,%lu,%d) failed.\n", x, y, pl);
return stracpy(e);
}
in_graphics_mode = 1;
}
return NULL;
bad_param:
return stracpy(cast_uchar "Bad -mode parameter.\n");
}
static void grx_set_graphics(void)
{
if (!in_graphics_mode) {
unsigned char *er;
er = set_mode_according_to_param(grx_driver_param);
if (er)
fatal_exit("grx: Unable to restore video mode '%s': %s", grx_driver_param, er);
}
}
static unsigned char *grx_init_driver(unsigned char *param, unsigned char *ignore)
{
unsigned char e[MAX_STR_LEN];
unsigned char *er;
const GrVideoMode *mode;
const GrFrameDriver *fd;
kbd_set_raw = 1;
grx_old_vd = NULL;
er = set_mode_according_to_param(param);
if (er)
return er;
mode = GrCurrentVideoMode();
fd = GrScreenFrameDriver();
if (GrNumPlanes() != (mode->bpp == 4 ? 4 : 1)) {
unsupported_videomode:
snprintf(cast_char e, MAX_STR_LEN, "Unsupported videomode: x %d, y %d, bpp (%d, %d), planes %d.\n", mode->width, mode->height, mode->bpp, fd->bits_per_pixel, (int)GrNumPlanes());
grx_restore();
return stracpy(e);
}
grx_driver.flags &= ~GD_SELECT_PALETTE;
switch (mode->bpp) {
case 4:
grx_driver.depth = 33;
break;
case 8:
grx_driver.depth = 65;
if (!grx_driver.param->palette_mode)
grx_driver.depth |= 0x300;
grx_driver.flags |= GD_SELECT_PALETTE;
break;
case 15:
grx_driver.depth = 122;
break;
case 16:
grx_driver.depth = 130;
break;
case 24:
case 32:
if (fd->bits_per_pixel == 24)
grx_driver.depth = 195;
else if (fd->bits_per_pixel == 32)
grx_driver.depth = 196;
else
goto unsupported_videomode;
break;
default:
goto unsupported_videomode;
}
grx_driver.get_color = get_color_fn(grx_driver.depth);
if (!grx_driver.get_color) internal_error("Unknown bit depth %x", grx_driver.depth);
grx_driver.x = mode->width;
grx_driver.y = mode->height;
if (mode->bpp >= 8) grx_driver.flags |= GD_DONT_USE_SCROLL;
else grx_driver.flags &= ~GD_DONT_USE_SCROLL;
/*fatal_exit("current mode: %d,%d,%d planes %d bits %d %d", mode->width, mode->height, mode->bpp, GrNumPlanes(), GrScreenFrameDriver()->bits_per_pixel, mode->bpp);*/
grx_set_palette();
grx_driver_param = stracpy(param ? param : cast_uchar "");
init_virtual_devices(&grx_driver, NUMBER_OF_DEVICES);
svgalib_kbd = handle_svgalib_keyboard(grx_key_in);
grx_mouse_init();
return NULL;
}
static void grx_shutdown_driver(void)
{
shutdown_virtual_devices();
grx_mouse_terminate();
svgalib_free_trm(svgalib_kbd);
grx_restore();
}
static void grx_emergency_shutdown(void)
{
grx_restore();
}
static unsigned char *grx_get_driver_param(void)
{
return grx_driver_param;
}
struct grx_bmp {
GrContext c;
};
static int grx_get_empty_bitmap(struct bitmap *bmp)
{
struct grx_bmp *b;
if (!in_graphics_mode)
internal_error("grx_get_empty_bitmap: not in graphics mode");
b = mem_alloc_mayfail(sizeof(struct grx_bmp));
if (!b) goto fail0;
again1:
if (!GrCreateContext(bmp->x, bmp->y, NULL, &b->c)) {
if (out_of_memory(0, NULL, 0))
goto again1;
goto fail1;
}
bmp->flags = b;
if (GrNumPlanes() == 1) {
bmp->data = b->c.gc_baseaddr[0];
bmp->skip = b->c.gc_lineoffset;
} else {
if (bmp->x && (unsigned)bmp->x * (unsigned)bmp->y / (unsigned)bmp->x != (unsigned)bmp->y) goto fail2;
if ((unsigned)bmp->x * (unsigned)bmp->y > (unsigned)MAXINT) goto fail2;
bmp->skip = bmp->x;
bmp->data = mem_alloc_mayfail(bmp->skip * bmp->y);
if (!bmp->data) goto fail2;
}
return 0;
fail2:
GrDestroyContext(&b->c);
fail1:
mem_free(b);
fail0:
bmp->data = NULL;
bmp->flags = NULL;
return -1;
}
static void grx_copy_planes(struct bitmap *bmp, int y, int n)
{
struct grx_bmp *b = bmp->flags;
int j;
if (!b) return;
for (j = 0; j < n; y++, j++) {
int i;
for (i = 0; i < GrNumPlanes(); i++) {
int x;
unsigned char *src = (unsigned char *)bmp->data + bmp->skip * j;
unsigned char *dst = (unsigned char *)b->c.gc_baseaddr[i] + y * b->c.gc_lineoffset;
unsigned char byt = 0;
for (x = 0; x < bmp->x; ) {
unsigned char bit = (*src++ >> i) & 1;
byt |= bit << ((x & 7) ^ 7);
x++;
if (!(x & 7)) *dst++ = byt, byt = 0;
}
if (x & 7) *dst = byt;
}
}
}
static void grx_register_bitmap(struct bitmap *bmp)
{
if (GrNumPlanes() != 1) {
grx_copy_planes(bmp, 0, bmp->y);
mem_free(bmp->data);
}
}
static void *grx_prepare_strip(struct bitmap *bmp, int top, int lines)
{
struct grx_bmp *b = bmp->flags;
if (!b) return NULL;
if (GrNumPlanes() != 1) {
bmp->data = mem_alloc_mayfail(bmp->skip * lines);
return bmp->data;
}
return ((unsigned char *)bmp->data) + bmp->skip * top;
}
static void grx_commit_strip(struct bitmap *bmp, int top, int lines)
{
if (GrNumPlanes() != 1) {
if (!bmp->data) return;
grx_copy_planes(bmp, top, lines);
mem_free(bmp->data);
}
}
static void grx_unregister_bitmap(struct bitmap *bmp)
{
struct grx_bmp *b = bmp->flags;
if (!b) return;
GrDestroyContext(&b->c);
mem_free(b);
}
static void grx_draw_bitmap(struct graphics_device *dev, struct bitmap *bmp, int x, int y)
{
struct grx_bmp *b = bmp->flags;
if (!b) return;
TEST_INACTIVITY
CLIP_DRAW_BITMAP
/* note: GrImageDisplay has buggy clipping.
It doesn't draw if the target x or y coordinate is one pixel
before the end of clip area */
GrBitBlt(NULL, x, y, &b->c, 0, 0, bmp->x - 1, bmp->y - 1, GrWRITE);
}
static void grx_fill_area(struct graphics_device *dev, int x1, int y1, int x2, int y2, long color)
{
TEST_INACTIVITY
CLIP_FILL_AREA
if (x1 >= x2 || y1 >= y2) return;
GrFilledBox(x1, y1, x2 - 1, y2 - 1, color);
}
static void grx_draw_hline(struct graphics_device *dev, int x1, int y, int x2, long color)
{
TEST_INACTIVITY
CLIP_DRAW_HLINE
GrHLine(x1, x2 - 1, y, color);
}
static void grx_draw_vline(struct graphics_device *dev, int x, int y1, int y2, long color)
{
TEST_INACTIVITY
CLIP_DRAW_VLINE
GrVLine(x, y1, y2 - 1, color);
}
static int grx_scroll(struct graphics_device *dev, struct rect_set **ignore, int scx, int scy)
{
TEST_INACTIVITY_0
GrBitBlt(NULL,
dev->clip.x1 + (scx >= 0 ? scx : 0),
dev->clip.y1 + (scy >= 0 ? scy : 0),
NULL,
dev->clip.x1 - (scx < 0 ? scx : 0),
dev->clip.y1 - (scy < 0 ? scy : 0),
dev->clip.x2 - (scx >= 0 ? scx : 0) - 1,
dev->clip.y2 - (scy >= 0 ? scy : 0) - 1,
GrWRITE);
return 1;
}
static void grx_set_clip_area(struct graphics_device *dev)
{
if (dev != current_virtual_device) return;
grx_set_clip();
}
static int grx_block(struct graphics_device *dev)
{
if (grx_old_vd) return 1;
grx_old_vd = current_virtual_device;
current_virtual_device = NULL;
grx_mouse_terminate();
svgalib_block_itrm(svgalib_kbd);
grx_set_text();
return 0;
}
static int grx_unblock(struct graphics_device *dev)
{
if (current_virtual_device) {
internal_error("grx_unblock called without grx_block");
return 0;
}
grx_set_graphics();
svgalib_unblock_itrm(svgalib_kbd);
current_virtual_device = grx_old_vd;
grx_old_vd = NULL;
grx_set_palette();
grx_set_clip();
grx_mouse_init();
if (current_virtual_device) current_virtual_device->redraw_handler(current_virtual_device, &current_virtual_device->size);
return 0;
}
struct graphics_driver grx_driver = {
cast_uchar "grx",
grx_init_driver,
init_virtual_device,
shutdown_virtual_device,
grx_shutdown_driver,
grx_emergency_shutdown,
NULL,
grx_get_driver_param,
NULL,
NULL,
NULL,
grx_get_empty_bitmap,
grx_register_bitmap,
grx_prepare_strip,
grx_commit_strip,
grx_unregister_bitmap,
grx_draw_bitmap,
NULL,
grx_fill_area,
grx_draw_hline,
grx_draw_vline,
grx_scroll,
grx_set_clip_area,
NULL,
grx_block,
grx_unblock,
grx_update_palette, /* set_palette */
NULL, /* get_real_colors */
NULL, /* set_title */
NULL, /* exec */
NULL, /* set_clipboard_text */
NULL, /* get_clipboard_text */
0, /* depth */
0, 0, /* size */
GD_NEED_CODEPAGE, /* flags */
NULL, /* param */
};
#endif