From a5b8a507fc7e0ce106f8f8b66f694189f456082d Mon Sep 17 00:00:00 2001 From: Dragorn421 Date: Sun, 12 Apr 2026 23:40:05 +0200 Subject: [PATCH] Texture software fixups (#2709) * fixup n64texconv app usage text and check u32|u64 * fix memory leaks in build_from_png * yeet -Werror * Remove n64texconv/ap and create build_jfif * gitignore build_jfif binary, oops * Makefile: Add BUILD_FROM_PNG and BUILD_JFIF variables --- Makefile | 11 +- tools/assets/Makefile | 4 +- tools/assets/build_from_png/Makefile | 2 +- tools/assets/build_from_png/build_from_png.c | 2 + tools/assets/build_jfif/.gitignore | 1 + tools/assets/build_jfif/Makefile | 17 +++ tools/assets/build_jfif/build_jfif.c | 60 ++++++++ tools/assets/n64texconv/Makefile | 23 +--- tools/assets/n64texconv/src/app/main.c | 137 ------------------- 9 files changed, 97 insertions(+), 160 deletions(-) create mode 100644 tools/assets/build_jfif/.gitignore create mode 100644 tools/assets/build_jfif/Makefile create mode 100644 tools/assets/build_jfif/build_jfif.c delete mode 100644 tools/assets/n64texconv/src/app/main.c diff --git a/Makefile b/Makefile index 83db1ea06d..fa0563db56 100644 --- a/Makefile +++ b/Makefile @@ -335,9 +335,10 @@ MKLDSCRIPT := tools/mkldscript MKDMADATA := tools/mkdmadata ELF2ROM := tools/elf2rom BIN2C := tools/bin2c -N64TEXCONV := tools/assets/n64texconv/n64texconv FADO := tools/fado/fado.elf PYTHON ?= $(VENV)/bin/python3 +BUILD_FROM_PNG := tools/assets/build_from_png/build_from_png +BUILD_JFIF := tools/assets/build_jfif/build_jfif # Command to replace $(BUILD_DIR) in some files with the build path. # We can't use the C preprocessor for this because it won't substitute inside string literals. @@ -997,24 +998,24 @@ $(BUILD_DIR)/src/overlays/%_reloc.o: $(BUILD_DIR)/spec # Assets from assets/ $(BUILD_DIR)/assets/%.inc.c: assets/%.png - tools/assets/build_from_png/build_from_png $< $(dir $@) assets/$(dir $*) $(wildcard $(EXTRACTED_DIR)/assets/$(dir $*)) + $(BUILD_FROM_PNG) $< $(dir $@) assets/$(dir $*) $(wildcard $(EXTRACTED_DIR)/assets/$(dir $*)) $(BUILD_DIR)/assets/%.bin.inc.c: assets/%.bin $(BIN2C) -t 1 $< $@ $(BUILD_DIR)/assets/%.jpg.inc.c: assets/%.jpg - $(N64TEXCONV) JFIF "" $< $@ + $(BUILD_JFIF) $< $@ # Assets from extracted/ $(BUILD_DIR)/assets/%.inc.c: $(EXTRACTED_DIR)/assets/%.png - tools/assets/build_from_png/build_from_png $< $(dir $@) $(wildcard assets/$(dir $*)) $(EXTRACTED_DIR)/assets/$(dir $*) + $(BUILD_FROM_PNG) $< $(dir $@) $(wildcard assets/$(dir $*)) $(EXTRACTED_DIR)/assets/$(dir $*) $(BUILD_DIR)/assets/%.bin.inc.c: $(EXTRACTED_DIR)/assets/%.bin $(BIN2C) -t 1 $< $@ $(BUILD_DIR)/assets/%.jpg.inc.c: $(EXTRACTED_DIR)/assets/%.jpg - $(N64TEXCONV) JFIF "" $< $@ + $(BUILD_JFIF) $< $@ # Audio diff --git a/tools/assets/Makefile b/tools/assets/Makefile index 324e19d571..c81e94cd13 100644 --- a/tools/assets/Makefile +++ b/tools/assets/Makefile @@ -1,11 +1,13 @@ all: -# must build n64texconv before build_from_png +# must build n64texconv before build_from_png and build_jfif $(MAKE) -C n64texconv $(MAKE) -C build_from_png + $(MAKE) -C build_jfif clean: $(MAKE) -C n64texconv clean $(MAKE) -C build_from_png clean + $(MAKE) -C build_jfif clean distclean: clean $(MAKE) -C n64texconv distclean diff --git a/tools/assets/build_from_png/Makefile b/tools/assets/build_from_png/Makefile index 4a74a0d6e8..88076bc0df 100644 --- a/tools/assets/build_from_png/Makefile +++ b/tools/assets/build_from_png/Makefile @@ -1,4 +1,4 @@ -CFLAGS := -Wall -Werror -O3 +CFLAGS := -Wall -Wextra -O3 ifeq ($(shell $(CC) --version | grep clang),) OMPFLAGS := -fopenmp diff --git a/tools/assets/build_from_png/build_from_png.c b/tools/assets/build_from_png/build_from_png.c index 5a0829e049..af70d784f7 100644 --- a/tools/assets/build_from_png/build_from_png.c +++ b/tools/assets/build_from_png/build_from_png.c @@ -406,6 +406,7 @@ static bool handle_ci_shared_tlut(const char* png_p, const struct fmt_info* fmt, len_pngs_with_tlut++; } } + free(direntry_tlut_name); } } free(direntry_name_buf); @@ -642,6 +643,7 @@ static bool handle_ci_shared_tlut(const char* png_p, const struct fmt_info* fmt, } if (ref_img != NULL) { + n64texconv_palette_free(ref_img->pal); n64texconv_image_free(ref_img); } diff --git a/tools/assets/build_jfif/.gitignore b/tools/assets/build_jfif/.gitignore new file mode 100644 index 0000000000..a55404d115 --- /dev/null +++ b/tools/assets/build_jfif/.gitignore @@ -0,0 +1 @@ +build_jfif diff --git a/tools/assets/build_jfif/Makefile b/tools/assets/build_jfif/Makefile new file mode 100644 index 0000000000..674881aa7c --- /dev/null +++ b/tools/assets/build_jfif/Makefile @@ -0,0 +1,17 @@ +CFLAGS := -Wall -Wextra -O3 + +ifeq ($(shell $(CC) --version | grep clang),) + OMPFLAGS := -fopenmp +else + OMPFLAGS := +endif + +default: build_jfif + +clean: + $(RM) build_jfif + +.PHONY: default clean + +build_jfif: build_jfif.c ../n64texconv/libn64texconv.a + $(CC) $(CFLAGS) -o $@ $^ $(OMPFLAGS) -lz -lm diff --git a/tools/assets/build_jfif/build_jfif.c b/tools/assets/build_jfif/build_jfif.c new file mode 100644 index 0000000000..9ad5ef9941 --- /dev/null +++ b/tools/assets/build_jfif/build_jfif.c @@ -0,0 +1,60 @@ +/* SPDX-FileCopyrightText: Copyright (C) 2025 ZeldaRET */ +/* SPDX-License-Identifier: MIT */ + +// Note: this is statically linked with GPL binaries, making the binary GPL-licensed + +#include +#include +#include +#include +#include +#include +#include + +#define NORETURN __attribute__((noreturn)) + +#include "../n64texconv/src/libn64texconv/jfif.h" + +static bool is_regular_file(const char* path) { + struct stat sb; + stat(path, &sb); + return S_ISREG(sb.st_mode); +} + +static NORETURN void usage(const char* progname) { + fprintf(stderr, + "build_jfif: Validate an input JFIF and convert to a C array.\n" + "Usage: %s \n", + progname); + exit(EXIT_FAILURE); +} + +int main(int argc, char** argv) { + const char* progname = argv[0]; + const char* in; + const char* out; + + if (argc != 3) + usage(progname); + + in = argv[1]; + out = argv[2]; + + if (!is_regular_file(in)) { + fprintf(stderr, "Could not open input file %s\n", in); + return EXIT_FAILURE; + } + + struct JFIF* jfif = jfif_fromfile(in, JFIF_BUFFER_SIZE); + if (jfif == NULL) { + fprintf(stderr, "Could not open input file %s\n", in); + return EXIT_FAILURE; + } + if (jfif_to_c_file(out, jfif, JFIF_BUFFER_SIZE)) { + fprintf(stderr, "Could not save output C file %s\n", out); + return EXIT_FAILURE; + } + jfif_free(jfif); + + return EXIT_SUCCESS; +} diff --git a/tools/assets/n64texconv/Makefile b/tools/assets/n64texconv/Makefile index fbe0300d77..c208512053 100644 --- a/tools/assets/n64texconv/Makefile +++ b/tools/assets/n64texconv/Makefile @@ -3,7 +3,6 @@ BUILD_DIR := build # Targets LIB := libn64texconv.a SOLIB := libn64texconv.so -APP := n64texconv INC := -Ilib/spng -Ilib/libimagequant @@ -27,35 +26,30 @@ LDLIBS := $(OMPFLAGS) -lz -lm AR := ar ARFLAGS := rcs -SRC_DIRS := $(shell find src -type d -not -path src/app) +SRC_DIRS := $(shell find src -type d) LIB_DIRS := $(shell find lib -type d) -APP_SRC_DIRS := $(shell find src/app -type d) C_FILES := $(foreach dir,$(SRC_DIRS) $(LIB_DIRS),$(wildcard $(dir)/*.c)) O_FILES := $(foreach f,$(C_FILES:.c=.o),$(BUILD_DIR)/$f) DEP_FILES := $(foreach f,$(O_FILES:.o=.d),$f) -APP_C_FILES := $(foreach dir,$(APP_SRC_DIRS),$(wildcard $(dir)/*.c)) -APP_O_FILES := $(foreach f,$(APP_C_FILES:.c=.o),$(BUILD_DIR)/$f) -APP_DEP_FILES := $(foreach f,$(APP_O_FILES:.o=.d),$f) - -FMT_C_FILES := $(foreach dir,$(SRC_DIRS) $(APP_SRC_DIRS),$(wildcard $(dir)/*.c)) -FMT_H_FILES := $(foreach dir,$(SRC_DIRS) $(APP_SRC_DIRS),$(wildcard $(dir)/*.h)) +FMT_C_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c)) +FMT_H_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.h)) FMT_FILES := $(FMT_C_FILES) $(FMT_H_FILES) CLANG_FORMAT := clang-format-14 FORMAT_ARGS := -i -style=file -$(shell mkdir -p $(BUILD_DIR) $(foreach dir,$(SRC_DIRS) $(LIB_DIRS) $(APP_SRC_DIRS),$(BUILD_DIR)/$(dir))) +$(shell mkdir -p $(BUILD_DIR) $(foreach dir,$(SRC_DIRS) $(LIB_DIRS),$(BUILD_DIR)/$(dir))) $(BUILD_DIR)/lib/libimagequant/%.o: CFLAGS += $(OMPFLAGS) -Wno-sign-compare -Wno-unused-parameter -Wno-shadow .PHONY: all clean distclean format -all: $(LIB) $(SOLIB) $(APP) +all: $(LIB) $(SOLIB) clean: - $(RM) -r $(LIB) $(SOLIB) $(APP) $(BUILD_DIR) + $(RM) -r $(LIB) $(SOLIB) $(BUILD_DIR) distclean: clean @@ -68,10 +62,7 @@ $(LIB): $(O_FILES) $(SOLIB): $(O_FILES) $(CC) -shared $^ $(LDLIBS) -o $@ -$(APP): $(APP_O_FILES) $(LIB) - $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ - $(BUILD_DIR)/%.o: %.c $(CC) $(CFLAGS) $(OPTFLAGS) -c $< -o $@ --include $(DEP_FILES) $(APP_DEP_FILES) +-include $(DEP_FILES) diff --git a/tools/assets/n64texconv/src/app/main.c b/tools/assets/n64texconv/src/app/main.c deleted file mode 100644 index 9829c512c1..0000000000 --- a/tools/assets/n64texconv/src/app/main.c +++ /dev/null @@ -1,137 +0,0 @@ -/* SPDX-FileCopyrightText: Copyright (C) 2025 ZeldaRET */ -/* SPDX-License-Identifier: MIT */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NORETURN __attribute__((noreturn)) -#define ARRLEN(a) (sizeof(a) / sizeof((a)[0])) -#define strequ(s1, s2) (strcmp((s1), (s2)) == 0) - -#include "../libn64texconv/n64texconv.h" -#include "../libn64texconv/jfif.h" - -static bool -is_regular_file(const char *path) -{ - struct stat sb; - stat(path, &sb); - return S_ISREG(sb.st_mode); -} - -static NORETURN void -usage(const char *progname) -{ - fprintf(stderr, - "n64texconv: Convert an input png to N64 data in the desired format.\n" - "Usage: %s [pal_out.c]\n" - " Valid types: i4 / i8 / ci4 / ci8 / ia4 / ia8 / ia16 / rgba16 / rgba32 / JFIF\n", - progname); - exit(EXIT_FAILURE); -} - -static const struct fmt_info { - const char *name; - int fmt; - int siz; -} fmt_map[] = { - // clang-format off - { "i4", G_IM_FMT_I, G_IM_SIZ_4b, }, - { "i8", G_IM_FMT_I, G_IM_SIZ_8b, }, - { "ci4", G_IM_FMT_CI, G_IM_SIZ_4b, }, - { "ci8", G_IM_FMT_CI, G_IM_SIZ_8b, }, - { "ia4", G_IM_FMT_IA, G_IM_SIZ_4b, }, - { "ia8", G_IM_FMT_IA, G_IM_SIZ_8b, }, - { "ia16", G_IM_FMT_IA, G_IM_SIZ_16b, }, - { "rgba16", G_IM_FMT_RGBA, G_IM_SIZ_16b, }, - { "rgba32", G_IM_FMT_RGBA, G_IM_SIZ_32b, }, - // clang-format on -}; - -int -main(int argc, char **argv) -{ - const char *progname = argv[0]; - const char *fmt; - const char *array_fmt; - const char *in; - const char *out; - const char *pal_out; - - if (argc < 5) - usage(progname); - - fmt = argv[1]; - array_fmt = argv[2]; - in = argv[3]; - out = argv[4]; - pal_out = (argc > 5) ? argv[5] : NULL; - - unsigned int byte_width = (strequ(array_fmt, "u32") ? 4 : 8); - - if (!is_regular_file(in)) { - fprintf(stderr, "Could not open input file %s\n", in); - return EXIT_FAILURE; - } - - if (strequ(fmt, "JFIF")) { - struct JFIF *jfif = jfif_fromfile(in, JFIF_BUFFER_SIZE); - if (jfif == NULL) { - fprintf(stderr, "Could not open input file %s\n", in); - return EXIT_FAILURE; - } - if (jfif_to_c_file(out, jfif, JFIF_BUFFER_SIZE)) { - fprintf(stderr, "Could not save output C file %s\n", out); - return EXIT_FAILURE; - } - jfif_free(jfif); - } else { - int rv; - const struct fmt_info *fmt_info = NULL; - for (size_t i = 0; i < ARRLEN(fmt_map); i++) { - if (strequ(fmt, fmt_map[i].name)) { - fmt_info = &fmt_map[i]; - break; - } - } - if (fmt_info == NULL) { - fprintf(stderr, "Error: Invalid fmt %s\n", fmt); - return EXIT_FAILURE; - } - - struct n64_image *img = n64texconv_image_from_png(in, fmt_info->fmt, fmt_info->siz, G_IM_FMT_RGBA); - if (img == NULL) { - fprintf(stderr, "Could not open input file %s\n", in); - return EXIT_FAILURE; - } - - if (img->pal != NULL) { - if (pal_out == NULL) { - fprintf(stderr, "Input file %s is color indexed, a palette output C file must be provided.\n", in); - usage(progname); - } - - if (rv = n64texconv_palette_to_c_file(pal_out, img->pal, false, byte_width), rv != 0) { - fprintf(stderr, "Could not save output C file %s (error %d)\n", pal_out, rv); - return EXIT_FAILURE; - } - } - - if (rv = n64texconv_image_to_c_file(out, img, false, false, byte_width), rv != 0) { - fprintf(stderr, "Could not save output C file %s (error %d)\n", out, rv); - return EXIT_FAILURE; - } - - if (img->pal != NULL) - n64texconv_palette_free(img->pal); - n64texconv_image_free(img); - } - - return EXIT_SUCCESS; -}