/* vi: set sw=4 ts=4: */ /* * CCE - Console Chinese Environment - * Copyright (C) 1998-2003 Rui He (rhe@3eti.com) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include "defs.h" #include "errors.h" #include "vc.h" #include "vga.h" #include "term.h" #include "mouse.h" #if defined(SUPPORT_GGILIB) #include #include #include "cceggi.h" ggi_visual_t ggiVis; static ggi_pixel ggiPix[16]; /* 16 VGA colors converted to pixel format */ static int ggiPixBytes; /* How many bytes per pixel? */ static unsigned char *ggiPixBuf; /* will dynamically allocated */ #ifdef USE_DYNAMIC_GGILIB int (*p_ggiInit)(void); int (*p_ggiExit)(void); ggi_visual_t (*p_ggiOpen)(const char *display,...); int (*p_ggiClose)(ggi_visual_t vis); int (*p_ggiSetMode)(ggi_visual_t visual,ggi_mode *tm); int (*p_ggiCheckGraphMode)(ggi_visual_t visual, int x, int y, int xv, int yv, ggi_graphtype type, ggi_mode *suggested_mode); const ggi_pixelformat *(*p_ggiGetPixelFormat)(ggi_visual_t vis); ggi_pixel (*p_ggiMapColor)(ggi_visual_t vis,ggi_color *col); int (*p_ggiSetGCForeground)(ggi_visual_t vis,ggi_pixel color); int (*p_ggiDrawBox)(ggi_visual_t vis,int x,int y,int w,int h); int (*p_ggiPutBox)(ggi_visual_t vis,int x,int y,int w,int h,void *buf); int (*p_ggiGetBox)(ggi_visual_t vis,int x,int y,int w,int h,void *buf); int (*p_ggiEventSelect)(ggi_visual_t vis, ggi_event_mask *mask, int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); int (*p_ggiEventRead)(ggi_visual_t vis, gii_event *ev, gii_event_mask mask); static void *ggiLibHandle; static char *ggiLibSearchPath[] = { #if defined(__WINDOWS__) "ggi.dll", #else "libggi.so", "libggi.so.2", /* sometimes there is no libSDL.so symbolic link ?*/ "/usr/local/lib/libggi.so", "/usr/local/lib/libggi.so.2", #endif NULL, }; static int LoadDynamicGGILibrary(void) { int i; for(i = 0; ggiLibSearchPath[i]; i++) { ggiLibHandle = dlopen(ggiLibSearchPath[i], RTLD_LAZY); if (ggiLibHandle) break; } if (!ggiLibHandle) { message("Failed to load GGI library %s.\r\n", ggiLibSearchPath[0]); return FAILURE; } p_ggiInit = dlsym(ggiLibHandle, SYMBOL_GGIINIT); p_ggiExit = dlsym(ggiLibHandle, SYMBOL_GGIEXIT); p_ggiOpen = dlsym(ggiLibHandle, SYMBOL_GGIOPEN); p_ggiClose = dlsym(ggiLibHandle, SYMBOL_GGICLOSE); p_ggiEventSelect = dlsym(ggiLibHandle, SYMBOL_GGIEVENTSELECT); p_ggiEventRead = dlsym(ggiLibHandle, SYMBOL_GGIEVENTREAD); p_ggiCheckGraphMode = dlsym(ggiLibHandle, SYMBOL_GGICHECKGRAPHMODE); p_ggiSetMode = dlsym(ggiLibHandle, SYMBOL_GGISETMODE); p_ggiGetBox = dlsym(ggiLibHandle, SYMBOL_GGIGETBOX); p_ggiPutBox = dlsym(ggiLibHandle, SYMBOL_GGIPUTBOX); p_ggiDrawBox = dlsym(ggiLibHandle, SYMBOL_GGIDRAWBOX); p_ggiSetGCForeground = dlsym(ggiLibHandle, SYMBOL_GGISETGCFOREGROUND); p_ggiMapColor = dlsym(ggiLibHandle, SYMBOL_GGIMAPCOLOR); p_ggiGetPixelFormat = dlsym(ggiLibHandle, SYMBOL_GGIGETPIXELFORMAT); if (!p_ggiInit || !p_ggiExit || !p_ggiEventSelect || !p_ggiEventRead || !p_ggiOpen || !p_ggiClose || !p_ggiCheckGraphMode || !p_ggiSetMode || !p_ggiGetBox || !p_ggiPutBox || !p_ggiDrawBox || !p_ggiSetGCForeground || !p_ggiMapColor || !p_ggiGetPixelFormat) { warn("Can't resolve all the required GGI routines.\r\n"); dlclose(ggiLibHandle); ggiLibHandle = NULL; return FAILURE; } return SUCCESS; } static void UnloadDynamicGGILibrary(void) { if (ggiLibHandle) { dlclose(ggiLibHandle); ggiLibHandle = NULL; } } #endif /* USE_DYNAMIC_GGILIB */ int IsGGIAvailable(void) { #ifdef USE_DYNAMIC_GGILIB if (LoadDynamicGGILibrary() != SUCCESS) return 0; #endif if (GGIINIT() != 0) { warn("Failed to initialize GGI library.\n"); goto err; } if ((ggiVis = GGIOPEN(NULL)) == NULL) /* NULL will open the default Visual */ { warn("Failed to open default GGI visual.\n"); GGIEXIT(); goto err; } dispInfo.type = TYPE_GGI; return 1; err: #ifdef USE_DYNAMIC_GGILIB UnloadDynamicGGILibrary(); #endif return 0; } static void GGIMapColors(u_short *red, u_short *green, u_short *blue) { int i; ggi_color color; for(i = 0; i < 16; i++) { color.r = red[i]; color.g = green[i]; color.b = blue[i]; /* r/g/b is 16 bits */ ggiPix[i] = GGIMAPCOLOR(ggiVis, &color); /* convert from ggi_color to ggi_pixel */ } } int GGIInit(void) { int res; const ggi_pixelformat *ggiPixFormat; ggi_mode ggiMode; if (GGIAvail && !ggiVis) /* haven't test it yet, do it now */ GGIAvail = IsGGIAvailable(); if (!GGIAvail) goto err; res = GGICHECKGRAPHMODE(ggiVis, GGI_AUTO, GGI_AUTO, GGI_AUTO, GGI_AUTO, GT_AUTO, &ggiMode); if (res != 0 || GGISETMODE(ggiVis, &ggiMode)) { warn("Failed to set default GGI graphics mode.\n"); goto err; } ggiPixFormat = GGIGETPIXELFORMAT(ggiVis); #ifdef DEBUG fprintf(stderr, "PixelFormat: depth=%d size=%d red_shift=%d green_shift=%d blue_shift=%d\n", ggiPixFormat->depth, ggiPixFormat->size, ggiPixFormat->red_shift, ggiPixFormat->green_shift, ggiPixFormat->blue_shift); #endif ggiPixBytes = (ggiPixFormat->size + 7) >> 3; GGIMapColors(red16, green16, blue16); dispInfo.gxdim = ggiMode.visible.x; dispInfo.gydim = ggiMode.visible.y; dispInfo.bpp = ggiPixFormat->depth; dispInfo.type = TYPE_GGI; dispInfo.glineByte = ggiPixBytes * dispInfo.gxdim; /* glineByte is not used ? */ ggiPixBuf = malloc(ggiPixBytes * (fontwidth*2+2) * (fontheight+2)); if (!ggiPixBuf) goto err; InitDispInfo(); message("Using %dx%d %d-bpp GGI screen, %dx%d terminal.\n", dispInfo.gxdim, dispInfo.gydim, dispInfo.bpp, dispInfo.txmax, dispInfo.tymax); mInfo.has_mouse = TRUE; /* use GGI's mouse support */ return SUCCESS; err: if (ggiVis) { GGICLOSE(ggiVis); /* ggiClose() will restore the old video settings! */ ggiVis = NULL; } GGIEXIT(); #ifdef USE_DYNAMIC_GGILIB UnloadDynamicGGILibrary(); #endif return FAILURE; } void GGIDetach(void) { if (ggiVis) { GGICLOSE(ggiVis); GGIEXIT(); ggiVis = NULL; } #ifdef USE_DYNAMIC_GGILIB UnloadDynamicGGILibrary(); #endif } #ifdef SUPPORT_FREETYPE_FONT #include "ftfont.h" void GGIDrawFreeTypeChar(int xpos, int ypos, FT_GlyphSlot glyph, int fc, int bc, int width, int height) { int i,j,k; u_char bits = 0, *code; uint8 *dest = (uint8 *)ggiPixBuf; ggi_pixel pix = 0; int top, left, row, col, pitch; if (glyph == NULL) { left=top=row=col=pitch=0; code = NULL; } else { left = ftXOrig + glyph->bitmap_left; /* bitmap_left should be >= 0 ? */ top = ftYOrig - glyph->bitmap_top; if (top < 0) top = 0; row = glyph->bitmap.rows; /* rows/width >= 0 */ col = glyph->bitmap.width; code = glyph->bitmap.buffer; pitch = glyph->bitmap.pitch; /* bitmap scan line bytes */ } for(i = 0; i < height; i++) { k = 0; for(j = 0; j < width; j++) { if (i < top || i >= top+row || j < left || j >= left+col) pix = ggiPix[bc]; else /* in freetype font region */ { if (glyph->bitmap.pixel_mode == ft_pixel_mode_mono) /* bit oriented */ { if ((k & 0x7) == 0) bits = code[k/8]; pix = ggiPix[ bits & (0x80 >> (k & 0x7)) ? fc : bc ]; } else /* byte oriented ft_pixel_mode_grays */ { ggi_color color; bits = code[k]; /* 0-255 gray scale */ if (DoAntiAlias && ggiPixBytes > 1) /* TrueColor, do anti-aliasing */ { color.r = red16[bc] + ((red16[fc]-red16[bc]) * bits)/255; color.g = green16[bc] + ((green16[fc]-green16[bc]) * bits)/255; color.b = blue16[bc] + ((blue16[fc]-blue16[bc]) * bits)/255; pix = GGIMAPCOLOR(ggiVis, &color); } else pix = ggiPix[ bits >= 128 ? fc: bc ]; /* do not do anti-alias */ } k++; } /* Fix deprecated cast-as-lvalue, which will cause warnings in GCC >= 3.3.4 */ switch(ggiPixBytes) { case 1: *dest++ = (uint8)(pix); /* palette-based, no anti-alias */ break; case 2: { /* *((uint16 *)dest)++ = (uint16)(pix); */ uint16 *temp = (uint16 *)dest; *temp = (uint16)(pix); dest = (uint8 *)temp; dest = (uint8 *)((uint16 *)dest + 1); break; } case 3: *dest++ = (uint8)(pix); pix >>= 8; *dest++ = (uint8)(pix); pix >>= 8; *dest++ = (uint8)(pix); break; case 4: { /* *((uint32 *)dest)++ = (uint32)(pix); */ uint32 *temp = (uint32 *)dest; *temp = (uint32)(pix); dest = (uint8 *)temp; dest = (uint8 *)((uint32 *)dest + 1); break; } } } /* for j */ if (k > 0) /* k>0 means code is used somehow, code could be NULL */ code += pitch; } GGIPUTBOX(ggiVis, xpos, ypos, width, height, ggiPixBuf); } #endif /* SUPPORT_FREETYPE_FONT */ static inline void GGIGenPixelBuf(u_char *code, int fc, int bc, int width, int height) { int i,j; u_char bits = 0; uint8 *dest = (uint8 *)ggiPixBuf; ggi_pixel pix; for(i = 0; i < height; i++) { for(j = 0; j < width; j++) { if ((j & 0x7) == 0) bits = *code++; /* j % 8 == 0 */ pix = ggiPix[ bits & (0x80 >> (j & 0x7)) ? fc : bc ]; /* Fix deprecated cast-as-lvalue, which will cause warnings in GCC >= 3.3.4 */ switch(ggiPixBytes) { case 1: *dest++ = (uint8)(pix); break; case 2: { /* *((uint16 *)dest)++ = (uint16)(pix); */ uint16 *temp = (uint16 *)dest; *temp = (uint16)(pix); dest = (uint8 *)temp; dest = (uint8 *)((uint16 *)dest + 1); break; } case 3: *dest++ = (uint8)(pix); pix >>= 8; *dest++ = (uint8)(pix); pix >>= 8; *dest++ = (uint8)(pix); break; case 4: { /* *((uint32 *)dest)++ = (uint32)(pix); */ uint32 *temp = (uint32 *)dest; *temp = (uint32)(pix); dest = (uint8 *)temp; dest = (uint8 *)((uint32 *)dest + 1); break; } } } } } void GGIOpDraw(int xpos, int ypos, u_char *code, int fc, int bc, int width, int height) { GGIGenPixelBuf(code, fc, bc, width, height); GGIPUTBOX(ggiVis, xpos, ypos, width, height, ggiPixBuf); } void GGIOpClear(int y, int height, int color) { GGISETGCFOREGROUND(ggiVis, ggiPix[color]); GGIDRAWBOX(ggiVis, 0, y, dispInfo.gxdim, height); } void GGIOpCursor(CursorInfo *ci, int xpos, int ypos) { int width = fontwidth; int height = cursorBtm - cursorTop; int i; if (kanjiCursor && ci->kanji) width *= 2; GGIGETBOX(ggiVis, xpos, ypos, width, height, ggiPixBuf); for(i = 0; i < width * ggiPixBytes * height; i++) { ggiPixBuf[i] ^= 0xFF; } GGIPUTBOX(ggiVis, xpos, ypos, width, height, ggiPixBuf); } void GGIScreenSaver(bool blank) { } void GGITextMode(void) { } void GGIGraphMode(void) { GGIOpClear(0, dispInfo.gydim - dispInfo.input, DEF_BGCOLOR); } void GGIStart(void) { cursorTop = fontheight - 2; cursorBtm = fontheight - 1; } VideoInfo GGIInfo = { GGIInit, GGIStart, GGITextMode, GGIGraphMode, CCEWput, CCEInputWput, CCESput, CCEInputSput, CCEInputDrawIcon, CCECursor, CCEClear, GGIScreenSaver, GGIDetach }; #endif