summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorYamaArashi <shadow962@live.com>2016-05-27 15:08:48 -0700
committerYamaArashi <shadow962@live.com>2016-05-30 02:19:25 -0700
commit0ebfe95d65fc2852a6b7f0528a2a114de7fe698e (patch)
treea20b2e0e839661df88664d6547841a3a79e07222 /tools
parent1d8ca2c1b995be87bb78dcf9bdfdc1d924a48979 (diff)
text.c
Diffstat (limited to 'tools')
-rw-r--r--tools/bin2c/.gitignore1
-rw-r--r--tools/bin2c/LICENSE19
-rw-r--r--tools/bin2c/Makefile13
-rw-r--r--tools/bin2c/bin2c.c201
-rw-r--r--tools/preproc/c_file.cpp14
-rw-r--r--tools/rsfont/.gitignore1
-rw-r--r--tools/rsfont/LICENSE19
-rw-r--r--tools/rsfont/Makefile15
-rw-r--r--tools/rsfont/convert_png.c169
-rw-r--r--tools/rsfont/convert_png.h11
-rw-r--r--tools/rsfont/font.c457
-rw-r--r--tools/rsfont/font.h30
-rw-r--r--tools/rsfont/gfx.h50
-rw-r--r--tools/rsfont/global.h31
-rw-r--r--tools/rsfont/main.c93
-rw-r--r--tools/rsfont/util.c124
-rw-r--r--tools/rsfont/util.h14
17 files changed, 1259 insertions, 3 deletions
diff --git a/tools/bin2c/.gitignore b/tools/bin2c/.gitignore
new file mode 100644
index 000000000..366f3d3e9
--- /dev/null
+++ b/tools/bin2c/.gitignore
@@ -0,0 +1 @@
+bin2c
diff --git a/tools/bin2c/LICENSE b/tools/bin2c/LICENSE
new file mode 100644
index 000000000..534d15349
--- /dev/null
+++ b/tools/bin2c/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 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.
diff --git a/tools/bin2c/Makefile b/tools/bin2c/Makefile
new file mode 100644
index 000000000..eee19af22
--- /dev/null
+++ b/tools/bin2c/Makefile
@@ -0,0 +1,13 @@
+CC = gcc
+
+CFLAGS = -Wall -Wextra -std=c11 -O2
+
+.PHONY: clean
+
+SRCS = bin2c.c
+
+bin2c: $(SRCS)
+ $(CC) $(CFLAGS) $(SRCS) -o $@
+
+clean:
+ $(RM) bin2c bin2c.exe
diff --git a/tools/bin2c/bin2c.c b/tools/bin2c/bin2c.c
new file mode 100644
index 000000000..b4bd437f0
--- /dev/null
+++ b/tools/bin2c/bin2c.c
@@ -0,0 +1,201 @@
+// 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 <string.h>
+#include <stdbool.h>
+
+#ifdef _MSC_VER
+
+#define FATAL_ERROR(format, ...) \
+do \
+{ \
+ fprintf(stderr, format, __VA_ARGS__); \
+ exit(1); \
+} while (0)
+
+#else
+
+#define FATAL_ERROR(format, ...) \
+do \
+{ \
+ fprintf(stderr, format, ##__VA_ARGS__); \
+ exit(1); \
+} while (0)
+
+#endif // _MSC_VER
+
+unsigned char *ReadWholeFile(char *path, int *size)
+{
+ FILE *fp = fopen(path, "rb");
+
+ if (fp == NULL)
+ FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
+
+ fseek(fp, 0, SEEK_END);
+
+ *size = ftell(fp);
+
+ unsigned char *buffer = malloc(*size);
+
+ if (buffer == NULL)
+ FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
+
+ rewind(fp);
+
+ if (fread(buffer, *size, 1, fp) != 1)
+ FATAL_ERROR("Failed to read \"%s\".\n", path);
+
+ fclose(fp);
+
+ return buffer;
+}
+
+int ExtractData(unsigned char *buffer, int offset, int size)
+{
+ switch (size)
+ {
+ case 1:
+ return buffer[offset];
+ case 2:
+ return (buffer[offset + 1] << 8)
+ | buffer[offset];
+ case 4:
+ return (buffer[offset + 3] << 24)
+ | (buffer[offset + 2] << 16)
+ | (buffer[offset + 1] << 8)
+ | buffer[offset];
+ default:
+ FATAL_ERROR("Invalid size passed to ExtractData.\n");
+ }
+}
+
+int main(int argc, char **argv)
+{
+ if (argc < 3)
+ FATAL_ERROR("Usage: bin2c INPUT_FILE VAR_NAME [OPTIONS...]\n");
+
+ int fileSize;
+ unsigned char *buffer = ReadWholeFile(argv[1], &fileSize);
+ char *var_name = argv[2];
+ int col = 1;
+ int pad = 0;
+ int size = 1;
+ bool isSigned = false;
+ bool isStatic = false;
+ bool isDecimal = false;
+
+ for (int i = 3; i < argc; i++)
+ {
+ if (!strcmp(argv[i], "-col"))
+ {
+ i++;
+
+ if (i >= argc)
+ FATAL_ERROR("Missing argument after '-col'.\n");
+
+ col = atoi(argv[i]);
+ }
+ else if (!strcmp(argv[i], "-pad"))
+ {
+ i++;
+
+ if (i >= argc)
+ FATAL_ERROR("Missing argument after '-pad'.\n");
+
+ pad = atoi(argv[i]);
+ }
+ else if (!strcmp(argv[i], "-size"))
+ {
+ i++;
+
+ if (i >= argc)
+ FATAL_ERROR("Missing argument after '-size'.\n");
+
+ size = atoi(argv[i]);
+
+ if (size != 1 && size != 2 && size != 4)
+ FATAL_ERROR("Size must be 1, 2, or 4.\n");
+ }
+ else if (!strcmp(argv[i], "-signed"))
+ {
+ isSigned = true;
+ isDecimal = true;
+ }
+ else if (!strcmp(argv[i], "-static"))
+ {
+ isStatic = true;
+ }
+ else if (!strcmp(argv[i], "-decimal"))
+ {
+ isDecimal = true;
+ }
+ else
+ {
+ FATAL_ERROR("Unrecognized option '%s'.\n", argv[i]);
+ }
+ }
+
+ if ((fileSize & (size - 1)) != 0)
+ FATAL_ERROR("Size %d doesn't evenly divide file size %d.\n", size, fileSize);
+
+ printf("// Generated file. Do not edit.\n\n");
+
+ if (isStatic)
+ printf("static ");
+
+ printf("const ");
+
+ if (isSigned)
+ printf("s%d ", 8 * size);
+ else
+ printf("u%d ", 8 * size);
+
+ printf("%s[] =\n{", var_name);
+
+ int count = fileSize / size;
+ int offset = 0;
+
+ for (int i = 0; i < count; i++)
+ {
+ if (i % col == 0)
+ printf("\n ");
+
+ int data = ExtractData(buffer, offset, size);
+ offset += size;
+
+ if (isDecimal)
+ {
+ if (isSigned)
+ printf("%*d, ", pad, data);
+ else
+ printf("%*uu, ", pad, data);
+ }
+ else
+ {
+ printf("%#*xu, ", pad, data);
+ }
+ }
+
+ printf("\n};\n");
+
+ return 0;
+}
diff --git a/tools/preproc/c_file.cpp b/tools/preproc/c_file.cpp
index 1e4dea359..aed53d44b 100644
--- a/tools/preproc/c_file.cpp
+++ b/tools/preproc/c_file.cpp
@@ -73,6 +73,7 @@ CFile::~CFile()
void CFile::Preproc()
{
bool inConcatMode = false;
+ bool noTerminator = false;
char stringChar = 0;
while (m_pos < m_size)
@@ -100,10 +101,13 @@ void CFile::Preproc()
else
{
if (inConcatMode ? m_buffer[m_pos] == '"'
- : m_buffer[m_pos] == '_' && m_buffer[m_pos + 1] == '"')
+ : (m_buffer[m_pos] == '_' || m_buffer[m_pos] == '@') && m_buffer[m_pos + 1] == '"')
{
if (!inConcatMode)
- m_pos++; // skip past underscore
+ {
+ noTerminator = (m_buffer[m_pos] == '@');
+ m_pos++; // skip past underscore or at-sign
+ }
unsigned char s[kMaxStringLength];
int length;
@@ -144,7 +148,11 @@ void CFile::Preproc()
if ((c != ' ' && c != '\t' && c != '\n') && inConcatMode)
{
- std::printf("0xFF }");
+ if (noTerminator)
+ std::printf(" }");
+ else
+ std::printf("0xFF }");
+
inConcatMode = false;
}
diff --git a/tools/rsfont/.gitignore b/tools/rsfont/.gitignore
new file mode 100644
index 000000000..3140ececc
--- /dev/null
+++ b/tools/rsfont/.gitignore
@@ -0,0 +1 @@
+rsfont
diff --git a/tools/rsfont/LICENSE b/tools/rsfont/LICENSE
new file mode 100644
index 000000000..b497950c1
--- /dev/null
+++ b/tools/rsfont/LICENSE
@@ -0,0 +1,19 @@
+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.
diff --git a/tools/rsfont/Makefile b/tools/rsfont/Makefile
new file mode 100644
index 000000000..78e0cab3a
--- /dev/null
+++ b/tools/rsfont/Makefile
@@ -0,0 +1,15 @@
+CC = gcc
+
+CFLAGS = -Wall -Wextra -std=c11 -O2
+
+LIBS = -lz -lpng
+
+SRCS = main.c convert_png.c util.c font.c
+
+.PHONY: clean
+
+rsfont: $(SRCS) convert_png.h gfx.h global.h util.h font.h
+ $(CC) $(CFLAGS) $(SRCS) -o $@ $(LIBS)
+
+clean:
+ $(RM) rsfont rsfont.exe
diff --git a/tools/rsfont/convert_png.c b/tools/rsfont/convert_png.c
new file mode 100644
index 000000000..f6a30804a
--- /dev/null
+++ b/tools/rsfont/convert_png.c
@@ -0,0 +1,169 @@
+// Copyright (c) 2015 YamaArashi
+
+#include <stdio.h>
+#include <setjmp.h>
+#include <png.h>
+#include "global.h"
+#include "convert_png.h"
+#include "gfx.h"
+
+void ReadPng(char *path, struct Image *image)
+{
+ FILE *fp = fopen(path, "rb");
+
+ if (fp == NULL)
+ FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
+
+ unsigned char sig[8];
+
+ if (fread(sig, 8, 1, fp) != 1)
+ FATAL_ERROR("Failed to read PNG signature from \"%s\".\n", path);
+
+ if (png_sig_cmp(sig, 0, 8))
+ FATAL_ERROR("\"%s\" does not have a valid PNG signature.\n", path);
+
+ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+
+ if (!png_ptr)
+ FATAL_ERROR("Failed to create PNG read struct.\n");
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+
+ if (!info_ptr)
+ FATAL_ERROR("Failed to create PNG info struct.\n");
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ FATAL_ERROR("Failed to init I/O for reading \"%s\".\n", path);
+
+ png_init_io(png_ptr, fp);
+ png_set_sig_bytes(png_ptr, 8);
+ png_read_info(png_ptr, info_ptr);
+
+ int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
+
+ if (bit_depth != image->bitDepth)
+ FATAL_ERROR("\"%s\" has a bit depth of %d, but the expected bit depth is %d.\n", path, bit_depth, image->bitDepth);
+
+ int color_type = png_get_color_type(png_ptr, info_ptr);
+
+ if (color_type != PNG_COLOR_TYPE_GRAY && color_type != PNG_COLOR_TYPE_PALETTE)
+ FATAL_ERROR("\"%s\" has an unsupported color type.\n", path);
+
+ // Check if the image has a palette so that we can tell if the colors need to be inverted later.
+ // Don't read the palette because it's not needed for now.
+ image->hasPalette = (color_type == PNG_COLOR_TYPE_PALETTE);
+
+ image->width = png_get_image_width(png_ptr, info_ptr);
+ image->height = png_get_image_height(png_ptr, info_ptr);
+
+ int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+
+ image->pixels = malloc(image->height * rowbytes);
+
+ if (image->pixels == NULL)
+ FATAL_ERROR("Failed to allocate pixel buffer.\n");
+
+ png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep));
+
+ if (row_pointers == NULL)
+ FATAL_ERROR("Failed to allocate row pointers.\n");
+
+ for (int i = 0; i < image->height; i++)
+ row_pointers[i] = (png_bytep)(image->pixels + (i * rowbytes));
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ FATAL_ERROR("Error reading from \"%s\".\n", path);
+
+ png_read_image(png_ptr, row_pointers);
+
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+
+ free(row_pointers);
+ fclose(fp);
+}
+
+void SetPngPalette(png_structp png_ptr, png_infop info_ptr, struct Palette *palette)
+{
+ png_colorp colors = malloc(palette->numColors * sizeof(png_color));
+
+ if (colors == NULL)
+ FATAL_ERROR("Failed to allocate PNG palette.\n");
+
+ for (int i = 0; i < palette->numColors; i++) {
+ colors[i].red = palette->colors[i].red;
+ colors[i].green = palette->colors[i].green;
+ colors[i].blue = palette->colors[i].blue;
+ }
+
+ png_set_PLTE(png_ptr, info_ptr, colors, palette->numColors);
+
+ free(colors);
+}
+
+void WritePng(char *path, struct Image *image)
+{
+ FILE *fp = fopen(path, "wb");
+
+ if (fp == NULL)
+ FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
+
+ png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+
+ if (!png_ptr)
+ FATAL_ERROR("Failed to create PNG write struct.\n");
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+
+ if (!info_ptr)
+ FATAL_ERROR("Failed to create PNG info struct.\n");
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ FATAL_ERROR("Failed to init I/O for writing \"%s\".\n", path);
+
+ png_init_io(png_ptr, fp);
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ FATAL_ERROR("Error writing header for \"%s\".\n", path);
+
+ int color_type = image->hasPalette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_GRAY;
+
+ png_set_IHDR(png_ptr, info_ptr, image->width, image->height,
+ image->bitDepth, color_type, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ if (image->hasPalette) {
+ SetPngPalette(png_ptr, info_ptr, &image->palette);
+
+ if (image->hasTransparency) {
+ png_byte trans = 0;
+ png_set_tRNS(png_ptr, info_ptr, &trans, 1, 0);
+ }
+ }
+
+ png_write_info(png_ptr, info_ptr);
+
+ png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep));
+
+ if (row_pointers == NULL)
+ FATAL_ERROR("Failed to allocate row pointers.\n");
+
+ int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+
+ for (int i = 0; i < image->height; i++)
+ row_pointers[i] = (png_bytep)(image->pixels + (i * rowbytes));
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ FATAL_ERROR("Error writing \"%s\".\n", path);
+
+ png_write_image(png_ptr, row_pointers);
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ FATAL_ERROR("Error ending write of \"%s\".\n", path);
+
+ png_write_end(png_ptr, NULL);
+
+ fclose(fp);
+
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ free(row_pointers);
+}
diff --git a/tools/rsfont/convert_png.h b/tools/rsfont/convert_png.h
new file mode 100644
index 000000000..55d3d6942
--- /dev/null
+++ b/tools/rsfont/convert_png.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2015 YamaArashi
+
+#ifndef CONVERT_PNG_H
+#define CONVERT_PNG_H
+
+#include "gfx.h"
+
+void ReadPng(char *path, struct Image *image);
+void WritePng(char *path, struct Image *image);
+
+#endif // CONVERT_PNG_H
diff --git a/tools/rsfont/font.c b/tools/rsfont/font.c
new file mode 100644
index 000000000..ba0e69cd2
--- /dev/null
+++ b/tools/rsfont/font.c
@@ -0,0 +1,457 @@
+// 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++)
+ {
+ unsigned char 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++)
+ {
+ unsigned char 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++)
+ {
+ unsigned char 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++)
+ {
+ unsigned char 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++)
+ {
+ unsigned char 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++)
+ {
+ unsigned char 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++)
+ {
+ unsigned long 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++)
+ {
+ unsigned long 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++)
+ {
+ unsigned long 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++)
+ {
+ unsigned long 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++)
+ {
+ unsigned long 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++)
+ {
+ unsigned long 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 tilesPerGlyph = layout > 0 ? 2 : 1;
+
+ 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);
+}
diff --git a/tools/rsfont/font.h b/tools/rsfont/font.h
new file mode 100644
index 000000000..1cd48757f
--- /dev/null
+++ b/tools/rsfont/font.h
@@ -0,0 +1,30 @@
+// 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.
+
+#ifndef FONT_H
+#define FONT_H
+
+#include <stdbool.h>
+#include "gfx.h"
+
+void ReadFont(char *path, struct Image *image, int numGlyphs, int bpp, int layout);
+void WriteFont(char *path, struct Image *image, int numGlyphs, int bpp, int layout);
+
+#endif // FONT_H
diff --git a/tools/rsfont/gfx.h b/tools/rsfont/gfx.h
new file mode 100644
index 000000000..04a3d80c7
--- /dev/null
+++ b/tools/rsfont/gfx.h
@@ -0,0 +1,50 @@
+// 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.
+
+#ifndef GFX_H
+#define GFX_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+struct Color
+{
+ unsigned char red;
+ unsigned char green;
+ unsigned char blue;
+};
+
+struct Palette
+{
+ struct Color colors[256];
+ int numColors;
+};
+
+struct Image {
+ int width;
+ int height;
+ int bitDepth;
+ unsigned char *pixels;
+ bool hasPalette;
+ struct Palette palette;
+ bool hasTransparency;
+};
+
+#endif // GFX_H
diff --git a/tools/rsfont/global.h b/tools/rsfont/global.h
new file mode 100644
index 000000000..65dd351d2
--- /dev/null
+++ b/tools/rsfont/global.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2015 YamaArashi
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef _MSC_VER
+
+#define FATAL_ERROR(format, ...) \
+do { \
+ fprintf(stderr, format, __VA_ARGS__); \
+ exit(1); \
+} while (0)
+
+#define UNUSED
+
+#else
+
+#define FATAL_ERROR(format, ...) \
+do { \
+ fprintf(stderr, format, ##__VA_ARGS__); \
+ exit(1); \
+} while (0)
+
+#define UNUSED __attribute__((__unused__))
+
+#endif // _MSC_VER
+
+#endif // GLOBAL_H
diff --git a/tools/rsfont/main.c b/tools/rsfont/main.c
new file mode 100644
index 000000000..2f5d9d971
--- /dev/null
+++ b/tools/rsfont/main.c
@@ -0,0 +1,93 @@
+// 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 <string.h>
+#include <stdbool.h>
+#include "global.h"
+#include "util.h"
+#include "gfx.h"
+#include "convert_png.h"
+#include "font.h"
+
+int ExtensionToBpp(const char *extension)
+{
+ if (!strcmp(extension, "1bpp"))
+ return 1;
+ else if (!strcmp(extension, "4bpp"))
+ return 4;
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ if (argc < 5)
+ FATAL_ERROR("Usage: rsfont INPUT_FILE OUTPUT_FILE NUM_GLYPHS LAYOUT_TYPE\n");
+
+ char *inputPath = argv[1];
+ char *outputPath = argv[2];
+ char *inputFileExtension = GetFileExtension(inputPath);
+ char *outputFileExtension = GetFileExtension(outputPath);
+
+ if (inputFileExtension == NULL)
+ FATAL_ERROR("Input file \"%s\" has no extension.\n", inputPath);
+
+ if (outputFileExtension == NULL)
+ FATAL_ERROR("Output file \"%s\" has no extension.\n", outputPath);
+
+ int numGlyphs;
+ int bpp;
+ int layout;
+
+ if (!ParseNumber(argv[3], NULL, 10, &numGlyphs))
+ FATAL_ERROR("Failed to parse number of glyphs.\n");
+
+ if (!ParseNumber(argv[4], NULL, 10, &layout))
+ FATAL_ERROR("Failed to parse layout type.\n");
+
+ if (layout < 0 || layout > 2)
+ FATAL_ERROR("Layout type %d is invalid. Layout type must be 0, 1, or 2.\n", layout);
+
+ bool toPng;
+
+ if (!strcmp(inputFileExtension, "png") && (bpp = ExtensionToBpp(outputFileExtension)) != 0)
+ toPng = false;
+ else if ((bpp = ExtensionToBpp(inputFileExtension)) != 0 && !strcmp(outputFileExtension, "png"))
+ toPng = true;
+ else
+ FATAL_ERROR("Don't know how to convert \"%s\" to \"%s\".\n", inputPath, outputPath);
+
+ if (bpp == 1 && layout == 2)
+ FATAL_ERROR("Layout type 2 is not supported with 1 BPP fonts.\n");
+
+ struct Image image;
+
+ if (toPng)
+ {
+ ReadFont(inputPath, &image, numGlyphs, bpp, layout);
+ WritePng(outputPath, &image);
+ }
+ else
+ {
+ image.bitDepth = 8;
+ ReadPng(inputPath, &image);
+ WriteFont(outputPath, &image, numGlyphs, bpp, layout);
+ }
+}
diff --git a/tools/rsfont/util.c b/tools/rsfont/util.c
new file mode 100644
index 000000000..87abeb31c
--- /dev/null
+++ b/tools/rsfont/util.c
@@ -0,0 +1,124 @@
+// Copyright (c) 2015 YamaArashi
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <limits.h>
+#include "global.h"
+#include "util.h"
+
+bool ParseNumber(char *s, char **end, int radix, int *intValue)
+{
+ char *localEnd;
+
+ if (end == NULL)
+ end = &localEnd;
+
+ errno = 0;
+
+ const long longValue = strtol(s, end, radix);
+
+ if (*end == s)
+ return false; // not a number
+
+ if ((longValue == LONG_MIN || longValue == LONG_MAX) && errno == ERANGE)
+ return false;
+
+ if (longValue > INT_MAX)
+ return false;
+
+ if (longValue < INT_MIN)
+ return false;
+
+ *intValue = (int)longValue;
+
+ return true;
+}
+
+char *GetFileExtension(char *path)
+{
+ char *extension = path;
+
+ while (*extension != 0)
+ extension++;
+
+ while (extension > path && *extension != '.')
+ extension--;
+
+ if (extension == path)
+ return NULL;
+
+ extension++;
+
+ if (*extension == 0)
+ return NULL;
+
+ return extension;
+}
+
+unsigned char *ReadWholeFile(char *path, int *size)
+{
+ FILE *fp = fopen(path, "rb");
+
+ if (fp == NULL)
+ FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
+
+ fseek(fp, 0, SEEK_END);
+
+ *size = ftell(fp);
+
+ unsigned char *buffer = malloc(*size);
+
+ if (buffer == NULL)
+ FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
+
+ rewind(fp);
+
+ if (fread(buffer, *size, 1, fp) != 1)
+ FATAL_ERROR("Failed to read \"%s\".\n", path);
+
+ fclose(fp);
+
+ return buffer;
+}
+
+unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount)
+{
+ FILE *fp = fopen(path, "rb");
+
+ if (fp == NULL)
+ FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
+
+ fseek(fp, 0, SEEK_END);
+
+ *size = ftell(fp);
+
+ unsigned char *buffer = calloc(*size + padAmount, 1);
+
+ if (buffer == NULL)
+ FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
+
+ rewind(fp);
+
+ if (fread(buffer, *size, 1, fp) != 1)
+ FATAL_ERROR("Failed to read \"%s\".\n", path);
+
+ fclose(fp);
+
+ return buffer;
+}
+
+void WriteWholeFile(char *path, void *buffer, int bufferSize)
+{
+ FILE *fp = fopen(path, "wb");
+
+ if (fp == NULL)
+ FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
+
+ if (fwrite(buffer, bufferSize, 1, fp) != 1)
+ FATAL_ERROR("Failed to write to \"%s\".\n", path);
+
+ fclose(fp);
+}
diff --git a/tools/rsfont/util.h b/tools/rsfont/util.h
new file mode 100644
index 000000000..6d7a9c21e
--- /dev/null
+++ b/tools/rsfont/util.h
@@ -0,0 +1,14 @@
+// Copyright (c) 2015 YamaArashi
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <stdbool.h>
+
+bool ParseNumber(char *s, char **end, int radix, int *intValue);
+char *GetFileExtension(char *path);
+unsigned char *ReadWholeFile(char *path, int *size);
+unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount);
+void WriteWholeFile(char *path, void *buffer, int bufferSize);
+
+#endif // UTIL_H