summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/gbafix/.gitignore1
-rw-r--r--tools/gbafix/gbafix.c32
-rw-r--r--tools/gbagfx/Makefile7
-rw-r--r--tools/gbagfx/gfx.c175
-rw-r--r--tools/gbagfx/gfx.h4
-rw-r--r--tools/gbagfx/main.c105
-rw-r--r--tools/gbagfx/options.h24
-rw-r--r--tools/mid2agb/Makefile7
-rw-r--r--tools/mid2agb/agb.cpp97
-rw-r--r--tools/mid2agb/main.cpp117
-rw-r--r--tools/mid2agb/midi.cpp26
-rw-r--r--tools/preproc/c_file.cpp92
-rw-r--r--tools/scaninc/c_file.cpp17
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()