Mercurial > hg > dmlib
view src/dmtext_bm.c @ 1785:86d10d5d4915
Fix case where DMGrowBuf is growing backwards and needs to be reallocated in
dmGrowBufRealloc() and the data is moved to the "end" of the newly grown
buffer. Previously we used clrsize as data size, but that is (in retrospect)
obviously incorrect. Use old buffer size instead.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Wed, 13 Jun 2018 01:39:06 +0300 |
parents | 5e5f75b45f8d |
children | a3983da9b8b9 |
line wrap: on
line source
/* * DMLib * -- Bitmap and TTF text & font support * Programmed and designed by Matti 'ccr' Hamalainen * (C) Copyright 2012 Tecnic Software productions (TNSP) */ #include "dmtext.h" void dmDrawBMTextConst(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt) { const char *ptr = fmt; DMUnscaledBlitFunc blit = NULL; while (*ptr) { int ch = *ptr++; SDL_Surface *glyph; if (ch >= 0 && ch < font->nglyphs && (glyph = font->glyphs[ch]) != NULL) { if (blit == NULL) blit = dmGetUnscaledBlitFunc(glyph->format, screen->format, mode); if (blit != NULL) { blit(glyph, xc, yc, screen); xc += condensed ? glyph->w : font->width; } } else xc += font->width; } } void dmDrawBMTextVA(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt, va_list ap) { char tmp[512]; vsnprintf(tmp, sizeof(tmp), fmt, ap); dmDrawBMTextConst(screen, font, condensed, mode, xc, yc, tmp); dmFree(tmp); } void dmDrawBMText(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt, ...) { va_list ap; va_start(ap, fmt); dmDrawBMTextVA(screen, font, condensed, mode, xc, yc, fmt, ap); va_end(ap); } 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; } 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; } } dmFree(font); return DMERR_OK; } /* Set the palette for each glyph. While the function allows you to * specify 'start' and 'end' indices and palette array freely, you should * typically use DMFONT_NPALETTE size palette starting at index 0. */ int dmSetBitmapFontPalette(DMBitmapFont *font, SDL_Color *pal, int start, 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); } } return DMERR_OK; } //#define FN_DEBUG int dmLoadBitmapFont(DMResource *res, DMBitmapFont **pfont) { DMBitmapFont *font; char magic[8]; 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); // 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 > 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 // 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; } // 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); } 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); // 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); } } 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(maxglyph, width, height)) == NULL) return DMERR_MALLOC; // Read glyph data, if any if (nglyphs > 0) { 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++) { pal[n].r = pal[n].g = pal[n].b = 0; pal[n].a = n > 0 ? 255 : 0; } 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; // 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); #ifdef FN_DEBUG fprintf(stderr, "#%d @ %d - w=%d, h=%d\n", i, index, width, height); #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); if (glyph == NULL) return DMERR_MALLOC; if (BitsPerPixel == 8) SDL_SetPaletteColors(glyph->format->palette, pal, 0, DMFONT_NPALETTE); // 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; } } } return DMERR_OK; }