Nuke changes to nitrogfx

The merge is just too complicated
This commit is contained in:
PikalaxALT 2025-11-29 09:14:31 -05:00
parent bf2e15d44f
commit c2fba5a463
No known key found for this signature in database
GPG Key ID: 7774E96AA69E5B61
17 changed files with 3329 additions and 2568 deletions

View File

@ -2,4 +2,5 @@
**/*.inc
**/*.json
lib/
tools/nitrogfx/
tools/nitrogfx/*.c
tools/nitrogfx/*.h

View File

@ -1,4 +1,4 @@
Copyright (c) 2015 YamaArashi, 2021-2024 red031000
Copyright (c) 2015 YamaArashi, 2021-2025 red031000
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

File diff suppressed because it is too large Load Diff

View File

@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ
/* project version */
#define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 7
#define CJSON_VERSION_PATCH 18
#define CJSON_VERSION_PATCH 19
#include <stddef.h>
@ -287,7 +287,10 @@ CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
#define cJSON_SetBoolValue(object, boolValue) ( \
(object != NULL && ((object)->type & (cJSON_False | cJSON_True))) ? (object)->type = ((object)->type & (~(cJSON_False | cJSON_True))) | ((boolValue) ? cJSON_True : cJSON_False) : cJSON_Invalid)
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
cJSON_Invalid\
)
/* Macro for iterating over an array or object */
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)

View File

@ -1,47 +1,39 @@
// Copyright (c) 2015 YamaArashi
#include "convert_png.h"
#include <png.h>
#include <setjmp.h>
#include <stdio.h>
#include <setjmp.h>
#include <png.h>
#include "global.h"
#include "convert_png.h"
#include "gfx.h"
static FILE *PngReadOpen(char *path, png_structp *pngStruct, png_infop *pngInfo) {
static FILE *PngReadOpen(char *path, png_structp *pngStruct, png_infop *pngInfo)
{
FILE *fp = fopen(path, "rb");
if (fp == NULL) {
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
}
unsigned char sig[8];
if (fread(sig, 8, 1, fp) != 1) {
if (fread(sig, 8, 1, fp) != 1)
FATAL_ERROR("Failed to read PNG signature from \"%s\".\n", path);
}
if (png_sig_cmp(sig, 0, 8)) {
if (png_sig_cmp(sig, 0, 8))
FATAL_ERROR("\"%s\" does not have a valid PNG signature.\n", path);
}
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
if (!png_ptr)
FATAL_ERROR("Failed to create PNG read struct.\n");
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
if (!info_ptr)
FATAL_ERROR("Failed to create PNG info struct.\n");
}
if (setjmp(png_jmpbuf(png_ptr))) {
if (setjmp(png_jmpbuf(png_ptr)))
FATAL_ERROR("Failed to init I/O for reading \"%s\".\n", path);
}
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, 8);
@ -53,7 +45,8 @@ static FILE *PngReadOpen(char *path, png_structp *pngStruct, png_infop *pngInfo)
return fp;
}
static unsigned char *ConvertBitDepth(unsigned char *src, int srcBitDepth, int destBitDepth, int numPixels) {
static unsigned char *ConvertBitDepth(unsigned char *src, int srcBitDepth, int destBitDepth, int numPixels)
{
// Round the number of bits up to the next 8 and divide by 8 to get the number of bytes.
int srcSize = ((numPixels * srcBitDepth + 7) & ~7) / 8;
int destSize = ((numPixels * destBitDepth + 7) & ~7) / 8;
@ -63,18 +56,20 @@ static unsigned char *ConvertBitDepth(unsigned char *src, int srcBitDepth, int d
int j;
int destBit = 8 - destBitDepth;
for (i = 0; i < srcSize; i++) {
for (i = 0; i < srcSize; i++)
{
unsigned char srcByte = src[i];
for (j = 8 - srcBitDepth; j >= 0; j -= srcBitDepth) {
for (j = 8 - srcBitDepth; j >= 0; j -= srcBitDepth)
{
unsigned char pixel = (srcByte >> j) % (1 << srcBitDepth);
if (pixel >= (1 << destBitDepth)) {
if (pixel >= (1 << destBitDepth))
FATAL_ERROR("Image exceeds the maximum color value for a %ibpp image.\n", destBitDepth);
}
*dest |= pixel << destBit;
destBit -= destBitDepth;
if (destBit < 0) {
if (destBit < 0)
{
dest++;
destBit = 8 - destBitDepth;
}
@ -84,7 +79,8 @@ static unsigned char *ConvertBitDepth(unsigned char *src, int srcBitDepth, int d
return output;
}
void ReadPng(char *path, struct Image *image) {
void ReadPng(char *path, struct Image *image)
{
png_structp png_ptr;
png_infop info_ptr;
@ -94,22 +90,12 @@ void ReadPng(char *path, struct Image *image) {
int color_type = png_get_color_type(png_ptr, info_ptr);
switch (color_type) {
case PNG_COLOR_TYPE_GRAY:
case PNG_COLOR_TYPE_GA:
case PNG_COLOR_TYPE_PALETTE:
case PNG_COLOR_TYPE_RGB:
case PNG_COLOR_TYPE_RGBA:
break;
default:
if (color_type != PNG_COLOR_TYPE_GRAY && color_type != PNG_COLOR_TYPE_PALETTE)
FATAL_ERROR("\"%s\" has an unsupported color type.\n", path);
}
// Check if the image has a palette so that we can tell if the colors need to be inverted later.
// Don't read the palette because it's not needed for now.
image->hasPalette = (color_type & PNG_COLOR_MASK_COLOR) != 0;
image->hasTransparency = color_type == PNG_COLOR_TYPE_PALETTE || ((color_type & PNG_COLOR_MASK_ALPHA) != 0);
image->pixelsAreRGB = (color_type & PNG_COLOR_MASK_COLOR) != 0 && (color_type & PNG_COLOR_MASK_PALETTE) == 0;
image->hasPalette = (color_type == PNG_COLOR_TYPE_PALETTE);
image->width = png_get_image_width(png_ptr, info_ptr);
image->height = png_get_image_height(png_ptr, info_ptr);
@ -118,23 +104,19 @@ void ReadPng(char *path, struct Image *image) {
image->pixels = malloc(image->height * rowbytes);
if (image->pixels == NULL) {
if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate pixel buffer.\n");
}
png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep));
if (row_pointers == NULL) {
if (row_pointers == NULL)
FATAL_ERROR("Failed to allocate row pointers.\n");
}
for (int i = 0; i < image->height; i++) {
for (int i = 0; i < image->height; i++)
row_pointers[i] = (png_bytep)(image->pixels + (i * rowbytes));
}
if (setjmp(png_jmpbuf(png_ptr))) {
if (setjmp(png_jmpbuf(png_ptr)))
FATAL_ERROR("Error reading from \"%s\".\n", path);
}
png_read_image(png_ptr, row_pointers);
@ -143,19 +125,20 @@ void ReadPng(char *path, struct Image *image) {
free(row_pointers);
fclose(fp);
if ((color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth != image->bitDepth) {
if (bit_depth != image->bitDepth)
{
unsigned char *src = image->pixels;
if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && bit_depth != 8) {
if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && bit_depth != 8)
FATAL_ERROR("Bit depth of image must be 1, 2, 4, or 8.\n");
}
image->pixels = ConvertBitDepth(image->pixels, bit_depth, image->bitDepth, image->width * image->height);
free(src);
image->bitDepth = bit_depth;
}
}
void ReadPngPalette(char *path, struct Palette *palette) {
void ReadPngPalette(char *path, struct Palette *palette)
{
png_structp png_ptr;
png_infop info_ptr;
png_colorp colors;
@ -163,17 +146,14 @@ void ReadPngPalette(char *path, struct Palette *palette) {
FILE *fp = PngReadOpen(path, &png_ptr, &info_ptr);
if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_PALETTE) {
if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_PALETTE)
FATAL_ERROR("The image \"%s\" does not contain a palette.\n", path);
}
if (png_get_PLTE(png_ptr, info_ptr, &colors, &numColors) != PNG_INFO_PLTE) {
if (png_get_PLTE(png_ptr, info_ptr, &colors, &numColors) != PNG_INFO_PLTE)
FATAL_ERROR("Failed to retrieve palette from \"%s\".\n", path);
}
if (numColors > 256) {
if (numColors > 256)
FATAL_ERROR("Images with more than 256 colors are not supported.\n");
}
palette->numColors = numColors;
for (int i = 0; i < numColors; i++) {
@ -189,12 +169,12 @@ void ReadPngPalette(char *path, struct Palette *palette) {
fclose(fp);
}
void SetPngPalette(png_structp png_ptr, png_infop info_ptr, struct Palette *palette) {
void SetPngPalette(png_structp png_ptr, png_infop info_ptr, struct Palette *palette)
{
png_colorp colors = malloc(palette->numColors * sizeof(png_color));
if (colors == NULL) {
if (colors == NULL)
FATAL_ERROR("Failed to allocate PNG palette.\n");
}
for (int i = 0; i < palette->numColors; i++) {
colors[i].red = palette->colors[i].red;
@ -207,50 +187,40 @@ void SetPngPalette(png_structp png_ptr, png_infop info_ptr, struct Palette *pale
free(colors);
}
void WritePng(char *path, struct Image *image) {
void WritePng(char *path, struct Image *image)
{
FILE *fp = fopen(path, "wb");
if (fp == NULL) {
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
}
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
if (!png_ptr)
FATAL_ERROR("Failed to create PNG write struct.\n");
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
if (!info_ptr)
FATAL_ERROR("Failed to create PNG info struct.\n");
}
if (setjmp(png_jmpbuf(png_ptr))) {
if (setjmp(png_jmpbuf(png_ptr)))
FATAL_ERROR("Failed to init I/O for writing \"%s\".\n", path);
}
png_init_io(png_ptr, fp);
if (setjmp(png_jmpbuf(png_ptr))) {
if (setjmp(png_jmpbuf(png_ptr)))
FATAL_ERROR("Error writing header for \"%s\".\n", path);
}
int color_type = PNG_COLOR_TYPE_GRAY;
int color_type = image->hasPalette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_GRAY;
png_set_IHDR(png_ptr, info_ptr, image->width, image->height,
image->bitDepth, color_type, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
if (image->hasPalette) {
color_type |= PNG_COLOR_MASK_COLOR;
if (!image->pixelsAreRGB) {
color_type |= PNG_COLOR_MASK_PALETTE;
}
}
if (image->hasTransparency && !(color_type & PNG_COLOR_MASK_PALETTE)) {
color_type |= PNG_COLOR_MASK_ALPHA;
}
png_set_IHDR(png_ptr, info_ptr, image->width, image->height, image->bitDepth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
if (color_type == PNG_COLOR_TYPE_PALETTE) {
SetPngPalette(png_ptr, info_ptr, &image->palette);
if (image->hasTransparency) {
png_byte trans = 0;
png_set_tRNS(png_ptr, info_ptr, &trans, 1, 0);
@ -261,25 +231,21 @@ void WritePng(char *path, struct Image *image) {
png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep));
if (row_pointers == NULL) {
if (row_pointers == NULL)
FATAL_ERROR("Failed to allocate row pointers.\n");
}
int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
for (int i = 0; i < image->height; i++) {
for (int i = 0; i < image->height; i++)
row_pointers[i] = (png_bytep)(image->pixels + (i * rowbytes));
}
if (setjmp(png_jmpbuf(png_ptr))) {
if (setjmp(png_jmpbuf(png_ptr)))
FATAL_ERROR("Error writing \"%s\".\n", path);
}
png_write_image(png_ptr, row_pointers);
if (setjmp(png_jmpbuf(png_ptr))) {
if (setjmp(png_jmpbuf(png_ptr)))
FATAL_ERROR("Error ending write of \"%s\".\n", path);
}
png_write_end(png_ptr, NULL);

View File

@ -1,32 +1,29 @@
// Copyright (c) 2015 YamaArashi
#include "font.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "global.h"
#include "font.h"
#include "gfx.h"
#include "options.h"
#include "util.h"
unsigned char gFontPalette[][3] = {
{ 0x90, 0xC8, 0xFF }, // bg (saturated blue that contrasts well with the shadow color)
{ 0x38, 0x38, 0x38 }, // fg (dark grey)
{ 0xD8, 0xD8, 0xD8 }, // shadow (light grey)
{ 0xFF, 0xFF, 0xFF } // box (white)
{0x90, 0xC8, 0xFF}, // bg (saturated blue that contrasts well with the shadow color)
{0x38, 0x38, 0x38}, // fg (dark grey)
{0xD8, 0xD8, 0xD8}, // shadow (light grey)
{0xFF, 0xFF, 0xFF} // box (white)
};
// special palette for DS subscreen font
unsigned char gFontPalette_Subscreen[][3] = {
{ 0x90, 0xC8, 0xFF }, // bg (saturated blue that contrasts well with the shadow color)
{ 0xFF, 0xFF, 0xFF }, // fg (white)
{ 0xD8, 0xD8, 0xD8 }, // shadow (light grey)
{ 0x38, 0x38, 0x38 }, // outline (dark grey)
{0x90, 0xC8, 0xFF}, // bg (saturated blue that contrasts well with the shadow color)
{0xFF, 0xFF, 0xFF}, // fg (white)
{0xD8, 0xD8, 0xD8}, // shadow (light grey)
{0x38, 0x38, 0x38}, // outline (dark grey)
};
static void ConvertFromLatinFont(unsigned char *src, unsigned char *dest, unsigned int numRows)
@ -39,7 +36,7 @@ static void ConvertFromLatinFont(unsigned char *src, unsigned char *dest, unsign
unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8);
for (unsigned int i = 0; i < 8; i++) {
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
unsigned int destPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
@ -88,7 +85,7 @@ static void ConvertFromHalfwidthJapaneseFont(unsigned char *src, unsigned char *
for (unsigned int i = 0; i < 8; i++) {
unsigned int pixelsY = (row * 16) + (glyphTile * 8) + i;
unsigned int destPixelsOffset = (pixelsY * 32) + (pixelsX / 4);
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
@ -171,7 +168,8 @@ static void ConvertToFullwidthJapaneseFont(unsigned char *src, unsigned char *de
}
}
static void ConvertFromNitroFont(unsigned char *src, unsigned char *dest, unsigned int numRows, struct NtrFontMetadata *metadata) {
static void ConvertFromNitroFont(unsigned char *src, unsigned char *dest, unsigned int numRows, struct NtrFontMetadata *metadata)
{
unsigned int srcPixelsOffset = 0;
unsigned int curGlyph = 0;
@ -194,7 +192,8 @@ static void ConvertFromNitroFont(unsigned char *src, unsigned char *dest, unsign
}
}
static void ConvertToNitroFont(unsigned char *src, unsigned char *dest, unsigned int numRows, struct NtrFontMetadata *metadata) {
static void ConvertToNitroFont(unsigned char *src, unsigned char *dest, unsigned int numRows, struct NtrFontMetadata *metadata)
{
unsigned int destPixelsOffset = 0;
unsigned int curGlyph = 0;
@ -232,7 +231,8 @@ static void SetFontPalette(struct Image *image)
image->hasTransparency = false;
}
static void SetSubscreenFontPalette(struct Image *image) {
static void SetSubscreenFontPalette(struct Image *image)
{
image->hasPalette = true;
image->palette.numColors = 4;
@ -253,9 +253,8 @@ void ReadLatinFont(char *path, struct Image *image)
int numGlyphs = fileSize / 64;
if (numGlyphs % 16 != 0) {
if (numGlyphs % 16 != 0)
FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs);
}
int numRows = numGlyphs / 16;
@ -264,9 +263,8 @@ void ReadLatinFont(char *path, struct Image *image)
image->bitDepth = 2;
image->pixels = malloc(fileSize);
if (image->pixels == NULL) {
if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
}
ConvertFromLatinFont(buffer, image->pixels, numRows);
@ -277,21 +275,18 @@ void ReadLatinFont(char *path, struct Image *image)
void WriteLatinFont(char *path, struct Image *image)
{
if (image->width != 256) {
if (image->width != 256)
FATAL_ERROR("The width of the font image (%d) is not 256.\n", image->width);
}
if (image->height % 16 != 0) {
if (image->height % 16 != 0)
FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height);
}
int numRows = image->height / 16;
int bufferSize = numRows * 16 * 64;
unsigned char *buffer = malloc(bufferSize);
if (buffer == NULL) {
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
}
ConvertToLatinFont(image->pixels, buffer, numRows);
@ -307,15 +302,13 @@ void ReadHalfwidthJapaneseFont(char *path, struct Image *image)
int glyphSize = 32;
if (fileSize % glyphSize != 0) {
if (fileSize % glyphSize != 0)
FATAL_ERROR("The file size (%d) is not a multiple of %d.\n", fileSize, glyphSize);
}
int numGlyphs = fileSize / glyphSize;
if (numGlyphs % 16 != 0) {
if (numGlyphs % 16 != 0)
FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs);
}
int numRows = numGlyphs / 16;
@ -324,9 +317,8 @@ void ReadHalfwidthJapaneseFont(char *path, struct Image *image)
image->bitDepth = 2;
image->pixels = malloc(fileSize);
if (image->pixels == NULL) {
if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
}
ConvertFromHalfwidthJapaneseFont(buffer, image->pixels, numRows);
@ -337,21 +329,18 @@ void ReadHalfwidthJapaneseFont(char *path, struct Image *image)
void WriteHalfwidthJapaneseFont(char *path, struct Image *image)
{
if (image->width != 128) {
if (image->width != 128)
FATAL_ERROR("The width of the font image (%d) is not 128.\n", image->width);
}
if (image->height % 16 != 0) {
if (image->height % 16 != 0)
FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height);
}
int numRows = image->height / 16;
int bufferSize = numRows * 16 * 32;
unsigned char *buffer = malloc(bufferSize);
if (buffer == NULL) {
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
}
ConvertToHalfwidthJapaneseFont(image->pixels, buffer, numRows);
@ -367,9 +356,8 @@ void ReadFullwidthJapaneseFont(char *path, struct Image *image)
int numGlyphs = fileSize / 64;
if (numGlyphs % 16 != 0) {
if (numGlyphs % 16 != 0)
FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs);
}
int numRows = numGlyphs / 16;
@ -378,9 +366,8 @@ void ReadFullwidthJapaneseFont(char *path, struct Image *image)
image->bitDepth = 2;
image->pixels = malloc(fileSize);
if (image->pixels == NULL) {
if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
}
ConvertFromFullwidthJapaneseFont(buffer, image->pixels, numRows);
@ -391,21 +378,18 @@ void ReadFullwidthJapaneseFont(char *path, struct Image *image)
void WriteFullwidthJapaneseFont(char *path, struct Image *image)
{
if (image->width != 256) {
if (image->width != 256)
FATAL_ERROR("The width of the font image (%d) is not 256.\n", image->width);
}
if (image->height % 16 != 0) {
if (image->height % 16 != 0)
FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height);
}
int numRows = image->height / 16;
int bufferSize = numRows * 16 * 64;
unsigned char *buffer = malloc(bufferSize);
if (buffer == NULL) {
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
}
ConvertToFullwidthJapaneseFont(image->pixels, buffer, numRows);
@ -414,14 +398,16 @@ void WriteFullwidthJapaneseFont(char *path, struct Image *image)
free(buffer);
}
static inline uint32_t ReadLittleEndianWord(unsigned char *buffer, size_t start) {
static inline uint32_t ReadLittleEndianWord(unsigned char *buffer, size_t start)
{
return (buffer[start + 3] << 24)
| (buffer[start + 2] << 16)
| (buffer[start + 1] << 8)
| (buffer[start]);
}
void ReadNtrFont(char *path, struct Image *image, struct NtrFontMetadata *metadata, bool useSubscreenPalette) {
void ReadNtrFont(char *path, struct Image *image, struct NtrFontMetadata *metadata, bool useSubscreenPalette)
{
int filesize;
unsigned char *buffer = ReadWholeFile(path, &filesize);
@ -443,37 +429,33 @@ void ReadNtrFont(char *path, struct Image *image, struct NtrFontMetadata *metada
image->bitDepth = 2;
image->pixels = malloc(filesize);
if (image->pixels == NULL) {
if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
}
ConvertFromNitroFont(buffer + metadata->size, image->pixels, numRows, metadata);
free(buffer);
if (useSubscreenPalette) {
if (useSubscreenPalette)
SetSubscreenFontPalette(image);
} else {
else
SetFontPalette(image);
}
}
void WriteNtrFont(char *path, struct Image *image, struct NtrFontMetadata *metadata) {
if (image->width != 256) {
void WriteNtrFont(char *path, struct Image *image, struct NtrFontMetadata *metadata)
{
if (image->width != 256)
FATAL_ERROR("The width of the font image (%d) is not 256.\n", image->width);
}
if (image->height % 16 != 0) {
if (image->height % 16 != 0)
FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height);
}
int numRows = image->height / 16;
int bufferSize = metadata->widthTableOffset + metadata->numGlyphs;
unsigned char *buffer = malloc(bufferSize);
if (buffer == NULL) {
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
}
buffer[0x00] = (metadata->size & 0x000000FF);
buffer[0x01] = (metadata->size & 0x0000FF00) >> 8;
@ -500,7 +482,8 @@ void WriteNtrFont(char *path, struct Image *image, struct NtrFontMetadata *metad
free(buffer);
}
void FreeNtrFontMetadata(struct NtrFontMetadata *metadata) {
void FreeNtrFontMetadata(struct NtrFontMetadata *metadata)
{
free(metadata->glyphWidthTable);
free(metadata);
}

View File

@ -4,7 +4,6 @@
#define FONT_H
#include <stdbool.h>
#include "gfx.h"
#include "options.h"

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +1,28 @@
// Copyright (c) 2015 YamaArashi, 2021-2024 red031000
// Copyright (c) 2015 YamaArashi, 2021-2025 red031000
#ifndef GFX_H
#define GFX_H
#include <stdbool.h>
#include <stdint.h>
#include <stdbool.h>
#include "options.h"
struct Color {
unsigned char red;
unsigned char green;
unsigned char blue;
unsigned char red;
unsigned char green;
unsigned char blue;
};
struct Palette {
struct Color colors[16 * 256];
int numColors;
int bitDepth;
struct Color colors[256];
int numColors;
int bitDepth;
};
struct Image {
int width;
int height;
int bitDepth;
int width;
int height;
int bitDepth;
/**
* Pseudocode for converting index in pixels to coordinates in image is as follows
* (where (0, 0) is the top left corner with the format (x, y) ):
@ -45,33 +44,22 @@ struct Image {
* pixel = pixels[i]
* pixel coordinates: (xCoord, yCoord)
*/
unsigned char *pixels;
bool hasPalette;
struct Palette palette;
bool hasTransparency;
bool pixelsAreRGB;
};
struct NSCRFile {
uint16_t scrnWidth; // output width in pixels
uint16_t scrnHeight; // output height in pixels
uint16_t colorMode; // 4bpp or 8bpp
uint16_t scrnMode; // text, affine, or extpltt
uint32_t scrnSize; // total data length
uint8_t data[]; // data
unsigned char *pixels;
bool hasPalette;
struct Palette palette;
bool hasTransparency;
};
void ReadImage(char *path, int tilesWide, int bitDepth, int colsPerChunk, int rowsPerChunk, struct Image *image, bool invertColors);
uint32_t ReadNtrImage(char *path, int tilesWide, int bitDepth, int colsPerChunk, int rowsPerChunk, struct Image *image, bool invertColors, bool scanFrontToBack);
void ApplyCellsToImage(char *cellFilePath, struct Image *image, bool toPNG);
void ApplyScrnToImage(char *scrnFilePath, struct Image *image);
uint32_t ReadNtrImage(char *path, int tilesWide, int bitDepth, int colsPerChunk, int rowsPerChunk, struct Image *image, bool invertColors, uint32_t encodeMode, bool convertTo8Bpp, int palIndex, bool verbose);
void ApplyCellsToImage(char *cellFilePath, struct Image *image, bool toPNG, bool snap);
void WriteImage(char *path, int numTiles, int bitDepth, int colsPerChunk, int rowsPerChunk, struct Image *image, bool invertColors);
void WriteNtrImage(char *path, int numTiles, int bitDepth, int colsPerChunk, int rowsPerChunk, struct Image *image, bool invertColors, bool clobberSize, bool byteOrder, bool version101, bool sopc, bool vram, uint32_t scanMode, uint32_t mappingType, uint32_t key, bool wrongSize);
void WriteNtrImage(char *path, int numTiles, int bitDepth, int colsPerChunk, int rowsPerChunk, struct Image *image, bool invertColors, bool clobberSize, bool byteOrder, bool version101, bool sopc, bool vram, bool scan, uint32_t encodeMode, uint32_t mappingType, uint32_t key, bool wrongSize, bool convertTo4Bpp);
void FreeImage(struct Image *image);
void ReadGbaPalette(char *path, struct Palette *palette);
void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIndex, bool inverted);
void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIndex, bool inverted, bool convertTo8Bpp);
void WriteGbaPalette(char *path, struct Palette *palette);
void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, int bitdepth, bool pad, int compNum, bool pcmp, bool inverted);
void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, int bitdepth, bool pad, int compNum, bool pcmp, int pcmpStartIndex, bool inverted, bool convertTo4Bpp);
void ReadNtrCell(char *path, struct JsonToCellOptions *options);
void WriteNtrCell(char *path, struct JsonToCellOptions *options);
void WriteNtrScreen(char *path, struct JsonToScreenOptions *options);

View File

@ -8,37 +8,30 @@
#ifdef _MSC_VER
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, __VA_ARGS__); \
exit(1); \
} while (0)
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, __VA_ARGS__); \
exit(1); \
} while (0)
#define UNUSED
#else
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, ##__VA_ARGS__); \
fprintf(stderr, " -- %s:%d\n", __FILE__, __LINE__); \
abort(); \
} while (0)
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, ##__VA_ARGS__); \
exit(1); \
} while (0)
#define UNUSED __attribute__((__unused__))
#endif // _MSC_VER
#define PTR_ADD(ptr, value) ((void *)((uintptr_t)(ptr) + (value)))
#define PTR_SUB(ptr, value) ((void *)((uintptr_t)(ptr) - (value)))
#define PTR_IADD(ptr, value) \
do { \
(ptr) = PTR_ADD(ptr, value); \
} while (0)
#define PTR_ISUB(ptr, value) \
do { \
(ptr) = PTR_SUB(ptr, value); \
} while (0)
#define PTR_ADD(ptr, value) ((void*)((uintptr_t)(ptr) + (value)))
#define PTR_SUB(ptr, value) ((void*)((uintptr_t)(ptr) - (value)))
#define PTR_IADD(ptr, value) do { (ptr) = PTR_ADD(ptr, value); } while (0)
#define PTR_ISUB(ptr, value) do { (ptr) = PTR_SUB(ptr, value); } while (0)
#define PTR_DIFF(right, left) ((uintptr_t)(right) - (uintptr_t)(left))
#endif // GLOBAL_H

View File

@ -1,4 +1,4 @@
// Copyright (c) 2021-2024 red031000
// Copyright (c) 2021-2025 red031000
#include "global.h"
#include "cJSON.h"
@ -47,13 +47,17 @@ struct JsonToCellOptions *ParseNCERJson(char *path)
}
cJSON *labelBool = cJSON_GetObjectItemCaseSensitive(json, "labelEnabled");
cJSON *dontPadKbecBool = cJSON_GetObjectItemCaseSensitive(json, "dontPadKbec");
cJSON *vramTransferBool = cJSON_GetObjectItemCaseSensitive(json, "vramTransferEnabled");
cJSON *ucatBool = cJSON_GetObjectItemCaseSensitive(json, "ucatEnabled");
cJSON *extended = cJSON_GetObjectItemCaseSensitive(json, "extended");
cJSON *cellCount = cJSON_GetObjectItemCaseSensitive(json, "cellCount");
cJSON *mappingType = cJSON_GetObjectItemCaseSensitive(json, "mappingType");
options->labelEnabled = GetBool(labelBool);
options->dontPadKbec = GetBool(dontPadKbecBool);
options->vramTransferEnabled = GetBool(vramTransferBool);
options->ucatEnabled = GetBool(ucatBool);
options->extended = GetBool(extended);
options->cellCount = GetInt(cellCount);
options->mappingType = GetInt(mappingType);
@ -79,17 +83,19 @@ struct JsonToCellOptions *ParseNCERJson(char *path)
}
}
if (options->vramTransferEnabled) {
if (options->vramTransferEnabled)
{
cJSON *vramTransferMaxSize = cJSON_GetObjectItemCaseSensitive(json, "vramTransferMaxSize");
options->vramTransferMaxSize = GetInt(vramTransferMaxSize);
options->transferData = malloc(sizeof(struct CellVramTransferData *) * options->cellCount);
cJSON *transfers = cJSON_GetObjectItemCaseSensitive(json, "transferData");
cJSON *transfer = NULL;
int j = 0;
cJSON_ArrayForEach(transfer, transfers) {
cJSON_ArrayForEach(transfer, transfers)
{
cJSON *vramTransferOffset = cJSON_GetObjectItemCaseSensitive(transfer, "offset");
cJSON *vramTransferSize = cJSON_GetObjectItemCaseSensitive(transfer, "size");
@ -101,6 +107,16 @@ struct JsonToCellOptions *ParseNCERJson(char *path)
}
}
if (options->ucatEnabled) {
cJSON *ucatCells = cJSON_GetObjectItemCaseSensitive(json, "cellAttributes");
options->ucatCellAttribtes = malloc(sizeof(uint32_t) * options->cellCount);
for (int i = 0; i < options->cellCount; i++) {
options->ucatCellAttribtes[i] = GetInt(cJSON_GetArrayItem(ucatCells, i));
}
}
for (int i = 0; i < options->cellCount; i++)
{
options->cells[i] = malloc(sizeof(struct Cell));
@ -172,7 +188,11 @@ struct JsonToCellOptions *ParseNCERJson(char *path)
cJSON *Colours = cJSON_GetObjectItemCaseSensitive(Attr0, "Colours");
cJSON *Shape = cJSON_GetObjectItemCaseSensitive(Attr0, "Shape");
options->cells[i]->oam[j].attr0.YCoordinate = GetInt(YCoordinate);
int y = GetInt(YCoordinate);
if (y & (1 << 7)) {
y &= 0xFF;
}
options->cells[i]->oam[j].attr0.YCoordinate = y;
options->cells[i]->oam[j].attr0.Rotation = GetBool(Rotation);
options->cells[i]->oam[j].attr0.SizeDisable = GetBool(SizeDisable);
options->cells[i]->oam[j].attr0.Mode = GetInt(Mode);
@ -187,7 +207,11 @@ struct JsonToCellOptions *ParseNCERJson(char *path)
cJSON *RotationScaling = cJSON_GetObjectItemCaseSensitive(Attr1, "RotationScaling");
cJSON *Size = cJSON_GetObjectItemCaseSensitive(Attr1, "Size");
options->cells[i]->oam[j].attr1.XCoordinate = GetInt(XCoordinate);
int x = GetInt(XCoordinate);
if (x & (1 << 8)) {
x &= 0x1FF;
}
options->cells[i]->oam[j].attr1.XCoordinate = x;
options->cells[i]->oam[j].attr1.RotationScaling = GetInt(RotationScaling);
options->cells[i]->oam[j].attr1.Size = GetInt(Size);
@ -218,8 +242,10 @@ char *GetNCERJson(struct JsonToCellOptions *options)
cJSON *ncer = cJSON_CreateObject();
cJSON_AddBoolToObject(ncer, "labelEnabled", options->labelEnabled);
cJSON_AddBoolToObject(ncer, "dontPadKbec", options->dontPadKbec);
cJSON_AddBoolToObject(ncer, "extended", options->extended);
cJSON_AddBoolToObject(ncer, "vramTransferEnabled", options->vramTransferEnabled);
cJSON_AddBoolToObject(ncer, "ucatEnabled", options->ucatEnabled);
cJSON_AddNumberToObject(ncer, "cellCount", options->cellCount);
cJSON_AddNumberToObject(ncer, "mappingType", options->mappingType);
@ -255,7 +281,11 @@ char *GetNCERJson(struct JsonToCellOptions *options)
cJSON *Attr0 = cJSON_AddObjectToObject(OAM, "Attr0");
cJSON_AddNumberToObject(Attr0, "YCoordinate", options->cells[i]->oam[j].attr0.YCoordinate);
int y = options->cells[i]->oam[j].attr0.YCoordinate;
if (y & (1 << 7)) {
y |= ~0xFF;
}
cJSON_AddNumberToObject(Attr0, "YCoordinate", y);
cJSON_AddBoolToObject(Attr0, "Rotation", options->cells[i]->oam[j].attr0.Rotation);
cJSON_AddBoolToObject(Attr0, "SizeDisable", options->cells[i]->oam[j].attr0.SizeDisable);
cJSON_AddNumberToObject(Attr0, "Mode", options->cells[i]->oam[j].attr0.Mode);
@ -265,7 +295,11 @@ char *GetNCERJson(struct JsonToCellOptions *options)
cJSON *Attr1 = cJSON_AddObjectToObject(OAM, "Attr1");
cJSON_AddNumberToObject(Attr1, "XCoordinate", options->cells[i]->oam[j].attr1.XCoordinate);
int x = options->cells[i]->oam[j].attr1.XCoordinate;
if (x & (1 << 8)) {
x |= ~0x1FF;
}
cJSON_AddNumberToObject(Attr1, "XCoordinate", x);
cJSON_AddNumberToObject(Attr1, "RotationScaling", options->cells[i]->oam[j].attr1.RotationScaling);
cJSON_AddNumberToObject(Attr1, "Size", options->cells[i]->oam[j].attr1.Size);
@ -288,11 +322,13 @@ char *GetNCERJson(struct JsonToCellOptions *options)
cJSON_AddNumberToObject(ncer, "labelCount", options->labelCount);
}
if (options->vramTransferEnabled) {
if (options->vramTransferEnabled)
{
cJSON_AddNumberToObject(ncer, "vramTransferMaxSize", options->vramTransferMaxSize);
cJSON *transfers = cJSON_AddArrayToObject(ncer, "transferData");
for (int idx = 0; idx < options->cellCount; idx++) {
for (int idx = 0; idx < options->cellCount; idx++)
{
cJSON *transfer = cJSON_CreateObject();
cJSON_AddNumberToObject(transfer, "offset", options->transferData[idx]->sourceDataOffset);
cJSON_AddNumberToObject(transfer, "size", options->transferData[idx]->size);
@ -300,6 +336,14 @@ char *GetNCERJson(struct JsonToCellOptions *options)
}
}
if (options->ucatEnabled) {
cJSON *ucatCells = cJSON_AddArrayToObject(ncer, "cellAttributes");
for (int i = 0; i < options->cellCount; i++) {
cJSON_AddNumberToObject(ucatCells, "cellAttr", options->ucatCellAttribtes[i]);
}
}
char *jsonString = cJSON_Print(ncer);
cJSON_Delete(ncer);
return jsonString;
@ -473,6 +517,9 @@ struct JsonToAnimationOptions *ParseNANRJson(char *path)
if (i > options->resultCount - 1)
FATAL_ERROR("Frame count is incorrect.\n");
// init padding to false, this is used in gfx.c to control padding, and is therefore checked there
options->animationResults[i]->padded = false;
cJSON *resultType = cJSON_GetObjectItemCaseSensitive(animationResult, "resultType");
options->animationResults[i]->resultType = GetInt(resultType);
switch (options->animationResults[i]->resultType) {
@ -538,6 +585,27 @@ struct JsonToAnimationOptions *ParseNANRJson(char *path)
}
}
cJSON *uaatBool = cJSON_GetObjectItemCaseSensitive(json, "uaatEnabled");
options->uaatEnabled = GetBool(uaatBool);
if (options->uaatEnabled) {
cJSON *uaatData = cJSON_GetObjectItemCaseSensitive(json, "uaatData");
cJSON *uaatSequences = cJSON_GetObjectItemCaseSensitive(uaatData, "sequenceAttributes");
options->uaatData.sequenceAttributes = malloc(sizeof(uint32_t) * options->sequenceCount);
for (int i = 0; i < options->sequenceCount; i++) {
cJSON *uaatSeq = cJSON_GetArrayItem(uaatSequences, i);
options->uaatData.sequenceAttributes[i] = GetInt(uaatSeq);
}
cJSON *uaatFrames = cJSON_GetObjectItemCaseSensitive(uaatData, "frameAttributes");
options->uaatData.frameAttributes = malloc(sizeof(uint32_t) * options->frameCount);
for (int i = 0; i < options->frameCount; i++) {
cJSON *uaatFra = cJSON_GetArrayItem(uaatFrames, i);
options->uaatData.frameAttributes[i] = GetInt(uaatFra);
}
}
cJSON_Delete(json);
free(jsonString);
return options;
@ -548,6 +616,7 @@ char *GetNANRJson(struct JsonToAnimationOptions *options)
cJSON *nanr = cJSON_CreateObject();
cJSON_AddBoolToObject(nanr, "labelEnabled", options->labelEnabled);
cJSON_AddBoolToObject(nanr, "uaatEnabled", options->uaatEnabled);
cJSON_AddNumberToObject(nanr, "sequenceCount", options->sequenceCount);
cJSON_AddNumberToObject(nanr, "frameCount", options->frameCount);
@ -617,6 +686,20 @@ char *GetNANRJson(struct JsonToAnimationOptions *options)
cJSON_AddNumberToObject(nanr, "labelCount", options->labelCount);
}
if (options->uaatEnabled) {
cJSON *uaat = cJSON_AddObjectToObject(nanr, "uaatData");
cJSON *uaatSequences = cJSON_AddArrayToObject(uaat, "sequenceAttributes");
for (int i = 0; i < options->sequenceCount; i++) {
cJSON_AddNumberToObject(uaatSequences, "seqAttr", options->uaatData.sequenceAttributes[i]);
}
cJSON *uaatFrames = cJSON_AddArrayToObject(uaat, "frameAttributes");
for (int i = 0; i < options->frameCount; i++) {
cJSON_AddNumberToObject(uaatFrames, "fraAttr", options->uaatData.frameAttributes[i]);
}
}
char *jsonString = cJSON_Print(nanr);
cJSON_Delete(nanr);
return jsonString;
@ -637,12 +720,17 @@ void FreeNCERCell(struct JsonToCellOptions *options)
}
free(options->labels);
}
if (options->vramTransferEnabled) {
for (int j = 0; j < options->cellCount; j++) {
if (options->vramTransferEnabled)
{
for (int j = 0; j < options->cellCount; j++)
{
free(options->transferData[j]);
}
free(options->transferData);
}
if (options->ucatEnabled) {
free(options->ucatCellAttribtes);
}
free(options->cells);
free(options);
}
@ -669,6 +757,10 @@ void FreeNANRAnimation(struct JsonToAnimationOptions *options)
{
free(options->animationResults[i]);
}
if (options->uaatEnabled) {
free(options->uaatData.sequenceAttributes);
free(options->uaatData.frameAttributes);
}
if (options->labelEnabled)
{
for (int j = 0; j < options->labelCount; j++)
@ -682,14 +774,16 @@ void FreeNANRAnimation(struct JsonToAnimationOptions *options)
free(options);
}
char *GetNtrFontMetadataJson(struct NtrFontMetadata *metadata) {
char *GetNtrFontMetadataJson(struct NtrFontMetadata *metadata)
{
cJSON *json = cJSON_CreateObject();
cJSON_AddNumberToObject(json, "maxGlyphWidth", metadata->maxWidth);
cJSON_AddNumberToObject(json, "maxGlyphHeight", metadata->maxHeight);
cJSON *glyphWidths = cJSON_AddArrayToObject(json, "glyphWidths");
for (int i = 0; i < metadata->numGlyphs; i++) {
for (int i = 0; i < metadata->numGlyphs; i++)
{
cJSON *width = cJSON_CreateNumber(metadata->glyphWidthTable[i]);
cJSON_AddItemToArray(glyphWidths, width);
}
@ -699,18 +793,20 @@ char *GetNtrFontMetadataJson(struct NtrFontMetadata *metadata) {
return jsonString;
}
#define TILE_DIMENSION_PIXELS 8
#define TILE_DIMENSION_PIXELS 8
#define PIXELS_FOR_DIMENSION(dim) ((dim) * TILE_DIMENSION_PIXELS)
#define TILES_FOR_PIXELS(num) (((num) + TILE_DIMENSION_PIXELS - 1) / TILE_DIMENSION_PIXELS)
#define PIXELS_PER_BYTE_2BPP 4
#define NTR_FONT_HEADER_SIZE 16
#define TILES_FOR_PIXELS(num) (((num) + TILE_DIMENSION_PIXELS - 1) / TILE_DIMENSION_PIXELS)
#define PIXELS_PER_BYTE_2BPP 4
#define NTR_FONT_HEADER_SIZE 16
struct NtrFontMetadata *ParseNtrFontMetadataJson(char *path) {
struct NtrFontMetadata *ParseNtrFontMetadataJson(char *path)
{
int fileLength;
unsigned char *jsonString = ReadWholeFile(path, &fileLength);
cJSON *json = cJSON_Parse((const char *)jsonString);
if (json == NULL) {
if (json == NULL)
{
const char *errorPtr = cJSON_GetErrorPtr();
FATAL_ERROR("Error in line \"%s\"\n", errorPtr);
}
@ -737,8 +833,10 @@ struct NtrFontMetadata *ParseNtrFontMetadataJson(char *path) {
uint8_t *glyphWidthCursor = metadata->glyphWidthTable;
cJSON *glyphWidthIter = NULL;
cJSON_ArrayForEach(glyphWidthIter, labelGlyphWidths) {
if (!cJSON_IsNumber(glyphWidthIter)) {
cJSON_ArrayForEach(glyphWidthIter, labelGlyphWidths)
{
if (!cJSON_IsNumber(glyphWidthIter))
{
const char *errorPtr = cJSON_GetErrorPtr();
FATAL_ERROR("Error in line \"%s\"\n", errorPtr);
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2021-2024 red031000
// Copyright (c) 2021-2025 red031000
#ifndef JSON_H
#define JSON_H

View File

@ -1,69 +1,39 @@
// Copyright (c) 2015 YamaArashi
#include "lz.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "global.h"
#include "lz.h"
static inline int getBlockSize(unsigned char *src, int *srcPos, int extFormat) {
int blockSize = (src[*srcPos] >> 4);
if (!extFormat) {
blockSize += 3;
} else {
if (blockSize > 1) {
blockSize += 1;
} else {
int isWide = (blockSize == 1 ? 1 : 0);
blockSize = (src[(*srcPos)++] & 0xF) << 4;
if (isWide) {
blockSize = (blockSize << 8) + (src[(*srcPos)++] << 4) + 0x100;
}
blockSize += 0x11 + (src[*srcPos] >> 4);
}
}
return blockSize;
}
unsigned char *LZDecompress(unsigned char *src, int srcSize, int *uncompressedSize) {
if (srcSize < 4) {
unsigned char *LZDecompress(unsigned char *src, int srcSize, int *uncompressedSize)
{
if (srcSize < 4)
goto fail;
}
if ((src[0] & 0xF0) != 0x10) {
goto fail;
}
int destSize = (src[3] << 16) | (src[2] << 8) | src[1];
unsigned char *dest = malloc(destSize);
if (dest == NULL) {
if (dest == NULL)
goto fail;
}
int srcPos = 4;
int destPos = 0;
int extFormat = src[0] & 0xF ? 1 : 0;
for (;;) {
if (srcPos >= srcSize) {
if (srcPos >= srcSize)
goto fail;
}
unsigned char flags = src[srcPos++];
for (int i = 0; i < 8; i++) {
if (flags & 0x80) {
if (srcPos + 1 >= srcSize) {
if (srcPos + 1 >= srcSize)
goto fail;
}
int blockSize = getBlockSize(src, &srcPos, extFormat);
int blockSize = (src[srcPos] >> 4) + 3;
int blockDistance = (((src[srcPos] & 0xF) << 8) | src[srcPos + 1]) + 1;
srcPos += 2;
@ -76,17 +46,14 @@ unsigned char *LZDecompress(unsigned char *src, int srcSize, int *uncompressedSi
fprintf(stderr, "Destination buffer overflow.\n");
}
if (blockPos < 0) {
if (blockPos < 0)
goto fail;
}
for (int j = 0; j < blockSize; j++) {
for (int j = 0; j < blockSize; j++)
dest[destPos++] = dest[blockPos + j];
}
} else {
if (srcPos >= srcSize || destPos >= destSize) {
if (srcPos >= srcSize || destPos >= destSize)
goto fail;
}
dest[destPos++] = src[srcPos++];
}
@ -104,66 +71,60 @@ fail:
FATAL_ERROR("Fatal error while decompressing LZ file.\n");
}
static void FindBestBlockForwards(unsigned char *src, int srcPos, int srcSize, const int minDistance, int *outBestBlockDistance, int *outBestBlockSize, bool extFormat) {
static void FindBestBlockForwards(unsigned char *src, int srcPos, int srcSize, const int minDistance, int *outBestBlockDistance, int *outBestBlockSize)
{
int blockStart = srcPos < 0x1000 ? 0 : srcPos - 0x1000;
int maxBlockSize = extFormat ? 0xF210 : 18;
while (blockStart != srcPos) {
int blockSize = 0;
while (blockSize < maxBlockSize
while (blockSize < 18
&& srcPos + blockSize < srcSize
&& src[blockStart + blockSize] == src[srcPos + blockSize]) {
&& src[blockStart + blockSize] == src[srcPos + blockSize])
blockSize++;
}
if (blockSize > *outBestBlockSize
&& srcPos - blockStart >= minDistance) {
*outBestBlockDistance = srcPos - blockStart;
*outBestBlockSize = blockSize;
if (blockSize == maxBlockSize) {
if (blockSize == 18)
break;
}
}
blockStart++;
}
}
static void FindBestBlockBackwards(unsigned char *src, int srcPos, int srcSize, const int minDistance, int *outBestBlockDistance, int *outBestBlockSize, bool extFormat) {
static void FindBestBlockBackwards(unsigned char *src, int srcPos, int srcSize, const int minDistance, int *outBestBlockDistance, int *outBestBlockSize)
{
int blockDistance = minDistance;
int maxBlockSize = extFormat ? 0xF210 : 18;
while (blockDistance <= srcPos && blockDistance <= 0x1000) {
int blockStart = srcPos - blockDistance;
int blockSize = 0;
while (blockSize < maxBlockSize
while (blockSize < 18
&& srcPos + blockSize < srcSize
&& src[blockStart + blockSize] == src[srcPos + blockSize]) {
&& src[blockStart + blockSize] == src[srcPos + blockSize])
blockSize++;
}
if (blockSize > *outBestBlockSize) {
*outBestBlockDistance = blockDistance;
*outBestBlockSize = blockSize;
if (blockSize == 18) {
if (blockSize == 18)
break;
}
}
blockDistance++;
}
}
typedef void (*FindBestBlockFunc)(unsigned char *src, int srcPos, int srcSize, const int minDistance, int *outBestBlockDistance, int *outBestBlockSize, bool extFormat);
typedef void (*FindBestBlockFunc)(unsigned char *src, int srcPos, int srcSize, const int minDistance, int *outBestBlockDistance, int *outBestBlockSize);
unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize, const int minDistance, bool forwardIteration, bool pad, bool extFormat) {
if (srcSize <= 0) {
unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize, const int minDistance, bool forwardIteration, bool pad) {
if (srcSize <= 0)
goto fail;
}
int worstCaseDestSize = 4 + srcSize + ((srcSize + 7) / 8);
@ -172,12 +133,11 @@ unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize,
unsigned char *dest = malloc(worstCaseDestSize);
if (dest == NULL) {
if (dest == NULL)
goto fail;
}
// header
dest[0] = 0x10 | extFormat; // LZ compression type
dest[0] = 0x10; // LZ compression type
dest[1] = (unsigned char)srcSize;
dest[2] = (unsigned char)(srcSize >> 8);
dest[3] = (unsigned char)(srcSize >> 16);
@ -194,48 +154,19 @@ unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize,
int bestBlockDistance = 0;
int bestBlockSize = 0;
FindBestBlock(src, srcPos, srcSize, minDistance, &bestBlockDistance, &bestBlockSize, extFormat);
FindBestBlock(src, srcPos, srcSize, minDistance, &bestBlockDistance, &bestBlockSize);
if (extFormat) {
if (bestBlockSize >= 272) {
*flags |= (0x80 >> i);
srcPos += bestBlockSize;
bestBlockSize -= 273;
bestBlockDistance--;
dest[destPos++] = ((bestBlockSize >> 12) & 0xF) | 0x10;
dest[destPos++] = bestBlockSize >> 4;
dest[destPos++] = (bestBlockSize << 4) | ((unsigned int)bestBlockDistance >> 8);
dest[destPos++] = (unsigned char)bestBlockDistance;
} else if (bestBlockSize >= 17) {
*flags |= (0x80 >> i);
srcPos += bestBlockSize;
bestBlockSize -= 17;
bestBlockDistance--;
dest[destPos++] = (bestBlockSize >> 4) & 0xF;
dest[destPos++] = (bestBlockSize << 4) | ((unsigned int)bestBlockDistance >> 8);
dest[destPos++] = (unsigned char)bestBlockDistance;
} else if (bestBlockSize >= 3) {
*flags |= (0x80 >> i);
srcPos += bestBlockSize;
bestBlockSize -= 1;
bestBlockDistance--;
dest[destPos++] = (bestBlockSize << 4) | ((unsigned int)bestBlockDistance >> 8);
dest[destPos++] = (unsigned char)bestBlockDistance;
} else {
dest[destPos++] = src[srcPos++];
}
if (bestBlockSize >= 3) {
*flags |= (0x80 >> i);
srcPos += bestBlockSize;
bestBlockSize -= 3;
bestBlockDistance--;
dest[destPos++] = (bestBlockSize << 4) | ((unsigned int)bestBlockDistance >> 8);
dest[destPos++] = (unsigned char)bestBlockDistance;
} else {
if (bestBlockSize >= 3) {
*flags |= (0x80 >> i);
srcPos += bestBlockSize;
bestBlockSize -= 3;
bestBlockDistance--;
dest[destPos++] = (bestBlockSize << 4) | ((unsigned int)bestBlockDistance >> 8);
dest[destPos++] = (unsigned char)bestBlockDistance;
} else {
dest[destPos++] = src[srcPos++];
}
dest[destPos++] = src[srcPos++];
}
if (srcPos == srcSize) {
if (pad) {
// Pad to multiple of 4 bytes.
@ -247,6 +178,7 @@ unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize,
}
}
}
*compressedSize = destPos;
return dest;
}

View File

@ -6,6 +6,6 @@
#include "stdbool.h"
unsigned char *LZDecompress(unsigned char *src, int srcSize, int *uncompressedSize);
unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize, const int minDistance, bool forwardIteration, bool pad, bool extFormat);
unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize, const int minDistance, bool forwardIteration, bool pad);
#endif // LZ_H

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,10 @@
// Copyright (c) 2018 huderlem, 2021-2024 red031000
// Copyright (c) 2018 huderlem, 2021-2025 red031000
#ifndef OPTIONS_H
#define OPTIONS_H
#include <stdbool.h>
#include <stdint.h>
#include <stdbool.h>
struct GbaToPngOptions {
char *paletteFilePath;
@ -25,6 +25,7 @@ struct PngToGbaOptions {
struct PngToNtrOptions {
char *cellFilePath;
bool cellSnap;
int numTiles;
int bitDepth;
int colsPerChunk;
@ -33,25 +34,29 @@ struct PngToNtrOptions {
bool byteOrder;
bool version101;
bool sopc;
uint32_t scanMode;
bool scan;
bool wrongSize;
bool handleEmpty;
bool vramTransfer;
int mappingType;
uint32_t encodeMode;
bool convertTo4Bpp;
};
struct NtrToPngOptions {
char *paletteFilePath;
char *cellFilePath;
char *scrnFilePath;
bool cellSnap;
int bitDepth;
bool hasTransparency;
int width;
int colsPerChunk;
int rowsPerChunk;
int palIndex;
bool scanFrontToBack;
bool handleEmpty;
uint32_t encodeMode;
bool convertTo8Bpp;
bool verbose;
};
struct CellVramTransferData {
@ -88,10 +93,10 @@ struct OAM {
};
struct CellAttributes {
bool hFlip; // 1 << 8
bool vFlip; // 1 << 9
bool hvFlip; // 1 << 10
bool boundingRect; // 1 << 11
bool hFlip; // 1 << 8
bool vFlip; // 1 << 9
bool hvFlip; // 1 << 10
bool boundingRect; // 1 << 11
int boundingSphereRadius; // 1 << 0 (6 bits);
};
@ -107,8 +112,10 @@ struct Cell {
struct JsonToCellOptions {
bool labelEnabled;
bool dontPadKbec;
bool extended;
bool vramTransferEnabled;
bool ucatEnabled;
int mappingType;
int cellCount;
struct Cell **cells;
@ -116,6 +123,7 @@ struct JsonToCellOptions {
struct CellVramTransferData **transferData;
char **labels;
int labelCount;
int *ucatCellAttribtes;
};
struct JsonToScreenOptions {
@ -151,7 +159,7 @@ struct AnimationDataSRT {
struct AnimationDataT {
short index;
// unsigned short rotation;
//unsigned short rotation;
short positionX;
short positionY;
};
@ -166,6 +174,11 @@ struct AnimationResults {
};
};
struct UaatData {
int *sequenceAttributes;
int *frameAttributes;
};
struct JsonToAnimationOptions {
bool multiCell;
short sequenceCount;
@ -176,6 +189,8 @@ struct JsonToAnimationOptions {
char **labels;
int labelCount;
short resultCount;
bool uaatEnabled;
struct UaatData uaatData;
};
struct NtrFontOptions {

View File

@ -14,29 +14,24 @@ bool ParseNumber(char *s, char **end, int radix, int *intValue)
{
char *localEnd;
if (end == NULL) {
if (end == NULL)
end = &localEnd;
}
errno = 0;
const long longValue = strtol(s, end, radix);
if (*end == s) {
if (*end == s)
return false; // not a number
}
if ((longValue == LONG_MIN || longValue == LONG_MAX) && errno == ERANGE) {
if ((longValue == LONG_MIN || longValue == LONG_MAX) && errno == ERANGE)
return false;
}
if (longValue > INT_MAX) {
if (longValue > INT_MAX)
return false;
}
if (longValue < INT_MIN) {
if (longValue < INT_MIN)
return false;
}
*intValue = (int)longValue;
@ -47,23 +42,19 @@ char *GetFileExtension(char *path)
{
char *extension = path;
while (*extension != 0) {
while (*extension != 0)
extension++;
}
while (extension > path && *extension != '.') {
while (extension > path && *extension != '.')
extension--;
}
if (extension == path) {
if (extension == path)
return NULL;
}
extension++;
if (*extension == 0) {
if (*extension == 0)
return NULL;
}
if (strcmp(extension, "lz") == 0) {
char *plainName = malloc(strlen(path) + 1);
@ -83,9 +74,8 @@ unsigned char *ReadWholeFile(char *path, int *size)
{
FILE *fp = fopen(path, "rb");
if (fp == NULL) {
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
}
fseek(fp, 0, SEEK_END);
@ -93,15 +83,13 @@ unsigned char *ReadWholeFile(char *path, int *size)
unsigned char *buffer = malloc(*size);
if (buffer == NULL) {
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
}
rewind(fp);
if (fread(buffer, *size, 1, fp) != 1) {
if (fread(buffer, *size, 1, fp) != 1)
FATAL_ERROR("Failed to read \"%s\".\n", path);
}
fclose(fp);
@ -112,9 +100,8 @@ unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount)
{
FILE *fp = fopen(path, "rb");
if (fp == NULL) {
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
}
fseek(fp, 0, SEEK_END);
@ -122,15 +109,13 @@ unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount)
unsigned char *buffer = calloc(*size + padAmount, 1);
if (buffer == NULL) {
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
}
rewind(fp);
if (fread(buffer, *size, 1, fp) != 1) {
if (fread(buffer, *size, 1, fp) != 1)
FATAL_ERROR("Failed to read \"%s\".\n", path);
}
fclose(fp);
@ -141,13 +126,11 @@ void WriteWholeStringToFile(char *path, char *string)
{
FILE *fp = fopen(path, "wb");
if (fp == NULL) {
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
}
if (fputs(string, fp) == EOF) {
if (fputs(string, fp) == EOF)
FATAL_ERROR("Failed to write to \"%s\".\n", path);
}
fclose(fp);
}
@ -156,13 +139,11 @@ void WriteWholeFile(char *path, void *buffer, int bufferSize)
{
FILE *fp = fopen(path, "wb");
if (fp == NULL) {
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
}
if (fwrite(buffer, bufferSize, 1, fp) != 1) {
if (fwrite(buffer, bufferSize, 1, fp) != 1)
FATAL_ERROR("Failed to write to \"%s\".\n", path);
}
fclose(fp);
}