summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/nitrogfx/convert_png.c2
-rw-r--r--tools/nitrogfx/gfx.c124
-rw-r--r--tools/nitrogfx/gfx.h1
-rw-r--r--tools/nitrogfx/main.c121
-rw-r--r--tools/nitrogfx/options.h10
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