mirror of
https://github.com/zeldaret/oot.git
synced 2025-02-22 06:45:31 +00:00
* 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>
174 lines
5 KiB
C
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;
|
|
}
|