diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/gbagfx/convert_png.c | 237 | ||||
-rw-r--r-- | tools/gbagfx/convert_png.h | 1 | ||||
-rw-r--r-- | tools/gbagfx/main.c | 9 | ||||
-rw-r--r-- | tools/scaninc/c_file.cpp | 175 | ||||
-rw-r--r-- | tools/scaninc/c_file.h | 6 | ||||
-rw-r--r-- | tools/scaninc/scaninc.cpp | 94 |
6 files changed, 329 insertions, 193 deletions
diff --git a/tools/gbagfx/convert_png.c b/tools/gbagfx/convert_png.c index f6a30804a..37904318c 100644 --- a/tools/gbagfx/convert_png.c +++ b/tools/gbagfx/convert_png.c @@ -7,163 +7,206 @@ #include "convert_png.h" #include "gfx.h" -void ReadPng(char *path, struct Image *image) +static FILE *PngReadOpen(char *path, png_structp *pngStruct, png_infop *pngInfo) { - FILE *fp = fopen(path, "rb"); + FILE *fp = fopen(path, "rb"); + + if (fp == NULL) + FATAL_ERROR("Failed to open \"%s\" for reading.\n", path); + + unsigned char sig[8]; + + if (fread(sig, 8, 1, fp) != 1) + FATAL_ERROR("Failed to read PNG signature from \"%s\".\n", path); + + if (png_sig_cmp(sig, 0, 8)) + FATAL_ERROR("\"%s\" does not have a valid PNG signature.\n", path); + + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + if (!png_ptr) + FATAL_ERROR("Failed to create PNG read struct.\n"); + + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (!info_ptr) + FATAL_ERROR("Failed to create PNG info struct.\n"); - if (fp == NULL) - FATAL_ERROR("Failed to open \"%s\" for reading.\n", path); + if (setjmp(png_jmpbuf(png_ptr))) + FATAL_ERROR("Failed to init I/O for reading \"%s\".\n", path); - unsigned char sig[8]; + png_init_io(png_ptr, fp); + png_set_sig_bytes(png_ptr, 8); + png_read_info(png_ptr, info_ptr); - if (fread(sig, 8, 1, fp) != 1) - FATAL_ERROR("Failed to read PNG signature from \"%s\".\n", path); + *pngStruct = png_ptr; + *pngInfo = info_ptr; - if (png_sig_cmp(sig, 0, 8)) - FATAL_ERROR("\"%s\" does not have a valid PNG signature.\n", path); + return fp; +} + +void ReadPng(char *path, struct Image *image) +{ + png_structp png_ptr; + png_infop info_ptr; + + FILE *fp = PngReadOpen(path, &png_ptr, &info_ptr); - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + int bit_depth = png_get_bit_depth(png_ptr, info_ptr); - if (!png_ptr) - FATAL_ERROR("Failed to create PNG read struct.\n"); + if (bit_depth != image->bitDepth) + FATAL_ERROR("\"%s\" has a bit depth of %d, but the expected bit depth is %d.\n", path, bit_depth, image->bitDepth); - png_infop info_ptr = png_create_info_struct(png_ptr); + int color_type = png_get_color_type(png_ptr, info_ptr); - if (!info_ptr) - FATAL_ERROR("Failed to create PNG info struct.\n"); + if (color_type != PNG_COLOR_TYPE_GRAY && color_type != PNG_COLOR_TYPE_PALETTE) + FATAL_ERROR("\"%s\" has an unsupported color type.\n", path); - if (setjmp(png_jmpbuf(png_ptr))) - FATAL_ERROR("Failed to init I/O for reading \"%s\".\n", path); + // Check if the image has a palette so that we can tell if the colors need to be inverted later. + // Don't read the palette because it's not needed for now. + image->hasPalette = (color_type == PNG_COLOR_TYPE_PALETTE); - png_init_io(png_ptr, fp); - png_set_sig_bytes(png_ptr, 8); - png_read_info(png_ptr, info_ptr); + image->width = png_get_image_width(png_ptr, info_ptr); + image->height = png_get_image_height(png_ptr, info_ptr); - int bit_depth = png_get_bit_depth(png_ptr, info_ptr); + int rowbytes = png_get_rowbytes(png_ptr, info_ptr); - if (bit_depth != image->bitDepth) - FATAL_ERROR("\"%s\" has a bit depth of %d, but the expected bit depth is %d.\n", path, bit_depth, image->bitDepth); + image->pixels = malloc(image->height * rowbytes); - int color_type = png_get_color_type(png_ptr, info_ptr); + if (image->pixels == NULL) + FATAL_ERROR("Failed to allocate pixel buffer.\n"); - if (color_type != PNG_COLOR_TYPE_GRAY && color_type != PNG_COLOR_TYPE_PALETTE) - FATAL_ERROR("\"%s\" has an unsupported color type.\n", path); + png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep)); - // Check if the image has a palette so that we can tell if the colors need to be inverted later. - // Don't read the palette because it's not needed for now. - image->hasPalette = (color_type == PNG_COLOR_TYPE_PALETTE); + if (row_pointers == NULL) + FATAL_ERROR("Failed to allocate row pointers.\n"); - image->width = png_get_image_width(png_ptr, info_ptr); - image->height = png_get_image_height(png_ptr, info_ptr); + for (int i = 0; i < image->height; i++) + row_pointers[i] = (png_bytep)(image->pixels + (i * rowbytes)); - int rowbytes = png_get_rowbytes(png_ptr, info_ptr); + if (setjmp(png_jmpbuf(png_ptr))) + FATAL_ERROR("Error reading from \"%s\".\n", path); - image->pixels = malloc(image->height * rowbytes); + png_read_image(png_ptr, row_pointers); - if (image->pixels == NULL) - FATAL_ERROR("Failed to allocate pixel buffer.\n"); + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + free(row_pointers); + fclose(fp); +} + +void ReadPngPalette(char *path, struct Palette *palette) +{ + png_structp png_ptr; + png_infop info_ptr; + png_colorp colors; + int numColors; - png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep)); + FILE *fp = PngReadOpen(path, &png_ptr, &info_ptr); - if (row_pointers == NULL) - FATAL_ERROR("Failed to allocate row pointers.\n"); + if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_PALETTE) + FATAL_ERROR("The image \"%s\" does not contain a palette.\n", path); - for (int i = 0; i < image->height; i++) - row_pointers[i] = (png_bytep)(image->pixels + (i * rowbytes)); + if (png_get_PLTE(png_ptr, info_ptr, &colors, &numColors) != PNG_INFO_PLTE) + FATAL_ERROR("Failed to retrieve palette from \"%s\".\n", path); - if (setjmp(png_jmpbuf(png_ptr))) - FATAL_ERROR("Error reading from \"%s\".\n", path); + if (numColors > 256) + FATAL_ERROR("Images with more than 256 colors are not supported.\n"); - png_read_image(png_ptr, row_pointers); + palette->numColors = numColors; + for (int i = 0; i < numColors; i++) { + palette->colors[i].red = colors[i].red; + palette->colors[i].green = colors[i].green; + palette->colors[i].blue = colors[i].blue; + } - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - free(row_pointers); - fclose(fp); + fclose(fp); } void SetPngPalette(png_structp png_ptr, png_infop info_ptr, struct Palette *palette) { - png_colorp colors = malloc(palette->numColors * sizeof(png_color)); + png_colorp colors = malloc(palette->numColors * sizeof(png_color)); - if (colors == NULL) - FATAL_ERROR("Failed to allocate PNG palette.\n"); + if (colors == NULL) + FATAL_ERROR("Failed to allocate PNG palette.\n"); - for (int i = 0; i < palette->numColors; i++) { - colors[i].red = palette->colors[i].red; - colors[i].green = palette->colors[i].green; - colors[i].blue = palette->colors[i].blue; - } + for (int i = 0; i < palette->numColors; i++) { + colors[i].red = palette->colors[i].red; + colors[i].green = palette->colors[i].green; + colors[i].blue = palette->colors[i].blue; + } - png_set_PLTE(png_ptr, info_ptr, colors, palette->numColors); + png_set_PLTE(png_ptr, info_ptr, colors, palette->numColors); - free(colors); + free(colors); } void WritePng(char *path, struct Image *image) { - FILE *fp = fopen(path, "wb"); + FILE *fp = fopen(path, "wb"); - if (fp == NULL) - FATAL_ERROR("Failed to open \"%s\" for writing.\n", path); + if (fp == NULL) + FATAL_ERROR("Failed to open \"%s\" for writing.\n", path); - png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) - FATAL_ERROR("Failed to create PNG write struct.\n"); + if (!png_ptr) + FATAL_ERROR("Failed to create PNG write struct.\n"); - png_infop info_ptr = png_create_info_struct(png_ptr); + png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) - FATAL_ERROR("Failed to create PNG info struct.\n"); + if (!info_ptr) + FATAL_ERROR("Failed to create PNG info struct.\n"); - if (setjmp(png_jmpbuf(png_ptr))) - FATAL_ERROR("Failed to init I/O for writing \"%s\".\n", path); + if (setjmp(png_jmpbuf(png_ptr))) + FATAL_ERROR("Failed to init I/O for writing \"%s\".\n", path); - png_init_io(png_ptr, fp); + png_init_io(png_ptr, fp); - if (setjmp(png_jmpbuf(png_ptr))) - FATAL_ERROR("Error writing header for \"%s\".\n", path); + if (setjmp(png_jmpbuf(png_ptr))) + FATAL_ERROR("Error writing header for \"%s\".\n", path); - int color_type = image->hasPalette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_GRAY; + int color_type = image->hasPalette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_GRAY; - png_set_IHDR(png_ptr, info_ptr, image->width, image->height, - image->bitDepth, color_type, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + png_set_IHDR(png_ptr, info_ptr, image->width, image->height, + image->bitDepth, color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - if (image->hasPalette) { - SetPngPalette(png_ptr, info_ptr, &image->palette); + if (image->hasPalette) { + SetPngPalette(png_ptr, info_ptr, &image->palette); - if (image->hasTransparency) { - png_byte trans = 0; - png_set_tRNS(png_ptr, info_ptr, &trans, 1, 0); - } - } + if (image->hasTransparency) { + png_byte trans = 0; + png_set_tRNS(png_ptr, info_ptr, &trans, 1, 0); + } + } - png_write_info(png_ptr, info_ptr); + png_write_info(png_ptr, info_ptr); - png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep)); + png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep)); - if (row_pointers == NULL) - FATAL_ERROR("Failed to allocate row pointers.\n"); + if (row_pointers == NULL) + FATAL_ERROR("Failed to allocate row pointers.\n"); - int rowbytes = png_get_rowbytes(png_ptr, info_ptr); + int rowbytes = png_get_rowbytes(png_ptr, info_ptr); - for (int i = 0; i < image->height; i++) - row_pointers[i] = (png_bytep)(image->pixels + (i * rowbytes)); + for (int i = 0; i < image->height; i++) + row_pointers[i] = (png_bytep)(image->pixels + (i * rowbytes)); - if (setjmp(png_jmpbuf(png_ptr))) - FATAL_ERROR("Error writing \"%s\".\n", path); + if (setjmp(png_jmpbuf(png_ptr))) + FATAL_ERROR("Error writing \"%s\".\n", path); - png_write_image(png_ptr, row_pointers); + png_write_image(png_ptr, row_pointers); - if (setjmp(png_jmpbuf(png_ptr))) - FATAL_ERROR("Error ending write of \"%s\".\n", path); + if (setjmp(png_jmpbuf(png_ptr))) + FATAL_ERROR("Error ending write of \"%s\".\n", path); - png_write_end(png_ptr, NULL); + png_write_end(png_ptr, NULL); - fclose(fp); + fclose(fp); - png_destroy_write_struct(&png_ptr, &info_ptr); - free(row_pointers); + png_destroy_write_struct(&png_ptr, &info_ptr); + free(row_pointers); } diff --git a/tools/gbagfx/convert_png.h b/tools/gbagfx/convert_png.h index 55d3d6942..caf081b73 100644 --- a/tools/gbagfx/convert_png.h +++ b/tools/gbagfx/convert_png.h @@ -7,5 +7,6 @@ void ReadPng(char *path, struct Image *image); void WritePng(char *path, struct Image *image); +void ReadPngPalette(char *path, struct Palette *palette); #endif // CONVERT_PNG_H diff --git a/tools/gbagfx/main.c b/tools/gbagfx/main.c index 37d3441fe..97db60e84 100644 --- a/tools/gbagfx/main.c +++ b/tools/gbagfx/main.c @@ -134,6 +134,14 @@ void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **a ConvertPngToGba(inputPath, outputPath, numTiles, bitDepth); } +void HandlePngToGbaPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +{ + struct Palette palette; + + ReadPngPalette(inputPath, &palette); + WriteGbaPalette(outputPath, &palette); +} + void HandleGbaToJascPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) { struct Palette palette; @@ -353,6 +361,7 @@ int main(int argc, char **argv) { "png", "1bpp", HandlePngToGbaCommand }, { "png", "4bpp", HandlePngToGbaCommand }, { "png", "8bpp", HandlePngToGbaCommand }, + { "png", "gbapal", HandlePngToGbaPaletteCommand }, { "gbapal", "pal", HandleGbaToJascPaletteCommand }, { "pal", "gbapal", HandleJascToGbaPaletteCommand }, { "latfont", "png", HandleLatinFontToPngCommand }, diff --git a/tools/scaninc/c_file.cpp b/tools/scaninc/c_file.cpp index b82276dd6..f7acc833f 100644 --- a/tools/scaninc/c_file.cpp +++ b/tools/scaninc/c_file.cpp @@ -45,8 +45,6 @@ CFile::CFile(std::string path) m_pos = 0; m_lineNum = 1; - - RemoveComments(); } CFile::~CFile() @@ -54,71 +52,6 @@ CFile::~CFile() delete[] m_buffer; } -// Removes comments to simplify further processing. -// It stops upon encountering a null character, -// which may or may not be the end of file marker. -// If it's not, the error will be caught later. -void CFile::RemoveComments() -{ - long pos = 0; - char stringChar = 0; - - for (;;) - { - if (m_buffer[pos] == 0) - return; - - if (stringChar != 0) - { - if (m_buffer[pos] == '\\' && m_buffer[pos + 1] == stringChar) - { - pos += 2; - } - else - { - if (m_buffer[pos] == stringChar) - stringChar = 0; - pos++; - } - } - else if (m_buffer[pos] == '/' && m_buffer[pos + 1] == '/') - { - while (m_buffer[pos] != '\n' && m_buffer[pos] != 0) - m_buffer[pos++] = ' '; - } - else if (m_buffer[pos] == '/' && m_buffer[pos + 1] == '*') - { - m_buffer[pos++] = ' '; - m_buffer[pos++] = ' '; - - for (;;) - { - if (m_buffer[pos] == 0) - return; - - if (m_buffer[pos] == '*' && m_buffer[pos + 1] == '/') - { - m_buffer[pos++] = ' '; - m_buffer[pos++] = ' '; - break; - } - else - { - if (m_buffer[pos] != '\n') - m_buffer[pos] = ' '; - pos++; - } - } - } - else - { - if (m_buffer[pos] == '"' || m_buffer[pos] == '\'') - stringChar = m_buffer[pos]; - pos++; - } - } -} - void CFile::FindIncbins() { char stringChar = 0; @@ -145,6 +78,8 @@ void CFile::FindIncbins() } else { + SkipWhitespace(); + CheckInclude(); CheckIncbin(); if (m_pos >= m_size) @@ -177,6 +112,13 @@ bool CFile::ConsumeHorizontalWhitespace() bool CFile::ConsumeNewline() { + if (m_buffer[m_pos] == '\n') + { + m_pos++; + m_lineNum++; + return true; + } + if (m_buffer[m_pos] == '\r' && m_buffer[m_pos + 1] == '\n') { m_pos += 2; @@ -184,10 +126,33 @@ bool CFile::ConsumeNewline() return true; } - if (m_buffer[m_pos] == '\n') + return false; +} + +bool CFile::ConsumeComment() +{ + if (m_buffer[m_pos] == '/' && m_buffer[m_pos + 1] == '*') { - m_pos++; - m_lineNum++; + m_pos += 2; + while (m_buffer[m_pos] != '*' && m_buffer[m_pos + 1] != '/') + { + if (m_buffer[m_pos] == 0) + return false; + if (!ConsumeNewline()) + m_pos++; + } + m_pos += 2; + return true; + } + else if (m_buffer[m_pos] == '/' && m_buffer[m_pos + 1] == '/') + { + m_pos += 2; + while (!ConsumeNewline()) + { + if (m_buffer[m_pos] == 0) + return false; + m_pos++; + } return true; } @@ -196,7 +161,7 @@ bool CFile::ConsumeNewline() void CFile::SkipWhitespace() { - while (ConsumeHorizontalWhitespace() || ConsumeNewline()) + while (ConsumeHorizontalWhitespace() || ConsumeNewline() || ConsumeComment()) ; } @@ -211,8 +176,43 @@ bool CFile::CheckIdentifier(const std::string& ident) return (i == ident.length()); } +void CFile::CheckInclude() +{ + if (m_buffer[m_pos] != '#') + return; + + std::string ident = "#include"; + + if (!CheckIdentifier(ident)) + { + return; + } + + m_pos += ident.length(); + + ConsumeHorizontalWhitespace(); + + std::string path = ReadPath(); + + if (!path.empty()) { + m_includes.emplace(path); + } +} + void CFile::CheckIncbin() { + // Optimization: assume most lines are not incbins + if (!(m_buffer[m_pos+0] == 'I' + && m_buffer[m_pos+1] == 'N' + && m_buffer[m_pos+2] == 'C' + && m_buffer[m_pos+3] == 'B' + && m_buffer[m_pos+4] == 'I' + && m_buffer[m_pos+5] == 'N' + && m_buffer[m_pos+6] == '_')) + { + return; + } + std::string idents[6] = { "INCBIN_S8", "INCBIN_U8", "INCBIN_S16", "INCBIN_U16", "INCBIN_S32", "INCBIN_U32" }; int incbinType = -1; @@ -246,8 +246,28 @@ void CFile::CheckIncbin() SkipWhitespace(); + std::string path = ReadPath(); + + SkipWhitespace(); + + if (m_buffer[m_pos] != ')') + FATAL_INPUT_ERROR("expected ')'"); + + m_pos++; + + m_incbins.emplace(path); +} + +std::string CFile::ReadPath() +{ if (m_buffer[m_pos] != '"') - FATAL_INPUT_ERROR("expected double quote"); + { + if (m_buffer[m_pos] == '<') + { + return std::string(); + } + FATAL_INPUT_ERROR("expected '\"' or '<'"); + } m_pos++; @@ -272,16 +292,7 @@ void CFile::CheckIncbin() m_pos++; } - std::string path(&m_buffer[startPos], m_pos - startPos); - m_pos++; - SkipWhitespace(); - - if (m_buffer[m_pos] != ')') - FATAL_INPUT_ERROR("expected ')'"); - - m_pos++; - - m_incbins.emplace(path); + return std::string(m_buffer + startPos, m_pos - 1 - startPos); } diff --git a/tools/scaninc/c_file.h b/tools/scaninc/c_file.h index 922cb4639..618901b85 100644 --- a/tools/scaninc/c_file.h +++ b/tools/scaninc/c_file.h @@ -33,6 +33,7 @@ public: ~CFile(); void FindIncbins(); const std::set<std::string>& GetIncbins() { return m_incbins; } + const std::set<std::string>& GetIncludes() { return m_includes; } private: char *m_buffer; @@ -41,13 +42,16 @@ private: int m_lineNum; std::string m_path; std::set<std::string> m_incbins; + std::set<std::string> m_includes; - void RemoveComments(); bool ConsumeHorizontalWhitespace(); bool ConsumeNewline(); + bool ConsumeComment(); void SkipWhitespace(); bool CheckIdentifier(const std::string& ident); + void CheckInclude(); void CheckIncbin(); + std::string ReadPath(); }; #endif // C_FILE_H diff --git a/tools/scaninc/scaninc.cpp b/tools/scaninc/scaninc.cpp index b6f7ba767..3dc221479 100644 --- a/tools/scaninc/scaninc.cpp +++ b/tools/scaninc/scaninc.cpp @@ -20,7 +20,8 @@ #include <cstdio> #include <cstdlib> -#include <stack> +#include <list> +#include <queue> #include <set> #include <string> #include "scaninc.h" @@ -38,15 +39,49 @@ bool CanOpenFile(std::string path) return true; } +const char *const USAGE = "Usage: scaninc [-I INCLUDE_PATH] FILE_PATH\n"; + int main(int argc, char **argv) { - if (argc < 2) - FATAL_ERROR("Usage: scaninc FILE_PATH\n"); - - std::stack<std::string> filesToProcess; + std::queue<std::string> filesToProcess; std::set<std::string> dependencies; - std::string initialPath(argv[1]); + std::list<std::string> includeDirs; + + argc--; + argv++; + + while (argc > 1) + { + std::string arg(argv[0]); + if (arg.substr(0, 2) == "-I") + { + std::string includeDir = arg.substr(2); + if (includeDir.empty()) + { + argc--; + argv++; + includeDir = std::string(argv[0]); + } + if (includeDir.back() != '/') + { + includeDir += '/'; + } + includeDirs.push_back(includeDir); + } + else + { + FATAL_ERROR(USAGE); + } + argc--; + argv++; + } + + if (argc != 1) { + FATAL_ERROR(USAGE); + } + + std::string initialPath(argv[0]); std::size_t pos = initialPath.find_last_of('.'); @@ -55,20 +90,53 @@ int main(int argc, char **argv) std::string extension = initialPath.substr(pos + 1); - if (extension == "c") + std::string srcDir(""); + std::size_t slash = initialPath.rfind('/'); + if (slash != std::string::npos) { - CFile file(initialPath); + srcDir = initialPath.substr(0, slash + 1); + } + includeDirs.push_back(srcDir); + + if (extension == "c" || extension == "h") + { + filesToProcess.push(initialPath); + + while (!filesToProcess.empty()) + { + CFile file(filesToProcess.front()); + filesToProcess.pop(); - file.FindIncbins(); - dependencies = file.GetIncbins(); + file.FindIncbins(); + for (auto incbin : file.GetIncbins()) + { + dependencies.insert(incbin); + } + for (auto include : file.GetIncludes()) + { + for (auto includeDir : includeDirs) + { + std::string path(includeDir + include); + if (CanOpenFile(path)) + { + bool inserted = dependencies.insert(path).second; + if (inserted) + { + filesToProcess.push(path); + } + break; + } + } + } + } } - else if (extension == "s") + else if (extension == "s" || extension == "inc") { - filesToProcess.push(std::string(argv[1])); + filesToProcess.push(initialPath); while (!filesToProcess.empty()) { - AsmFile file(filesToProcess.top()); + AsmFile file(filesToProcess.front()); filesToProcess.pop(); |