// Copyright(c) 2015-2016 YamaArashi // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #include #include #include #include #include "global.h" #include "font.h" #include "gfx.h" #include "util.h" unsigned char gFontPalette[][3] = { {0xFF, 0xFF, 0xFF}, // bg (white) {0x38, 0x38, 0x38}, // fg (dark grey) {0xD8, 0xD8, 0xD8}, // shadow (light grey) }; void ConvertFromTiles1Bpp(unsigned char *src, unsigned char *dest, int numGlyphs, int layout) { for (int glyph = 0; glyph < numGlyphs; glyph++) { if (layout == 0) { for (int i = 0; i < 8; i++) { uint8_t srcRow = src[(glyph * 8) + i]; for (int j = 0; j < 8; j++) { int x = ((glyph % 16) * 8) + j; int y = ((glyph / 16) * 8) + i; dest[(y * 128) + x] = (srcRow >> (7 - j)) & 1; } } } else { // layout type 1 int tile1Offset = glyph * 16; int tile2Offset = tile1Offset + 8; for (int i = 0; i < 8; i++) { uint8_t srcRow = src[tile1Offset + i]; for (int j = 0; j < 8; j++) { int x = ((glyph % 16) * 8) + j; int y = ((glyph / 16) * 16) + i; dest[(y * 128) + x] = (srcRow >> (7 - j)) & 1; } } for (int i = 0; i < 8; i++) { uint8_t srcRow = src[tile2Offset + i]; for (int j = 0; j < 8; j++) { int x = ((glyph % 16) * 8) + j; int y = ((glyph / 16) * 16) + 8 + i; dest[(y * 128) + x] = (srcRow >> (7 - j)) & 1; } } } } } void ConvertToTiles1Bpp(unsigned char *src, unsigned char *dest, int numGlyphs, int layout) { for (int glyph = 0; glyph < numGlyphs; glyph++) { if (layout == 0) { for (int i = 0; i < 8; i++) { uint8_t destRow = 0; for (int j = 0; j < 8; j++) { int x = ((glyph % 16) * 8) + j; int y = ((glyph / 16) * 8) + i; unsigned char color = src[(y * 128) + x]; if (color > 1) FATAL_ERROR("More than 2 colors in 1 BPP font.\n"); destRow <<= 1; destRow |= color; } dest[(glyph * 8) + i] = destRow; } } else { // layout type 1 int tile1Offset = glyph * 16; int tile2Offset = tile1Offset + 8; for (int i = 0; i < 8; i++) { uint8_t destRow = 0; for (int j = 0; j < 8; j++) { int x = ((glyph % 16) * 8) + j; int y = ((glyph / 16) * 16) + i; unsigned char color = src[(y * 128) + x]; if (color > 1) FATAL_ERROR("More than 2 colors in 1 BPP font.\n"); destRow <<= 1; destRow |= color; } dest[tile1Offset + i] = destRow; } for (int i = 0; i < 8; i++) { uint8_t destRow = 0; for (int j = 0; j < 8; j++) { int x = ((glyph % 16) * 8) + j; int y = ((glyph / 16) * 16) + 8 + i; unsigned char color = src[(y * 128) + x]; if (color > 1) FATAL_ERROR("More than 2 colors in 1 BPP font.\n"); destRow <<= 1; destRow |= color; } dest[tile2Offset + i] = destRow; } } } } void ConvertFromTiles4Bpp(unsigned char *src, unsigned char *dest, int numGlyphs, int layout) { static unsigned char table[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, }; for (int glyph = 0; glyph < numGlyphs; glyph++) { if (layout == 0) { int offset = glyph * 32; for (int i = 0; i < 8; i++) { uint32_t srcRow = (src[offset + 3] << 24) | (src[offset + 2] << 16) | (src[offset + 1] << 8) | src[offset]; for (int j = 0; j < 8; j++) { int x = ((glyph % 16) * 8) + j; int y = ((glyph / 16) * 8) + i; dest[(y * 128) + x] = table[srcRow & 0xF]; srcRow >>= 4; } offset += 4; } } else { int tile1Offset; int tile2Offset; if (layout == 1) { tile1Offset = glyph * 64; tile2Offset = tile1Offset + 32; } else { tile1Offset = ((glyph / 16) * 1024) + ((glyph % 16) * 32); tile2Offset = tile1Offset + 512; } for (int i = 0; i < 8; i++) { uint32_t srcRow = (src[tile1Offset + 3] << 24) | (src[tile1Offset + 2] << 16) | (src[tile1Offset + 1] << 8) | src[tile1Offset]; for (int j = 0; j < 8; j++) { int x = ((glyph % 16) * 8) + j; int y = ((glyph / 16) * 16) + i; dest[(y * 128) + x] = table[srcRow & 0xF]; srcRow >>= 4; } tile1Offset += 4; } for (int i = 0; i < 8; i++) { uint32_t srcRow = (src[tile2Offset + 3] << 24) | (src[tile2Offset + 2] << 16) | (src[tile2Offset + 1] << 8) | src[tile2Offset]; for (int j = 0; j < 8; j++) { int x = ((glyph % 16) * 8) + j; int y = ((glyph / 16) * 16) + 8 + i; dest[(y * 128) + x] = table[srcRow & 0xF]; srcRow >>= 4; } tile2Offset += 4; } } } } void ConvertToTiles4Bpp(unsigned char *src, unsigned char *dest, int numGlyphs, int layout) { static unsigned char table[3] = { 0, 15, 14, }; for (int glyph = 0; glyph < numGlyphs; glyph++) { if (layout == 0) { int offset = glyph * 32; for (int i = 0; i < 8; i++) { uint32_t destRow = 0; for (int j = 0; j < 8; j++) { int x = ((glyph % 16) * 8) + j; int y = ((glyph / 16) * 8) + i; unsigned char color = src[(y * 128) + x]; if (color > 2) FATAL_ERROR("More than 3 colors in 4 BPP font.\n"); destRow >>= 4; destRow |= (table[color] << 28); } dest[offset] = destRow & 0xFF; dest[offset + 1] = (destRow >> 8) & 0xFF; dest[offset + 2] = (destRow >> 16) & 0xFF; dest[offset + 3] = (destRow >> 24) & 0xFF; offset += 4; } } else { int tile1Offset; int tile2Offset; if (layout == 1) { tile1Offset = glyph * 64; tile2Offset = tile1Offset + 32; } else { tile1Offset = ((glyph / 16) * 1024) + ((glyph % 16) * 32); tile2Offset = tile1Offset + 512; } for (int i = 0; i < 8; i++) { uint32_t destRow = 0; for (int j = 0; j < 8; j++) { int x = ((glyph % 16) * 8) + j; int y = ((glyph / 16) * 16) + i; unsigned char color = src[(y * 128) + x]; if (color > 2) FATAL_ERROR("More than 3 colors in 4 BPP font.\n"); destRow >>= 4; destRow |= (table[color] << 28); } dest[tile1Offset] = destRow & 0xFF; dest[tile1Offset + 1] = (destRow >> 8) & 0xFF; dest[tile1Offset + 2] = (destRow >> 16) & 0xFF; dest[tile1Offset + 3] = (destRow >> 24) & 0xFF; tile1Offset += 4; } for (int i = 0; i < 8; i++) { uint32_t destRow = 0; for (int j = 0; j < 8; j++) { int x = ((glyph % 16) * 8) + j; int y = ((glyph / 16) * 16) + 8 + i; unsigned char color = src[(y * 128) + x]; if (color > 2) FATAL_ERROR("More than 3 colors in 4 BPP font.\n"); destRow >>= 4; destRow |= (table[color] << 28); } dest[tile2Offset] = destRow & 0xFF; dest[tile2Offset + 1] = (destRow >> 8) & 0xFF; dest[tile2Offset + 2] = (destRow >> 16) & 0xFF; dest[tile2Offset + 3] = (destRow >> 24) & 0xFF; tile2Offset += 4; } } } } static void SetFontPalette(struct Image *image) { image->hasPalette = true; image->palette.numColors = 3; for (int i = 0; i < image->palette.numColors; i++) { image->palette.colors[i].red = gFontPalette[i][0]; image->palette.colors[i].green = gFontPalette[i][1]; image->palette.colors[i].blue = gFontPalette[i][2]; } image->hasTransparency = false; } int CalcFileSize(int numGlyphs, int bpp, int layout) { if (layout == 2) { // assume 4 BPP int numFullRows = numGlyphs / 16; int remainder = numGlyphs % 16; int fullRowsSize = numFullRows * 1024; int remainderSize = 0; if (remainder != 0) remainderSize = 1024 - (16 - remainder) * 32; return fullRowsSize + remainderSize; } else { int tilesPerGlyph = layout > 0 ? 2 : 1; int bytesPerTile = 8 * bpp; return numGlyphs * tilesPerGlyph * bytesPerTile; } } void ReadFont(char *path, struct Image *image, int numGlyphs, int bpp, int layout) { int fileSize; unsigned char *buffer = ReadWholeFile(path, &fileSize); int expectedFileSize = CalcFileSize(numGlyphs, bpp, layout); if (fileSize != expectedFileSize) FATAL_ERROR("The file size is %d but should be %d.\n", fileSize, expectedFileSize); int numRows = (numGlyphs + 15) / 16; int rowHeight = layout > 0 ? 16 : 8; image->width = 128; image->height = numRows * rowHeight; image->bitDepth = 8; image->pixels = calloc(image->width * image->height, 1); if (image->pixels == NULL) FATAL_ERROR("Failed to allocate memory for font.\n"); if (bpp == 1) ConvertFromTiles1Bpp(buffer, image->pixels, numGlyphs, layout); else ConvertFromTiles4Bpp(buffer, image->pixels, numGlyphs, layout); free(buffer); SetFontPalette(image); } void WriteFont(char *path, struct Image *image, int numGlyphs, int bpp, int layout) { if (image->width != 128) FATAL_ERROR("The width of the font image (%d) is not 128.\n", image->width); int numRows = (numGlyphs + 15) / 16; int rowHeight = layout > 0 ? 16 : 8; int expectedHeight = numRows * rowHeight; if (image->height < expectedHeight) FATAL_ERROR("The height of the font image (%d) is less than %d.\n", image->height, expectedHeight); int fileSize = CalcFileSize(numGlyphs, bpp, layout); unsigned char *buffer = calloc(fileSize, 1); if (buffer == NULL) FATAL_ERROR("Failed to allocate memory for font.\n"); if (bpp == 1) ConvertToTiles1Bpp(image->pixels, buffer, numGlyphs, layout); else ConvertToTiles4Bpp(image->pixels, buffer, numGlyphs, layout); WriteWholeFile(path, buffer, fileSize); free(buffer); }