mirror of
https://github.com/zeldaret/oot.git
synced 2025-07-15 20:35:13 +00:00
Add n64texconv
and bin2c
tools to convert extracted .png and .bin to C arrays during build (#2477)
* n64texconv and bin2c * mv tools/n64texconv tools/assets/ * fix * more light fixes * Silence -Wshadow for libimagequant * Add reference counting gc for palette objects in python bindings * Fix missing alignment in n64texconv_*_to_c functions Co-authored-by: Dragorn421 <Dragorn421@users.noreply.github.com> * Check palette size in n64texconv_image_from_png * accept memoryview as well as bytes for binary data * minimal doc on n64texconv_quantize_shared * fix a buffer size passed to libimagequant * assert pal count <= 256 on png write * Disable palette size check for input pngs, ZAPD fails the check * No OpenMP for clang * When reading an indexed png into a CI format, requantize if there are too many colors for the target texel size --------- Co-authored-by: Dragorn421 <Dragorn421@users.noreply.github.com>
This commit is contained in:
parent
ec30dcbe4e
commit
3d61fb85ef
41 changed files with 15634 additions and 9 deletions
174
tools/bin2c.c
Normal file
174
tools/bin2c.c
Normal file
|
@ -0,0 +1,174 @@
|
|||
/* SPDX-FileCopyrightText: (C) 2025 ZeldaRET */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "endian.h"
|
||||
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
|
||||
static void NORETURN
|
||||
verror(const char *fmt, va_list args)
|
||||
{
|
||||
fputs("\x1b[91merror\x1b[97m: ", stderr);
|
||||
vfprintf(stderr, fmt, args);
|
||||
fputs("\x1b[0m", stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void NORETURN
|
||||
error(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
verror(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void NORETURN
|
||||
error_post_open(const char *path_to_rm, FILE *file_to_rm, const char *fmt, ...)
|
||||
{
|
||||
// cleanup output file
|
||||
fclose(file_to_rm);
|
||||
if (remove(path_to_rm) != 0)
|
||||
fprintf(stderr, "error calling remove(): %s", strerror(errno));
|
||||
|
||||
// error as normal
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
verror(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void NORETURN
|
||||
usage(const char *progname)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s -t <fmt> [-pad] input.bin output.inc.c" "\n"
|
||||
" fmt must be one of { 1, 2, 4, 8 }" "\n"
|
||||
" if pad, align to fmt by filling with 0s, otherwise error if input is not aligned" "\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#define BYTES_PER_ROW 32
|
||||
#define LINE_MASK (BYTES_PER_ROW - 1)
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
const char *progname = argv[0];
|
||||
const char *inpath = NULL;
|
||||
const char *outpath = NULL;
|
||||
const char *fmt_opt = NULL;
|
||||
int fmt = 0;
|
||||
bool pad = false;
|
||||
|
||||
// Collect arguments
|
||||
|
||||
int narg = 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-') {
|
||||
if (strcmp(argv[i], "-t") == 0) {
|
||||
if (++i == argc)
|
||||
usage(progname);
|
||||
fmt_opt = argv[i];
|
||||
char *end;
|
||||
fmt = strtol(argv[i], &end, 10);
|
||||
if (end != &argv[i][strlen(argv[i])])
|
||||
error("Invalid base 10 integer %s\n", argv[i]);
|
||||
} else if (strcmp(argv[i], "-pad") == 0) {
|
||||
pad = true;
|
||||
} else {
|
||||
usage(progname);
|
||||
}
|
||||
} else {
|
||||
switch (narg) {
|
||||
case 0:
|
||||
inpath = argv[i];
|
||||
break;
|
||||
case 1:
|
||||
outpath = argv[i];
|
||||
break;
|
||||
default:
|
||||
usage(progname);
|
||||
break;
|
||||
}
|
||||
narg++;
|
||||
}
|
||||
}
|
||||
|
||||
// Check arguments
|
||||
|
||||
if (inpath == NULL || outpath == NULL || fmt_opt == NULL)
|
||||
usage(progname);
|
||||
|
||||
if (fmt != 1 && fmt != 2 && fmt != 4 && fmt != 8)
|
||||
error("Invalid fmt option '%s'. Valid options: [1, 2, 4, 8]\n", fmt_opt);
|
||||
|
||||
// Open the input binary file
|
||||
|
||||
FILE *infile = fopen(inpath, "rb");
|
||||
if (infile == NULL)
|
||||
error("Failed to open input file '%s' for reading: %s\n", inpath, strerror(errno));
|
||||
|
||||
// Get size
|
||||
|
||||
if (fseek(infile, 0, SEEK_END) != 0)
|
||||
error("Could not ascertain input file size, could not seek to end: %s\n", strerror(errno));
|
||||
size_t file_size = ftell(infile);
|
||||
if (fseek(infile, 0, SEEK_SET) != 0)
|
||||
error("Could not ascertain input file size, could not seek to start: %s\n", strerror(errno));
|
||||
|
||||
// Check alignment
|
||||
|
||||
if ((file_size & (fmt - 1)) != 0 && !pad) {
|
||||
// Not aligned to data size and don't pad, error
|
||||
error("Input file '%s' size (%lu) is not aligned to %d bytes\n", inpath, file_size, fmt);
|
||||
}
|
||||
|
||||
// Open the output text file
|
||||
|
||||
FILE *outfile = fopen(outpath, "w");
|
||||
if (outfile == NULL)
|
||||
error("Failed to open output file '%s' for writing: %s\n", outpath, strerror(errno));
|
||||
|
||||
// Write data. If the input binary size was not aligned we either don't get this far or the option
|
||||
// to pad with 0s is set.
|
||||
|
||||
bool was_newline = false;
|
||||
for (size_t p = 0; p < file_size; p += fmt) {
|
||||
size_t rem = fmt;
|
||||
if (rem > file_size - p) // For any remaining unaligned data, rest will be padded with 0
|
||||
rem = file_size - p;
|
||||
|
||||
// Read input
|
||||
uint64_t d = 0;
|
||||
if (fread(&d, 1, rem, infile) != rem)
|
||||
error_post_open(outpath, outfile, "Error reading from input file '%s': %s\n", inpath, strerror(errno));
|
||||
|
||||
// Byteswap + shift
|
||||
d = be64toh(d) >> (64 - 8 * fmt);
|
||||
|
||||
// Write output
|
||||
bool was_newline = (((p + fmt) & LINE_MASK) == 0);
|
||||
char end = was_newline ? '\n' : ' ';
|
||||
if (fprintf(outfile, "0x%0*" PRIX64 ",%c", 2 * fmt, d, end) < 0)
|
||||
error_post_open(outpath, outfile, "Error writing to output file '%s': %s\n", outpath, strerror(errno));
|
||||
}
|
||||
if (!was_newline) {
|
||||
if (fputs("\n", outfile) == EOF)
|
||||
error_post_open(outpath, outfile, "Error writing to output file '%s': %s\n", outpath, strerror(errno));
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
fclose(outfile);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue