diff options
author | Marcus Huderle <huderlem@gmail.com> | 2018-10-13 10:22:58 -0500 |
---|---|---|
committer | Marcus Huderle <huderlem@gmail.com> | 2018-10-13 10:22:58 -0500 |
commit | b24559d69b6fa0abf042a1b7cdbcab3d1ec91fd6 (patch) | |
tree | 7b51d7b9cb9a370fe1dd9db8eeadc23089ba1328 /tools | |
parent | fa9d1759bd7fa17ced37225bd31d46466da857c6 (diff) | |
parent | a2a6700966cc802185577e44ba88a9154429c93b (diff) |
Merge remote-tracking branch 'upstream/master' into shop
# Conflicts:
# asm/shop.s
Diffstat (limited to 'tools')
-rw-r--r-- | tools/gbafix/.gitignore | 1 | ||||
-rw-r--r-- | tools/gbafix/gbafix.c | 32 | ||||
-rw-r--r-- | tools/gbagfx/Makefile | 7 | ||||
-rw-r--r-- | tools/gbagfx/gfx.c | 175 | ||||
-rw-r--r-- | tools/gbagfx/gfx.h | 4 | ||||
-rw-r--r-- | tools/gbagfx/main.c | 105 | ||||
-rw-r--r-- | tools/gbagfx/options.h | 24 | ||||
-rw-r--r-- | tools/mid2agb/Makefile | 7 | ||||
-rw-r--r-- | tools/mid2agb/agb.cpp | 97 | ||||
-rw-r--r-- | tools/mid2agb/main.cpp | 117 | ||||
-rw-r--r-- | tools/mid2agb/midi.cpp | 26 | ||||
-rw-r--r-- | tools/preproc/c_file.cpp | 92 | ||||
-rw-r--r-- | tools/scaninc/c_file.cpp | 17 |
13 files changed, 474 insertions, 230 deletions
diff --git a/tools/gbafix/.gitignore b/tools/gbafix/.gitignore index 23abdd29c..3cebf8ae8 100644 --- a/tools/gbafix/.gitignore +++ b/tools/gbafix/.gitignore @@ -1 +1,2 @@ gbafix +README diff --git a/tools/gbafix/gbafix.c b/tools/gbafix/gbafix.c index 60e4ccb4f..d5e2f62ab 100644 --- a/tools/gbafix/gbafix.c +++ b/tools/gbafix/gbafix.c @@ -33,6 +33,7 @@ History ------- + v1.06 - added output silencing, (Diegoisawesome) v1.05 - added debug offset argument, (Diegoisawesome) v1.04 - converted to plain C, (WinterMute) v1.03 - header.fixed, header.device_type @@ -48,7 +49,7 @@ #include <string.h> #include <stdint.h> -#define VER "1.05" +#define VER "1.06" #define ARGV argv[arg] #define VALUE (ARGV+2) #define NUMBER strtoul(VALUE, NULL, 0) @@ -135,6 +136,7 @@ int main(int argc, char *argv[]) int arg; char *argfile = 0; FILE *infile; + int silent = 0; int size,bit; @@ -142,7 +144,7 @@ int main(int argc, char *argv[]) if (argc <= 1) { printf("GBA ROM fixer v"VER" by Dark Fader / BlackThunder / WinterMute / Diegoisawesome \n"); - printf("Syntax: gbafix <rom.gba> [-p] [-t[title]] [-c<game_code>] [-m<maker_code>] [-r<version>] [-d<debug>]\n"); + printf("Syntax: gbafix <rom.gba> [-p] [-t[title]] [-c<game_code>] [-m<maker_code>] [-r<version>] [-d<debug>] [--silent]\n"); printf("\n"); printf("parameters:\n"); printf(" -p Pad to next exact power of 2. No minimum size!\n"); @@ -151,25 +153,27 @@ int main(int argc, char *argv[]) printf(" -m<maker_code> Patch maker code (two characters)\n"); printf(" -r<version> Patch game version (number)\n"); printf(" -d<debug> Enable debugging handler and set debug entry point (0 or 1)\n"); + printf(" --silent Silence non-error output\n"); return -1; } // get filename for (arg=1; arg<argc; arg++) { - if ((ARGV[0] != '-')) { argfile=ARGV; break; } + if ((ARGV[0] != '-')) { argfile=ARGV; } + if (strncmp("--silent", &ARGV[0], 7) == 0) { silent = 1; } } // check filename if (!argfile) { - printf("Filename needed!\n"); + fprintf(stderr, "Filename needed!\n"); return -1; } // read file infile = fopen(argfile, "r+b"); - if (!infile) { printf("Error opening input file!\n"); return -1; } + if (!infile) { fprintf(stderr, "Error opening input file!\n"); return -1; } fseek(infile, 0, SEEK_SET); fread(&header, sizeof(header), 1, infile); @@ -215,7 +219,7 @@ int main(int argc, char *argv[]) t = strrchr(s, '/'); if (t) begin = t+1; t = strrchr(s, '.'); if (t) *t = 0; strncpy(title, begin, sizeof(header.title)); - printf("%s\n",begin); + if (!silent) printf("%s\n",begin); } memcpy(header.title, title, sizeof(header.title)); // copy break; @@ -223,7 +227,7 @@ int main(int argc, char *argv[]) case 'c': // game code { - //if (!VALUE[0]) { printf("Need value for %s\n", ARGV); break; } + //if (!VALUE[0]) { fprintf(stderr, "Need value for %s\n", ARGV); break; } //header.game_code = NUMBER; header.game_code = VALUE[0] | VALUE[1]<<8 | VALUE[2]<<16 | VALUE[3]<<24; break; @@ -231,7 +235,7 @@ int main(int argc, char *argv[]) case 'm': // maker code { - //if (!VALUE[0]) { printf("Need value for %s\n", ARGV); break; } + //if (!VALUE[0]) { fprintf(stderr, "Need value for %s\n", ARGV); break; } //header.maker_code = (unsigned short)NUMBER; header.maker_code = VALUE[0] | VALUE[1]<<8; break; @@ -244,19 +248,23 @@ int main(int argc, char *argv[]) case 'r': // version { - if (!VALUE[0]) { printf("Need value for %s\n", ARGV); break; } + if (!VALUE[0]) { fprintf(stderr, "Need value for %s\n", ARGV); break; } header.game_version = (unsigned char)NUMBER; break; } case 'd': // debug { - if (!VALUE[0]) { printf("Need value for %s\n", ARGV); break; } + if (!VALUE[0]) { fprintf(stderr, "Need value for %s\n", ARGV); break; } header.logo[0x9C-0x04] = 0xA5; // debug enable header.device_type = (unsigned char)((NUMBER & 1) << 7); // debug handler entry point break; } - + case '-': // long arguments + { + if (strncmp("silent", &ARGV[2], 6) == 0) { continue; } + break; + } default: { printf("Invalid option: %s\n", ARGV); @@ -275,7 +283,7 @@ int main(int argc, char *argv[]) fwrite(&header, sizeof(header), 1, infile); fclose(infile); - printf("ROM fixed!\n"); + if (!silent) printf("ROM fixed!\n"); return 0; } diff --git a/tools/gbagfx/Makefile b/tools/gbagfx/Makefile index 6f11b1b3f..c10b258de 100644 --- a/tools/gbagfx/Makefile +++ b/tools/gbagfx/Makefile @@ -1,12 +1,15 @@ CC = gcc -CFLAGS = -Wall -Wextra -Werror -std=c11 -O2 -DPNG_SKIP_SETJMP_CHECK +CFLAGS = -Wall -Wextra -Werror -std=c11 -O2 -s -DPNG_SKIP_SETJMP_CHECK LIBS = -lpng -lz SRCS = main.c convert_png.c gfx.c jasc_pal.c lz.c rl.c util.c font.c -.PHONY: clean +.PHONY: all clean + +all: gbagfx + @: gbagfx: $(SRCS) convert_png.h gfx.h global.h jasc_pal.h lz.h rl.h util.h font.h $(CC) $(CFLAGS) $(SRCS) -o $@ $(LDFLAGS) $(LIBS) diff --git a/tools/gbagfx/gfx.c b/tools/gbagfx/gfx.c index c0f7f492c..f927deed9 100644 --- a/tools/gbagfx/gfx.c +++ b/tools/gbagfx/gfx.c @@ -18,16 +18,35 @@ #define DOWNCONVERT_BIT_DEPTH(x) ((x) / 8) -static void ConvertFromTiles1Bpp(unsigned char *src, unsigned char *dest, int numTiles, int tilesWidth, bool invertColors) +static void AdvanceMetatilePosition(int *subTileX, int *subTileY, int *metatileX, int *metatileY, int metatilesWide, int metatileWidth, int metatileHeight) { - int tilesX = 0; - int tilesY = 0; - int pitch = tilesWidth; + (*subTileX)++; + if (*subTileX == metatileWidth) { + *subTileX = 0; + (*subTileY)++; + if (*subTileY == metatileHeight) { + *subTileY = 0; + (*metatileX)++; + if (*metatileX == metatilesWide) { + *metatileX = 0; + (*metatileY)++; + } + } + } +} + +static void ConvertFromTiles1Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) +{ + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = metatilesWide * metatileWidth; for (int i = 0; i < numTiles; i++) { for (int j = 0; j < 8; j++) { - int destY = tilesY * 8 + j; - int destX = tilesX; + int destY = (metatileY * metatileHeight + subTileY) * 8 + j; + int destX = metatileX * metatileWidth + subTileX; unsigned char srcPixelOctet = *src++; unsigned char *destPixelOctet = &dest[destY * pitch + destX]; @@ -38,27 +57,24 @@ static void ConvertFromTiles1Bpp(unsigned char *src, unsigned char *dest, int nu } } - tilesX++; - - if (tilesX == tilesWidth) { - tilesX = 0; - tilesY++; - } + AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); } } -static void ConvertFromTiles4Bpp(unsigned char *src, unsigned char *dest, int numTiles, int tilesWidth, bool invertColors) +static void ConvertFromTiles4Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) { - int tilesX = 0; - int tilesY = 0; - int pitch = tilesWidth * 4; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = (metatilesWide * metatileWidth) * 4; for (int i = 0; i < numTiles; i++) { for (int j = 0; j < 8; j++) { - int destY = tilesY * 8 + j; + int destY = (metatileY * metatileHeight + subTileY) * 8 + j; for (int k = 0; k < 4; k++) { - int destX = tilesX * 4 + k; + int destX = (metatileX * metatileWidth + subTileX) * 4 + k; unsigned char srcPixelPair = *src++; unsigned char leftPixel = srcPixelPair & 0xF; unsigned char rightPixel = srcPixelPair >> 4; @@ -72,27 +88,24 @@ static void ConvertFromTiles4Bpp(unsigned char *src, unsigned char *dest, int nu } } - tilesX++; - - if (tilesX == tilesWidth) { - tilesX = 0; - tilesY++; - } + AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); } } -static void ConvertFromTiles8Bpp(unsigned char *src, unsigned char *dest, int numTiles, int tilesWidth, bool invertColors) +static void ConvertFromTiles8Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) { - int tilesX = 0; - int tilesY = 0; - int pitch = tilesWidth * 8; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = (metatilesWide * metatileWidth) * 8; for (int i = 0; i < numTiles; i++) { for (int j = 0; j < 8; j++) { - int destY = tilesY * 8 + j; + int destY = (metatileY * metatileHeight + subTileY) * 8 + j; for (int k = 0; k < 8; k++) { - int destX = tilesX * 8 + k; + int destX = (metatileX * metatileWidth + subTileX) * 8 + k; unsigned char srcPixel = *src++; if (invertColors) @@ -102,25 +115,22 @@ static void ConvertFromTiles8Bpp(unsigned char *src, unsigned char *dest, int nu } } - tilesX++; - - if (tilesX == tilesWidth) { - tilesX = 0; - tilesY++; - } + AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); } } -static void ConvertToTiles1Bpp(unsigned char *src, unsigned char *dest, int numTiles, int tilesWidth, bool invertColors) +static void ConvertToTiles1Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) { - int tilesX = 0; - int tilesY = 0; - int pitch = tilesWidth; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = metatilesWide * metatileWidth; for (int i = 0; i < numTiles; i++) { for (int j = 0; j < 8; j++) { - int srcY = tilesY * 8 + j; - int srcX = tilesX; + int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; + int srcX = metatileX * metatileWidth + subTileX; unsigned char srcPixelOctet = src[srcY * pitch + srcX]; unsigned char *destPixelOctet = dest++; @@ -131,27 +141,24 @@ static void ConvertToTiles1Bpp(unsigned char *src, unsigned char *dest, int numT } } - tilesX++; - - if (tilesX == tilesWidth) { - tilesX = 0; - tilesY++; - } + AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); } } -static void ConvertToTiles4Bpp(unsigned char *src, unsigned char *dest, int numTiles, int tilesWidth, bool invertColors) +static void ConvertToTiles4Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) { - int tilesX = 0; - int tilesY = 0; - int pitch = tilesWidth * 4; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = (metatilesWide * metatileWidth) * 4; for (int i = 0; i < numTiles; i++) { for (int j = 0; j < 8; j++) { - int srcY = tilesY * 8 + j; + int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; for (int k = 0; k < 4; k++) { - int srcX = tilesX * 4 + k; + int srcX = (metatileX * metatileWidth + subTileX) * 4 + k; unsigned char srcPixelPair = src[srcY * pitch + srcX]; unsigned char leftPixel = srcPixelPair >> 4; unsigned char rightPixel = srcPixelPair & 0xF; @@ -165,27 +172,24 @@ static void ConvertToTiles4Bpp(unsigned char *src, unsigned char *dest, int numT } } - tilesX++; - - if (tilesX == tilesWidth) { - tilesX = 0; - tilesY++; - } + AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); } } -static void ConvertToTiles8Bpp(unsigned char *src, unsigned char *dest, int numTiles, int tilesWidth, bool invertColors) +static void ConvertToTiles8Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) { - int tilesX = 0; - int tilesY = 0; - int pitch = tilesWidth * 8; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = (metatilesWide * metatileWidth) * 8; for (int i = 0; i < numTiles; i++) { for (int j = 0; j < 8; j++) { - int srcY = tilesY * 8 + j; + int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; for (int k = 0; k < 8; k++) { - int srcX = tilesX * 8 + k; + int srcX = (metatileX * metatileWidth + subTileX) * 8 + k; unsigned char srcPixel = src[srcY * pitch + srcX]; if (invertColors) @@ -195,16 +199,11 @@ static void ConvertToTiles8Bpp(unsigned char *src, unsigned char *dest, int numT } } - tilesX++; - - if (tilesX == tilesWidth) { - tilesX = 0; - tilesY++; - } + AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); } } -void ReadImage(char *path, int tilesWidth, int bitDepth, struct Image *image, bool invertColors) +void ReadImage(char *path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors) { int tileSize = bitDepth * 8; @@ -215,6 +214,12 @@ void ReadImage(char *path, int tilesWidth, int bitDepth, struct Image *image, bo int tilesHeight = (numTiles + tilesWidth - 1) / tilesWidth; + 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); + image->width = tilesWidth * 8; image->height = tilesHeight * 8; image->bitDepth = bitDepth; @@ -223,22 +228,24 @@ void ReadImage(char *path, int tilesWidth, int bitDepth, struct Image *image, bo if (image->pixels == NULL) FATAL_ERROR("Failed to allocate memory for pixels.\n"); + int metatilesWide = tilesWidth / metatileWidth; + switch (bitDepth) { case 1: - ConvertFromTiles1Bpp(buffer, image->pixels, numTiles, tilesWidth, invertColors); + ConvertFromTiles1Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); break; case 4: - ConvertFromTiles4Bpp(buffer, image->pixels, numTiles, tilesWidth, invertColors); + ConvertFromTiles4Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); break; case 8: - ConvertFromTiles8Bpp(buffer, image->pixels, numTiles, tilesWidth, invertColors); + ConvertFromTiles8Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); break; } free(buffer); } -void WriteImage(char *path, int numTiles, int bitDepth, struct Image *image, bool invertColors) +void WriteImage(char *path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors) { int tileSize = bitDepth * 8; @@ -251,6 +258,12 @@ void WriteImage(char *path, int numTiles, int bitDepth, struct Image *image, boo 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) @@ -264,15 +277,17 @@ void WriteImage(char *path, int numTiles, int bitDepth, struct Image *image, boo if (buffer == NULL) FATAL_ERROR("Failed to allocate memory for pixels.\n"); + int metatilesWide = tilesWidth / metatileWidth; + switch (bitDepth) { case 1: - ConvertToTiles1Bpp(image->pixels, buffer, numTiles, tilesWidth, invertColors); + ConvertToTiles1Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); break; case 4: - ConvertToTiles4Bpp(image->pixels, buffer, numTiles, tilesWidth, invertColors); + ConvertToTiles4Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); break; case 8: - ConvertToTiles8Bpp(image->pixels, buffer, numTiles, tilesWidth, invertColors); + ConvertToTiles8Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); break; } diff --git a/tools/gbagfx/gfx.h b/tools/gbagfx/gfx.h index ecd436652..5355ced85 100644 --- a/tools/gbagfx/gfx.h +++ b/tools/gbagfx/gfx.h @@ -27,8 +27,8 @@ struct Image { bool hasTransparency; }; -void ReadImage(char *path, int tilesWidth, int bitDepth, struct Image *image, bool invertColors); -void WriteImage(char *path, int numTiles, int bitDepth, struct Image *image, bool invertColors); +void ReadImage(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 FreeImage(struct Image *image); void ReadGbaPalette(char *path, struct Palette *palette); void WriteGbaPalette(char *path, struct Palette *palette); diff --git a/tools/gbagfx/main.c b/tools/gbagfx/main.c index 97db60e84..86b0afa53 100644 --- a/tools/gbagfx/main.c +++ b/tools/gbagfx/main.c @@ -5,6 +5,7 @@ #include <stdbool.h> #include "global.h" #include "util.h" +#include "options.h" #include "gfx.h" #include "convert_png.h" #include "jasc_pal.h" @@ -19,13 +20,13 @@ struct CommandHandler void(*function)(char *inputPath, char *outputPath, int argc, char **argv); }; -void ConvertGbaToPng(char *inputPath, char *outputPath, int width, int bitDepth, char *paletteFilePath, bool hasTransparency) +void ConvertGbaToPng(char *inputPath, char *outputPath, struct GbaToPngOptions *options) { struct Image image; - if (paletteFilePath != NULL) + if (options->paletteFilePath != NULL) { - ReadGbaPalette(paletteFilePath, &image.palette); + ReadGbaPalette(options->paletteFilePath, &image.palette); image.hasPalette = true; } else @@ -33,24 +34,24 @@ void ConvertGbaToPng(char *inputPath, char *outputPath, int width, int bitDepth, image.hasPalette = false; } - ReadImage(inputPath, width, bitDepth, &image, !image.hasPalette); + ReadImage(inputPath, options->width, options->bitDepth, options->metatileWidth, options->metatileHeight, &image, !image.hasPalette); - image.hasTransparency = hasTransparency; + image.hasTransparency = options->hasTransparency; WritePng(outputPath, &image); FreeImage(&image); } -void ConvertPngToGba(char *inputPath, char *outputPath, int numTiles, int bitDepth) +void ConvertPngToGba(char *inputPath, char *outputPath, struct PngToGbaOptions *options) { struct Image image; - image.bitDepth = bitDepth; + image.bitDepth = options->bitDepth; ReadPng(inputPath, &image); - WriteImage(outputPath, numTiles, bitDepth, &image, !image.hasPalette); + WriteImage(outputPath, options->numTiles, options->bitDepth, options->metatileWidth, options->metatileHeight, &image, !image.hasPalette); FreeImage(&image); } @@ -58,10 +59,13 @@ void ConvertPngToGba(char *inputPath, char *outputPath, int numTiles, int bitDep void HandleGbaToPngCommand(char *inputPath, char *outputPath, int argc, char **argv) { char *inputFileExtension = GetFileExtension(inputPath); - int bitDepth = inputFileExtension[0] - '0'; - char *paletteFilePath = NULL; - bool hasTransparency = false; - int width = 1; + struct GbaToPngOptions options; + options.paletteFilePath = NULL; + options.bitDepth = inputFileExtension[0] - '0'; + options.hasTransparency = false; + options.width = 1; + options.metatileWidth = 1; + options.metatileHeight = 1; for (int i = 3; i < argc; i++) { @@ -74,11 +78,11 @@ void HandleGbaToPngCommand(char *inputPath, char *outputPath, int argc, char **a i++; - paletteFilePath = argv[i]; + options.paletteFilePath = argv[i]; } else if (strcmp(option, "-object") == 0) { - hasTransparency = true; + options.hasTransparency = true; } else if (strcmp(option, "-width") == 0) { @@ -87,26 +91,59 @@ void HandleGbaToPngCommand(char *inputPath, char *outputPath, int argc, char **a i++; - if (!ParseNumber(argv[i], NULL, 10, &width)) + if (!ParseNumber(argv[i], NULL, 10, &options.width)) FATAL_ERROR("Failed to parse width.\n"); - if (width < 1) + if (options.width < 1) FATAL_ERROR("Width 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 { FATAL_ERROR("Unrecognized option \"%s\".\n", option); } } - ConvertGbaToPng(inputPath, outputPath, width, bitDepth, paletteFilePath, hasTransparency); + if (options.metatileWidth > options.width) + options.width = options.metatileWidth; + + ConvertGbaToPng(inputPath, outputPath, &options); } void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **argv) { char *outputFileExtension = GetFileExtension(outputPath); int bitDepth = outputFileExtension[0] - '0'; - int numTiles = 0; + struct PngToGbaOptions options; + options.numTiles = 0; + options.bitDepth = bitDepth; + options.metatileWidth = 1; + options.metatileHeight = 1; for (int i = 3; i < argc; i++) { @@ -119,19 +156,45 @@ void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **a i++; - if (!ParseNumber(argv[i], NULL, 10, &numTiles)) + if (!ParseNumber(argv[i], NULL, 10, &options.numTiles)) FATAL_ERROR("Failed to parse number of tiles.\n"); - if (numTiles < 1) + 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 { FATAL_ERROR("Unrecognized option \"%s\".\n", option); } } - ConvertPngToGba(inputPath, outputPath, numTiles, bitDepth); + ConvertPngToGba(inputPath, outputPath, &options); } void HandlePngToGbaPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) diff --git a/tools/gbagfx/options.h b/tools/gbagfx/options.h new file mode 100644 index 000000000..2ff3967a4 --- /dev/null +++ b/tools/gbagfx/options.h @@ -0,0 +1,24 @@ +// Copyright (c) 2018 huderlem + +#ifndef OPTIONS_H +#define OPTIONS_H + +#include <stdbool.h> + +struct GbaToPngOptions { + char *paletteFilePath; + int bitDepth; + bool hasTransparency; + int width; + int metatileWidth; + int metatileHeight; +}; + +struct PngToGbaOptions { + int numTiles; + int bitDepth; + int metatileWidth; + int metatileHeight; +}; + +#endif // OPTIONS_H diff --git a/tools/mid2agb/Makefile b/tools/mid2agb/Makefile index 7fd5d5fc8..4dc2f123f 100644 --- a/tools/mid2agb/Makefile +++ b/tools/mid2agb/Makefile @@ -1,12 +1,15 @@ CXX := g++ -CXXFLAGS := -std=c++11 -O2 -Wall -Wno-switch -Werror +CXXFLAGS := -std=c++11 -O2 -s -Wall -Wno-switch -Werror SRCS := agb.cpp error.cpp main.cpp midi.cpp tables.cpp HEADERS := agb.h error.h main.h midi.h tables.h -.PHONY: clean +.PHONY: all clean + +all: mid2agb + @: mid2agb: $(SRCS) $(HEADERS) $(CXX) $(CXXFLAGS) $(SRCS) -o $@ $(LDFLAGS) diff --git a/tools/mid2agb/agb.cpp b/tools/mid2agb/agb.cpp index 9ff1efa86..d4d79f133 100644 --- a/tools/mid2agb/agb.cpp +++ b/tools/mid2agb/agb.cpp @@ -38,6 +38,9 @@ static bool s_noteChanged; static bool s_velocityChanged; static bool s_inPattern; static int s_extendedCommand; +static int s_memaccOp; +static int s_memaccParam1; +static int s_memaccParam2; void PrintAgbHeader() { @@ -247,6 +250,84 @@ void PrintSeqLoopLabel(const Event& event) ResetTrackVars(); } +void PrintMemAcc(const Event& event) +{ + switch (s_memaccOp) + { + case 0x00: + PrintByte("MEMACC, mem_set, 0x%02X, %u", s_memaccParam1, event.param2); + break; + case 0x01: + PrintByte("MEMACC, mem_add, 0x%02X, %u", s_memaccParam1, event.param2); + break; + case 0x02: + PrintByte("MEMACC, mem_sub, 0x%02X, %u", s_memaccParam1, event.param2); + break; + case 0x03: + PrintByte("MEMACC, mem_mem_set, 0x%02X, 0x%02X", s_memaccParam1, event.param2); + break; + case 0x04: + PrintByte("MEMACC, mem_mem_add, 0x%02X, 0x%02X", s_memaccParam1, event.param2); + break; + case 0x05: + PrintByte("MEMACC, mem_mem_sub, 0x%02X, 0x%02X", s_memaccParam1, event.param2); + break; + // TODO: everything else + case 0x06: + break; + case 0x07: + break; + case 0x08: + break; + case 0x09: + break; + case 0x0A: + break; + case 0x0B: + break; + case 0x0C: + break; + case 0x0D: + break; + case 0x0E: + break; + case 0x0F: + break; + case 0x10: + break; + case 0x11: + break; + case 0x46: + break; + case 0x47: + break; + case 0x48: + break; + case 0x49: + break; + case 0x4A: + break; + case 0x4B: + break; + case 0x4C: + break; + case 0x4D: + break; + case 0x4E: + break; + case 0x4F: + break; + case 0x50: + break; + case 0x51: + break; + default: + break; + } + + PrintWait(event.time); +} + void PrintExtendedOp(const Event& event) { // TODO: support for other extended commands @@ -280,16 +361,19 @@ void PrintControllerOp(const Event& event) break; case 0x0C: case 0x10: - // TODO: memacc + PrintMemAcc(event); break; case 0x0D: - // TODO: memacc var + s_memaccOp = event.param2; + PrintWait(event.time); break; case 0x0E: - // TODO: memacc var + s_memaccParam1 = event.param2; + PrintWait(event.time); break; case 0x0F: - // TODO: memacc var + s_memaccParam2 = event.param2; + PrintWait(event.time); break; case 0x11: std::fprintf(g_outputFile, "%s_%u_L%u:\n", g_asmLabel.c_str(), g_agbTrack, event.param2); @@ -334,8 +418,6 @@ void PrintAgbTrack(std::vector<Event>& events) { std::fprintf(g_outputFile, "\n@**************** Track %u (Midi-Chn.%u) ****************@\n\n", g_agbTrack, g_midiChan + 1); std::fprintf(g_outputFile, "%s_%u:\n", g_asmLabel.c_str(), g_agbTrack); - PrintWait(g_initialWait); - PrintByte("KEYSH , %s_key%+d", g_asmLabel.c_str(), 0); int wholeNoteCount = 0; int loopEndBlockNum = 0; @@ -359,6 +441,9 @@ void PrintAgbTrack(std::vector<Event>& events) if (!foundVolBeforeNote) PrintByte("\tVOL , 127*%s_mvl/mxv", g_asmLabel.c_str()); + PrintWait(g_initialWait); + PrintByte("KEYSH , %s_key%+d", g_asmLabel.c_str(), 0); + for (unsigned i = 0; events[i].type != EventType::EndOfTrack; i++) { const Event& event = events[i]; diff --git a/tools/mid2agb/main.cpp b/tools/mid2agb/main.cpp index 9b883fba5..ea2b294ac 100644 --- a/tools/mid2agb/main.cpp +++ b/tools/mid2agb/main.cpp @@ -50,7 +50,8 @@ bool g_compressionEnabled = true; " input_file filename(.mid) of MIDI file\n" " output_file filename(.s) for AGB file (default:input_file)\n" "\n" - "options -V??? master volume (default:127)\n" + "options -L??? label for assembler (default:output_file)\n" + " -V??? master volume (default:127)\n" " -G??? voice group number (default:0)\n" " -P??? priority (default:0)\n" " -R??? reverb (default:off)\n" @@ -85,57 +86,45 @@ static std::string GetExtension(std::string s) return ""; } -struct Option +static std::string BaseName(std::string s) { - char letter = 0; - const char *arg = NULL; -}; + std::size_t posAfterSlash = s.find_last_of("/\\"); -static Option ParseOption(int& index, const int argc, char** argv) -{ - static std::set<char> optionsWithArg = { 'L', 'V', 'G', 'P', 'R' }; - static std::set<char> optionsWithoutArg = { 'X', 'E', 'N' }; - - assert(index >= 0 && index < argc); - - const char *opt = argv[index]; + if (posAfterSlash == std::string::npos) + posAfterSlash = 0; + else + posAfterSlash++; - assert(opt[0] == '-'); - assert(std::strlen(opt) == 2); + std::size_t dotPos = s.find_first_of('.', posAfterSlash); + if (dotPos > posAfterSlash && dotPos != std::string::npos) + s = s.substr(posAfterSlash, dotPos - posAfterSlash); - char letter = std::toupper(opt[1]); - - bool isOption = false; - bool hasArg = false; + return s; +} - if (optionsWithArg.count(letter) != 0) - { - isOption = true; - hasArg = true; - } - else if (optionsWithoutArg.count(letter) != 0) - { - isOption = true; - } +static const char *GetArgument(int argc, char **argv, int& index) +{ + assert(index >= 0 && index < argc); - if (!isOption) - PrintUsage(); + const char *option = argv[index]; - Option retVal; + assert(option != nullptr); + assert(option[0] == '-'); - retVal.letter = letter; + // If there is text following the letter, return that. + if (std::strlen(option) >= 3) + return option + 2; - if (hasArg) + // Otherwise, try to get the next arg. + if (index + 1 < argc) { index++; - - if (index >= argc) - RaiseError("missing argument for \"-%c\"", letter); - - retVal.arg = argv[index]; + return argv[index]; + } + else + { + return nullptr; } - - return retVal; } int main(int argc, char** argv) @@ -145,51 +134,65 @@ int main(int argc, char** argv) for (int i = 1; i < argc; i++) { - if (argv[i][0] == '-' && std::strlen(argv[i]) == 2) + const char *option = argv[i]; + + if (option[0] == '-' && option[1] != '\0') { - Option option = ParseOption(i, argc, argv); + const char *arg; - switch (option.letter) + switch (std::toupper(option[1])) { case 'E': g_exactGateTime = true; break; case 'G': - g_voiceGroup = std::stoi(option.arg); + arg = GetArgument(argc, argv, i); + if (arg == nullptr) + PrintUsage(); + g_voiceGroup = std::stoi(arg); break; case 'L': - g_asmLabel = option.arg; + arg = GetArgument(argc, argv, i); + if (arg == nullptr) + PrintUsage(); + g_asmLabel = arg; break; case 'N': g_compressionEnabled = false; break; case 'P': - g_priority = std::stoi(option.arg); + arg = GetArgument(argc, argv, i); + if (arg == nullptr) + PrintUsage(); + g_priority = std::stoi(arg); break; case 'R': - g_reverb = std::stoi(option.arg); + arg = GetArgument(argc, argv, i); + if (arg == nullptr) + PrintUsage(); + g_reverb = std::stoi(arg); break; case 'V': - g_masterVolume = std::stoi(option.arg); + arg = GetArgument(argc, argv, i); + if (arg == nullptr) + PrintUsage(); + g_masterVolume = std::stoi(arg); break; case 'X': g_clocksPerBeat = 2; break; + default: + PrintUsage(); } } else { - switch (i) - { - case 1: + if (inputFilename.empty()) inputFilename = argv[i]; - break; - case 2: + else if (outputFilename.empty()) outputFilename = argv[i]; - break; - default: + else PrintUsage(); - } } } @@ -206,7 +209,7 @@ int main(int argc, char** argv) RaiseError("output filename extension is not \"s\""); if (g_asmLabel.empty()) - g_asmLabel = StripExtension(outputFilename); + g_asmLabel = BaseName(outputFilename); g_inputFile = std::fopen(inputFilename.c_str(), "rb"); diff --git a/tools/mid2agb/midi.cpp b/tools/mid2agb/midi.cpp index ba5dd654a..fa7d9ce28 100644 --- a/tools/mid2agb/midi.cpp +++ b/tools/mid2agb/midi.cpp @@ -52,6 +52,7 @@ static std::int32_t s_absoluteTime; static int s_blockCount = 0; static int s_minNote; static int s_maxNote; +static int s_runningStatus; void Seek(long offset) { @@ -170,6 +171,7 @@ void StartTrack() { Seek(s_trackDataStart); s_absoluteTime = 0; + s_runningStatus = 0; } void SkipEventData() @@ -181,15 +183,24 @@ void DetermineEventCategory(MidiEventCategory& category, int& typeChan, int& siz { typeChan = ReadInt8(); + if (typeChan < 0x80) + { + // If data byte was found, use the running status. + ungetc(typeChan, g_inputFile); + typeChan = s_runningStatus; + } + if (typeChan == 0xFF) { category = MidiEventCategory::Meta; size = 0; + s_runningStatus = 0; } else if (typeChan >= 0xF0) { category = MidiEventCategory::SysEx; size = 0; + s_runningStatus = 0; } else if (typeChan >= 0x80) { @@ -205,6 +216,7 @@ void DetermineEventCategory(MidiEventCategory& category, int& typeChan, int& siz size = 2; break; } + s_runningStatus = typeChan; } else { @@ -421,7 +433,10 @@ bool CheckNoteEnd(Event& event) void FindNoteEnd(Event& event) { + // Save the current file position and running status + // which get modified by CheckNoteEnd. long startPos = ftell(g_inputFile); + int savedRunningStatus = s_runningStatus; event.param2 = 0; @@ -429,6 +444,7 @@ void FindNoteEnd(Event& event) ; Seek(startPos); + s_runningStatus = savedRunningStatus; } bool ReadTrackEvent(Event& event) @@ -764,7 +780,7 @@ int CalculateCompressionScore(std::vector<Event>& events, int index) std::uint8_t lastVelocity = 0x80u; EventType lastType = events[index].type; std::int32_t lastDuration = 0x80000000; - std::uint8_t lastNote = 0x80u; + std::uint8_t lastNote = 0x40u; if (events[index].time > 0) score++; @@ -828,7 +844,7 @@ int CalculateCompressionScore(std::vector<Event>& events, int index) lastType = events[i].type; if (events[i].time) - ++score; + score++; } return score; @@ -836,6 +852,12 @@ int CalculateCompressionScore(std::vector<Event>& events, int index) bool IsCompressionMatch(std::vector<Event>& events, int index1, int index2) { + if (events[index1].type != events[index2].type || + events[index1].note != events[index2].note || + events[index1].param1 != events[index2].param1 || + events[index1].time != events[index2].time) + return false; + index1++; index2++; diff --git a/tools/preproc/c_file.cpp b/tools/preproc/c_file.cpp index 2f4bfea7c..229f568fa 100644 --- a/tools/preproc/c_file.cpp +++ b/tools/preproc/c_file.cpp @@ -325,66 +325,74 @@ void CFile::TryConvertIncbin() m_pos++; - SkipWhitespace(); + std::printf("{"); - if (m_buffer[m_pos] != '"') - RaiseError("expected double quote"); + while (true) + { + SkipWhitespace(); - m_pos++; + if (m_buffer[m_pos] != '"') + RaiseError("expected double quote"); - int startPos = m_pos; + m_pos++; - while (m_buffer[m_pos] != '"') - { - if (m_buffer[m_pos] == 0) - { - if (m_pos >= m_size) - RaiseError("unexpected EOF in path string"); - else - RaiseError("unexpected null character in path string"); - } + int startPos = m_pos; - if (m_buffer[m_pos] == '\r' || m_buffer[m_pos] == '\n') - RaiseError("unexpected end of line character in path string"); + while (m_buffer[m_pos] != '"') + { + if (m_buffer[m_pos] == 0) + { + if (m_pos >= m_size) + RaiseError("unexpected EOF in path string"); + else + RaiseError("unexpected null character in path string"); + } - if (m_buffer[m_pos] == '\\') - RaiseError("unexpected escape in path string"); - - m_pos++; - } + if (m_buffer[m_pos] == '\r' || m_buffer[m_pos] == '\n') + RaiseError("unexpected end of line character in path string"); - std::string path(&m_buffer[startPos], m_pos - startPos); + if (m_buffer[m_pos] == '\\') + RaiseError("unexpected escape in path string"); + + m_pos++; + } - m_pos++; + std::string path(&m_buffer[startPos], m_pos - startPos); - SkipWhitespace(); + m_pos++; - if (m_buffer[m_pos] != ')') - RaiseError("expected ')'"); + int fileSize; + std::unique_ptr<unsigned char[]> buffer = ReadWholeFile(path, fileSize); - m_pos++; + if ((fileSize % size) != 0) + RaiseError("Size %d doesn't evenly divide file size %d.\n", size, fileSize); - std::printf("{"); + int count = fileSize / size; + int offset = 0; - int fileSize; - std::unique_ptr<unsigned char[]> buffer = ReadWholeFile(path, fileSize); + for (int i = 0; i < count; i++) + { + int data = ExtractData(buffer, offset, size); + offset += size; - if ((fileSize % size) != 0) - RaiseError("Size %d doesn't evenly divide file size %d.\n", size, fileSize); + if (isSigned) + std::printf("%d,", data); + else + std::printf("%uu,", data); + } - int count = fileSize / size; - int offset = 0; + SkipWhitespace(); - for (int i = 0; i < count; i++) - { - int data = ExtractData(buffer, offset, size); - offset += size; + if (m_buffer[m_pos] != ',') + break; - if (isSigned) - std::printf("%d,", data); - else - std::printf("%uu,", data); + m_pos++; } + + if (m_buffer[m_pos] != ')') + RaiseError("expected ')'"); + + m_pos++; std::printf("}"); } diff --git a/tools/scaninc/c_file.cpp b/tools/scaninc/c_file.cpp index f7acc833f..d470f959d 100644 --- a/tools/scaninc/c_file.cpp +++ b/tools/scaninc/c_file.cpp @@ -244,18 +244,27 @@ void CFile::CheckIncbin() m_pos++; - SkipWhitespace(); + while (true) + { + SkipWhitespace(); - std::string path = ReadPath(); + std::string path = ReadPath(); - SkipWhitespace(); + SkipWhitespace(); + + m_incbins.emplace(path); + + if (m_buffer[m_pos] != ',') + break; + + m_pos++; + } if (m_buffer[m_pos] != ')') FATAL_INPUT_ERROR("expected ')'"); m_pos++; - m_incbins.emplace(path); } std::string CFile::ReadPath() |