diff --git a/CMakeLists.txt b/CMakeLists.txt index dd229a2..86f5923 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,3 +2,4 @@ project(SpriteExtractor) set(SOURCES main.c) add_executable(sprite_extractor ${SOURCES}) +target_link_libraries(sprite_extractor m) diff --git a/main.c b/main.c index 6548913..942785f 100644 --- a/main.c +++ b/main.c @@ -2,6 +2,7 @@ #include #include #include +#include #define MAX_FRAMES 65536 #define MAX_POINTS 100000 @@ -48,6 +49,7 @@ typedef struct int maxDistFromEdge; int minW, minH; bool pot; + bool ground; int dw; int packW, packH; bool label; @@ -162,8 +164,10 @@ static void PrintUsage(const char* app) fprintf(stderr, "\t--label\n\t\tPrints the rectangle indices into the top-left corner of the frames.\n"); fprintf(stderr, "\t--metadata\n\t\tIf specified, the rectangles are output to a text file in the format mentioned below.\n"); fprintf(stderr, "\t--pack PACKED_IMAGE_WIDTH PACKED_IMAGE_HEIGHT\n\t\tIf this is supplied, then the frames are tightly packed and metadata is generated for each frame.\n\t\tThe metadata is simply a text file with the number of frames followed by 4 integers\n\t\tfor each frame: x y w h\n"); + fprintf(stderr, "\t--ground\n\t\tIf this is supplied, then the frames are grounded on the floor instead of centered\n"); } + static bool ParseArgs(Args* args, int argc, char** argv) { if(argc < 2) { @@ -206,6 +210,8 @@ static bool ParseArgs(Args* args, int argc, char** argv) i += 2; } else if(strcmp(argv[i], "--pot") == 0) { args->pot = true; + } else if(strcmp(argv[i], "--ground") == 0) { + args->ground = true; } else if (strcmp(argv[i], "--label") == 0) { args->label = true; } else if (strcmp(argv[i], "--row-thresh") == 0) { @@ -452,7 +458,7 @@ int main(int argc, char** argv) } if(args.isDir) { - tfTraverse(args.inputImage, TraverseImages, &args); + tfTraverseAlphabetically(args.inputImage, TraverseImages, &args); } else { ExtractFrames(args.inputImage, &args); } @@ -569,7 +575,11 @@ int main(int argc, char** argv) int columns = dw / fw; dx = (i % columns) * fw + fw / 2 - r.w / 2; - dy = (i / columns) * fh + fh / 2 - r.h / 2; + if(args.ground) { + dy = (i / columns) * fh + fh - r.h; + } else { + dy = (i / columns) * fh + fh / 2 - r.h / 2; + } } else { dx = rects[i].x; dy = rects[i].y; diff --git a/tinyfiles.h b/tinyfiles.h index 01a1b79..26d6576 100644 --- a/tinyfiles.h +++ b/tinyfiles.h @@ -54,6 +54,7 @@ #endif #include // strerror, strncpy +#include // qsort // change to 0 to compile out any debug checks #define TF_DEBUG_CHECKS 1 @@ -258,6 +259,51 @@ void tfTraverse( const char* path, tfCallback cb, void* udata ) tfDirClose( &dir ); } +static int compareFiles(const void* a, const void* b) { + tfFILE* fileA = (tfFILE*)a; + tfFILE* fileB = (tfFILE*)b; + return strcmp(fileA->name, fileB->name); +} + +void tfTraverseAlphabetically(const char* path, tfCallback cb, void* udata) { + tfDIR dir; + tfFILE files[1024]; + int fileCount = 0; + + if (!tfDirOpen(&dir, path)) { + return; + } + + while (dir.has_next) { + tfFILE file; + if (tfReadFile(&dir, &file)) { + files[fileCount++] = file; + } + tfDirNext(&dir); + } + + tfDirClose(&dir); + + qsort(files, fileCount, sizeof(tfFILE), compareFiles); + + for (int i = 0; i < fileCount; ++i) { + tfFILE* file = &files[i]; + + if (file->is_dir && file->name[0] != '.') { + char path2[TF_MAX_PATH]; + int n = tfSafeStrCpy(path2, path, 0, TF_MAX_PATH); + n = tfSafeStrCpy(path2, "/", n - 1, TF_MAX_PATH); + tfSafeStrCpy(path2, file->name, n - 1, TF_MAX_PATH); + tfTraverse(path2, cb, udata); + } + + if (file->is_reg) { + cb(file, udata); + } + } +} + + int tfMatchExt( tfFILE* file, const char* ext ) { if (*ext == '.') ++ext;