/* 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_SDLLIB) #include "ccesdl.h" SDL_Surface *sdlScreen; static Uint32 sdlPix[16]; static int sdlPixBytes; /* How many bytes per pixel? */ static int sdlMustLock; /* Do we need to lock the surface? Not necessary for fb and X11 */ #define SDL_TITLE_STR "CCE/SDL" #define SDL_ICON_STR "CCE/SDL" #ifdef USE_DYNAMIC_SDLLIB int (*p_SDL_Init)(Uint32 flags); void (*p_SDL_Quit)(void); char * (*p_SDL_VideoDriverName)(char *namebuf, int maxlen); const SDL_VideoInfo * (*p_SDL_GetVideoInfo)(void); SDL_Rect ** (*p_SDL_ListModes)(SDL_PixelFormat *format, Uint32 flags); SDL_Surface * (*p_SDL_SetVideoMode)(int width, int height, int bpp, Uint32 flags); void (*p_SDL_WM_SetCaption)(const char *title, const char *icon); int (*p_SDL_FillRect)(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color); Uint32 (*p_SDL_MapRGB)(SDL_PixelFormat *fmt, Uint8 r, Uint8 g, Uint8 b); int (*p_SDL_SetColors)(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors); int (*p_SDL_LockSurface)(SDL_Surface *surface); void (*p_SDL_UnlockSurface)(SDL_Surface *surface); void (*p_SDL_UpdateRect)(SDL_Surface *screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h); int (*p_SDL_Flip)(SDL_Surface *screen); void (*p_SDL_WarpMouse)(Uint16 x, Uint16 y); int (*p_SDL_PollEvent)(SDL_Event *event); int (*p_SDL_EnableKeyRepeat)(int delay, int interval); int (*p_SDL_EnableUNICODE)(int enable); static void *sdlLibHandle; static char *sdlLibSearchPath[] = { #if defined(__WINDOWS__) "SDL.dll", #else "libSDL.so", "libSDL-1.2.so.0", /* sometimes there is no libSDL.so symbolic link ?*/ "/usr/local/lib/libSDL.so", "/usr/local/lib/libSDL-1.2.so.0", #endif NULL, }; static int LoadDynamicSDLLibrary(void) { int i; for(i = 0; sdlLibSearchPath[i]; i++) { sdlLibHandle = dlopen(sdlLibSearchPath[i], RTLD_LAZY); if (sdlLibHandle) break; } if (!sdlLibHandle) { message("Failed to load SDL library %s.\r\n", sdlLibSearchPath[0]); return FAILURE; } p_SDL_Init = dlsym(sdlLibHandle, SYMBOL_SDL_INIT); p_SDL_Quit = dlsym(sdlLibHandle, SYMBOL_SDL_QUIT); p_SDL_VideoDriverName = dlsym(sdlLibHandle, SYMBOL_SDL_VIDEODRIVERNAME); p_SDL_GetVideoInfo = dlsym(sdlLibHandle, SYMBOL_SDL_GETVIDEOINFO); p_SDL_ListModes = dlsym(sdlLibHandle, SYMBOL_SDL_LISTMODES); p_SDL_SetVideoMode = dlsym(sdlLibHandle, SYMBOL_SDL_SETVIDEOMODE); p_SDL_WM_SetCaption = dlsym(sdlLibHandle, SYMBOL_SDL_WM_SETCAPTION); p_SDL_FillRect = dlsym(sdlLibHandle, SYMBOL_SDL_FILLRECT); p_SDL_MapRGB = dlsym(sdlLibHandle, SYMBOL_SDL_MAPRGB); p_SDL_SetColors = dlsym(sdlLibHandle, SYMBOL_SDL_SETCOLORS); p_SDL_LockSurface = dlsym(sdlLibHandle, SYMBOL_SDL_LOCKSURFACE); p_SDL_UnlockSurface = dlsym(sdlLibHandle, SYMBOL_SDL_UNLOCKSURFACE); p_SDL_UpdateRect = dlsym(sdlLibHandle, SYMBOL_SDL_UPDATERECT); p_SDL_Flip = dlsym(sdlLibHandle, SYMBOL_SDL_FLIP); p_SDL_WarpMouse = dlsym(sdlLibHandle, SYMBOL_SDL_WARPMOUSE); p_SDL_PollEvent = dlsym(sdlLibHandle, SYMBOL_SDL_POLLEVENT); p_SDL_EnableKeyRepeat = dlsym(sdlLibHandle, SYMBOL_SDL_ENABLEKEYREPEAT); p_SDL_EnableUNICODE = dlsym(sdlLibHandle, SYMBOL_SDL_ENABLEUNICODE); if (!p_SDL_Init || !p_SDL_Quit || !p_SDL_GetVideoInfo || !p_SDL_ListModes || !p_SDL_SetVideoMode || !p_SDL_FillRect || !p_SDL_MapRGB || !p_SDL_Flip || !p_SDL_LockSurface || !p_SDL_UnlockSurface || !p_SDL_UpdateRect || !p_SDL_VideoDriverName || !p_SDL_WarpMouse || !p_SDL_PollEvent || !p_SDL_EnableKeyRepeat || !p_SDL_EnableUNICODE || !p_SDL_SetColors || !p_SDL_WM_SetCaption) { warn("Can't resolve all the required SDL routines.\r\n"); dlclose(sdlLibHandle); sdlLibHandle = NULL; return FAILURE; } return SUCCESS; } static void UnloadDynamicSDLLibrary(void) { if (sdlLibHandle) { dlclose(sdlLibHandle); sdlLibHandle = NULL; } } #endif /* USE_DYNAMIC_SDLLIB */ int IsSDLAvailable(void) { const SDL_VideoInfo *info; SDL_Rect **modes; char driver[64]; int i; #ifdef USE_DYNAMIC_SDLLIB if (LoadDynamicSDLLibrary() != SUCCESS) return 0; #endif if (SDL_INIT(SDL_INIT_VIDEO) != 0) { warn("Failed to initialize SDL library.\r\n"); goto err2; } if (SDL_VIDEODRIVERNAME(driver, sizeof(driver)) ) { message("SDL library using video driver: %s.\r\n", driver); } info = SDL_GETVIDEOINFO(); #ifdef DEBUG fprintf(stderr, "Current display: %d bits-per-pixel\n",info->vfmt->BitsPerPixel); if ( info->vfmt->palette == NULL ) { fprintf(stderr, " Red Mask = 0x%.8x\n", info->vfmt->Rmask); fprintf(stderr, " Green Mask = 0x%.8x\n", info->vfmt->Gmask); fprintf(stderr, " Blue Mask = 0x%.8x\n", info->vfmt->Bmask); } #endif modes = SDL_LISTMODES(NULL, SDL_FULLSCREEN); if ( modes == (SDL_Rect **)0 || modes == (SDL_Rect **)-1) { fprintf(stderr, "No available fullscreen video modes\n"); goto err; } #ifdef DEBUG else { fprintf(stderr, "Fullscreen video modes:\n"); for ( i=0; modes[i]; ++i ) { fprintf(stderr, "\t%dx%dx%d\n", modes[i]->w, modes[i]->h, info->vfmt->BitsPerPixel); } } #endif if (!strcasecmp(driver, "ps2gs") && StartFromConsole) /* PS2 Graphics Synthesizer ?*/ { dispInfo.gxdim = 640; dispInfo.gydim = 480; } else { dispInfo.gxdim = modes[0]->w; dispInfo.gydim = modes[0]->h; if (dispInfo.gxdim > 1280) /* too big? */ { for(i = 0; modes[i]; i++) if (modes[i]->w <= 1280) /* try to get one smaller than 1280x1024? */ { dispInfo.gxdim = modes[i]->w; dispInfo.gydim = modes[i]->h; break; } } } dispInfo.type = TYPE_SDL; return 1; err: SDL_QUIT(); err2: #ifdef USE_DYNAMIC_SDLLIB UnloadDynamicSDLLibrary(); #endif return 0; } static void SDLMapColors(u_char *red, u_char *green, u_char *blue) { int i; for(i = 0; i < 16; i++) { sdlPix[i] = SDL_MAPRGB(sdlScreen->format, red[i], green[i], blue[i]); } } static void SDLSetPels(Uint8 *red, Uint8 *green, Uint8 *blue) { int i; SDL_Color colors[16]; for(i = 0; i < 16; i++) { colors[i].r = red[i]; colors[i].g = green[i]; colors[i].b = blue[i]; } SDL_SETCOLORS(sdlScreen, colors, 0, 16); } int SDLInit(void) { /* int res; */ Uint32 flags = SDL_HWSURFACE | SDL_ANYFORMAT; if (SDLAvail && dispInfo.type != TYPE_SDL) /* haven't test it yet, do it now */ SDLAvail = IsSDLAvailable(); if (!SDLAvail) goto err; #if defined(__Darwin__) if (1) /* MacOSX/SDL will be faster if using full screen mode, otherwise too slow? */ #else if (StartFromConsole) #endif flags |= SDL_FULLSCREEN; else { if (dispInfo.gxdim >= 1024 && fontwidth > 10) /* 12*24 font? */ { dispInfo.gxdim = 1024; dispInfo.gydim = 768; } else if (dispInfo.gxdim >= 1024 || (fontwidth > 10 && dispInfo.gxdim >= 800)) { dispInfo.gxdim = 800; dispInfo.gydim = 600; } else /* otherwise 640x480 */ { dispInfo.gxdim = 640; dispInfo.gydim = 480; } } sdlScreen = SDL_SETVIDEOMODE(dispInfo.gxdim, dispInfo.gydim, 0/* dispInfo.bpp */, flags); if (!sdlScreen) { warn("Failed to set default SDL graphics mode.\n"); goto err; } #ifdef DEBUG fprintf(stderr, "SDL_Surface: flags=0x%x width=%d height=%d pitch=%d bpp=%d BytesPerPixel=%d\n", sdlScreen->flags, sdlScreen->w, sdlScreen->h, sdlScreen->pitch, sdlScreen->format->BitsPerPixel, sdlScreen->format->BytesPerPixel); #endif sdlPixBytes = sdlScreen->format->BytesPerPixel; sdlMustLock = SDL_MUSTLOCK(sdlScreen); dispInfo.gxdim = sdlScreen->w; dispInfo.gydim = sdlScreen->h; dispInfo.bpp = sdlScreen->format->BitsPerPixel; dispInfo.type = TYPE_SDL; dispInfo.glineByte = sdlScreen->pitch; /* not used ? */ if (dispInfo.bpp <= 8) SDLSetPels(red8, green8, blue8); SDLMapColors(red8, green8, blue8); InitDispInfo(); message("Using %dx%d %d-bpp SDL, %dx%d terminal.\n", dispInfo.gxdim, dispInfo.gydim, dispInfo.bpp, dispInfo.txmax, dispInfo.tymax); mInfo.has_mouse = TRUE; /* use SDL's mouse support */ cursorInfo.interval *= 2; /* increase the cursor interval since SDL select() use a shorter time */ SDL_WARPMOUSE(0,0); /* move the cursor to (0,0) */ SDL_ENABLEKEYREPEAT(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); SDL_ENABLEUNICODE(1); /* enable translation of keysym to printable format */ SDL_WM_SETCAPTION(SDL_TITLE_STR, SDL_ICON_STR); return SUCCESS; err: if (sdlScreen) sdlScreen = NULL; SDL_QUIT(); #ifdef USE_DYNAMIC_SDLLIB UnloadDynamicSDLLibrary(); #endif return FAILURE; } void SDLDetach(void) { if (sdlScreen) { SDL_QUIT(); sdlScreen = NULL; } #ifdef USE_DYNAMIC_SDLLIB UnloadDynamicSDLLibrary(); #endif } void SDLOpDraw(int xpos, int ypos, u_char *code, int fc, int bc, int width, int height) { int i,j; u_char bits = 0; Uint8 *dest, *line; Uint32 pix; if (sdlMustLock) SDL_LOCKSURFACE(sdlScreen); /* for direct surface access */ line = ((Uint8 *)sdlScreen->pixels) + ypos * sdlScreen->pitch + sdlPixBytes * xpos; for(i = 0; i < height; i++) { dest = line; for(j = 0; j < width; j++) { if ((j & 0x7) == 0) bits = *code++; /* j % 8 == 0 */ pix = sdlPix[ bits & (0x80 >> (j & 0x7)) ? fc : bc ]; /* Fix deprecated cast-as-lvalue, which will cause warnings in GCC >= 3.3.4 */ switch(sdlPixBytes) { 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; } } } line += sdlScreen->pitch; } if (sdlMustLock) SDL_UNLOCKSURFACE(sdlScreen); SDL_UPDATERECT(sdlScreen, xpos, ypos, width, height); } void SDLOpClear(int y, int height, int color) { SDL_Rect rect; rect.x = 0; rect.y = y; rect.w = dispInfo.gxdim; rect.h = height; SDL_FILLRECT(sdlScreen, &rect, sdlPix[color]); SDL_FLIP(sdlScreen); } void SDLOpCursor(CursorInfo *ci, int xpos, int ypos) { int width = fontwidth; int height = cursorBtm - cursorTop; int i,j; Uint8 *dest; if (kanjiCursor && ci->kanji) width *= 2; if (sdlMustLock) SDL_LOCKSURFACE(sdlScreen); /* for direct surface access */ dest = ((Uint8 *)sdlScreen->pixels) + ypos * sdlScreen->pitch + sdlPixBytes * xpos; for(i = 0; i < height; i++) { for(j = 0; j < width * sdlPixBytes; j++) { dest[j] ^= 0xFF; } dest += sdlScreen->pitch; } if (sdlMustLock) SDL_UNLOCKSURFACE(sdlScreen); SDL_UPDATERECT(sdlScreen, xpos, ypos, width, height); } #ifdef SUPPORT_FREETYPE_FONT #include "ftfont.h" void SDLDrawFreeTypeChar(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, *line; Uint32 pix; 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 */ } if (sdlMustLock) SDL_LOCKSURFACE(sdlScreen); /* for direct surface access */ line = ((Uint8 *)sdlScreen->pixels) + ypos * sdlScreen->pitch + sdlPixBytes * xpos; for(i = 0; i < height; i++) { dest = line; k = 0; for(j = 0; j < width; j++) { if (i < top || i >= top+row || j < left || j >= left+col) pix = sdlPix[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 = sdlPix[ bits & (0x80 >> (k & 0x7)) ? fc : bc ]; } else { bits = code[k]; /* 0-255 gray scale */ if (DoAntiAlias && sdlPixBytes > 1) /* TrueColor, will do anti-alias */ { pix = SDL_MAPRGB(sdlScreen->format, (Uint8)(red8[bc] + ((red8[fc]-red8[bc]) * bits)/255), (Uint8)(green8[bc] + ((green8[fc]-green8[bc]) * bits)/255), (Uint8)(blue8[bc] + ((blue8[fc]-blue8[bc]) * bits)/255)); } else pix = sdlPix[ bits >= 128? fc : bc]; /* won't do anti-alias */ } k++; } /* Fix deprecated cast-as-lvalue, which will cause warnings in GCC >= 3.3.4 */ switch(sdlPixBytes) { 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; } } } line += sdlScreen->pitch; if (k > 0) /* k>0 means code is used somehow, code could be NULL */ code += pitch; } if (sdlMustLock) SDL_UNLOCKSURFACE(sdlScreen); SDL_UPDATERECT(sdlScreen, xpos, ypos, width, height); } #endif /* SUPPORT_FREETYPE_FONT */ void SDLScreenSaver(bool blank) { } void SDLTextMode(void) { } void SDLGraphMode(void) { SDLOpClear(0, dispInfo.gydim - dispInfo.input, DEF_BGCOLOR); } void SDLStart(void) { cursorTop = fontheight - 2; cursorBtm = fontheight - 1; } VideoInfo SDLInfo = { SDLInit, SDLStart, SDLTextMode, SDLGraphMode, CCEWput, CCEInputWput, CCESput, CCEInputSput, CCEInputDrawIcon, CCECursor, CCEClear, SDLScreenSaver, SDLDetach }; #endif