summaryrefslogtreecommitdiff
path: root/tools/rsfont/font.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/rsfont/font.c')
-rw-r--r--tools/rsfont/font.c455
1 files changed, 455 insertions, 0 deletions
diff --git a/tools/rsfont/font.c b/tools/rsfont/font.c
new file mode 100644
index 0000000..ed48b31
--- /dev/null
+++ b/tools/rsfont/font.c
@@ -0,0 +1,455 @@
+// 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#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);
+}