From 8aece65315f4c87e3524a936732cd1f291e244bb Mon Sep 17 00:00:00 2001 From: Egor Date: Sun, 3 Sep 2023 06:48:26 +0300 Subject: [PATCH] thanm: an option to extract images from multiple ANM files at once new test failures (that aren't related to previous ones) 09 Files /tmp/anmtemp/a/result00.anm and /tmp/anmtemp/i/result00.anm differ 12 Files /tmp/anmtemp/a/stgenm01.anm and /tmp/anmtemp/i/stgenm01.anm differ 128 Files /tmp/anmtemp/a/boss00.anm and /tmp/anmtemp/i/boss00.anm differ 14 Files /tmp/anmtemp/a/st07enm2.anm and /tmp/anmtemp/i/st07enm2.anm differ 16 Files /tmp/anmtemp/a/pl02sub.anm and /tmp/anmtemp/i/pl02sub.anm differ 165 Files /tmp/anmtemp/a/enm01.anm and /tmp/anmtemp/i/enm01.anm differ 18 Files /tmp/anmtemp/a/pl02.anm and /tmp/anmtemp/i/pl02.anm differ --- NEWS | 1 + contrib/anmtest.sh | 30 +++++++++++----- thanm/thanm.1 | 8 ++--- thanm/thanm.c | 86 ++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 106 insertions(+), 19 deletions(-) diff --git a/NEWS b/NEWS index 937e469..ed0d35d 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ What's new in thtk master - Support th143/bestshot.anm - Two new options (-u and -uu) were added to help with rebuilding TH19 files bit-perfectly. See documentation for more details. +- A new option (-X) to extract images from multiple ANM files at once. #### thanm.old - Will be removed in the next release. diff --git a/contrib/anmtest.sh b/contrib/anmtest.sh index b4b7bfe..2a73f4c 100755 --- a/contrib/anmtest.sh +++ b/contrib/anmtest.sh @@ -5,25 +5,29 @@ # - regular unpacking to separate dirs # (one dir per anm file) # - unpacking with -uu option +# - unpacking with -X option # # This doesn't test the most common way to extract ANM (no flags, everything in # one dir), because that's clearly the wrong way to do it. # # Summary of directories being created: -# -uu |ZUN| separate -# flag| | dirs -# ----|---|---------- -# g | a | c e | packed -# \ |/ \| / \ / -# \ / \ / \ / -# f| |b d | unpacked +# -X |-uu |ZUN| separate +# flag |flag| | dirs +# -----|----|---|---------- +# i |g | a | c e | packed +# \ | \ |/|\| / \ / +# \ | \ / | \ / \ / +# h | f| | |b d | unpacked +# \ / +# \-----/ # # Comparisions being done: # a = c (rebuilding) # b = d (consistency) # c = e (consistency) # a = g (rebuilding) -# The a = c comparision can't be practically done for th19... at least for now. +# a = i (rebuilding) +# The a = c and a = i comparisions can't be practically done for th19... at least for now. script_dir=$(cd "$(dirname "$0")" || exit 1; pwd) || exit 1 : "${THDAT:=$script_dir/../build/thdat/thdat}" : "${THANM:=$script_dir/../build/thanm/thanm}" @@ -59,7 +63,7 @@ do else datfiles="$datfile" fi - mkdir -p "$ANMTEMP/a" "$ANMTEMP/b" "$ANMTEMP/c" "$ANMTEMP/d" "$ANMTEMP/e" "$ANMTEMP/f" "$ANMTEMP/g" + mkdir -p "$ANMTEMP/a" "$ANMTEMP/b" "$ANMTEMP/c" "$ANMTEMP/d" "$ANMTEMP/e" "$ANMTEMP/f" "$ANMTEMP/g" "$ANMTEMP/h" "$ANMTEMP/i" anmfiles=$(cd "$ANMTEMP/a" || exit 1; for i in $datfiles; do "$THDAT" -gx"$version" "$DATDIR/$i" "*anm" >/dev/null; done; ls) || exit 1 for i in $anmfiles; do mkdir -p "$ANMTEMP/b/$i" @@ -84,8 +88,16 @@ do for i in $anmfiles; do (cd "$ANMTEMP/f" || exit 1; "$THANM" $THANMFLAGS -uuc"$version" "$ANMTEMP/g/$i" "$ANMTEMP/f/$i.txt") || exit 1 done + for i in $anmfiles; do + "$THANM" $THANMFLAGS -l"$version" "$ANMTEMP/a/$i" >"$ANMTEMP/h/$i.txt" + done + (cd "$ANMTEMP/h" || exit 1; "$THANM" $THANMFLAGS -X"$version" "$ANMTEMP/a/"*.anm) || exit 1 + for i in $anmfiles; do + (cd "$ANMTEMP/h" || exit 1; "$THANM" $THANMFLAGS -c"$version" "$ANMTEMP/i/$i" "$ANMTEMP/h/$i.txt") || exit 1 + done diff -rq "$ANMTEMP/a" "$ANMTEMP/c" diff -rq "$ANMTEMP/b" "$ANMTEMP/d" diff -rq "$ANMTEMP/c" "$ANMTEMP/e" diff -rq "$ANMTEMP/a" "$ANMTEMP/g" + diff -rq "$ANMTEMP/a" "$ANMTEMP/i" done diff --git a/thanm/thanm.1 b/thanm/thanm.1 index 0405521..c2a77fe 100644 --- a/thanm/thanm.1 +++ b/thanm/thanm.1 @@ -33,7 +33,7 @@ .Sh SYNOPSIS .Nm .Op Fl Vfouv -.Op Oo Fl l | x | r | c Oc Ar version +.Op Oo Fl l | x | X | r | c Oc Ar version .Oo Fl m Ar anmmap Oc Ns Ar ... .Oo Fl s Ar symbols Oc .Op Ar archive Op Ar ... @@ -48,6 +48,8 @@ Displays a specification of the archive. .It Nm Fl x Ar version Oo Fl fouv Oc Ar archive Op Ar Extracts image files. If no files are specified, all files are extracted. +.It Nm Fl X Ar version Oo Fl fouv Oc Ar archives Ns Ar ... +Extracts all image files from multiple archives. .It Nm Fl r Ar version Oo Fl fouv Oc Ar archive Ar name Ar file Replaces an entry in the archive. The name can be obtained by the @@ -119,13 +121,11 @@ the appropriate format. .It Composition when creating Po Fl c Pc or replacing Po Fl r Pc : The source image is read from a file, decoded as PNG, cropped, and encoded in the texture format. -.It Composition when extracting Po Fl x Pc : +.It Composition when extracting Po Fl x No and Fl X Pc : Each texture is decoded into RGBA, and placed on a canvas. The canvas is encoded as PNG and written to the destination file. .El .Pp -Currently there's no way to compose textures from multiple ANM files. -.Pp The .Fl u option extracts each texture into its own file. diff --git a/thanm/thanm.c b/thanm/thanm.c index 00a6cb6..ba63d56 100644 --- a/thanm/thanm.c +++ b/thanm/thanm.c @@ -1442,6 +1442,7 @@ util_entry_by_name( } return rv; } + static void anm_build_name_lists( const anm_archive_t *anm) @@ -1457,6 +1458,30 @@ anm_build_name_lists( } } } + +static void +anm_build_name_lists_multiple( + list_t *anms) +{ + const anm_archive_t *anm, *anm2; + const char *name; + anm_entry_t *entry, *tmp, **nextloc; + list_for_each(anms, anm) + list_for_each(&anm->names, name) { + nextloc = &tmp; + list_for_each(anms, anm2) + list_for_each(&anm2->entries, entry) + if (entry->name == name || !strcmp(name, entry->name)) { + name = entry->name; + if (entry->next_by_name) + goto next_name; /* we already did this name */ + *nextloc = entry; + nextloc = &entry->next_by_name; + } + next_name:; + } +} + static void util_total_entry_size( anm_entry_t* entry, @@ -1535,7 +1560,7 @@ anm_replace( image = png_read(filename); } - if (width != image->width || height != image->height) { + if (width > image->width || height > image->height) { fprintf(stderr, "%s:%s:%s: wrong image dimensions for %s: %u, %u instead of %u, %u\n", argv0, current_input, entry_first->name, filename, image->width, image->height, @@ -2286,6 +2311,7 @@ print_usage(void) " -l VERSION ARCHIVE list archive\n" #ifdef HAVE_LIBPNG " -x VERSION ARCHIVE [FILE...] extract entries\n" + " -X VERSION ARCHIVE... extract all entries from multiple archives\n" " -r VERSION ARCHIVE NAME FILE replace entry in archive\n" " -c VERSION ARCHIVE SPEC create archive\n" " -s SYMBOLS save symbol ids to the given file as globaldefs\n" @@ -2318,7 +2344,7 @@ main( const char commands[] = ":l:om:" #ifdef HAVE_LIBPNG - "x:r:c:s:" + "x:X:r:c:s:" #endif "Vfuv"; int command = -1; @@ -2349,6 +2375,7 @@ main( /* fallthrough */ case 'l': case 'x': + case 'X': case 'r': if(command != -1) { fprintf(stderr,"%s: More than one mode specified\n",argv0); @@ -2445,7 +2472,7 @@ main( current_input = argv[0]; in = fopen(argv[0], "rb"); if (!in) { - fprintf(stderr, "%s: couldn't open %s for reading\n", argv[0], current_input); + fprintf(stderr, "%s: couldn't open %s for reading\n", argv0, current_input); exit(1); } anm = anm_read_file(in, version); @@ -2464,7 +2491,7 @@ main( current_input = argv[0]; in = fopen(argv[0], "rb"); if (!in) { - fprintf(stderr, "%s: couldn't open %s for reading\n", argv[0], current_input); + fprintf(stderr, "%s: couldn't open %s for reading\n", argv0, current_input); exit(1); } anm = anm_read_file(in, version); @@ -2516,6 +2543,53 @@ main( anm_free(anm); exit(0); + case 'X': { + list_t anms; + list_init(&anms); + + if (argc < 1) { + print_usage(); + exit(1); + } + + for (i = 0; i < argc; ++i) { + current_input = argv[i]; + in = fopen(argv[i], "rb"); + if (!in) { + fprintf(stderr, "%s: couldn't open %s for reading\n", argv0, current_input); + exit(1); + } + anm = anm_read_file(in, version); + list_append_new(&anms, anm); + fclose(in); + } + + anm_build_name_lists_multiple(&anms); + + i = 0; + list_for_each(&anms, anm) { + int j = 0; + list_for_each(&anm->entries, entry) { + if (!entry->processed) { + char *filename = 0; + current_output = entry->name; + if (option_verbose >= 1) + fprintf(stderr, "%s\n", entry->name); + if (option_unique_filenames) + filename = anm_make_unique_filename(entry->name, argv[i], j); + anm_extract(entry, filename ? filename : entry->name, version); + free(filename); + } + j++; + } + i++; + } + + list_for_each(&anms, anm) + anm_free(anm); + list_free_nodes(&anms); + exit(0); + } case 'r': if (argc != 3) { print_usage(); @@ -2524,7 +2598,7 @@ main( if (version == 19) { /* NEWHU: 19 */ /* FIXME: */ - fprintf(stderr, "%s: -r doesn't work with th19\n", argv[0]); + fprintf(stderr, "%s: -r doesn't work with th19\n", argv0); exit(1); } @@ -2532,7 +2606,7 @@ main( current_input = argv[0]; in = fopen(argv[0], "rb"); if (!in) { - fprintf(stderr, "%s: couldn't open %s for reading\n", argv[0], current_input); + fprintf(stderr, "%s: couldn't open %s for reading\n", argv0, current_input); exit(1); } anm = anm_read_file(in, version);