Mercurial > hg > dmlib
diff src/dmtext_bm.c @ 1957:ef08af6887b7
Revamp the bitmap font system to use single SDL_Surface for the font
graphics instead of N surfaces for each separate glyph.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 30 Jun 2018 05:24:12 +0300 |
parents | ebcb7713bb6a |
children | 934cc71c97eb |
line wrap: on
line diff
--- a/src/dmtext_bm.c Sat Jun 30 05:22:15 2018 +0300 +++ b/src/dmtext_bm.c Sat Jun 30 05:24:12 2018 +0300 @@ -7,26 +7,33 @@ #include "dmtext.h" -void dmDrawBMTextConst(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt) +void dmDrawBMTextConst(SDL_Surface *screen, const DMBitmapFont *font, + const BOOL condensed, const int mode, int xc, int yc, const char *fmt) { const char *ptr = fmt; - DMUnscaledBlitFunc blit = NULL; + DMUnscaledBlitFunc blit = dmGetUnscaledBlitFunc(font->glyphs->format, screen->format, mode); + SDL_Surface surf; + Uint8 *orig = font->glyphs->pixels; + + memcpy(&surf, font->glyphs, sizeof(SDL_Surface)); while (*ptr) { - int ch = *ptr++; - SDL_Surface *glyph; - - if (ch >= 0 && ch < font->nglyphs && (glyph = font->glyphs[ch]) != NULL) + unsigned char ch = *ptr++; + if (ch < font->maxglyph) { - if (blit == NULL) - blit = dmGetUnscaledBlitFunc(glyph->format, screen->format, mode); + DMBitmapGlyph *glyph = &font->glyphMap[ch]; + if (glyph->index >= 0) + { + surf.pixels = orig + glyph->index * font->gsize; + surf.w = glyph->width; + surf.h = glyph->height; - if (blit != NULL) - { - blit(glyph, xc, yc, screen); - xc += condensed ? glyph->w : font->width; + blit(&surf, xc, yc, screen); + xc += condensed ? glyph->width : font->width; } + else + xc += font->width; } else xc += font->width; @@ -34,7 +41,9 @@ } -void dmDrawBMTextVA(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt, va_list ap) +void dmDrawBMTextVA(SDL_Surface *screen, const DMBitmapFont *font, + const BOOL condensed, const int mode, const int xc, const int yc, + const char *fmt, va_list ap) { char tmp[512]; vsnprintf(tmp, sizeof(tmp), fmt, ap); @@ -43,7 +52,9 @@ } -void dmDrawBMText(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt, ...) +void dmDrawBMText(SDL_Surface *screen, const DMBitmapFont *font, + const BOOL condensed, const int mode, const int xc, const int yc, + const char *fmt, ...) { va_list ap; @@ -53,42 +64,53 @@ } -DMBitmapFont *dmNewBitmapFont(const int nglyphs, const int width, const int height) +DMBitmapFont *dmNewBitmapFont(const int nglyphs, const int maxglyph, + const int width, const int height, const int bpp) { DMBitmapFont *font = dmMalloc0(sizeof(DMBitmapFont)); - if (font == NULL) + if (font == NULL || (bpp != 8 && bpp != 32)) return NULL; font->width = width; font->height = height; font->nglyphs = nglyphs; - font->glyphs = dmCalloc(nglyphs, sizeof(SDL_Surface *)); - if (font->glyphs == NULL) + font->maxglyph = maxglyph; + + if ((font->glyphMap = dmCalloc(font->maxglyph, sizeof(DMBitmapGlyph))) == NULL) + goto error; + + if ((font->glyphs = SDL_CreateRGBSurfaceWithFormat( + 0, width, height * (nglyphs + 1), bpp, + bpp == 8 ? SDL_PIXELFORMAT_INDEX8 : SDL_PIXELFORMAT_RGBA32)) == NULL) + goto error; + + font->gsize = font->height * font->glyphs->pitch; + + for (int i = 0; i < font->maxglyph; i++) { - dmFree(font); - return NULL; + DMBitmapGlyph *glyph = &font->glyphMap[i]; + glyph->width = width; + glyph->height = height; + glyph->index = -1; // means that this index is empty/unused } return font; + +error: + dmFreeBitmapFont(font); + return NULL; } int dmFreeBitmapFont(DMBitmapFont *font) { - int i; - if (font == NULL) return DMERR_NULLPTR; - for (i = 0; i < font->nglyphs; i++) - { - if (font->glyphs[i] != NULL) - { - SDL_FreeSurface(font->glyphs[i]); - font->glyphs[i] = NULL; - } - } + if (font->glyphs != NULL) + SDL_FreeSurface(font->glyphs); + dmFree(font->glyphMap); dmFree(font); return DMERR_OK; } @@ -100,22 +122,13 @@ */ int dmSetBitmapFontPalette(DMBitmapFont *font, const SDL_Color *pal, const int start, const int size) { - int i; - if (font == NULL) return DMERR_NULLPTR; if (start < 0 || size < 1) return DMERR_INVALID_ARGS; - for (i = 0; i < font->nglyphs; i++) - { - SDL_Surface *glyph = font->glyphs[i]; - if (glyph != NULL) - { - SDL_SetPaletteColors(glyph->format->palette, pal, start, size); - } - } + SDL_SetPaletteColors(font->glyphs->format->palette, pal, start, size); return DMERR_OK; } @@ -123,32 +136,34 @@ //#define FN_DEBUG -int dmLoadBitmapFont(DMResource *res, DMBitmapFont **pfont) + +int dmLoadBitmapFont(DMResource *fp, DMBitmapFont **pfont) { DMBitmapFont *font; char magic[8]; Uint16 version, nglyphs, maxglyph; - int width, height; + Uint8 width, height, bpp; BOOL tsfont = FALSE; // Check magic and version - if (!dmf_read_str(res, (Uint8 *) &magic, 6) || - !dmf_read_le16(res, &version)) + if (!dmf_read_str(fp, (Uint8 *) &magic, 6) || + !dmf_read_le16(fp, &version)) return DMERR_FREAD; // 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); + int encoding = dmfgetc(fp); tsfont = TRUE; - if (version > TSFONT_VERSION) - return DMERR_VERSION; +#ifdef FN_DEBUG + fprintf(stderr, "TSFONT v%d.%d (0x%04x), encoding=%d\n", + version >> 8, version & 0xff, version, encoding); +#endif -#ifdef FN_DEBUG - fprintf(stderr, "TSFONT v%d.%d (0x%04x), encoding=%d\n", version >> 8, version & 0xff, version, encoding); -#endif + if (version > TSFONT_VERSION || version < 0x0200) + return DMERR_VERSION; // There were only two encodings, 0 = none and 1 = RLE // of which RLE was never actually used ... derp. @@ -156,140 +171,138 @@ return DMERR_NOT_SUPPORTED; } else + if (memcmp(magic, DMFONT_MAGIC, 6) == 0) { - if (memcmp(magic, DMFONT_MAGIC, 6) != 0) - return DMERR_INVALID; +#ifdef FN_DEBUG + fprintf(stderr, "DMFONT v%d.%d (0x%04x)\n", + version >> 8, version & 0xff, version); +#endif if (version > DMFONT_VERSION) return DMERR_VERSION; } + else + return DMERR_INVALID; // Read other header data if (tsfont) { - // TSFONT only has number of glyphs stored in the file - nglyphs = dmfgetc(res); - - // Maximum glyph number - maxglyph = 256; - } - else - { - dmf_read_le16(res, &nglyphs); - dmf_read_le16(res, &maxglyph); - } + // TSFONT has number of glyphs and dimensions + Uint8 tmp, unused; + if (!dmf_read_byte(fp, &tmp) || + !dmf_read_byte(fp, &width) || + !dmf_read_byte(fp, &height) || + !dmf_read_byte(fp, &unused)) + return DMERR_FREAD; - width = dmfgetc(res); - height = dmfgetc(res); - -#ifdef FN_DEBUG - fprintf(stderr, "nglyphs=%d (0x%02x), maxglyph=%d (0x%02x) width=%d, height=%d\n", - nglyphs, nglyphs, maxglyph, maxglyph, width, height); -#endif - - if (tsfont) - { - // TSFONT color assignments (boolean) .. we discard this. - dmfgetc(res); + nglyphs = tmp; + maxglyph = 256; + bpp = 8; // Very old TSFONTs have some extra data that is not used // .. can't actually even remember what it was for. if (version == 0x0200) { - int i; - for (i = 0; i < 32; i++) - dmfgetc(res); + for (int i = 0; i < 32; i++) + { + if (!dmf_read_byte(fp, &unused)) + return DMERR_FREAD; + } } } + else + { + // DMFONT has Uint16 values for nglyphs and maxglyph, plus BPP + if (!dmf_read_le16(fp, &nglyphs) || + !dmf_read_le16(fp, &maxglyph) || + !dmf_read_byte(fp, &width) || + !dmf_read_byte(fp, &height) || + !dmf_read_byte(fp, &bpp)) + return DMERR_FREAD; + } + +#ifdef FN_DEBUG + fprintf(stderr, "nglyphs=%d, maxglyph=%d, width=%d, height=%d, bpp=%d\n", + nglyphs, maxglyph, width, height, bpp); +#endif if (width < DMFONT_MIN_WIDTH || height < DMFONT_MIN_HEIGHT || width > DMFONT_MAX_WIDTH || height > DMFONT_MAX_HEIGHT || nglyphs > DMFONT_MAX_GLYPHS || + nglyphs > maxglyph || maxglyph > DMFONT_MAX_GLYPHS || maxglyph < 1) return DMERR_INVALID_DATA; + if (bpp != 8 && bpp != 32) + return DMERR_NOT_SUPPORTED; + // Allocate font - if ((*pfont = font = dmNewBitmapFont(maxglyph, width, height)) == NULL) + if ((*pfont = font = dmNewBitmapFont(nglyphs, maxglyph, width, height, bpp)) == NULL) return DMERR_MALLOC; - // Read glyph data, if any - if (nglyphs > 0) + // Setup palette for 8bpp fonts + if (bpp == 8) { - int n, i; - Uint32 BitsPerPixel, Rmask, Gmask, Bmask, Amask; SDL_Color pal[DMFONT_NPALETTE]; - - // Setup palette for 8bpp fonts - for (n = 0; n < DMFONT_NPALETTE; n++) + for (int n = 0; n < DMFONT_NPALETTE; n++) { - pal[n].r = pal[n].g = pal[n].b = 0; + pal[n].r = pal[n].g = pal[n].b = n > 0 ? 255 : 0; pal[n].a = n > 0 ? 255 : 0; } + SDL_SetPaletteColors(font->glyphs->format->palette, pal, 0, DMFONT_NPALETTE); + } - 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); - } + // Read glyph data, if any + for (int i = 0; i < nglyphs; i++) + { + DMBitmapGlyph *glyph; + Uint8 gwidth, gheight; + Uint16 gindex; + Uint8 *pixels; - for (i = 0; i < nglyphs; i++) - { - int y; - Uint16 index; - Uint8 *pixels; - SDL_Surface *glyph; + // TSFONT format has only byte sized index + if (tsfont) + gindex = dmfgetc(fp); + else + dmf_read_le16(fp, &gindex); - // TSFONT format has only byte sized index - if (tsfont) - index = dmfgetc(res); - else - dmf_read_le16(res, &index); - - // Read dimensions - width = dmfgetc(res); - height = dmfgetc(res); + // Read dimensions + if (!dmf_read_byte(fp, &gwidth) || + !dmf_read_byte(fp, &gheight)) + return DMERR_FREAD; #ifdef FN_DEBUG - fprintf(stderr, "#%d @ %d - w=%d, h=%d\n", i, index, width, height); + fprintf(stderr, "#%d @ %d - %d x %d\n", i, gindex, gwidth, gheight); #endif - if (width < DMFONT_MIN_WIDTH || - height < DMFONT_MIN_HEIGHT || - width > DMFONT_MAX_WIDTH || - height > DMFONT_MAX_HEIGHT || - index >= maxglyph) - return DMERR_INVALID_DATA; - - // Allocate bitmap - font->glyphs[index] = glyph = SDL_CreateRGBSurface( - SDL_SWSURFACE, width, height, - BitsPerPixel, Rmask, Gmask, Bmask, Amask); + // Check the glyph data + if (gwidth < DMFONT_MIN_WIDTH || + gheight < DMFONT_MIN_HEIGHT || + gwidth > DMFONT_MAX_WIDTH || + gheight > DMFONT_MAX_HEIGHT || + gwidth > width || + gheight > height || + gindex >= maxglyph) + return DMERR_INVALID_DATA; - if (glyph == NULL) - return DMERR_MALLOC; - - if (BitsPerPixel == 8) - SDL_SetPaletteColors(glyph->format->palette, pal, 0, DMFONT_NPALETTE); + // Set glyph data + glyph = &font->glyphMap[gindex]; + glyph->width = gwidth; + glyph->height = gheight; + glyph->index = i; - // Read pixel data - pixels = glyph->pixels; - for (y = 0; y < glyph->h; y++) - { - if (dmfread(pixels, glyph->format->BytesPerPixel, glyph->w, res) != (size_t) glyph->w) - return DMERR_FREAD; - pixels += glyph->pitch; - } + // Read pixel data + pixels = font->glyphs->pixels + (i * font->gsize); + for (int y = 0; y < glyph->height; y++) + { + if (dmfread(pixels, font->glyphs->format->BytesPerPixel, + glyph->width, fp) != (size_t) glyph->width) + return DMERR_FREAD; + + pixels += font->glyphs->pitch; } }