/***********************************************************/ /* */ /* BFONT.c v. 1.1.0 - Billi Font Library by Diego Billi */ /* */ /* mail: dbilli@cs.unibo.it */ /* home: http://www.cs.unibo.it/~dbilli (ITALIAN) */ /* */ /***********************************************************/ #include "stdio.h" #include "string.h" #include "stdlib.h" #include "stdarg.h" #include "SDL_image.h" #include "BFont.h" /* ATTENTION: MS Visual C++ do not declarate vsnprintf in */ #ifdef WIN32 #define vsnprintf _vsnprintf #endif /* The first character in BFont fonts is '!' */ #define BFONT_FIRST_FONT_CHAR 33 /* ASCII value for "space" */ #define SPACE 32 /* BFont_Info structure */ struct _BFont_Info { int h; /* font height */ SDL_Surface *Surface; /* font surface */ SDL_Rect Chars[BFONT_NUM_CHARS]; /* characters width */ }; /* Current font */ static BFont_Info *CurrentFont; /* buffer size for buffered prints*/ #define BFONT_BUFFER_LEN 1024 /* Single global var for buffered prints */ static char bfont_buffer[BFONT_BUFFER_LEN]; /* utility functions */ static Uint32 GetPixel(SDL_Surface *Surface, Sint32 X, Sint32 Y); static void PutPixel(SDL_Surface *surface, Sint32 X, Sint32 Y, Uint32 pixel); /***************************** BFont Functions ********************************/ void InitFont(BFont_Info *Font) { int x = 0, i = 0; Uint32 separator_color; i= BFONT_FIRST_FONT_CHAR; if (SDL_MUSTLOCK(Font->Surface)) SDL_LockSurface(Font->Surface); separator_color = GetPixel(Font->Surface,0,0); x=0; while ( (x < (Font->Surface->w-1)) && (i < BFONT_NUM_CHARS) ) { if(GetPixel(Font->Surface,x,0) != separator_color) { Font->Chars[i].x = x; Font->Chars[i].y = 1; Font->Chars[i].h = Font->Surface->h; for ( ; (GetPixel(Font->Surface, x, 0) != separator_color) && (x < Font->Surface->w); ++x) ; Font->Chars[i].w = (x - Font->Chars[i].x); i++; } else { x++; } } Font->Chars[SPACE].x = 0; Font->Chars[SPACE].y = 0; Font->Chars[SPACE].h = Font->Surface->h; Font->Chars[SPACE].w = Font->Chars[BFONT_FIRST_FONT_CHAR].w; Font->h = Font->Surface->h; SDL_SetColorKey(Font->Surface, SDL_SRCCOLORKEY, GetPixel(Font->Surface, 0, Font->Surface->h-1)); if (SDL_MUSTLOCK(Font->Surface)) SDL_UnlockSurface(Font->Surface); } BFont_Info * BFont_LoadFont (const char *filename) { SDL_Surface *surface = NULL; int x; BFont_Info *Font = NULL; Font = (BFont_Info *) malloc(sizeof(BFont_Info)); if (Font == NULL) return NULL; surface = (SDL_Surface *) IMG_Load(filename); if (surface == NULL) { free(Font); return NULL; } Font->Surface = surface; for (x=0; x < BFONT_NUM_CHARS ; x++) { Font->Chars[x].x = 0; Font->Chars[x].y = 0; Font->Chars[x].h = 0; Font->Chars[x].w = 0; } InitFont(Font); BFont_SetCurrentFont(Font); return Font; } BFont_Info * BFont_LoadFontFromSurface (SDL_Surface *Surface) { int i; BFont_Info *Font=NULL; Font = (BFont_Info *) malloc(sizeof(BFont_Info)); if (Font == NULL) return NULL; Font->Surface = Surface; for (i=0; i < BFONT_NUM_CHARS; i++) { Font->Chars[i].x = 0; Font->Chars[i].y = 0; Font->Chars[i].h = 0; Font->Chars[i].w = 0; } InitFont(Font); BFont_SetCurrentFont(Font); return Font; } void BFont_FreeFont(BFont_Info *Font) { SDL_FreeSurface(Font->Surface); free(Font); Font = NULL; } BFont_Info * BFont_SetFontColor(BFont_Info *Font,Uint8 r, Uint8 g, Uint8 b) { int x,y; BFont_Info *newfont; SDL_Surface *surface = NULL; Uint32 pixel; Uint8 old_r, old_g, old_b, old_a; Uint8 new_r, new_g, new_b, new_a; Uint32 color_key; newfont = (BFont_Info *) malloc(sizeof(BFont_Info)); if (newfont == NULL) return NULL; newfont->h = Font->h; for (x=0; x < BFONT_NUM_CHARS; x++) { newfont->Chars[x].x = Font->Chars[x].x; newfont->Chars[x].y = Font->Chars[x].y; newfont->Chars[x].h = Font->Chars[x].h; newfont->Chars[x].w = Font->Chars[x].w; } surface = SDL_ConvertSurface(Font->Surface, Font->Surface->format, Font->Surface->flags); if (surface == NULL) { free(newfont); return NULL; } if (SDL_MUSTLOCK(surface)) SDL_LockSurface(surface); if (SDL_MUSTLOCK(Font->Surface)) SDL_LockSurface(Font->Surface); color_key = GetPixel(surface, 0, surface->h-1); for( x=0; x < Font->Surface->w; x++) { for( y=0; y < Font->Surface->h; y++) { old_r = old_g = old_b = 0; pixel = GetPixel(Font->Surface,x,y); if (pixel != color_key) { SDL_GetRGBA(pixel, surface->format, &old_r, &old_g, &old_b, &old_a); new_r = (Uint8) ((old_r * r) / 255); new_g = (Uint8) ((old_g * g) / 255); new_b = (Uint8) ((old_b * b) / 255); /* Next line modified by Antti Mannisto */ new_a = old_a; pixel = SDL_MapRGBA(surface->format, new_r, new_g, new_b, new_a); PutPixel(surface,x,y,pixel); } } } if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface); if (SDL_MUSTLOCK(Font->Surface)) SDL_UnlockSurface(Font->Surface); SDL_SetColorKey(surface, SDL_SRCCOLORKEY, color_key); newfont->Surface = surface; return newfont; } void BFont_SetCurrentFont(BFont_Info *Font) { CurrentFont = Font; } BFont_Info * BFont_GetCurrentFont(void) { return CurrentFont; } int BFont_FontHeight (BFont_Info *Font) { return (Font->h); } void BFont_SetFontHeight(BFont_Info *Font, int height) { if (height >= 0) Font->h = height; } int BFont_CharWidth(BFont_Info *Font,int c) { return Font->Chars[c].w; } int BFont_PutChar(SDL_Surface *Surface, int x, int y, int c) { return BFont_PutCharFont(Surface, CurrentFont, x, y, c); } int BFont_PutCharFont(SDL_Surface *Surface, BFont_Info *Font,int x, int y, int c) { SDL_Rect dest; SDL_Rect src; src = Font->Chars[c]; if (src.h > Font->h) src.h = Font->h; dest = src; dest.x = x; dest.y = y; if (c != SPACE) { SDL_BlitSurface( Font->Surface, &src, Surface, &dest); } /* Next line modified by Antti Mannisto */ return (Font->Chars[c].w); } void BFont_PutString(SDL_Surface *Surface, int x, int y, const char *text) { BFont_PutStringFont(Surface, CurrentFont, x, y, text); } void BFont_PutStringFont(SDL_Surface *Surface, BFont_Info *Font, int x, int y, const char *text) { while ( *text ) { x += BFont_PutCharFont(Surface,Font,x,y, *text); text++;; } } int BFont_TextWidth(const char *text) { return BFont_TextWidthFont( CurrentFont, text); } int BFont_TextWidthFont(BFont_Info *Font, const char *text) { int x=0; while (*text) { x += BFont_CharWidth(Font,*text); text++; } return x; } /* counts the spaces of the strings */ static int count (const char *text) { char *p = NULL; int pos = -1; int i = 0; /* Calculate the space occupied by the text without spaces */ while ((p=strchr(&text[pos+1],SPACE)) != NULL) { i++; pos = p - text; } return i; } void BFont_JustifiedPutString(SDL_Surface *Surface, int y, const char *text) { BFont_JustifiedPutStringFont( Surface, CurrentFont, y,text); } void BFont_JustifiedPutStringFont(SDL_Surface *Surface, BFont_Info *Font, int y, const char *text) { int spaces = 0; int gap; int single_gap; int dif; char *strtmp; char *p; int pos = -1; int xpos = 0; if (strchr(text,SPACE) == NULL) { BFont_PutStringFont(Surface, Font, 0, y, text); } else { gap = (Surface->w-1) - BFont_TextWidthFont(Font,text); if (gap <= 0) { BFont_PutStringFont(Surface, Font,0,y,text); } else { spaces = count(text); dif = gap % spaces; single_gap = (gap - dif) / spaces; xpos=0; pos = -1; while ( spaces > 0 ) { p = strstr(&text[pos+1]," "); strtmp = NULL; strtmp = (char *) calloc ((p - &text[pos+1]) + 1,sizeof(char)); if (strtmp != NULL) { strncpy (strtmp, &text[pos+1], (p - &text[pos+1])); BFont_PutStringFont(Surface, Font, xpos, y, strtmp); xpos = xpos + BFont_TextWidthFont(Font, strtmp) + single_gap + BFont_CharWidth(Font,SPACE); if (dif >= 0) { xpos ++; dif--; } pos = p - text; spaces--; free(strtmp); } } strtmp = NULL; strtmp = (char *) calloc (strlen(&text[pos+1]) + 1,sizeof(char)); if (strtmp != NULL) { strncpy (strtmp, &text[pos+1], strlen( &text[pos+1])); BFont_PutStringFont(Surface, Font,xpos, y, strtmp); free(strtmp); } } } } void BFont_CenteredPutString(SDL_Surface *Surface, int y, const char *text) { BFont_CenteredPutStringFont(Surface, CurrentFont, y, text); } void BFont_CenteredPutStringFont(SDL_Surface *Surface, BFont_Info *Font, int y, const char *text) { BFont_PutStringFont(Surface, Font, (Surface->w/2) - (BFont_TextWidthFont(Font,text)/2), y, text); } void BFont_RightPutString(SDL_Surface *Surface, int y, const char *text) { BFont_RightPutStringFont(Surface, CurrentFont, y, text); } void BFont_RightPutStringFont(SDL_Surface *Surface, BFont_Info *Font, int y, const char *text) { BFont_PutStringFont(Surface, Font, Surface->w - BFont_TextWidthFont(Font,text) - 1, y, text); } void BFont_LeftPutString(SDL_Surface *Surface, int y, const char *text) { BFont_LeftPutStringFont(Surface, CurrentFont, y, text); } void BFont_LeftPutStringFont(SDL_Surface *Surface, BFont_Info *Font, int y, const char *text) { BFont_PutStringFont(Surface, Font, 0, y, text); } /******/ void BFont_PrintString (SDL_Surface *Surface, int x, int y, const char *fmt, ...) { va_list args; va_start (args,fmt); vsnprintf(bfont_buffer,BFONT_BUFFER_LEN,fmt,args); va_end(args); bfont_buffer[BFONT_BUFFER_LEN-1] = '\0'; BFont_PutStringFont(Surface, CurrentFont, x, y, bfont_buffer); } void BFont_PrintStringFont(SDL_Surface *Surface, BFont_Info *Font, int x, int y, const char *fmt, ...) { va_list args; va_start (args,fmt); vsnprintf(bfont_buffer,BFONT_BUFFER_LEN,fmt,args); va_end(args); bfont_buffer[BFONT_BUFFER_LEN-1] = '\0'; BFont_PutStringFont(Surface, Font, x, y, bfont_buffer); } void BFont_CenteredPrintString(SDL_Surface *Surface, int y, const char *fmt, ...) { va_list args; va_start (args,fmt); vsnprintf(bfont_buffer,BFONT_BUFFER_LEN,fmt,args); va_end(args); bfont_buffer[BFONT_BUFFER_LEN-1] = '\0'; BFont_CenteredPutString(Surface, y, bfont_buffer); } void BFont_CenteredPrintStringFont(SDL_Surface *Surface, BFont_Info *Font, int y, const char *fmt, ...) { va_list args; va_start (args,fmt); vsnprintf(bfont_buffer,BFONT_BUFFER_LEN,fmt,args); va_end(args); bfont_buffer[BFONT_BUFFER_LEN-1] = '\0'; BFont_CenteredPutStringFont(Surface, Font, y, bfont_buffer); } void BFont_RightPrintString(SDL_Surface *Surface, int y, const char *fmt, ...) { va_list args; va_start (args,fmt); vsnprintf(bfont_buffer,BFONT_BUFFER_LEN,fmt,args); va_end(args); bfont_buffer[BFONT_BUFFER_LEN-1] = '\0'; BFont_RightPutString(Surface, y, bfont_buffer); } void BFont_RightPrintStringFont(SDL_Surface *Surface, BFont_Info *Font, int y, const char *fmt, ...) { va_list args; va_start (args,fmt); vsnprintf(bfont_buffer,BFONT_BUFFER_LEN,fmt,args); va_end(args); bfont_buffer[BFONT_BUFFER_LEN-1] = '\0'; BFont_RightPutStringFont(Surface, Font, y, bfont_buffer); } void BFont_LeftPrintString(SDL_Surface *Surface, int y, const char *fmt, ...) { va_list args; va_start (args,fmt); vsnprintf(bfont_buffer,BFONT_BUFFER_LEN,fmt,args); va_end(args); bfont_buffer[BFONT_BUFFER_LEN-1] = '\0'; BFont_LeftPutString(Surface, y, bfont_buffer); } void BFont_LeftPrintStringFont(SDL_Surface *Surface, BFont_Info *Font, int y, const char *fmt, ...) { va_list args; va_start (args,fmt); vsnprintf(bfont_buffer,BFONT_BUFFER_LEN,fmt,args); va_end(args); bfont_buffer[BFONT_BUFFER_LEN-1] = '\0'; BFont_LeftPutStringFont(Surface, Font, y, bfont_buffer); } void BFont_JustifiedPrintString(SDL_Surface *Surface, int y, const char *fmt, ...) { va_list args; va_start (args,fmt); vsnprintf(bfont_buffer,BFONT_BUFFER_LEN,fmt,args); va_end(args); bfont_buffer[BFONT_BUFFER_LEN-1] = '\0'; BFont_JustifiedPutString( Surface, y,bfont_buffer); } void BFont_JustifiedPrintStringFont(SDL_Surface *Surface, BFont_Info *Font, int y, const char *fmt, ...) { va_list args; va_start (args,fmt); vsnprintf(bfont_buffer,BFONT_BUFFER_LEN,fmt,args); va_end(args); bfont_buffer[BFONT_BUFFER_LEN-1] = '\0'; BFont_JustifiedPutStringFont( Surface, Font, y,bfont_buffer); } SDL_Surface * BFont_CreateSurfaceFont (BFont_Info *Font, const char *text) { SDL_Surface *surface = NULL; Uint32 color_key; surface = SDL_CreateRGBSurface(Font->Surface->flags, BFont_TextWidthFont(Font, text), BFont_FontHeight(Font), Font->Surface->format->BitsPerPixel, Font->Surface->format->Rmask, Font->Surface->format->Gmask, Font->Surface->format->Bmask, 0); if (surface == NULL) return NULL; if (SDL_MUSTLOCK(Font->Surface)) SDL_LockSurface(Font->Surface); color_key = GetPixel(Font->Surface, 0, Font->Surface->h - 1); if (SDL_MUSTLOCK(Font->Surface)) SDL_UnlockSurface(Font->Surface); SDL_FillRect(surface, NULL, color_key); BFont_PutStringFont(surface, Font, 0, 0, text); SDL_SetColorKey(surface, SDL_SRCCOLORKEY, color_key); return surface; } SDL_Surface * BFont_CreateSurface (const char *text) { return BFont_CreateSurfaceFont(CurrentFont, text); } /*********************************************************************************************************/ /*********************************************************************************************************/ /*********************************************************************************************************/ static void PutPixel(SDL_Surface *surface, Sint32 X, Sint32 Y, Uint32 pixel) { int bpp = surface->format->BytesPerPixel; /* Here p is the address to the pixel we want to set */ Uint8 *p = (Uint8 *)surface->pixels + Y * surface->pitch + X * bpp; switch(bpp) { case 1: *p = pixel; break; case 2: *(Uint16 *)p = pixel; break; case 3: if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { p[0] = (pixel >> 16) & 0xff; p[1] = (pixel >> 8) & 0xff; p[2] = pixel & 0xff; } else { p[0] = pixel & 0xff; p[1] = (pixel >> 8) & 0xff; p[2] = (pixel >> 16) & 0xff; } break; case 4: *(Uint32 *)p = pixel; break; } } static Uint32 GetPixel(SDL_Surface *Surface, Sint32 X, Sint32 Y) { Uint8 *bits; Uint32 Bpp; if (X<0) puts("x too small in GetPixel!"); if (X>=Surface->w) puts("x too big in GetPixel!"); Bpp = Surface->format->BytesPerPixel; bits = ((Uint8 *)Surface->pixels)+Y*Surface->pitch+X*Bpp; // Get the pixel switch(Bpp) { case 1: return *((Uint8 *)Surface->pixels + Y * Surface->pitch + X); break; case 2: return *((Uint16 *)Surface->pixels + Y * Surface->pitch/2 + X); break; case 3: { // Format/endian independent Uint8 r, g, b; r = *((bits)+Surface->format->Rshift/8); g = *((bits)+Surface->format->Gshift/8); b = *((bits)+Surface->format->Bshift/8); return SDL_MapRGB(Surface->format, r, g, b); } break; case 4: return *((Uint32 *)Surface->pixels + Y * Surface->pitch/4 + X); break; } return -1; }