diff options
author | red031000 <rubenru09@aol.com> | 2020-06-22 18:34:26 +0100 |
---|---|---|
committer | red031000 <rubenru09@aol.com> | 2020-06-22 18:34:26 +0100 |
commit | 49a400ceeb43a32108e4ab1cf8a1726b04ef3ddf (patch) | |
tree | e6bf1bf7072b46ce1a03b22783baead3eebb940f | |
parent | c9a26fd84fad7ba98035c22d13233e0bc4c429f6 (diff) |
nitrogfx NCGR support
-rw-r--r-- | tools/nitrogfx/convert_png.c | 2 | ||||
-rw-r--r-- | tools/nitrogfx/gfx.c | 124 | ||||
-rw-r--r-- | tools/nitrogfx/gfx.h | 1 | ||||
-rw-r--r-- | tools/nitrogfx/main.c | 121 | ||||
-rw-r--r-- | tools/nitrogfx/options.h | 10 |
5 files changed, 246 insertions, 12 deletions
diff --git a/tools/nitrogfx/convert_png.c b/tools/nitrogfx/convert_png.c index cdfa39a7..efd6989f 100644 --- a/tools/nitrogfx/convert_png.c +++ b/tools/nitrogfx/convert_png.c @@ -162,6 +162,8 @@ void ReadPngPalette(char *path, struct Palette *palette) palette->colors[i].blue = colors[i].blue; } + palette->bitDepth = png_get_bit_depth(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); diff --git a/tools/nitrogfx/gfx.c b/tools/nitrogfx/gfx.c index 31ebf64b..3d9d5848 100644 --- a/tools/nitrogfx/gfx.c +++ b/tools/nitrogfx/gfx.c @@ -359,6 +359,98 @@ void WriteImage(char *path, int numTiles, int bitDepth, int metatileWidth, int m free(buffer); } +void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors, bool clobberSize, bool byteOrder) +{ + FILE *fp = fopen(path, "wb"); + + if (fp == NULL) + FATAL_ERROR("Failed to open \"%s\" for writing.\n", path); + + int tileSize = bitDepth * 8; + + if (image->width % 8 != 0) + FATAL_ERROR("The width in pixels (%d) isn't a multiple of 8.\n", image->width); + + if (image->height % 8 != 0) + FATAL_ERROR("The height in pixels (%d) isn't a multiple of 8.\n", image->height); + + int tilesWidth = image->width / 8; + int tilesHeight = image->height / 8; + + if (tilesWidth % metatileWidth != 0) + FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth); + + if (tilesHeight % metatileHeight != 0) + FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight, metatileHeight); + + int maxNumTiles = tilesWidth * tilesHeight; + + if (numTiles == 0) + numTiles = maxNumTiles; + else if (numTiles > maxNumTiles) + FATAL_ERROR("The specified number of tiles (%d) is greater than the maximum possible value (%d).\n", numTiles, maxNumTiles); + + int bufferSize = numTiles * tileSize; + unsigned char *pixelBuffer = malloc(bufferSize); + + if (pixelBuffer == NULL) + FATAL_ERROR("Failed to allocate memory for pixels.\n"); + + int metatilesWide = tilesWidth / metatileWidth; + + switch (bitDepth) { + case 4: + ConvertToTiles4Bpp(image->pixels, pixelBuffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); + break; + case 8: + ConvertToTiles8Bpp(image->pixels, pixelBuffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); + break; + } + + WriteGenericNtrHeader(fp, "RGCN", bufferSize + 0x20, byteOrder); + + unsigned char charHeader[0x20] = { 0x52, 0x41, 0x48, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00 }; + + charHeader[4] = (bufferSize + 0x20) & 0xFF; + charHeader[5] = ((bufferSize + 0x20) >> 8) & 0xFF; + charHeader[6] = ((bufferSize + 0x20) >> 16) & 0xFF; + charHeader[7] = ((bufferSize + 0x20) >> 24) & 0xFF; + + if (!clobberSize) + { + charHeader[8] = numTiles & 0xFF; + charHeader[9] = (numTiles >> 8) & 0xFF; + + charHeader[10] = tileSize & 0xFF; + charHeader[11] = (tileSize >> 8) & 0xFF; + } + else + { + charHeader[8] = 0xFF; + charHeader[9] = 0xFF; + charHeader[10] = 0xFF; + charHeader[11] = 0xFF; + + charHeader[16] = 0x10; //seems to be set when size is clobbered + } + + charHeader[12] = bitDepth == 4 ? 3 : 4; + + charHeader[24] = bufferSize & 0xFF; + charHeader[25] = (bufferSize >> 8) & 0xFF; + charHeader[26] = (bufferSize >> 16) & 0xFF; + charHeader[27] = (bufferSize >> 24) & 0xFF; + + fwrite(charHeader, 1, 0x20, fp); + + fwrite(pixelBuffer, 1, bufferSize, fp); + + free(pixelBuffer); + fclose(fp); +} + void FreeImage(struct Image *image) { free(image->pixels); @@ -450,7 +542,7 @@ void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr) if (fp == NULL) FATAL_ERROR("Failed to open \"%s\" for writing.\n", path); - uint32_t size = palette->numColors * 2; + uint32_t size = 256 * 2; //todo check if there's a better way to detect :/ uint32_t extSize = size + (ncpr ? 0x10 : 0x18); //NCLR header @@ -481,21 +573,29 @@ void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr) fwrite(palHeader, 1, 0x18, fp); - unsigned char colours[palette->numColors * 2]; + unsigned char colours[256 * 2]; //palette data - for (int i = 0; i < palette->numColors; i++) + for (int i = 0; i < 256; i++) { - unsigned char red = DOWNCONVERT_BIT_DEPTH(palette->colors[i].red); - unsigned char green = DOWNCONVERT_BIT_DEPTH(palette->colors[i].green); - unsigned char blue = DOWNCONVERT_BIT_DEPTH(palette->colors[i].blue); - - uint16_t paletteEntry = SET_GBA_PAL(red, green, blue); - - colours[i * 2] = paletteEntry & 0xFF; - colours[i * 2 + 1] = paletteEntry >> 8; + if (i < palette->numColors) + { + unsigned char red = DOWNCONVERT_BIT_DEPTH(palette->colors[i].red); + unsigned char green = DOWNCONVERT_BIT_DEPTH(palette->colors[i].green); + unsigned char blue = DOWNCONVERT_BIT_DEPTH(palette->colors[i].blue); + + uint16_t paletteEntry = SET_GBA_PAL(red, green, blue); + + colours[i * 2] = paletteEntry & 0xFF; + colours[i * 2 + 1] = paletteEntry >> 8; + } + else + { + colours[i * 2] = 0x00; + colours[i * 2 + 1] = 0x00; + } } - fwrite(colours, 1, palette->numColors * 2, fp); + fwrite(colours, 1, 256 * 2, fp); fclose(fp); } diff --git a/tools/nitrogfx/gfx.h b/tools/nitrogfx/gfx.h index 9835021e..da56c5c5 100644 --- a/tools/nitrogfx/gfx.h +++ b/tools/nitrogfx/gfx.h @@ -31,6 +31,7 @@ struct Image { void ReadImage(char *path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors); void ReadNtrImage(char *path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors); void WriteImage(char *path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors); +void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors, bool clobberSize, bool byteOrder); void FreeImage(struct Image *image); void ReadGbaPalette(char *path, struct Palette *palette); void ReadNtrPalette(char *path, struct Palette *palette); diff --git a/tools/nitrogfx/main.c b/tools/nitrogfx/main.c index aa46d7b0..2f5b2735 100644 --- a/tools/nitrogfx/main.c +++ b/tools/nitrogfx/main.c @@ -80,6 +80,19 @@ void ConvertPngToGba(char *inputPath, char *outputPath, struct PngToGbaOptions * FreeImage(&image); } +void ConvertPngToNtr(char *inputPath, char *outputPath, struct PngToNtrOptions *options) +{ + struct Image image; + + image.bitDepth = options->bitDepth; + + ReadPng(inputPath, &image); + + WriteNtrImage(outputPath, options->numTiles, options->bitDepth, options->metatileWidth, options->metatileHeight, &image, !image.hasPalette, options->clobberSize, options->byteOrder); + + FreeImage(&image); +} + void HandleGbaToPngCommand(char *inputPath, char *outputPath, int argc, char **argv) { char *inputFileExtension = GetFileExtension(inputPath); @@ -298,6 +311,89 @@ void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **a ConvertPngToGba(inputPath, outputPath, &options); } +void HandlePngToNtrCommand(char *inputPath, char *outputPath, int argc, char **argv) +{ + struct PngToNtrOptions options; + options.numTiles = 0; + options.bitDepth = 4; + options.metatileWidth = 1; + options.metatileHeight = 1; + options.clobberSize = false; + options.byteOrder = true; + + for (int i = 3; i < argc; i++) + { + char *option = argv[i]; + + if (strcmp(option, "-num_tiles") == 0) + { + if (i + 1 >= argc) + FATAL_ERROR("No number of tiles following \"-num_tiles\".\n"); + + i++; + + if (!ParseNumber(argv[i], NULL, 10, &options.numTiles)) + FATAL_ERROR("Failed to parse number of tiles.\n"); + + if (options.numTiles < 1) + FATAL_ERROR("Number of tiles must be positive.\n"); + } + else if (strcmp(option, "-mwidth") == 0) + { + if (i + 1 >= argc) + FATAL_ERROR("No metatile width value following \"-mwidth\".\n"); + + i++; + + if (!ParseNumber(argv[i], NULL, 10, &options.metatileWidth)) + FATAL_ERROR("Failed to parse metatile width.\n"); + + if (options.metatileWidth < 1) + FATAL_ERROR("metatile width must be positive.\n"); + } + else if (strcmp(option, "-mheight") == 0) + { + if (i + 1 >= argc) + FATAL_ERROR("No metatile height value following \"-mheight\".\n"); + + i++; + + if (!ParseNumber(argv[i], NULL, 10, &options.metatileHeight)) + FATAL_ERROR("Failed to parse metatile height.\n"); + + if (options.metatileHeight < 1) + FATAL_ERROR("metatile height must be positive.\n"); + } + else if (strcmp(option, "-bitdepth") == 0) + { + if (i + 1 >= argc) + FATAL_ERROR("No bitdepth value following \"-bitdepth\".\n"); + + i++; + + if (!ParseNumber(argv[i], NULL, 10, &options.bitDepth)) + FATAL_ERROR("Failed to parse bitdepth.\n"); + + if (options.bitDepth != 4 && options.bitDepth != 8) + FATAL_ERROR("bitdepth must be either 4 or 8.\n"); + } + else if (strcmp(option, "-clobbersize") == 0) + { + options.clobberSize = true; + } + else if (strcmp(option, "-nobyteorder") == 0) + { + options.byteOrder = false; + } + else + { + FATAL_ERROR("Unrecognized option \"%s\".\n", option); + } + } + + ConvertPngToNtr(inputPath, outputPath, &options); +} + void HandlePngToGbaPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) { struct Palette palette; @@ -306,6 +402,29 @@ void HandlePngToGbaPaletteCommand(char *inputPath, char *outputPath, int argc UN WriteGbaPalette(outputPath, &palette); } +void HandlePngToNtrPaletteCommand(char *inputPath, char *outputPath, int argc, char **argv) +{ + struct Palette palette; + bool ncpr = false; + + for (int i = 3; i < argc; i++) + { + char *option = argv[i]; + + if (strcmp(option, "-ncpr") == 0) + { + ncpr = true; + } + else + { + FATAL_ERROR("Unrecognized option \"%s\".\n", option); + } + } + + ReadPngPalette(inputPath, &palette); + WriteNtrPalette(outputPath, &palette, ncpr); +} + void HandleGbaToJascPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) { struct Palette palette; @@ -645,7 +764,9 @@ int main(int argc, char **argv) { "png", "1bpp", HandlePngToGbaCommand }, { "png", "4bpp", HandlePngToGbaCommand }, { "png", "8bpp", HandlePngToGbaCommand }, + { "png", "NCGR", HandlePngToNtrCommand }, { "png", "gbapal", HandlePngToGbaPaletteCommand }, + { "png", "NCLR", HandlePngToNtrPaletteCommand }, { "gbapal", "pal", HandleGbaToJascPaletteCommand }, { "NCLR", "pal", HandleNtrToJascPaletteCommand }, { "NCPR", "pal", HandleNtrToJascPaletteCommand }, diff --git a/tools/nitrogfx/options.h b/tools/nitrogfx/options.h index 2ff3967a..8376348f 100644 --- a/tools/nitrogfx/options.h +++ b/tools/nitrogfx/options.h @@ -21,4 +21,14 @@ struct PngToGbaOptions { int metatileHeight; }; +struct PngToNtrOptions { + int numTiles; + int bitDepth; + int metatileWidth; + int metatileHeight; + bool clobberSize; + bool byteOrder; +}; + + #endif // OPTIONS_H |