大家注意到没有,RA2的中文版本使用的是GBK点阵字库,这样做有一个好处:不管玩家是用的简体还是繁体都能识别显示的文字。
GBK的意思大概是“国家标准汉字扩展字符集”吧,记不清了。但它的确是个好东东,比GB2312、BIG5什么的强多了。因为它包括GB2312、GBK的所有字符而且还补充了很多字,另外,还包括日文、朝鲜文以及大量的符号字符。
我在UCDOS for win版本里面找到了GBK的点阵字库(HZK12.GBK、HZK14.GBK、HZK16.GBK)。分析了一下,知道了结构。这里是我写的一个演示程序,程序编译需要有sdl库。遵循“惯例”,按F4切换全屏/窗口状态,Esc退出。程序把标准输出和标准错误重定向到"stdout.txt"和"stderr.txt"中。
#include <time.h> #include <stdio.h> #include <stdlib.h> #include <windows.h>
#include "sdl.h" #include "SDL_image.h" #include "sfont.h"
//--------------------------------------------------------------------------- #define STDOUT_FILE "stdout.txt" #define STDERR_FILE "stderr.txt"
SDL_Surface *screen; Uint32 fps; Uint32 AppStartTime = 0; Uint32 frame_count = 0; static Uint32 frames;
SDL_Event event; SDL_Surface * SetMode( int Width, int Height, int BPP, int Flags ); SDL_Surface * LoadBMP( char * filename ); void MainLoops( int ( * EventFunc)( ), void ( * DrawFunc )( ), int DelayTime ); void Blt( SDL_Surface * image, int x, int y ); void TileBlt( SDL_Surface * image, int x, int y ); void SetTransparentColor( SDL_Surface * sprite, int R, int G, int B ); void IoRedirect( ); void cleanup_output( ); void initfps();
//--------------------------------------------------------------------------- Uint8 HZK12[574560]; Uint8 HZK14[670320]; Uint8 HZK16[766080]; BOOL HZ_Init(); BOOL HZ_TextOut( SDL_Surface * image, int x, int y, int width, int space, unsigned char * str ); //---------------------------------------------------------------------------
int ProcessEvent( ); void DrawFrame( );
SDL_Surface * bg, * font; int ix, iy, jx, jy; int Width = 640; int Height = 480; int bpp = 16; int ScreenMode = 0;
WINAPI WinMain(HINSTANCE hInstPre, HINSTANCE hInstance, LPSTR cmd, int xxx ) { char TimeString[256]; time_t timer; struct tm *tblock;
HZ_Init(); IoRedirect( ); frames = 0; timer = time(NULL); tblock = localtime(&timer); strftime( TimeString, 256, "Time=%Z: %Y-%m-%d %a %H:%M:%S", tblock ); printf( "%s\n", TimeString );
SetMode( Width, Height, bpp, SDL_SWSURFACE|ScreenMode ); SDL_ShowCursor(0); SDL_WM_SetCaption( "demo", "demo" );
bg = IMG_Load( ".\\2k_bg.gif" ); font = IMG_Load( ".\\small.gif" );
InitFont(font); SDL_SetAlpha( font, SDL_SRCALPHA|SDL_RLEACCEL, 127 );
ix=iy=0; jx=jy= Height>>1; srand( (Uint32)timer );
MainLoops( ProcessEvent, DrawFrame, 0 );
printf( "ScreenMode=%d*%d*%d\nFPS=%u", Width, Height, bpp, fps );
return 0; }
int ProcessEvent( ) { Uint8 *keystate;
keystate = SDL_GetKeyState( NULL ); if ( ( keystate[SDLK_ESCAPE] ) || ( keystate[SDLK_q] ) ) return 0; if ( keystate[SDLK_F4] ) { if ( ScreenMode ) ScreenMode = 0; else ScreenMode = SDL_FULLSCREEN;
SetMode( Width, Height, bpp, SDL_SWSURFACE|ScreenMode ); initfps( ); }
return 1; }
void DrawFrame( ) { char tmp[256]; int step = 4;
// sprintf( tmp, "TotalFrame=%u", frames );
TileBlt( bg, 0, 0 );
SDL_SetAlpha( font, SDL_SRCALPHA|SDL_RLEACCEL, 4 ); PutString( screen, ix % Width - 6, iy % Height - 6, tmp ); SDL_SetAlpha( font, SDL_SRCALPHA|SDL_RLEACCEL, 8 ); PutString( screen, ix % Width - 5, iy % Height - 5, tmp ); SDL_SetAlpha( font, SDL_SRCALPHA|SDL_RLEACCEL, 16 ); PutString( screen, ix % Width - 4, iy % Height - 4, tmp ); SDL_SetAlpha( font, SDL_SRCALPHA|SDL_RLEACCEL, 32 ); PutString( screen, ix % Width - 3, iy % Height - 3, tmp ); SDL_SetAlpha( font, SDL_SRCALPHA|SDL_RLEACCEL, 64 ); PutString( screen, ix % Width - 2, iy % Height - 2, tmp ); SDL_SetAlpha( font, SDL_SRCALPHA|SDL_RLEACCEL, 128 ); PutString( screen, ix % Width - 1, iy % Height - 1, tmp ); SDL_SetAlpha( font, SDL_SRCALPHA|SDL_RLEACCEL, 192 ); PutString( screen, ix % Width, iy % Height, tmp );
PutString( screen, ix % Width, iy % Height + 40, tmp );
if ( rand( ) % 400 < 2 ) { jx = rand( ) % ( Width - 10 ); jy = rand( ) % ( Height - 10 ); }
sprintf( tmp, "FPS=%d", fps ); PutString( screen, 7, 7, tmp ); //聞波,2000 HZ_TextOut( screen, 10, 300, 16, 0, "十步殺一人,千里不留行"); HZ_TextOut( screen, 10, 318, 14, 0, "十步殺一人,千里不留行" ); HZ_TextOut( screen, 10, 334, 12, 0, "十步殺一人,千里不留行" ); ix += step; iy += step; } //---------------------------------------------------------------------------
//--------------------------------------------------------------------------- SDL_Surface * SetMode( int Width, int Height, int BPP, int Flags ) { /* Initialize the SDL library */ if ( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError( ) ); return NULL; }
/* Clean up on exit */ atexit(SDL_Quit);
/* Initialize the display in a 640x480 8-bit palettized mode */ screen = SDL_SetVideoMode( Width, Height, BPP, Flags ); if ( screen == NULL ) { fprintf( stderr, "Couldn't set %dx%dx%d video mode: %s\n", Width, Height, BPP, SDL_GetError( ) ); }
return screen; } //---------------------------------------------------------------------------
void initfps( ) { AppStartTime = SDL_GetTicks(); frame_count = 0; } //---------------------------------------------------------------------------
void MainLoops( int ( * EventFunc)( ), void ( * DrawFunc)( ), int DelayTime ) { if ( EventFunc&&DrawFunc ) { memset( &event, 0, sizeof( SDL_Event ) ); initfps( );
while( EventFunc( ) ) { SDL_PollEvent(&event); if ( event.type == SDL_ACTIVEEVENT ) { if ( ( ( event.active.state & SDL_APPACTIVE ) == FALSE ) || ( event.active.gain == FALSE ) ) initfps( ); } SDL_PumpEvents(); DrawFunc( ); SDL_UpdateRect(screen,0, 0, 0, 0); frame_count ++; frames ++; fps = frame_count * 1000 / ( SDL_GetTicks( ) - AppStartTime ); if ( DelayTime ) SDL_Delay( DelayTime ); } } } //---------------------------------------------------------------------------
SDL_Surface * LoadBMP( char * filename ) { SDL_Surface * imagebmp, * image;
imagebmp = SDL_LoadBMP( filename ); if ( imagebmp == NULL ) return NULL;
if ( imagebmp->format->palette != NULL ) { SDL_SetColors( screen, imagebmp->format->palette->colors, 0, imagebmp->format->palette->ncolors ); }
/* Convert the image to the video format (maps colors) */ image = SDL_DisplayFormat( imagebmp ); SDL_FreeSurface( imagebmp );
return image; } //---------------------------------------------------------------------------
void Blt( SDL_Surface * image, int x, int y ) { int Row, Col, r, c, shiftx, shifty; SDL_Rect dest, src;
/* out of screen */ if ( ( x > screen->w ) || ( y > screen->h ) || ( x + image->w < 1 ) || ( y + image->h < 1 ) ) return;
src.x = 0; src.y = 0; src.w = image->w; src.h = image->h; dest.x = x; dest.y = y; dest.w = src.w; if ( y < 0 ) { src.y = 0 - y; src.h = image->h + src.y; dest.y = 0; } dest.h = src.h;
SDL_BlitSurface( image, &src, screen, &dest ); } //---------------------------------------------------------------------------
void TileBlt( SDL_Surface * image, int x, int y ) { int Row, Col, r, c, shiftx, shifty; SDL_Rect dest, src;
shiftx = x % image->w; shifty = y % image->h;
if ( shiftx >0 ) shiftx -= image->w; if ( shifty >0 ) shifty -= image->h;
Row = screen->h / image->h + 2; Col = screen->w / image->w + 2;
dest.x = 0; dest.y = 0; dest.w = image->w; dest.h = image->h; src.x = 0; src.y = 0; src.w = image->w; src.h = image->h;
for ( r = 0; r < Row; r ++ ) { if ( r ) { src.y = 0; src.h = image->h; dest.h = image->h; dest.y = image->h * r + shifty; } else { /* first line ? */ src.y = 0 - shifty; src.h = image->h; dest.h = image->h + shifty; dest.y = 0; }
for ( c = 0; c < Col; c ++ ) { dest.x = image->w * c + shiftx; SDL_BlitSurface( image, &src, screen, &dest ); } } } //---------------------------------------------------------------------------
void SetTransparentColor( SDL_Surface * sprite, int R, int G, int B ) { SDL_SetColorKey( sprite, SDL_SRCCOLORKEY|SDL_RLEACCEL, SDL_MapRGB( sprite->format, R, G, B ) ); } //---------------------------------------------------------------------------
/* Remove the output files if there was no output written */ static void cleanup_output( ) { FILE *file; int empty;
/* Flush the output in case anything is queued */ fclose(stdout); fclose(stderr);
/* See if the files have any output in them */ file = fopen(STDOUT_FILE, "rb"); if ( file ) { empty = (fgetc(file) == EOF) ? 1 : 0; fclose(file); if ( empty ) remove(STDOUT_FILE); } file = fopen(STDERR_FILE, "rb"); if ( file ) { empty = (fgetc(file) == EOF) ? 1 : 0; fclose(file); if ( empty ) remove(STDERR_FILE); } } //---------------------------------------------------------------------------
void IoRedirect( ) { FILE *newfp;
/* Redirect standard standard output */ newfp = freopen(STDOUT_FILE, "w", stdout); if ( newfp == NULL ) { /* This happens on NT */ #if !defined(stdout) stdout = fopen(STDOUT_FILE, "w"); #else newfp = fopen(STDOUT_FILE, "w"); if ( newfp ) *stdout = *newfp; #endif }
/* Redirect standard standard error */ newfp = freopen(STDERR_FILE, "w", stderr); if ( newfp == NULL ) { /* This happens on NT */ #if !defined(stderr) stderr = fopen(STDERR_FILE, "w"); #else newfp = fopen(STDERR_FILE, "w"); if ( newfp ) *stderr = *newfp; #endif }
setvbuf(stdout, NULL, _IOLBF, BUFSIZ); /* Line buffered */ setbuf(stderr, NULL); /* No buffering */ atexit(cleanup_output); } //---------------------------------------------------------------------------
BOOL HZ_Init() { FILE * file;
file = fopen( ".\\HZK16.GBK", "rb" ); fread( HZK16, 32, 0x5d84, file ); fclose( file ); file = fopen( ".\\HZK14.GBK", "rb" ); fread( HZK14, 28, 0x5d84, file ); fclose( file ); file = fopen( ".\\HZK12.GBK", "rb" ); fread( HZK12, 24, 0x5d84, file ); fclose( file );
return TRUE; } //---------------------------------------------------------------------------
BOOL HZ_TextOut( SDL_Surface * image, int x, int y, int width, int space, unsigned char * str ) { Uint8 * bufptr; Uint8 * HZK; Uint16 Bits[16]; int i,j,k, m, offset = 0; unsigned char q; unsigned char w;
switch ( width ) { case 12: HZK = HZK12; break; case 14: HZK = HZK14; break; case 16: HZK = HZK16; break; default: return FALSE; } bufptr = (unsigned char*)image->pixels;
m = strlen( str ); for ( k = 0; k < m; k +=2 ) { Uint32 X, Y, Z, M; q = str[k]; w = str[k+1];
if ( w > 0xa0 ) { M = 0x5e; Y = w - 0xa1; if ( q > 0xa0 ) { X = q - 0xa1; Z = 0; } else { X = q - 0x81; Z = 0x2284; } } else { M = 0x60; if ( w > 0x7f ) Y = w - 0x41; else Y = w - 0x40;
if ( q > 0xa0 ) { X = q - 0xa1; Z = 0x3a44; } else { X = q - 0x81; Z = 0x2e44; } } memcpy( Bits, HZK + ( X * M + Y + Z ) * width * 2, width * 2 );
for ( i = 0; i < width; i ++ ) // row { Uint16 line;
line = Bits[ i ]; line = ( line >> 8 ) + ( line << 8 );
for ( j = 0; j < 16 ; j ++ ) //col { int index; int mask = 1;
index = offset + x + 16 - j - 1 + ( y + i ) * image->pitch / image->format->BytesPerPixel; mask <<= j; if ( mask & line ) { bufptr[ index * 2 ] = 0xff; bufptr[ index * 2 + 1 ] = 0xff; } } } offset += width + space; } return TRUE; } //---------------------------------------------------------------------------
| |