diff --git a/lib/libvgl/Makefile b/lib/libvgl/Makefile index fe71c3510171..11b0b7533469 100644 --- a/lib/libvgl/Makefile +++ b/lib/libvgl/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ LIB= vgl -SHLIB_MAJOR= 1 +SHLIB_MAJOR= 2 SHLIB_MINOR= 0 CFLAGS+=-Wall -I${.CURDIR} SRCS= main.c simple.c bitmap.c text.c mouse.c keyboard.c diff --git a/lib/libvgl/bitmap.c b/lib/libvgl/bitmap.c index e66150ca2348..2714e890a506 100644 --- a/lib/libvgl/bitmap.c +++ b/lib/libvgl/bitmap.c @@ -30,9 +30,11 @@ #include #include +#include #include "vgl.h" -static byte VGLPlane[4][128]; +#define min(x, y) (((x) < (y)) ? (x) : (y)) + static byte mask[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; static int color2bit[16] = {0x00000000, 0x00000001, 0x00000100, 0x00000101, 0x00010000, 0x00010001, 0x00010100, 0x00010101, @@ -43,20 +45,28 @@ static void WriteVerticalLine(VGLBitmap *dst, int x, int y, int width, byte *line) { int i, pos, last, planepos, start_offset, end_offset, offset; + int len; unsigned int word = 0; byte *address; + byte *VGLPlane[4]; switch (dst->Type) { case VIDBUF4: - address = dst->Bitmap + (dst->Xsize/8 * y) + x/8; + case VIDBUF4S: start_offset = (x & 0x07); end_offset = (x + width) & 0x07; - offset = start_offset; + i = (width + start_offset) / 8; + if (end_offset) + i++; + VGLPlane[0] = VGLBuf; + VGLPlane[1] = VGLPlane[0] + i; + VGLPlane[2] = VGLPlane[1] + i; + VGLPlane[3] = VGLPlane[2] + i; pos = 0; planepos = 0; + last = 8 - start_offset; while (pos < width) { word = 0; - last = pos + 8 - offset; while (pos < last && pos < width) word = (word<<1) | color2bit[line[pos++]&0x0f]; VGLPlane[0][planepos] = word; @@ -64,7 +74,7 @@ WriteVerticalLine(VGLBitmap *dst, int x, int y, int width, byte *line) VGLPlane[2][planepos] = word>>16; VGLPlane[3][planepos] = word>>24; planepos++; - offset = 0; + last += 8; } planepos--; if (end_offset) { @@ -76,20 +86,43 @@ WriteVerticalLine(VGLBitmap *dst, int x, int y, int width, byte *line) } if (start_offset || end_offset) width+=8; + width /= 8; + outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */ + outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */ for (i=0; i<4; i++) { outb(0x3c4, 0x02); outb(0x3c5, 0x01<Type == VIDBUF4) { + if (end_offset) + VGLPlane[i][planepos] |= dst->Bitmap[pos+planepos] & mask[end_offset]; + if (start_offset) + VGLPlane[i][0] |= dst->Bitmap[pos] & ~mask[start_offset]; + bcopy(&VGLPlane[i][0], dst->Bitmap + pos, width); + } else { /* VIDBUF4S */ + if (end_offset) { + offset = VGLSetSegment(pos + planepos); + VGLPlane[i][planepos] |= dst->Bitmap[offset] & mask[end_offset]; + } + offset = VGLSetSegment(pos); + if (start_offset) + VGLPlane[i][0] |= dst->Bitmap[offset] & ~mask[start_offset]; + for (last = width; ; ) { + len = min(VGLAdpInfo.va_window_size - offset, last); + bcopy(&VGLPlane[i][width - last], dst->Bitmap + offset, len); + pos += len; + last -= len; + if (last <= 0) + break; + offset = VGLSetSegment(pos); + } + } } break; case VIDBUF8X: - address = dst->Bitmap + (dst->Xsize/2 * y) + x/4; + address = dst->Bitmap + VGLAdpInfo.va_line_width * y + x/4; for (i=0; i<4; i++) { outb(0x3c4, 0x02); outb(0x3c5, 0x01 << ((x + i)%4)); @@ -99,9 +132,20 @@ WriteVerticalLine(VGLBitmap *dst, int x, int y, int width, byte *line) ++address; } break; + case VIDBUF8S: + pos = dst->VXsize * y + x; + while (width > 0) { + offset = VGLSetSegment(pos); + i = min(VGLAdpInfo.va_window_size - offset, width); + bcopy(line, dst->Bitmap + offset, i); + line += i; + pos += i; + width -= i; + } + break; case VIDBUF8: case MEMBUF: - address = dst->Bitmap + (dst->Xsize * y) + x; + address = dst->Bitmap + dst->VXsize * y + x; bcopy(line, address, width); break; @@ -113,40 +157,67 @@ static void ReadVerticalLine(VGLBitmap *src, int x, int y, int width, byte *line) { int i, bit, pos, count, planepos, start_offset, end_offset, offset; + int width2, len; byte *address; + byte *VGLPlane[4]; switch (src->Type) { - case VIDBUF4: - address = src->Bitmap + (src->Xsize/8 * y) + x/8; + case VIDBUF4S: start_offset = (x & 0x07); end_offset = (x + width) & 0x07; - offset = start_offset; - if (start_offset) - count = (width - (8 - start_offset)) / 8 + 1; - else - count = width / 8; + count = (width + start_offset) / 8; if (end_offset) - count++; + count++; + VGLPlane[0] = VGLBuf; + VGLPlane[1] = VGLPlane[0] + count; + VGLPlane[2] = VGLPlane[1] + count; + VGLPlane[3] = VGLPlane[2] + count; + for (i=0; i<4; i++) { + outb(0x3ce, 0x04); + outb(0x3cf, i); + pos = VGLAdpInfo.va_line_width*y + x/8; + for (width2 = count; width2 > 0; ) { + offset = VGLSetSegment(pos); + len = min(VGLAdpInfo.va_window_size - offset, width2); + bcopy(src->Bitmap + offset, &VGLPlane[i][count - width2], len); + pos += len; + width2 -= len; + } + } + goto read_planar; + case VIDBUF4: + address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/8; + start_offset = (x & 0x07); + end_offset = (x + width) & 0x07; + count = (width + start_offset) / 8; + if (end_offset) + count++; + VGLPlane[0] = VGLBuf; + VGLPlane[1] = VGLPlane[0] + count; + VGLPlane[2] = VGLPlane[1] + count; + VGLPlane[3] = VGLPlane[2] + count; for (i=0; i<4; i++) { outb(0x3ce, 0x04); outb(0x3cf, i); bcopy(address, &VGLPlane[i][0], count); } +read_planar: pos = 0; planepos = 0; + bit = 7 - start_offset; while (pos < width) { - for (bit = (7-offset); bit >= 0 && pos < width; bit--, pos++) { + for (; bit >= 0 && pos < width; bit--, pos++) { line[pos] = (VGLPlane[0][planepos] & (1<Bitmap + (src->Xsize/2 * y) + x/4; + address = src->Bitmap + VGLAdpInfo.va_line_width * y + x/4; for (i=0; i<4; i++) { outb(0x3ce, 0x04); outb(0x3cf, (x + i)%4); @@ -156,9 +227,20 @@ ReadVerticalLine(VGLBitmap *src, int x, int y, int width, byte *line) ++address; } break; + case VIDBUF8S: + pos = src->VXsize * y + x; + while (width > 0) { + offset = VGLSetSegment(pos); + i = min(VGLAdpInfo.va_window_size - offset, width); + bcopy(src->Bitmap + offset, line, i); + line += i; + pos += i; + width -= i; + } + break; case VIDBUF8: case MEMBUF: - address = src->Bitmap + (src->Xsize * y) + x; + address = src->Bitmap + src->VXsize * y + x; bcopy(address, line, width); break; default: @@ -171,7 +253,8 @@ __VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy, { int srcline, dstline; - if (srcx>src->Xsize||srcy>src->Ysize||dstx>dst->Xsize||dsty>dst->Ysize) + if (srcx>src->VXsize || srcy>src->VYsize + || dstx>dst->VXsize || dsty>dst->VYsize) return -1; if (srcx < 0) { width=width+srcx; dstx-=srcx; srcx=0; @@ -185,34 +268,45 @@ __VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy, if (dsty < 0) { hight=hight+dsty; srcy-=dsty; dsty=0; } - if (srcx+width > src->Xsize) - width=src->Xsize-srcx; - if (srcy+hight > src->Ysize) - hight=src->Ysize-srcy; - if (dstx+width > dst->Xsize) - width=dst->Xsize-dstx; - if (dsty+hight > dst->Ysize) - hight=dst->Ysize-dsty; + if (srcx+width > src->VXsize) + width=src->VXsize-srcx; + if (srcy+hight > src->VYsize) + hight=src->VYsize-srcy; + if (dstx+width > dst->VXsize) + width=dst->VXsize-dstx; + if (dsty+hight > dst->VYsize) + hight=dst->VYsize-dsty; if (width < 0 || hight < 0) return -1; if (src->Type == MEMBUF) { for (srcline=srcy, dstline=dsty; srclineBitmap+(srcline*src->Xsize)+srcx)); + (src->Bitmap+(srcline*src->VXsize)+srcx)); } } else if (dst->Type == MEMBUF) { for (srcline=srcy, dstline=dsty; srclineBitmap+(dstline*dst->Xsize)+dstx)); + (dst->Bitmap+(dstline*dst->VXsize)+dstx)); } } else { - byte buffer[1024]; - for (srcline=srcy, dstline=dsty; srcline sizeof(buffer)) { + p = malloc(width); + if (p == NULL) + return 1; + } else { + p = buffer; } + for (srcline=srcy, dstline=dsty; srcline sizeof(buffer)) + free(p); } return 0; } @@ -229,3 +323,42 @@ VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy, return error; } +VGLBitmap +*VGLBitmapCreate(int type, int xsize, int ysize, byte *bits) +{ + VGLBitmap *object; + + if (type != MEMBUF) + return NULL; + if (xsize < 0 || ysize < 0) + return NULL; + object = (VGLBitmap *)malloc(sizeof(*object)); + if (object == NULL) + return NULL; + object->Type = type; + object->Xsize = xsize; + object->Ysize = ysize; + object->VXsize = xsize; + object->VYsize = ysize; + object->Xorigin = 0; + object->Yorigin = 0; + object->Bitmap = bits; + return object; +} + +void +VGLBitmapDestroy(VGLBitmap *object) +{ + if (object->Bitmap) + free(object->Bitmap); + free(object); +} + +int +VGLBitmapAllocateBits(VGLBitmap *object) +{ + object->Bitmap = (byte *)malloc(object->VXsize*object->VYsize); + if (object->Bitmap == NULL) + return -1; + return 0; +} diff --git a/lib/libvgl/main.c b/lib/libvgl/main.c index fc13f46b0c43..8211842ddc98 100644 --- a/lib/libvgl/main.c +++ b/lib/libvgl/main.c @@ -37,14 +37,21 @@ #include #include "vgl.h" +#define min(x, y) (((x) < (y)) ? (x) : (y)) +#define max(x, y) (((x) > (y)) ? (x) : (y)) + VGLBitmap *VGLDisplay; +video_info_t VGLModeInfo; +video_adapter_info_t VGLAdpInfo; +byte *VGLBuf; static int VGLMode; static int VGLOldMode; -static byte *VGLBuf; -static byte *VGLMem; +static size_t VGLBufSize; +static byte *VGLMem = MAP_FAILED; static int VGLSwitchPending; static int VGLOnDisplay; +static unsigned int VGLCurWindow; static int VGLInitDone = 0; void @@ -54,11 +61,15 @@ struct vt_mode smode; if (!VGLInitDone) return; - if (VGLOnDisplay && !VGLSwitchPending) { - outb(0x3c4, 0x02); - outb(0x3c5, 0x0f); - bzero(VGLMem, 64*1024); + VGLInitDone = 0; + + signal(SIGUSR1, SIG_IGN); + + if (VGLMem != MAP_FAILED) { + VGLClear(VGLDisplay, 0); + munmap(VGLMem, VGLAdpInfo.va_window_size); } + if (VGLOldMode >= M_VESA_BASE) { /* ugly, but necessary */ ioctl(0, _IO('V', VGLOldMode - M_VESA_BASE), 0); @@ -76,8 +87,11 @@ struct vt_mode smode; ioctl(0, KDSETMODE, KD_TEXT); smode.mode = VT_AUTO; ioctl(0, VT_SETMODE, &smode); - free(VGLBuf); + if (VGLBuf) + free(VGLBuf); + VGLBuf = NULL; free(VGLDisplay); + VGLDisplay = NULL; VGLKeyboardEnd(); } @@ -103,8 +117,10 @@ int VGLInit(int mode) { struct vt_mode smode; - struct winsize winsz; - int error; + int adptype; + + if (VGLInitDone) + return -1; signal(SIGUSR1, VGLSwitch); signal(SIGINT, VGLAbort); @@ -115,76 +131,142 @@ VGLInit(int mode) VGLOnDisplay = 1; VGLSwitchPending = 0; - ioctl(0, CONS_GET, &VGLOldMode); + if (ioctl(0, CONS_GET, &VGLOldMode) || ioctl(0, CONS_CURRENT, &adptype)) + return -1; + if (IOCGROUP(mode) == 'V') /* XXX: this is ugly */ + VGLModeInfo.vi_mode = (mode & 0x0ff) + M_VESA_BASE; + else + VGLModeInfo.vi_mode = mode & 0x0ff; + if (ioctl(0, CONS_MODEINFO, &VGLModeInfo)) /* FBIO_MODEINFO */ + return -1; - VGLMem = (byte*)mmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_FILE, - open("/dev/mem", O_RDWR), 0xA0000); - if (VGLMem <= (byte*)0) - return 1; + VGLDisplay = (VGLBitmap *)malloc(sizeof(VGLBitmap)); + if (VGLDisplay == NULL) + return -2; - VGLBuf = (byte*)malloc(256*1024); - if (VGLBuf == NULL) - return 1; - - VGLDisplay = (VGLBitmap*) malloc(sizeof(VGLBitmap)); - if (VGLDisplay == NULL) { - free(VGLBuf); - return 1; + if (ioctl(0, KDENABIO, 0)) { + free(VGLDisplay); + return -3; } - switch (mode) { - case SW_BG640x480: case SW_CG640x480: + VGLInitDone = 1; + + /* + * vi_mem_model specifies the memory model of the current video mode + * in -CURRENT. + */ + switch (VGLModeInfo.vi_mem_model) { + case V_INFO_MM_PLANAR: + /* we can handle EGA/VGA planner modes only */ + if (VGLModeInfo.vi_depth != 4 || VGLModeInfo.vi_planes != 4 + || (adptype != KD_EGA && adptype != KD_VGA)) { + VGLEnd(); + return -4; + } VGLDisplay->Type = VIDBUF4; break; - case SW_VGA_CG320: + case V_INFO_MM_PACKED: + /* we can do only 256 color packed modes */ + if (VGLModeInfo.vi_depth != 8) { + VGLEnd(); + return -4; + } VGLDisplay->Type = VIDBUF8; break; - case SW_VGA_MODEX: + case V_INFO_MM_VGAX: VGLDisplay->Type = VIDBUF8X; break; default: VGLEnd(); - return 1; + return -4; } - if ((error = ioctl(0, KDENABIO, 0))) - return error; - ioctl(0, VT_WAITACTIVE, 0); ioctl(0, KDSETMODE, KD_GRAPHICS); - if ((error = ioctl(0, mode, 0))) { - ioctl(0, KDSETMODE, KD_TEXT); - ioctl(0, KDDISABIO, 0); - return error; + if (ioctl(0, mode, 0)) { + VGLEnd(); + return -5; + } + if (ioctl(0, CONS_ADPINFO, &VGLAdpInfo)) { /* FBIO_ADPINFO */ + VGLEnd(); + return -6; + } + + /* + * Calculate the shadow screen buffer size. In -CURRENT, va_buffer_size + * always holds the entire frame buffer size, wheather it's in the linear + * mode or windowed mode. + * VGLBufSize = VGLAdpInfo.va_buffer_size; + * In -STABLE, va_buffer_size holds the frame buffer size, only if + * the linear frame buffer mode is supported. Otherwise the field is zero. + * We shall calculate the minimal size in this case: + * VGLAdpInfo.va_line_width*VGLModeInfo.vi_height*VGLModeInfo.vi_planes + * or + * VGLAdpInfo.va_window_size*VGLModeInfo.vi_planes; + * Use whichever is larger. + */ + if (VGLAdpInfo.va_buffer_size != 0) + VGLBufSize = VGLAdpInfo.va_buffer_size; + else + VGLBufSize = max(VGLAdpInfo.va_line_width*VGLModeInfo.vi_height, + VGLAdpInfo.va_window_size)*VGLModeInfo.vi_planes; + VGLBuf = malloc(VGLBufSize); + if (VGLBuf == NULL) { + VGLEnd(); + return -7; + } + +#ifdef LIBVGL_DEBUG + fprintf(stderr, "VGLBufSize:0x%x\n", VGLBufSize); +#endif + + /* see if we are in the windowed buffer mode or in the linear buffer mode */ + if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size) { + if (VGLDisplay->Type == VIDBUF4) + VGLDisplay->Type = VIDBUF4S; + else if (VGLDisplay->Type == VIDBUF8) + VGLDisplay->Type = VIDBUF8S; } VGLMode = mode; + VGLCurWindow = 0; - outb(0x3c4, 0x02); - outb(0x3c5, 0x0f); - bzero(VGLMem, 64*1024); + VGLDisplay->Xsize = VGLModeInfo.vi_width; + VGLDisplay->Ysize = VGLModeInfo.vi_height; + VGLDisplay->VXsize = VGLAdpInfo.va_line_width + *8/(VGLModeInfo.vi_depth/VGLModeInfo.vi_planes); + VGLDisplay->VYsize = VGLBufSize/VGLModeInfo.vi_planes/VGLAdpInfo.va_line_width; + VGLDisplay->Xorigin = 0; + VGLDisplay->Yorigin = 0; - if (ioctl(0, TIOCGWINSZ, &winsz)) { + VGLMem = (byte*)mmap(0, VGLAdpInfo.va_window_size, PROT_READ|PROT_WRITE, + MAP_FILE, 0, 0); + if (VGLMem == MAP_FAILED) { VGLEnd(); - return 1; + return -7; } - VGLDisplay->Bitmap = VGLMem; - VGLDisplay->Xsize = winsz.ws_xpixel; - VGLDisplay->Ysize = winsz.ws_ypixel; + VGLSavePalette(); +#ifdef LIBVGL_DEBUG + fprintf(stderr, "va_line_width:%d\n", VGLAdpInfo.va_line_width); + fprintf(stderr, "VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n", + VGLDisplay->Xsize, VGLDisplay->Ysize, + VGLDisplay->VXsize, VGLDisplay->VYsize); +#endif + smode.mode = VT_PROCESS; smode.waitv = 0; smode.relsig = SIGUSR1; smode.acqsig = SIGUSR1; smode.frsig = SIGINT; - if (ioctl(0, VT_SETMODE, &smode) == -1) { + if (ioctl(0, VT_SETMODE, &smode)) { VGLEnd(); - return 1; + return -9; } VGLTextSetFontFile((byte*)0); - VGLInitDone = 1; + VGLClear(VGLDisplay, 0); return 0; } @@ -192,6 +274,8 @@ void VGLCheckSwitch() { while (VGLSwitchPending) { + unsigned int offset; + unsigned int len; int i; VGLSwitchPending = 0; @@ -199,44 +283,195 @@ VGLCheckSwitch() ioctl(0, KDENABIO, 0); ioctl(0, KDSETMODE, KD_GRAPHICS); ioctl(0, VGLMode, 0); - outb(0x3c6, 0xff); - for (i=0; i<4; i++) { - outb(0x3c4, 0x02); - outb(0x3c5, 0x01<Type = VIDBUF8; /* XXX */ + switch (VGLModeInfo.vi_mem_model) { + case V_INFO_MM_PLANAR: + if (VGLModeInfo.vi_depth == 4 && VGLModeInfo.vi_planes == 4) { + if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size) + VGLDisplay->Type = VIDBUF4S; + else + VGLDisplay->Type = VIDBUF4; + } else { + /* shouldn't be happening */ + } + break; + case V_INFO_MM_PACKED: + if (VGLModeInfo.vi_depth == 8) { + if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size) + VGLDisplay->Type = VIDBUF8S; + else + VGLDisplay->Type = VIDBUF8; + } else { + /* shouldn't be happening */ + } + break; + case V_INFO_MM_VGAX: + VGLDisplay->Type = VIDBUF8X; + break; + default: + /* shouldn't be happening */ + break; + } + + VGLDisplay->Bitmap = VGLMem; + VGLDisplay->Xsize = VGLModeInfo.vi_width; + VGLDisplay->Ysize = VGLModeInfo.vi_height; + VGLSetVScreenSize(VGLDisplay, VGLDisplay->VXsize, VGLDisplay->VYsize); + VGLPanScreen(VGLDisplay, VGLDisplay->Xorigin, VGLDisplay->Yorigin); + switch (VGLDisplay->Type) { + case VIDBUF4S: + outb(0x3c6, 0xff); + outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */ + outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */ + for (offset = 0; offset < VGLBufSize/VGLModeInfo.vi_planes; + offset += len) { + VGLSetSegment(offset); + len = min(VGLBufSize/VGLModeInfo.vi_planes - offset, + VGLAdpInfo.va_window_size); + for (i = 0; i < VGLModeInfo.vi_planes; i++) { + outb(0x3c4, 0x02); + outb(0x3c5, 0x01<Bitmap = VGLMem; - switch (VGLMode) { - case SW_BG640x480: case SW_CG640x480: - VGLDisplay->Type = VIDBUF4; - break; - case SW_VGA_CG320: - VGLDisplay->Type = VIDBUF8; - break; - case SW_VGA_MODEX: - VGLDisplay->Type = VIDBUF8X; - break; - default: - VGLDisplay->Type = VIDBUF8; /* XXX */ - break; - } } else { - for (i=0; i<4; i++) { - outb(0x3ce, 0x04); - outb(0x3cf, i); - bcopy(VGLMem, &VGLBuf[i*64*1024], 64*1024); + switch (VGLDisplay->Type) { + case VIDBUF4S: + for (offset = 0; offset < VGLBufSize/VGLModeInfo.vi_planes; + offset += len) { + VGLSetSegment(offset); + len = min(VGLBufSize/VGLModeInfo.vi_planes - offset, + VGLAdpInfo.va_window_size); + for (i = 0; i < VGLModeInfo.vi_planes; i++) { + outb(0x3ce, 0x04); + outb(0x3cf, i); + bcopy(VGLMem, &VGLBuf[i*VGLBufSize/VGLModeInfo.vi_planes + offset], + len); + } + } + break; + case VIDBUF4: + case VIDBUF8X: + /* + * NOTE: the saved buffer is NOT in the MEMBUF format which + * the ordinary memory bitmap object is stored in. XXX + */ + for (i = 0; i < VGLModeInfo.vi_planes; i++) { + outb(0x3ce, 0x04); + outb(0x3cf, i); + bcopy(VGLMem, &VGLBuf[i*VGLAdpInfo.va_window_size], + VGLAdpInfo.va_window_size); + } + break; + case VIDBUF8: + case VIDBUF8S: + for (offset = 0; offset < VGLBufSize; offset += len) { + VGLSetSegment(offset); + len = min(VGLBufSize - offset, VGLAdpInfo.va_window_size); + bcopy(VGLMem, &VGLBuf[offset], len); + } + break; } + VGLMem = MAP_FAILED; + munmap(VGLDisplay->Bitmap, VGLAdpInfo.va_window_size); ioctl(0, VGLOldMode, 0); ioctl(0, KDSETMODE, KD_TEXT); ioctl(0, KDDISABIO, 0); ioctl(0, VT_RELDISP, VT_TRUE); VGLDisplay->Bitmap = VGLBuf; VGLDisplay->Type = MEMBUF; + VGLDisplay->Xsize = VGLDisplay->VXsize; + VGLDisplay->Ysize = VGLDisplay->VYsize; while (!VGLOnDisplay) pause(); } } } - + +int +VGLSetSegment(unsigned int offset) +{ + if (offset/VGLAdpInfo.va_window_size != VGLCurWindow) { + ioctl(0, CONS_SETWINORG, offset); /* FBIO_SETWINORG */ + VGLCurWindow = offset/VGLAdpInfo.va_window_size; + } + return (offset%VGLAdpInfo.va_window_size); +} + +int +VGLSetVScreenSize(VGLBitmap *object, int VXsize, int VYsize) +{ + if (VXsize < object->Xsize || VYsize < object->Ysize) + return -1; + if (object->Type == MEMBUF) + return -1; + if (ioctl(0, FBIO_SETLINEWIDTH, &VXsize)) + return -1; + ioctl(0, CONS_ADPINFO, &VGLAdpInfo); /* FBIO_ADPINFO */ + object->VXsize = VGLAdpInfo.va_line_width + *8/(VGLModeInfo.vi_depth/VGLModeInfo.vi_planes); + object->VYsize = VGLBufSize/VGLModeInfo.vi_planes/VGLAdpInfo.va_line_width; + if (VYsize < object->VYsize) + object->VYsize = VYsize; + +#ifdef LIBVGL_DEBUG + fprintf(stderr, "new size: VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n", + object->Xsize, object->Ysize, object->VXsize, object->VYsize); +#endif + + return 0; +} + +int +VGLPanScreen(VGLBitmap *object, int x, int y) +{ + video_display_start_t origin; + + if (x < 0 || x + object->Xsize > object->VXsize + || y < 0 || y + object->Ysize > object->VYsize) + return -1; + if (object->Type == MEMBUF) + return 0; + origin.x = x; + origin.y = y; + if (ioctl(0, FBIO_SETDISPSTART, &origin)) + return -1; + object->Xorigin = x; + object->Yorigin = y; + +#ifdef LIBVGL_DEBUG + fprintf(stderr, "new origin: (%d, %d)\n", x, y); +#endif + + return 0; +} diff --git a/lib/libvgl/mouse.c b/lib/libvgl/mouse.c index a5ded2f2a424..390ec6cd86d2 100644 --- a/lib/libvgl/mouse.c +++ b/lib/libvgl/mouse.c @@ -35,9 +35,6 @@ #include #include "vgl.h" -/* prototype for internal function */ -int __VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy, VGLBitmap *dst, int dstx, int dsty, int width, int hight); - #define X 0xff static byte StdAndMask[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE] = { X,X,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -77,12 +74,13 @@ static byte StdOrMask[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE] = { }; #undef X static VGLBitmap VGLMouseStdAndMask = - { MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, StdAndMask }; + VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, StdAndMask); static VGLBitmap VGLMouseStdOrMask = - { MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, StdOrMask }; + VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, StdOrMask); static VGLBitmap *VGLMouseAndMask, *VGLMouseOrMask; static byte map[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE]; -static VGLBitmap VGLMouseSave = { MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, map}; +static VGLBitmap VGLMouseSave = + VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, map); static int VGLMouseVisible = 0; static int VGLMouseFrozen = 0; static int VGLMouseShown = 0; @@ -94,7 +92,8 @@ void VGLMousePointerShow() { byte buf[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE]; - VGLBitmap buffer = { MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, buf }; + VGLBitmap buffer = + VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, buf); byte crtcidx, crtcval, gdcidx, gdcval; int pos; diff --git a/lib/libvgl/simple.c b/lib/libvgl/simple.c index 2ca923ca7ff7..0dfc23704210 100644 --- a/lib/libvgl/simple.c +++ b/lib/libvgl/simple.c @@ -38,45 +38,41 @@ static byte VGLSavePaletteBlue[256]; #define ABS(a) (((a)<0) ? -(a) : (a)) #define SGN(a) (((a)<0) ? -1 : 1) - +#define min(x, y) (((x) < (y)) ? (x) : (y)) +#define max(x, y) (((x) > (y)) ? (x) : (y)) void VGLSetXY(VGLBitmap *object, int x, int y, byte color) { + int offset; + VGLCheckSwitch(); - if (x>=0 && xXsize && y>=0 && yYsize) { + if (x>=0 && xVXsize && y>=0 && yVYsize) { if (!VGLMouseFreeze(x, y, 1, 1, color)) { switch (object->Type) { case MEMBUF: case VIDBUF8: - object->Bitmap[y*object->Xsize+x]=(color); + object->Bitmap[y*object->VXsize+x]=(color); break; + case VIDBUF8S: + object->Bitmap[VGLSetSegment(y*object->VXsize+x)]=(color); + break; case VIDBUF8X: outb(0x3c4, 0x02); outb(0x3c5, 0x01 << (x&0x3)); - object->Bitmap[(unsigned)(object->Xsize/2*y)+(x/4)] = (color); + object->Bitmap[(unsigned)(VGLAdpInfo.va_line_width*y)+(x/4)] = (color); break; + case VIDBUF4S: + offset = VGLSetSegment(y*VGLAdpInfo.va_line_width + x/8); + goto set_planar; case VIDBUF4: - outb(0x3c4, 0x02); outb(0x3c5, 0x01); - outb(0x3ce, 0x04); outb(0x3cf, 0x00); - object->Bitmap[(y*object->Xsize/8+x/8)&0xffff] = - ( object->Bitmap[(y*object->Xsize/8+x/8)&0xffff] & ~(0x80>>(x%8)) ) - | ((color & 0x01) ? (0x80>>(x%8)) : 0); - outb(0x3c4, 0x02); outb(0x3c5, 0x02); - outb(0x3ce, 0x04); outb(0x3cf, 0x01); - object->Bitmap[(y*object->Xsize/8+x/8)&0xffff] = - ( object->Bitmap[(y*object->Xsize/8+x/8)&0xffff] & ~(0x80>>(x%8)) ) - | ((color & 0x02) ? (0x80>>(x%8)) : 0); - outb(0x3c4, 0x02); outb(0x3c5, 0x04); - outb(0x3ce, 0x04); outb(0x3cf, 0x02); - object->Bitmap[(y*object->Xsize/8+x/8)&0xffff] = - ( object->Bitmap[(y*object->Xsize/8+x/8)&0xffff] & ~(0x80>>(x%8)) ) - | ((color & 0x04) ? (0x80>>(x%8)) : 0); - outb(0x3c4, 0x02); outb(0x3c5, 0x08); - outb(0x3ce, 0x04); outb(0x3cf, 0x03); - object->Bitmap[(y*object->Xsize/8+x/8)&0xffff] = - ( object->Bitmap[(y*object->Xsize/8+x/8)&0xffff] & ~(0x80>>(x%8)) ) - | ((color & 0x08) ? (0x80>>(x%8)) : 0); + offset = y*VGLAdpInfo.va_line_width + x/8; +set_planar: + outb(0x3c4, 0x02); outb(0x3c5, 0x0f); + outb(0x3ce, 0x00); outb(0x3cf, color & 0x0f); /* set/reset */ + outb(0x3ce, 0x01); outb(0x3cf, 0x0f); /* set/reset enable */ + outb(0x3ce, 0x08); outb(0x3cf, 0x80 >> (x%8)); /* bit mask */ + object->Bitmap[offset] |= color; } } VGLMouseUnFreeze(); @@ -86,19 +82,42 @@ VGLSetXY(VGLBitmap *object, int x, int y, byte color) byte VGLGetXY(VGLBitmap *object, int x, int y) { + int offset; +#if 0 + int i; + byte color; + byte mask; +#endif + VGLCheckSwitch(); + if (x<0 || x>=object->VXsize || y<0 || y>=object->VYsize) + return 0; switch (object->Type) { case MEMBUF: case VIDBUF8: - return object->Bitmap[((y*object->Xsize)+x)]; - break; + return object->Bitmap[((y*object->VXsize)+x)]; + case VIDBUF8S: + return object->Bitmap[VGLSetSegment(y*object->VXsize+x)]; case VIDBUF8X: outb(0x3ce, 0x04); outb(0x3cf, x & 0x3); - return object->Bitmap[(unsigned)(object->Xsize/2*y)+(x/4)]; - break; + return object->Bitmap[(unsigned)(VGLAdpInfo.va_line_width*y)+(x/4)]; + case VIDBUF4S: + offset = VGLSetSegment(y*VGLAdpInfo.va_line_width + x/8); + goto get_planar; case VIDBUF4: - return (object->Bitmap[((y*object->Xsize/8)+x/8)]&(0x80>>(x%8))) ? 1 : 0; - break; + offset = y*VGLAdpInfo.va_line_width + x/8; +get_planar: +#if 1 + return (object->Bitmap[offset]&(0x80>>(x%8))) ? 1 : 0; /* XXX */ +#else + color = 0; + mask = 0x80 >> (x%8); + for (i = 0; i < VGLModeInfo.vi_planes; i++) { + outb(0x3ce, 0x04); outb(0x3cf, i); + color |= (object->Bitmap[offset] & mask) ? (1 << i) : 0; + } + return color; +#endif } return 0; } @@ -234,22 +253,49 @@ VGLFilledEllipse(VGLBitmap *object, int xc, int yc, int a, int b, byte color) void VGLClear(VGLBitmap *object, byte color) { + int offset; + int len; + VGLCheckSwitch(); VGLMouseFreeze(0, 0, object->Xsize, object->Ysize, color); switch (object->Type) { case MEMBUF: case VIDBUF8: - memset(object->Bitmap, color, object->Xsize*object->Ysize); + memset(object->Bitmap, color, object->VXsize*object->VYsize); break; + + case VIDBUF8S: + for (offset = 0; offset < object->VXsize*object->VYsize; ) { + VGLSetSegment(offset); + len = min(object->VXsize*object->VYsize - offset, + VGLAdpInfo.va_window_size); + memset(object->Bitmap, color, len); + offset += len; + } + break; + case VIDBUF8X: /* XXX works only for Xsize % 4 = 0 */ + outb(0x3c6, 0xff); outb(0x3c4, 0x02); outb(0x3c5, 0x0f); - memset(object->Bitmap, color, object->Xsize*object->Ysize/4); + memset(object->Bitmap, color, VGLAdpInfo.va_line_width*object->VYsize); break; case VIDBUF4: + case VIDBUF4S: /* XXX works only for Xsize % 8 = 0 */ - memset(object->Bitmap, color, object->Xsize/8*object->Ysize); + outb(0x3c4, 0x02); outb(0x3c5, 0x0f); + outb(0x3ce, 0x05); outb(0x3cf, 0x02); /* mode 2 */ + outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */ + outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */ + for (offset = 0; offset < VGLAdpInfo.va_line_width*object->VYsize; ) { + VGLSetSegment(offset); + len = min(object->VXsize*object->VYsize - offset, + VGLAdpInfo.va_window_size); + memset(object->Bitmap, color, len); + offset += len; + } + outb(0x3ce, 0x05); outb(0x3cf, 0x00); break; } VGLMouseUnFreeze(); diff --git a/lib/libvgl/text.c b/lib/libvgl/text.c index a2c6417301e5..09b09644a3e9 100644 --- a/lib/libvgl/text.c +++ b/lib/libvgl/text.c @@ -29,6 +29,7 @@ */ #include +#include #include "vgl.h" static VGLText *VGLTextFont = 0; diff --git a/lib/libvgl/vgl.3 b/lib/libvgl/vgl.3 index 5a25a02e806c..c63503ffd6f6 100644 --- a/lib/libvgl/vgl.3 +++ b/lib/libvgl/vgl.3 @@ -25,11 +25,14 @@ .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD$ -.Dd October 28, 1999 +.Dd November 7, 1999 .Dt VGL 3 .Os FreeBSD 3.0 .Sh NAME +.Nm VGLBitmapAllocateBits , .Nm VGLBitmapCopy , +.Nm VGLBitmapCreate , +.Nm VGLBitmapDestroy , .Nm VGLBitmapPutChar , .Nm VGLBitmapString , .Nm VGLBlankDisplay , @@ -42,14 +45,19 @@ .Nm VGLFilledEllipse , .Nm VGLInit , .Nm VGLLine , +.Nm VGLKeyboardInit , +.Nm VGLKeyboardEnd , +.Nm VGLKeyboardGetCh , .Nm VGLMouseInit , .Nm VGLMouseMode , .Nm VGLMouseSetImage , .Nm VGLMouseSetStdImage , .Nm VGLMouseStatus , +.Nm VGLPanScreen , .Nm VGLSetBorder , .Nm VGLSetPalette , .Nm VGLSetPaletteIndex , +.Nm VGLSetVScreenSize , .Nm VGLTextSetFontFile .Nd Video Graphics Library functions (libvgl) .Sh SYNOPSIS @@ -62,6 +70,12 @@ .Fn VGLCheckSwitch "void" .Ft int .Fn VGLTextSetFontFile "char *filename" +.Ft int +.Fn VGLKeyboardInit "int code" +.Ft void +.Fn VGLKeyboardEnd "void" +.Ft int +.Fn VGLKeyboardGetCh "void" .Ft int .Fn VGLMouseInit "int mode" .Ft void @@ -82,6 +96,12 @@ .Fn VGLEllipse "VGLBitmap *object" "int xc" "int yc" "int a" "int b" "byte color" .Ft void .Fn VGLFilledEllipse "VGLBitmap *object" "int xc" "int yc" "int a" "int b" "byte color" +.Ft VGLBitmap * +.Fn VGLBitmapCreate "int type" "int xsize" "int ysize" "byte *bits" +.Ft void +.Fn VGLBitmapDestroy "VGLBitmap *object" +.Ft int +.Fn VGLBitmapAllocateBits "VGLBitmap *object" .Ft int .Fn VGLBitmapCopy "VGLBitmap *src" "int srcx" "int srcy" "VGLBitmap *dst" "int dstx" "int dsty" "int width" "int hight" .Ft void @@ -96,6 +116,10 @@ .Fn VGLSetPaletteIndex "byte color" "byte red" "byte green" "byte blue" .Ft void .Fn VGLSetBorder "byte color" +.Ft int +.Fn VGLSetVScreenSize "VGLBitmap *object" "int vxsize" "int vysize" +.Ft int +.Fn VGLPanSreen "VGLBitmap *object" "int x" "int y" .Ft void .Fn VGLBlankDisplay "int blank" .Sh DESCRIPTION @@ -136,6 +160,34 @@ instruct the char/string functions to use the font in file .Em filename instead of the builtin font. .Pp +.Fn VGLKeyboardInit +set up the keyboard in the ``raw'' I/O mode and +specify the key code to be used. +.Em code +must be +.Em VGL_XLATEKEYS , +.Em VGL_CODEKEYS , +or +.Em VGL_RAWKEYS . +When +.Em VGL_XLATEKEYS +is specified, the keyboard translate the raw keyboard scan code into +a character code. +If +.Em VGL_RAWKEYS +is used, the raw keyboard scan code is read as is. +.Em VGL_CODEKEYS +is the intermediate key code; each key is assigned a unique code whereas +more than one raw scan code may be generated when a key is pressed. +.Pp +.Fn VGLKeyboardEnd +when you have finished using the keyboard, call this function. +.Pp +.Fn VGLKeyboardGetCh +read one byte from the keyboard. As the keyboard I/O is in the ``raw'' +input mode, the function will not block even if there is no input data, +and returns 0. +.Pp .Fn VGLMouseInit initialize the mouse. The optional on-screen mouse pointer is shown if the argument is @@ -204,6 +256,26 @@ pixels wide, and pixels high in color .Em color . .Pp +.Fn VGLBitmapCreate +create a bitmap object and initialize it with the specified +values and bit data. +.Em type +must be +.Em MEMBUF +for the in-memory bitmap. +.Em bits +may be NULL so that bitmap data may be associated later. +.Pp +There also is a macro, +.Fn VGLBITMAP_INITIALIZER "type" "xsize" "ysize" "bits" +to initialize a statically declared bitmap object. +.Pp +.Fn VGLBitmapDestroy +free the bitmap data and the bitmap object. +.Pp +.Fn VGLBitmapAllocateBits +allocate a bit data buffer for the specified object. +.Pp .Fn VGLBitmapCopy copy a rectangle of pixels from bitmap .Em src @@ -264,6 +336,39 @@ to the specified RGB value. set the border color to color .Em color . .Pp +.Fn VGLSetVScreenSize +change the virtual screen size of the display. Note that this +function must be called when our vty is in the foreground. +And +.Em object +must be +.Em VGLDisplay . +Passing a in-memory bitmap to this function results in error. +.Pp +The desired virtual screen width may not be achievable because +of the video card hardware. In such case the video driver (and +underlaying video BIOS) may choose the next largest values. +Always examine +.Em object->VXsize +and +.Em VYsize +after calling this function, in order to see how the virtual screen +is actually set up. +.Pp +In order to set up the largest possible virtual screen, you may +call this function with arbitrary large values. +.Pp +.Dl VGLSetVScreenSize(10000, 10000); +.Pp +.Fn VGLPanSreen +change the origin of the displayed screen in the virtual screen. +Note that this function must be called when our vty is in the +foreground. +.Em object +must be +.Em VGLDisplay . +Passing a in-memory bitmap to this function results in error. +.Pp .Fn VGLBlankDisplay blank the display if the argment .Em blank diff --git a/lib/libvgl/vgl.h b/lib/libvgl/vgl.h index 8704ac97ecdf..4aa34c6ca066 100644 --- a/lib/libvgl/vgl.h +++ b/lib/libvgl/vgl.h @@ -37,9 +37,14 @@ typedef unsigned char byte; typedef struct { byte Type; int Xsize, Ysize; + int VXsize, VYsize; + int Xorigin, Yorigin; byte *Bitmap; } VGLBitmap; +#define VGLBITMAP_INITIALIZER(t, x, y, bits) \ + { (t), (x), (y), 0, 0, 0, 0, (bits) } + /* * Defined Type's */ @@ -47,6 +52,8 @@ typedef struct { #define VIDBUF4 1 #define VIDBUF8 2 #define VIDBUF8X 3 +#define VIDBUF8S 4 +#define VIDBUF4S 5 #define NOBUF 255 typedef struct VGLText { @@ -78,7 +85,10 @@ typedef struct VGLObject { #define VGL_CODEKEYS 2 #define VGL_XLATEKEYS 3 -extern VGLBitmap *VGLDisplay; +extern video_adapter_info_t VGLAdpInfo; +extern video_info_t VGLModeInfo; +extern VGLBitmap *VGLDisplay; +extern byte *VGLBuf; /* * Prototypes @@ -86,6 +96,9 @@ extern VGLBitmap *VGLDisplay; /* bitmap.c */ int __VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy, VGLBitmap *dst, int dstx, int dsty, int width, int hight); int VGLBitmapCopy(VGLBitmap *src, int srcx, int srcy, VGLBitmap *dst, int dstx, int dsty, int width, int hight); +VGLBitmap *VGLBitmapCreate(int type, int xsize, int ysize, byte *bits); +void VGLBitmapDestroy(VGLBitmap *object); +int VGLBitmapAllocateBits(VGLBitmap *object); /* keyboard.c */ int VGLKeyboardInit(int mode); void VGLKeyboardEnd(void); @@ -94,6 +107,9 @@ int VGLKeyboardGetCh(void); void VGLEnd(void); int VGLInit(int mode); void VGLCheckSwitch(void); +int VGLSetVScreenSize(VGLBitmap *object, int VXsize, int VYsize); +int VGLPanScreen(VGLBitmap *object, int x, int y); +int VGLSetSegment(unsigned int offset); /* mouse.c */ void VGLMousePointerShow(void); void VGLMousePointerHide(void); diff --git a/share/examples/libvgl/demo.c b/share/examples/libvgl/demo.c index 3147c47687c7..f2a28d31a2ba 100644 --- a/share/examples/libvgl/demo.c +++ b/share/examples/libvgl/demo.c @@ -36,7 +36,7 @@ int main(int argc, char **argv) { int x, y, xsize, ysize, i,j; - VGLBitmap tmp; + VGLBitmap *tmp; // set graphics mode, here 320x240 256 colors // supported modes are (from ): @@ -53,9 +53,10 @@ main(int argc, char **argv) xsize=VGLDisplay->Xsize; ysize=VGLDisplay->Ysize; - // alloc a new bitmap (there should be a function for this) - tmp.Type = MEMBUF; tmp.Bitmap = (char*)malloc(256*256); - tmp.Xsize = 256; tmp.Ysize = 256; + // alloc a new bitmap + tmp = VGLBitmapCreate(MEMBUF, 256, 256, NULL); + VGLBitmapAllocateBits(tmp); + VGLClear(tmp, 0); // fill the screen with colored lines for (y=0; yBitmap[i+256*j] = i%16; + VGLBitmapCopy(tmp, 0, 0, VGLDisplay, 0, 0, 128, 128); for (i=0; i<256; i++) for (j=0; j<256; j++) - tmp.Bitmap[i+256*j] = j%16; - VGLBitmapCopy(&tmp, 0, 0, VGLDisplay, 3, 128, 128, 128); + tmp->Bitmap[i+256*j] = j%16; + VGLBitmapCopy(tmp, 0, 0, VGLDisplay, 3, 128, 128, 128); sleep(2); - VGLBitmapCopy(VGLDisplay, 237, 311, &tmp, 64, 64, 128, 128); - VGLBitmapCopy(&tmp, 32, 32, VGLDisplay, 400, 128, 128, 128); + VGLBitmapCopy(VGLDisplay, 237, 311, tmp, 64, 64, 128, 128); + VGLBitmapCopy(tmp, 32, 32, VGLDisplay, 400, 128, 128, 128); sleep(2); VGLBitmapCopy(VGLDisplay, 300, 300, VGLDisplay, 500, 128, 128, 128); sleep(5);