diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/gbagfx/Makefile | 6 | ||||
-rw-r--r-- | tools/gbagfx/convert_png.c | 2 | ||||
-rw-r--r-- | tools/gbagfx/font.c | 326 | ||||
-rw-r--r-- | tools/gbagfx/font.h | 16 | ||||
-rw-r--r-- | tools/gbagfx/gfx.h | 2 | ||||
-rw-r--r-- | tools/gbagfx/global.h | 12 | ||||
-rw-r--r-- | tools/gbagfx/main.c | 363 | ||||
-rw-r--r-- | tools/gbagfx/util.c | 42 | ||||
-rw-r--r-- | tools/gbagfx/util.h | 4 |
9 files changed, 529 insertions, 244 deletions
diff --git a/tools/gbagfx/Makefile b/tools/gbagfx/Makefile index 1bf37e301..e7f089445 100644 --- a/tools/gbagfx/Makefile +++ b/tools/gbagfx/Makefile @@ -1,14 +1,14 @@ CC = gcc -CFLAGS = -Wall -std=c11 -O2 +CFLAGS = -Wall -Wextra -std=c11 -O2 LIBS = -lz -lpng -SRCS = main.c convert_png.c gfx.c jasc_pal.c lz.c util.c +SRCS = main.c convert_png.c gfx.c jasc_pal.c lz.c util.c font.c .PHONY: clean -gbagfx: $(SRCS) convert_png.h gfx.h global.h jasc_pal.h lz.h util.h +gbagfx: $(SRCS) convert_png.h gfx.h global.h jasc_pal.h lz.h util.h font.h $(CC) $(CFLAGS) $(SRCS) -o $@ $(LIBS) clean: diff --git a/tools/gbagfx/convert_png.c b/tools/gbagfx/convert_png.c index ffc1b3d41..f6a30804a 100644 --- a/tools/gbagfx/convert_png.c +++ b/tools/gbagfx/convert_png.c @@ -134,7 +134,7 @@ void WritePng(char *path, struct Image *image) if (image->hasPalette) { SetPngPalette(png_ptr, info_ptr, &image->palette); - if (image->isObject) { + if (image->hasTransparency) { png_byte trans = 0; png_set_tRNS(png_ptr, info_ptr, &trans, 1, 0); } diff --git a/tools/gbagfx/font.c b/tools/gbagfx/font.c new file mode 100644 index 000000000..0dd6fbc3e --- /dev/null +++ b/tools/gbagfx/font.c @@ -0,0 +1,326 @@ +// Copyright (c) 2015 YamaArashi + +#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] = { + {0x90, 0xC8, 0xFF}, // bg (saturated blue that contrasts well with the shadow color) + {0x38, 0x38, 0x38}, // fg (dark grey) + {0xD8, 0xD8, 0xD8}, // shadow (light grey) + {0xFF, 0xFF, 0xFF} // box (white) +}; + +static void ConvertFromLatinFont(unsigned char *src, unsigned char *dest, unsigned int numRows) +{ + unsigned int srcPixelsOffset = 0; + + for (unsigned int row = 0; row < numRows; row++) { + for (unsigned int column = 0; column < 16; column++) { + for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) { + unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8); + + for (unsigned int i = 0; i < 8; i++) { + unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i; + unsigned int destPixelsOffset = (pixelsY * 64) + (pixelsX / 4); + + dest[destPixelsOffset] = src[srcPixelsOffset + 1]; + dest[destPixelsOffset + 1] = src[srcPixelsOffset]; + + srcPixelsOffset += 2; + } + } + } + } +} + +static void ConvertToLatinFont(unsigned char *src, unsigned char *dest, unsigned int numRows) +{ + unsigned int destPixelsOffset = 0; + + for (unsigned int row = 0; row < numRows; row++) { + for (unsigned int column = 0; column < 16; column++) { + for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) { + unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8); + + for (unsigned int i = 0; i < 8; i++) { + unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i; + unsigned int srcPixelsOffset = (pixelsY * 64) + (pixelsX / 4); + + dest[destPixelsOffset] = src[srcPixelsOffset + 1]; + dest[destPixelsOffset + 1] = src[srcPixelsOffset]; + + destPixelsOffset += 2; + } + } + } + } +} + +static void ConvertFromHalfwidthJapaneseFont(unsigned char *src, unsigned char *dest, unsigned int numRows) +{ + for (unsigned int row = 0; row < numRows; row++) { + for (unsigned int column = 0; column < 16; column++) { + unsigned int glyphIndex = (row * 16) + column; + + for (unsigned int glyphTile = 0; glyphTile < 2; glyphTile++) { + unsigned int pixelsX = column * 8; + unsigned int srcPixelsOffset = 512 * (glyphIndex >> 4) + 16 * (glyphIndex & 0xF) + 256 * glyphTile; + + for (unsigned int i = 0; i < 8; i++) { + unsigned int pixelsY = (row * 16) + (glyphTile * 8) + i; + unsigned int destPixelsOffset = (pixelsY * 32) + (pixelsX / 4); + + dest[destPixelsOffset] = src[srcPixelsOffset + 1]; + dest[destPixelsOffset + 1] = src[srcPixelsOffset]; + + srcPixelsOffset += 2; + } + } + } + } +} + +static void ConvertToHalfwidthJapaneseFont(unsigned char *src, unsigned char *dest, unsigned int numRows) +{ + for (unsigned int row = 0; row < numRows; row++) { + for (unsigned int column = 0; column < 16; column++) { + unsigned int glyphIndex = (row * 16) + column; + + for (unsigned int glyphTile = 0; glyphTile < 2; glyphTile++) { + unsigned int pixelsX = column * 8; + unsigned int destPixelsOffset = 512 * (glyphIndex >> 4) + 16 * (glyphIndex & 0xF) + 256 * glyphTile; + + for (unsigned int i = 0; i < 8; i++) { + unsigned int pixelsY = (row * 16) + (glyphTile * 8) + i; + unsigned int srcPixelsOffset = (pixelsY * 32) + (pixelsX / 4); + + dest[destPixelsOffset] = src[srcPixelsOffset + 1]; + dest[destPixelsOffset + 1] = src[srcPixelsOffset]; + + destPixelsOffset += 2; + } + } + } + } +} + +static void ConvertFromFullwidthJapaneseFont(unsigned char *src, unsigned char *dest, unsigned int numRows) +{ + for (unsigned int row = 0; row < numRows; row++) { + for (unsigned int column = 0; column < 16; column++) { + unsigned int glyphIndex = (row * 16) + column; + + for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) { + unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8); + unsigned int srcPixelsOffset = 512 * (glyphIndex >> 3) + 32 * (glyphIndex & 7) + 256 * (glyphTile >> 1) + 16 * (glyphTile & 1); + + for (unsigned int i = 0; i < 8; i++) { + unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i; + unsigned int destPixelsOffset = (pixelsY * 64) + (pixelsX / 4); + + dest[destPixelsOffset] = src[srcPixelsOffset + 1]; + dest[destPixelsOffset + 1] = src[srcPixelsOffset]; + + srcPixelsOffset += 2; + } + } + } + } +} + +static void ConvertToFullwidthJapaneseFont(unsigned char *src, unsigned char *dest, unsigned int numRows) +{ + for (unsigned int row = 0; row < numRows; row++) { + for (unsigned int column = 0; column < 16; column++) { + unsigned int glyphIndex = (row * 16) + column; + + for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) { + unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8); + unsigned int destPixelsOffset = 512 * (glyphIndex >> 3) + 32 * (glyphIndex & 7) + 256 * (glyphTile >> 1) + 16 * (glyphTile & 1); + + for (unsigned int i = 0; i < 8; i++) { + unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i; + unsigned int srcPixelsOffset = (pixelsY * 64) + (pixelsX / 4); + + dest[destPixelsOffset] = src[srcPixelsOffset + 1]; + dest[destPixelsOffset + 1] = src[srcPixelsOffset]; + + destPixelsOffset += 2; + } + } + } + } +} + +static void SetFontPalette(struct Image *image) +{ + image->hasPalette = true; + + image->palette.numColors = 4; + + 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; +} + +void ReadLatinFont(char *path, struct Image *image) +{ + int fileSize; + unsigned char *buffer = ReadWholeFile(path, &fileSize); + + int numGlyphs = fileSize / 64; + + if (numGlyphs % 16 != 0) + FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs); + + int numRows = numGlyphs / 16; + + image->width = 256; + image->height = numRows * 16; + image->bitDepth = 2; + image->pixels = malloc(fileSize); + + if (image->pixels == NULL) + FATAL_ERROR("Failed to allocate memory for font.\n"); + + ConvertFromLatinFont(buffer, image->pixels, numRows); + + free(buffer); + + SetFontPalette(image); +} + +void WriteLatinFont(char *path, struct Image *image) +{ + if (image->width != 256) + FATAL_ERROR("The width of the font image (%d) is not 256.\n", image->width); + + if (image->height % 16 != 0) + FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height); + + int numRows = image->height / 16; + int bufferSize = numRows * 16 * 64; + unsigned char *buffer = malloc(bufferSize); + + if (buffer == NULL) + FATAL_ERROR("Failed to allocate memory for font.\n"); + + ConvertToLatinFont(image->pixels, buffer, numRows); + + WriteWholeFile(path, buffer, bufferSize); + + free(buffer); +} + +void ReadHalfwidthJapaneseFont(char *path, struct Image *image) +{ + int fileSize; + unsigned char *buffer = ReadWholeFile(path, &fileSize); + + int glyphSize = 32; + + if (fileSize % glyphSize != 0) + FATAL_ERROR("The file size (%d) is not a multiple of %d.\n", fileSize, glyphSize); + + int numGlyphs = fileSize / glyphSize; + + if (numGlyphs % 16 != 0) + FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs); + + int numRows = numGlyphs / 16; + + image->width = 128; + image->height = numRows * 16; + image->bitDepth = 2; + image->pixels = malloc(fileSize); + + if (image->pixels == NULL) + FATAL_ERROR("Failed to allocate memory for font.\n"); + + ConvertFromHalfwidthJapaneseFont(buffer, image->pixels, numRows); + + free(buffer); + + SetFontPalette(image); +} + +void WriteHalfwidthJapaneseFont(char *path, struct Image *image) +{ + if (image->width != 128) + FATAL_ERROR("The width of the font image (%d) is not 128.\n", image->width); + + if (image->height % 16 != 0) + FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height); + + int numRows = image->height / 16; + int bufferSize = numRows * 16 * 32; + unsigned char *buffer = malloc(bufferSize); + + if (buffer == NULL) + FATAL_ERROR("Failed to allocate memory for font.\n"); + + ConvertToHalfwidthJapaneseFont(image->pixels, buffer, numRows); + + WriteWholeFile(path, buffer, bufferSize); + + free(buffer); +} + +void ReadFullwidthJapaneseFont(char *path, struct Image *image) +{ + int fileSize; + unsigned char *buffer = ReadWholeFile(path, &fileSize); + + int numGlyphs = fileSize / 64; + + if (numGlyphs % 16 != 0) + FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs); + + int numRows = numGlyphs / 16; + + image->width = 256; + image->height = numRows * 16; + image->bitDepth = 2; + image->pixels = malloc(fileSize); + + if (image->pixels == NULL) + FATAL_ERROR("Failed to allocate memory for font.\n"); + + ConvertFromFullwidthJapaneseFont(buffer, image->pixels, numRows); + + free(buffer); + + SetFontPalette(image); +} + +void WriteFullwidthJapaneseFont(char *path, struct Image *image) +{ + if (image->width != 256) + FATAL_ERROR("The width of the font image (%d) is not 256.\n", image->width); + + if (image->height % 16 != 0) + FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height); + + int numRows = image->height / 16; + int bufferSize = numRows * 16 * 64; + unsigned char *buffer = malloc(bufferSize); + + if (buffer == NULL) + FATAL_ERROR("Failed to allocate memory for font.\n"); + + ConvertToFullwidthJapaneseFont(image->pixels, buffer, numRows); + + WriteWholeFile(path, buffer, bufferSize); + + free(buffer); +} diff --git a/tools/gbagfx/font.h b/tools/gbagfx/font.h new file mode 100644 index 000000000..88c61b638 --- /dev/null +++ b/tools/gbagfx/font.h @@ -0,0 +1,16 @@ +// Copyright (c) 2015 YamaArashi + +#ifndef FONT_H +#define FONT_H + +#include<stdbool.h> +#include "gfx.h" + +void ReadLatinFont(char *path, struct Image *image); +void WriteLatinFont(char *path, struct Image *image); +void ReadHalfwidthJapaneseFont(char *path, struct Image *image); +void WriteHalfwidthJapaneseFont(char *path, struct Image *image); +void ReadFullwidthJapaneseFont(char *path, struct Image *image); +void WriteFullwidthJapaneseFont(char *path, struct Image *image); + +#endif // FONT_H diff --git a/tools/gbagfx/gfx.h b/tools/gbagfx/gfx.h index 473640d44..ecd436652 100644 --- a/tools/gbagfx/gfx.h +++ b/tools/gbagfx/gfx.h @@ -24,7 +24,7 @@ struct Image { unsigned char *pixels; bool hasPalette; struct Palette palette; - bool isObject; + bool hasTransparency; }; void ReadImage(char *path, int tilesWidth, int bitDepth, struct Image *image, bool invertColors); diff --git a/tools/gbagfx/global.h b/tools/gbagfx/global.h index ce4d6925d..65dd351d2 100644 --- a/tools/gbagfx/global.h +++ b/tools/gbagfx/global.h @@ -14,6 +14,8 @@ do { \ exit(1); \ } while (0) +#define UNUSED + #else #define FATAL_ERROR(format, ...) \ @@ -22,14 +24,8 @@ do { \ exit(1); \ } while (0) -#endif // _MSC_VER - -#define GBAGFX_MAX_PATH 255 +#define UNUSED __attribute__((__unused__)) -#define CHECK_PATH_LENGTH(path) \ -do { \ - if (strlen(path) > GBAGFX_MAX_PATH) \ - FATAL_ERROR("\"%s\" is too long a path.\n", path); \ -} while (0) +#endif // _MSC_VER #endif // GLOBAL_H diff --git a/tools/gbagfx/main.c b/tools/gbagfx/main.c index 472a87f79..56a1c2c7b 100644 --- a/tools/gbagfx/main.c +++ b/tools/gbagfx/main.c @@ -9,25 +9,18 @@ #include "convert_png.h" #include "jasc_pal.h" #include "lz.h" +#include "font.h" -void ConvertToPng(char *imageFilePath, char *outputFilePath, char *paletteFilePath, bool isObject, int width) +struct CommandHandler { - struct Image image; - int bitDepth = 0; - - char *extension = GetFileExtension(imageFilePath); - - if (extension == NULL) - FATAL_ERROR("\"%s\" has no file extension.\n", imageFilePath); + const char *inputFileExtension; + const char *outputFileExtension; + void(*function)(char *inputPath, char *outputPath, int argc, char **argv); +}; - if (strcmp(extension, "1bpp") == 0) - bitDepth = 1; - else if (strcmp(extension, "4bpp") == 0) - bitDepth = 4; - else if (strcmp(extension, "8bpp") == 0) - bitDepth = 8; - else - FATAL_ERROR("Unexpected file extension \"%s\". Expected \"1bpp\", \"4bpp\", or \"8bpp\".\n", extension); +void ConvertGbaToPng(char *inputPath, char *outputPath, int width, int bitDepth, char *paletteFilePath, bool hasTransparency) +{ + struct Image image; if (paletteFilePath != NULL) { ReadGbaPalette(paletteFilePath, &image.palette); @@ -36,249 +29,249 @@ void ConvertToPng(char *imageFilePath, char *outputFilePath, char *paletteFilePa image.hasPalette = false; } - ReadImage(imageFilePath, width, bitDepth, &image, !image.hasPalette); - - image.isObject = isObject; + ReadImage(inputPath, width, bitDepth, &image, !image.hasPalette); - if (outputFilePath == NULL) { - ChangeFileExtension(imageFilePath, "png"); - outputFilePath = imageFilePath; - } + image.hasTransparency = hasTransparency; - WritePng(outputFilePath, &image); + WritePng(outputPath, &image); FreeImage(&image); } -void ConvertFromPng(char *imageFilePath, char *outputFilePath, int numTiles, int bitDepth) +void ConvertPngToGba(char *inputPath, char *outputPath, int numTiles, int bitDepth) { struct Image image; image.bitDepth = bitDepth; - ExpectFileExtension(imageFilePath, "png"); - - ReadPng(imageFilePath, &image); - - if (outputFilePath == NULL) { - char newExtension[5]; - snprintf(newExtension, 5, "%dbpp", bitDepth); - ChangeFileExtension(imageFilePath, newExtension); - outputFilePath = imageFilePath; - } + ReadPng(inputPath, &image); - WriteImage(outputFilePath, numTiles, bitDepth, &image, !image.hasPalette); + WriteImage(outputPath, numTiles, bitDepth, &image, !image.hasPalette); FreeImage(&image); } -void ConvertToJascPalette(char *paletteFilePath) +void HandleGbaToPngCommand(char *inputPath, char *outputPath, int argc, char **argv) { - struct Palette palette; + char *inputFileExtension = GetFileExtension(inputPath); + int bitDepth = inputFileExtension[0] - '0'; + char *paletteFilePath; + bool hasPalette = false; + bool hasTransparency = false; + int width = 1; - ExpectFileExtension(paletteFilePath, "gbapal"); + for (int i = 3; i < argc; i++) { + char *option = argv[i]; - ReadGbaPalette(paletteFilePath, &palette); + if (strcmp(option, "-palette") == 0) { + if (i + 1 >= argc) + FATAL_ERROR("No palette file path following \"-palette\".\n"); - ChangeFileExtension(paletteFilePath, "pal"); + i++; - WriteJascPalette(paletteFilePath, &palette); -} + paletteFilePath = argv[i]; -void ConvertFromJascPalette(char *paletteFilePath) -{ - struct Palette palette; + hasPalette = true; + } else if (strcmp(option, "-object") == 0) { + hasTransparency = true; + } else if (strcmp(option, "-width") == 0) { + if (i + 1 >= argc) + FATAL_ERROR("No width following \"-width\".\n"); - ExpectFileExtension(paletteFilePath, "pal"); + i++; - ReadJascPalette(paletteFilePath, &palette); + if (!ParseNumber(argv[i], NULL, 10, &width)) + FATAL_ERROR("Failed to parse width.\n"); - ChangeFileExtension(paletteFilePath, "gbapal"); + if (width < 1) + FATAL_ERROR("Width must be positive.\n"); + } else { + FATAL_ERROR("Unrecognized option \"%s\".\n", option); + } + } - WriteGbaPalette(paletteFilePath, &palette); + ConvertGbaToPng(inputPath, outputPath, width, bitDepth, hasPalette ? paletteFilePath : NULL, hasTransparency); } -void LZCompressFile(char *path) +void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **argv) { - int fileSize; - unsigned char *buffer = ReadWholeFile(path, &fileSize); + char *outputFileExtension = GetFileExtension(outputPath); + int bitDepth = outputFileExtension[0] - '0'; + int numTiles = 0; - int compressedSize; - unsigned char *compressedData = LZCompress(buffer, fileSize, &compressedSize); + for (int i = 3; i < argc; i++) { + char *option = argv[i]; - free(buffer); + if (strcmp(option, "-num_tiles") == 0) { + if (i + 1 >= argc) + FATAL_ERROR("No number of tiles following \"-num_tiles\".\n"); - AddFileExtension(path, "lz"); + i++; - WriteWholeFile(path, compressedData, compressedSize); + if (!ParseNumber(argv[i], NULL, 10, &numTiles)) + FATAL_ERROR("Failed to parse number of tiles.\n"); - free(compressedData); + if (numTiles < 1) + FATAL_ERROR("Number of tiles must be positive.\n"); + } else { + FATAL_ERROR("Unrecognized option \"%s\".\n", option); + } + } + + ConvertPngToGba(inputPath, outputPath, numTiles, bitDepth); } -void LZDecompressFile(char *path) +void HandleGbaToJascPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) { - ExpectFileExtension(path, "lz"); - - int fileSize; - unsigned char *buffer = ReadWholeFile(path, &fileSize); - - int uncompressedSize; - unsigned char *uncompressedData = LZDecompress(buffer, fileSize, &uncompressedSize); - - free(buffer); - - RemoveFileExtension(path); - - WriteWholeFile(path, uncompressedData, uncompressedSize); + struct Palette palette; - free(uncompressedData); + ReadGbaPalette(inputPath, &palette); + WriteJascPalette(outputPath, &palette); } -int main(int argc, char **argv) +void HandleJascToGbaPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) { - if (argc < 2) - FATAL_ERROR("No args.\n"); - - char *command = argv[1]; - - if (strcmp(command, "png") == 0) { - if (argc < 3) - FATAL_ERROR("No image file path arg.\n"); - - CHECK_PATH_LENGTH(argv[2]); - - char imageFilePath[GBAGFX_MAX_PATH + 1]; - strcpy(imageFilePath, argv[2]); - - char *outputFilePath = NULL; - char paletteFilePath[GBAGFX_MAX_PATH + 1]; - bool hasPalette = false; - bool isObject = false; - int width = 1; - - for (int i = 3; i < argc; i++) { - char *option = argv[i]; - - if (strcmp(option, "-output") == 0) { - if (i + 1 >= argc) - FATAL_ERROR("No output file path following \"-output\".\n"); + struct Palette palette; - i++; + ReadJascPalette(inputPath, &palette); + WriteGbaPalette(outputPath, &palette); +} - outputFilePath = argv[i]; - } else if (strcmp(option, "-palette") == 0) { - if (i + 1 >= argc) - FATAL_ERROR("No palette file path following \"-palette\".\n"); +void HandleLatinFontToPngCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +{ + struct Image image; - i++; + ReadLatinFont(inputPath, &image); + WritePng(outputPath, &image); - CHECK_PATH_LENGTH(argv[i]); + FreeImage(&image); +} - strcpy(paletteFilePath, argv[i]); +void HandlePngToLatinFontCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +{ + struct Image image; - hasPalette = true; - } else if (strcmp(option, "-object") == 0) { - isObject = true; - } else if (strcmp(option, "-width") == 0) { - if (i + 1 >= argc) - FATAL_ERROR("No width following \"-width\".\n"); + image.bitDepth = 2; - i++; + ReadPng(inputPath, &image); + WriteLatinFont(outputPath, &image); - if (!ParseNumber(argv[i], NULL, 10, &width)) - FATAL_ERROR("Failed to parse width.\n"); + FreeImage(&image); +} - if (width < 1) - FATAL_ERROR("Width must be positive.\n"); - } else { - FATAL_ERROR("Unrecognized option \"%s\".\n", option); - } - } +void HandleHalfwidthJapaneseFontToPngCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +{ + struct Image image; - ConvertToPng(imageFilePath, outputFilePath, hasPalette ? paletteFilePath : NULL, isObject, width); - } else if (strcmp(command, "1bpp") == 0 || strcmp(command, "4bpp") == 0 || strcmp(command, "8bpp") == 0) { - if (argc < 3) - FATAL_ERROR("No image file path arg.\n"); + ReadHalfwidthJapaneseFont(inputPath, &image); + WritePng(outputPath, &image); - CHECK_PATH_LENGTH(argv[2]); + FreeImage(&image); +} - char imageFilePath[GBAGFX_MAX_PATH + 1]; - strcpy(imageFilePath, argv[2]); +void HandlePngToHalfwidthJapaneseFontCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +{ + struct Image image; - char *outputFilePath = NULL; - int numTiles = 0; - int bitDepth = command[0] - '0'; + image.bitDepth = 2; - for (int i = 3; i < argc; i++) { - char *option = argv[i]; + ReadPng(inputPath, &image); + WriteHalfwidthJapaneseFont(outputPath, &image); - if (strcmp(option, "-output") == 0) { - if (i + 1 >= argc) - FATAL_ERROR("No output file path following \"-output\".\n"); + FreeImage(&image); +} - i++; +void HandleFullwidthJapaneseFontToPngCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +{ + struct Image image; - outputFilePath = argv[i]; - } else if (strcmp(option, "-num_tiles") == 0) { - if (i + 1 >= argc) - FATAL_ERROR("No number of tiles following \"-num_tiles\".\n"); + ReadFullwidthJapaneseFont(inputPath, &image); + WritePng(outputPath, &image); - i++; + FreeImage(&image); +} - if (!ParseNumber(argv[i], NULL, 10, &numTiles)) - FATAL_ERROR("Failed to parse number of tiles.\n"); +void HandlePngToFullwidthJapaneseFontCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +{ + struct Image image; - if (numTiles < 1) - FATAL_ERROR("Number of tiles must be positive.\n"); - } else { - FATAL_ERROR("Unrecognized option \"%s\".\n", option); - } - } + image.bitDepth = 2; - ConvertFromPng(imageFilePath, outputFilePath, numTiles, bitDepth); - } else if (strcmp(command, "pal") == 0) { - if (argc < 3) - FATAL_ERROR("No palette file path arg.\n"); + ReadPng(inputPath, &image); + WriteFullwidthJapaneseFont(outputPath, &image); - CHECK_PATH_LENGTH(argv[2]); + FreeImage(&image); +} - char paletteFilePath[GBAGFX_MAX_PATH + 1]; - strcpy(paletteFilePath, argv[2]); +void HandleLZCompressCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +{ + int fileSize; + unsigned char *buffer = ReadWholeFile(inputPath, &fileSize); - ConvertToJascPalette(paletteFilePath); - } else if (strcmp(command, "gbapal") == 0) { - if (argc < 3) - FATAL_ERROR("No palette file path arg.\n"); + int compressedSize; + unsigned char *compressedData = LZCompress(buffer, fileSize, &compressedSize); - CHECK_PATH_LENGTH(argv[2]); + free(buffer); - char paletteFilePath[GBAGFX_MAX_PATH + 1]; - strcpy(paletteFilePath, argv[2]); + WriteWholeFile(outputPath, compressedData, compressedSize); - ConvertFromJascPalette(paletteFilePath); - } else if (strcmp(command, "lz") == 0) { - if (argc < 3) - FATAL_ERROR("No file path arg.\n"); + free(compressedData); +} - CHECK_PATH_LENGTH(argv[2]); +void HandleLZDecompressCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +{ + int fileSize; + unsigned char *buffer = ReadWholeFile(inputPath, &fileSize); - char path[GBAGFX_MAX_PATH + 1]; - strcpy(path, argv[2]); + int uncompressedSize; + unsigned char *uncompressedData = LZDecompress(buffer, fileSize, &uncompressedSize); - LZCompressFile(path); - } else if (strcmp(command, "unlz") == 0) { - if (argc < 3) - FATAL_ERROR("No file path arg.\n"); + free(buffer); - CHECK_PATH_LENGTH(argv[2]); + WriteWholeFile(outputPath, uncompressedData, uncompressedSize); - char path[GBAGFX_MAX_PATH + 1]; - strcpy(path, argv[2]); + free(uncompressedData); +} - LZDecompressFile(path); - } else { - FATAL_ERROR("Unrecognized command \"%s\".\n", command); +int main(int argc, char **argv) +{ + if (argc < 3) + FATAL_ERROR("Usage: gbagfx INPUT_PATH OUTPUT_PATH [options...]\n"); + + struct CommandHandler handlers[] = + { + { "1bpp", "png", HandleGbaToPngCommand }, + { "4bpp", "png", HandleGbaToPngCommand }, + { "8bpp", "png", HandleGbaToPngCommand }, + { "png", "1bpp", HandlePngToGbaCommand }, + { "png", "4bpp", HandlePngToGbaCommand }, + { "png", "8bpp", HandlePngToGbaCommand }, + { "gbapal", "pal", HandleGbaToJascPaletteCommand }, + { "pal", "gbapal", HandleJascToGbaPaletteCommand }, + { "latfont", "png", HandleLatinFontToPngCommand }, + { "png", "latfont", HandlePngToLatinFontCommand }, + { "hwjpnfont", "png", HandleHalfwidthJapaneseFontToPngCommand }, + { "png", "hwjpnfont", HandlePngToHalfwidthJapaneseFontCommand }, + { "fwjpnfont", "png", HandleFullwidthJapaneseFontToPngCommand }, + { "png", "fwjpnfont", HandlePngToFullwidthJapaneseFontCommand }, + { NULL, "lz", HandleLZCompressCommand }, + { "lz", NULL, HandleLZDecompressCommand }, + { NULL, NULL, NULL } + }; + + char *inputPath = argv[1]; + char *outputPath = argv[2]; + + for (int i = 0; handlers[i].function != NULL; i++) { + char *inputFileExtension = GetFileExtension(inputPath); + char *outputFileExtension = GetFileExtension(outputPath); + + if ((handlers[i].inputFileExtension == NULL || strcmp(handlers[i].inputFileExtension, inputFileExtension) == 0) + && (handlers[i].outputFileExtension == NULL || strcmp(handlers[i].outputFileExtension, outputFileExtension) == 0)) { + handlers[i].function(inputPath, outputPath, argc, argv); + return 0; + } } - return 0; + FATAL_ERROR("Don't know how to convert \"%s\" to \"%s\".\n", inputPath, outputPath); } diff --git a/tools/gbagfx/util.c b/tools/gbagfx/util.c index 180b93d9b..5af380184 100644 --- a/tools/gbagfx/util.c +++ b/tools/gbagfx/util.c @@ -58,48 +58,6 @@ char *GetFileExtension(char *path) return extension; } -void ExpectFileExtension(char *path, char *expectedExtension) -{ - char *extension = GetFileExtension(path); - - if (extension == NULL) - FATAL_ERROR("\"%s\" has no file extension.\n", path); - - if (strcmp(extension, expectedExtension) != 0) - FATAL_ERROR("Unexpected file extension \"%s\". Expected \"%s\".\n", extension, expectedExtension); -} - -void AddFileExtension(char *path, char *extension) -{ - int pathLength = strlen(path); - int extensionLength = strlen(extension); - - if (pathLength + 1 + extensionLength > GBAGFX_MAX_PATH) - FATAL_ERROR("\"%s\" is too long a path to add the extension \"%s\".\n", path, extension); - - path[pathLength] = '.'; - memcpy(path + pathLength + 1, extension, extensionLength); - path[pathLength + 1 + extensionLength] = 0; -} - -void RemoveFileExtension(char *path) -{ - char *extension = GetFileExtension(path); - - if (extension == NULL) - FATAL_ERROR("\"%s\" doesn't have a file extension.\n", path); - - extension--; - - *extension = 0; -} - -void ChangeFileExtension(char *path, char *extension) -{ - RemoveFileExtension(path); - AddFileExtension(path, extension); -} - unsigned char *ReadWholeFile(char *path, int *size) { FILE *fp = fopen(path, "rb"); diff --git a/tools/gbagfx/util.h b/tools/gbagfx/util.h index ec81471c0..cb26a31ef 100644 --- a/tools/gbagfx/util.h +++ b/tools/gbagfx/util.h @@ -7,10 +7,6 @@ bool ParseNumber(char *s, char **end, int radix, int *intValue); char *GetFileExtension(char *path); -void ExpectFileExtension(char *path, char *expectedExtension); -void AddFileExtension(char *path, char *extension); -void RemoveFileExtension(char *path); -void ChangeFileExtension(char *path, char *extension); unsigned char *ReadWholeFile(char *path, int *size); void WriteWholeFile(char *path, void *buffer, int bufferSize); |