1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2025-02-22 06:45:31 +00:00
oot/tools/bin2c.c
Tharo 3d61fb85ef
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>
2025-02-17 17:09:42 -05:00

174 lines
5 KiB
C

/* 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;
}