/* DOSEMU mouse graphics cursor code */ /* written by David Etherton, etherton@netcom.com. */ #include #include #include #include "vc.h" #include "port.h" #include "vgaemu.h" #include "mousevid.h" #include "mouse.h" #include "gcursor.h" /* store pre-shifted versions of our cursor and screen masks for speed. */ /* this allows us to treat our cursor draws as (masked) byte transfers, removing the expensive shifting out of the speed-sensitive loops */ /* (the mouse cursor only needs to be clipped to the screen extents, which are always on byte boundaries) */ /* A 16x16 cursor at... 8 ppb is 3 bytes/line * 16 lines * 8 shifts, or 384 bytes 4 ppb is 5 bytes/line * 16 lines * 4 shifts, or 320 bytes 1 ppb is 16 bytes/line * 16 lines * 1 shift, or 256 bytes */ static unsigned char screenmasks[384]; static unsigned char cursormasks[384]; static struct mousevideoinfo mouse_current_video; static int get_current_graphics_video_mode(void); static void realize_mask(unsigned char *dest, unsigned short *src, int org, int vga_val) { static int pixelsPerByte[] = { 0, 8, 4, 8, 1 }; static int bytesPerLine[] = { 0, 3, 5, 3, 16 }; int ppb = pixelsPerByte[org]; int pass, x, y; int fill1s = (vga_val == 255); /* are we doing screen mask? */ #if 0 unsigned char *orig_dest = dest; #endif memset(dest,0,384); for (pass=0; pass < ppb; pass++) { for (y=0; y<16; y++) { unsigned mask; unsigned srcy = src[y]; static unsigned char lut8[] = { 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01 }; static unsigned char lut4[] = { 0xC0,0x30,0x0C,0x03 }; if (ppb == 8) { for (x=0, mask=0x8000; x<16; x++,mask>>=1) if (mask & srcy) dest[(x + pass) >> 3] |= lut8[(x + pass) & 7]; if (fill1s) { dest[0] |= 0xFF << (8 - pass); dest[2] |= 0xFF >> pass; } } else if (ppb == 4) { for (x=0, mask=0x8000; x<16; x++,mask>>=1) if (mask & srcy) dest[(x + pass) >> 2] |= lut4[(x + pass) & 3]; if (fill1s) { dest[0] |= 0xFF << (8 - (pass + pass)); dest[4] |= 0xFF >> (pass + pass); } } else { for (x=0, mask=0x8000; x<16; x++,mask>>=1) if (mask & srcy) dest[x] = vga_val; } dest += bytesPerLine[org]; } } #if 0 { int x,y; m_printf("INPUT MASK:\n"); for (y=0; y<16; y++) m_printf("%04x\n",src[y]); m_printf("org = %d COMPILED MASK DUMP:\n",org); for (y=0; y<16; y++) { for (x=0; x> 1) * 80) + offset; } /* if we're on scanline y, return the offset to the start of scanline (y+1) */ static inline int cga_nextscan(int y) { if (y & 1) return - 0x2000 + 80; else return 0x2000; } static void cga2_bitblt(int x,int y,int width,int height,int toscr,int bpl, unsigned char *bs) { int byteWidth = ((x + width - 1) >> 3) - (x >> 3) + 1; unsigned scr = GRBASE + cga_scanline(y) + (x >> 3); if (toscr) while (height--) { memcpy_to_vga(scr,bs,byteWidth); bs += byteWidth; scr += cga_nextscan(y++); } else while (height--) { memcpy_from_vga(bs,scr,byteWidth); bs += byteWidth; scr += cga_nextscan(y++); } } static void cga4_bitblt(int x,int y,int width,int height,int toscr,int bpl, unsigned char *bs) { int byteWidth = ((x + width - 1) >> 2) - (x >> 2) + 1; unsigned scr = GRBASE + cga_scanline(y) + (x >> 2); if (toscr) while (height--) { memcpy_to_vga(scr,bs,byteWidth); bs += byteWidth; scr += cga_nextscan(y++); } else while (height--) { memcpy_from_vga(bs,scr,byteWidth); bs += byteWidth; scr += cga_nextscan(y++); } } static void ega16_bitblt(int x,int y,int width,int height,int toscr,int bpl, unsigned char *bs) { int byteWidth = ((x + width - 1) >> 3) - (x >> 3) + 1; int plane; unsigned scr = GRBASE + (y * bpl) + (x >> 3); SAVE_EGA_STATE for (plane=0; plane<4; plane++) { int h = height; unsigned s = scr; if (toscr) { /* only enable writes to a single plane */ write_ega_reg(SEQ_I,0x2,1<> 3) + (yofs * 3) + (x & 7) * 48; int bwidth = ((x + width - 1) >> 3) - (x >> 3); unsigned scr = GRBASE + cga_scanline(y) + (x >> 3); while (height--) { unsigned s = scr; int i = index; switch (bwidth) { case 2: do_pixel case 1: do_pixel case 0: do_pixel } scr += cga_nextscan(y++); index += 3; } } static void cga4_cursor(int x,int y,int width,int height,int xofs,int yofs,int bpl) { int index = (xofs >> 2) + (yofs * 5) + (x & 3) * 80; int bwidth = ((x + width - 1) >> 2) - (x >> 2); unsigned scr = GRBASE + cga_scanline(y) + (x >> 2); while (height--) { unsigned s = scr; int i = index; switch (bwidth) { case 4: do_pixel case 3: do_pixel case 2: do_pixel case 1: do_pixel case 0: do_pixel } scr += cga_nextscan(y++); index += 5; } } static void ega16_cursor(int x,int y,int width,int height,int xofs,int yofs,int bpl) { int index = (xofs >> 3) + (yofs * 3) + (x & 7) * 48; int bwidth = ((x + width - 1) >> 3) - (x >> 3); unsigned scr = GRBASE + (y * bpl) + (x >> 3); int plane; SAVE_EGA_STATE /* repeat once for each plane. requires more vram accesses but fewer port writes. these days that's usually a win. */ for (plane = 0; plane < 4; plane++) { int h = height; int ii = index; unsigned ss = scr; /* enable reads from this plane */ write_ega_reg(GRA_I,0x4,plane); /* enable writes to this plane */ write_ega_reg(SEQ_I,0x2,1<drawn && get_current_graphics_video_mode()) { mouse_blitters[mouse_current_video.organization]( erase->x,erase->y, erase->width,erase->height, 1,mouse_current_video.bytesperline, erase->backingstore.graphics); erase->drawn = FALSE; } } void draw_graphics_cursor(int x,int y,int hotx,int hoty,int width,int height, mouse_erase_t *erase) { int xofs, yofs; if (!get_current_graphics_video_mode()) return; /* adjust for hot spot */ erase->x = x - hotx; /* left clip */ if (erase->x < 0) { width += erase->x; xofs = -erase->x; erase->x = 0; } else { /* right clip? (never need both) */ xofs = 0; if (erase->x + width > mouse_current_video.width) width = mouse_current_video.width - erase->x; } /* adjust for hot spot */ erase->y = y - hoty; /* top clip */ if (erase->y < 0) { height += erase->y; yofs = -erase->y; erase->y = 0; } else { /* bottom clip? (never need both) */ yofs = 0; if (erase->y + height > mouse_current_video.height) height = mouse_current_video.height - erase->y; } /* remember final (clipped) width and height */ erase->width = width; erase->height = height; if (width > 0 && height > 0) { /* remember contents beneath cursor. */ mouse_blitters[mouse_current_video.organization]( erase->x,erase->y, erase->width,erase->height, 0,mouse_current_video.bytesperline, erase->backingstore.graphics); /* draw new cursor */ mouse_cursors[mouse_current_video.organization]( erase->x,erase->y, erase->width,erase->height, xofs,yofs, mouse_current_video.bytesperline); /* remember that we need to erase it. */ erase->drawn = TRUE; } }