# HG changeset patch # User Matti Hamalainen # Date 1349182364 -10800 # Node ID b10884934aca85053bbdf324dac6eed678ad6cc7 # Parent aa9fbdbcea70e152abde6af0249f3b717a60091c Various improvements in bitmapped font support, and addition of legacy TSFONT loading support (untested as of now). diff -r aa9fbdbcea70 -r b10884934aca dmtext.h --- a/dmtext.h Tue Oct 02 14:25:47 2012 +0300 +++ b/dmtext.h Tue Oct 02 15:52:44 2012 +0300 @@ -22,19 +22,30 @@ */ #ifdef DM_GFX_BM_TEXT -#define DMFONT_MAGIC "DMFONT" -#define DMFONT_VERSION 0x0100 +// DMFONT format constants +#define DMFONT_MAGIC "DMFONT" +#define DMFONT_VERSION 0x0100 + +#define DMFONT_MIN_WIDTH 3 +#define DMFONT_MIN_HEIGHT 3 +#define DMFONT_MAX_WIDTH 128 +#define DMFONT_MAX_HEIGHT 128 +#define DMFONT_MAX_GLYPHS 1024 + +// Legacy TSFONT loading support +#define TSFONT_MAGIC "TSFONT" +#define TSFONT_VERSION 0x0205 + typedef struct { - int width, height; - - int nglyphs; - SDL_Surface **glyphs; + int width, height; // Dimensions + int nglyphs; // Size of glyphs array + SDL_Surface **glyphs; // NOTE! Not all glyphs may be allocated } DMBitmapFont; -DMBitmapFont *dmNewBitmapFont(int nglyphs); +DMBitmapFont *dmNewBitmapFont(int nglyphs, int width, int height); int dmFreeBitmapFont(DMBitmapFont *font); int dmLoadBitmapFont(DMResource *res, DMBitmapFont **pfont); int dmSaveBitmapFont(DMResource *res, DMBitmapFont *font); diff -r aa9fbdbcea70 -r b10884934aca dmtext_bm.c --- a/dmtext_bm.c Tue Oct 02 14:25:47 2012 +0300 +++ b/dmtext_bm.c Tue Oct 02 15:52:44 2012 +0300 @@ -69,15 +69,22 @@ } -DMBitmapFont *dmNewBitmapFont(int nglyphs) +DMBitmapFont *dmNewBitmapFont(int nglyphs, int width, int height) { DMBitmapFont *font = dmMalloc0(sizeof(DMBitmapFont)); if (font == NULL) return NULL; + font->width = width; + font->height = height; font->nglyphs = nglyphs; font->glyphs = dmCalloc(nglyphs, sizeof(SDL_Surface *)); - + if (font->glyphs == NULL) + { + dmFree(font); + return NULL; + } + return font; } @@ -114,12 +121,9 @@ xglyphs = image->w / width; yglyphs = image->h / height; - if ((font = dmNewBitmapFont(xglyphs * yglyphs)) == NULL) + if ((font = dmNewBitmapFont(xglyphs * yglyphs, width, height)) == NULL) return DMERR_MALLOC; - font->width = width; - font->height = height; - /* fprintf(stderr, "%d x %d split as %d x %d blocks => %d x %d = %d glyphs\n", image->w, image->h, @@ -164,56 +168,114 @@ { DMBitmapFont *font; char magic[8]; - Uint16 version; - Uint32 width, height, nglyphs; + Uint16 version, nglyphs, maxglyph; + int width, height; + BOOL tsfont = FALSE; // Check magic and version dmf_read_str(res, (Uint8 *) &magic, 6); dmf_read_le16(res, &version); - if (memcmp(magic, DMFONT_MAGIC, 6) != 0) - return DMERR_INVALID; + // Check if it is a legacy TSFONT file + if (memcmp(magic, TSFONT_MAGIC, 6) == 0) + { + // Yep, we handle these a bit differently + int encoding = dmfgetc(res); + tsfont = TRUE; - if (version != DMFONT_VERSION) - return DMERR_VERSION; + if (version > TSFONT_VERSION) + return DMERR_VERSION; + + // There were only two encodings, 0 = none and 1 = RLE + // of which RLE was never actually used ... derp. + if (encoding != 0) + return DMERR_NOT_SUPPORTED; + } + else + { + if (memcmp(magic, DMFONT_MAGIC, 6) != 0) + return DMERR_INVALID; + + if (version > DMFONT_VERSION) + return DMERR_VERSION; + } // Check other data - dmf_read_le32(res, &width); - dmf_read_le32(res, &height); - dmf_read_le32(res, &nglyphs); + if (tsfont) + { + nglyphs = dmfgetc(res); + maxglyph = 256; + } + else + { + dmf_read_le16(res, &nglyphs); + dmf_read_le16(res, &maxglyph); + } + + width = dmfgetc(res); + height = dmfgetc(res); - if (width > 128 || height > 128 || nglyphs > 1024) + if (tsfont) + { + // TSFONT color assigns (boolean) .. we discard this. + dmfgetc(res); + } + + if (width < DMFONT_MIN_WIDTH || + height < DMFONT_MIN_HEIGHT || + width > DMFONT_MAX_WIDTH || + height > DMFONT_MAX_HEIGHT || + nglyphs > DMFONT_MAX_GLYPHS || + maxglyph > DMFONT_MAX_GLYPHS || + maxglyph < 1) return DMERR_INVALID_DATA; // Allocate font - if ((*pfont = font = dmNewBitmapFont(nglyphs)) == NULL) + if ((*pfont = font = dmNewBitmapFont(maxglyph, width, height)) == NULL) return DMERR_MALLOC; - font->width = width; - font->height = height; - font->nglyphs = nglyphs; - // Read glyph data, if any if (nglyphs > 0) { - Uint32 i, BitsPerPixel, Rmask, Gmask, Bmask, Amask, pitch; + Uint32 i, BitsPerPixel, Rmask, Gmask, Bmask, Amask; - BitsPerPixel = dmfgetc(res); - dmf_read_le32(res, &Rmask); - dmf_read_le32(res, &Gmask); - dmf_read_le32(res, &Bmask); - dmf_read_le32(res, &Amask); + if (tsfont) + { + BitsPerPixel = 8; + Rmask = Gmask = Bmask = Amask = 0; + } + else + { + BitsPerPixel = dmfgetc(res); + dmf_read_le32(res, &Rmask); + dmf_read_le32(res, &Gmask); + dmf_read_le32(res, &Bmask); + dmf_read_le32(res, &Amask); + } for (i = 0; i < nglyphs; i++) { int y; + Uint16 index; Uint8 *pixels; SDL_Surface *glyph; - dmf_read_le32(res, &width); - dmf_read_le32(res, &height); - dmf_read_le32(res, &pitch); + + if (tsfont) + index = dmfgetc(res); + else + dmf_read_le16(res, &index); + + width = dmfgetc(res); + height = dmfgetc(res); - font->glyphs[i] = glyph = SDL_CreateRGBSurface( + if (width < DMFONT_MIN_WIDTH || + height < DMFONT_MIN_HEIGHT || + width > DMFONT_MAX_WIDTH || + height > DMFONT_MAX_HEIGHT || + index > DMFONT_MAX_GLYPHS) + return DMERR_INVALID_DATA; + + font->glyphs[index] = glyph = SDL_CreateRGBSurface( SDL_SWSURFACE, width, height, BitsPerPixel, Rmask, Gmask, Bmask, @@ -225,7 +287,7 @@ pixels = glyph->pixels; for (y = 0; y < glyph->h; y++) { - if (dmfread(pixels, glyph->format->BytesPerPixel, glyph->w, res) != glyph->w) + if (dmfread(pixels, glyph->format->BytesPerPixel, glyph->w, res) != (size_t) glyph->w) return DMERR_FREAD; pixels += glyph->pitch; } @@ -238,22 +300,37 @@ int dmSaveBitmapFont(DMResource *res, DMBitmapFont *font) { + int count, n; if (font == NULL) return DMERR_NULLPTR; + + if (font->nglyphs > DMFONT_MAX_GLYPHS || + font->width > DMFONT_MAX_WIDTH || + font->height > DMFONT_MAX_HEIGHT || + font->width < DMFONT_MIN_WIDTH || + font->height < DMFONT_MIN_HEIGHT) + return DMERR_INVALID_DATA; + + // Count number of actually existing glyphs + for (count = n = 0; n < font->nglyphs; n++) + if (font->glyphs[n] != NULL) count++; + // Write the DMFONT header if (!dmf_write_str(res, (Uint8 *) DMFONT_MAGIC, 6)) return DMERR_FWRITE; - + dmf_write_le16(res, DMFONT_VERSION); - dmf_write_le32(res, font->width); - dmf_write_le32(res, font->height); - dmf_write_le32(res, font->nglyphs); + dmf_write_le16(res, count); // # of glyphs actually + dmf_write_le16(res, font->nglyphs); // Max glyph # + dmfputc(font->width, res); + dmfputc(font->height, res); if (font->nglyphs > 0) { int i; SDL_Surface *glyph = font->glyphs[0]; + // If there are actual glyphs stored, save thi dmfputc(glyph->format->BitsPerPixel, res); dmf_write_le32(res, glyph->format->Rmask); dmf_write_le32(res, glyph->format->Gmask); @@ -262,18 +339,30 @@ for (i = 0; i < font->nglyphs; i++) { - int y; glyph = font->glyphs[i]; - Uint8 *pixels = glyph->pixels; + if (glyph != NULL) + { + int y; + Uint8 *pixels = glyph->pixels; + + if (glyph->w < DMFONT_MIN_WIDTH || + glyph->h < DMFONT_MIN_HEIGHT || + glyph->w > DMFONT_MAX_WIDTH || + glyph->h > DMFONT_MAX_HEIGHT) + return DMERR_INVALID_DATA; - dmf_write_le32(res, glyph->w); - dmf_write_le32(res, glyph->h); + // Each glyph has its table index and w/h stored + dmf_write_le16(res, i); + dmf_write_le16(res, glyph->w); + dmf_write_le16(res, glyph->h); - for (y = 0; y < glyph->h; y++) - { - if (dmfwrite(pixels, glyph->format->BytesPerPixel, glyph->w, res) != glyph->w) - return DMERR_FWRITE; - pixels += glyph->pitch; + // Write the pixel data + for (y = 0; y < glyph->h; y++) + { + if (dmfwrite(pixels, glyph->format->BytesPerPixel, glyph->w, res) != (size_t) glyph->w) + return DMERR_FWRITE; + pixels += glyph->pitch; + } } } }