mirror of
https://github.com/pret/pokeheartgold.git
synced 2024-11-26 22:50:22 +00:00
update nitrogfx to the latest version
This commit is contained in:
parent
edbd0f84a7
commit
a3fb90b51c
@ -2,3 +2,4 @@
|
||||
**/*.inc
|
||||
**/*.json
|
||||
lib/
|
||||
tools/nitrogfx/
|
||||
|
1
tools/nitrogfx/.gitignore
vendored
1
tools/nitrogfx/.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
nitrogfx
|
||||
nitrogfx-debug
|
||||
.vscode/
|
||||
|
@ -19,7 +19,7 @@ all: nitrogfx
|
||||
@:
|
||||
|
||||
nitrogfx-debug: $(SRCS) convert_png.h gfx.h global.h jasc_pal.h lz.h rl.h util.h font.h json.h cJSON.h
|
||||
$(CC) $(CFLAGS) -g -DDEBUG $(SRCS) -o $@ $(LDFLAGS) $(LIBS) -fsanitize=address,undefined
|
||||
$(CC) $(CFLAGS) -g -DDEBUG $(SRCS) -o $@ $(LDFLAGS) $(LIBS)
|
||||
|
||||
nitrogfx: $(SRCS) convert_png.h gfx.h global.h jasc_pal.h lz.h rl.h util.h font.h json.h cJSON.h
|
||||
$(CC) $(CFLAGS) -O2 $(SRCS) -o $@ $(LDFLAGS) $(LIBS)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 15
|
||||
#define CJSON_VERSION_PATCH 18
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@ -137,6 +137,12 @@ typedef int cJSON_bool;
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* Limits the length of circular references can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_CIRCULAR_LIMIT
|
||||
#define CJSON_CIRCULAR_LIMIT 10000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
@ -279,6 +285,13 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
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\
|
||||
)
|
||||
|
||||
/* 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)
|
||||
|
||||
|
@ -4,323 +4,486 @@
|
||||
#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)
|
||||
};
|
||||
|
||||
static void ConvertFromLatinFont(unsigned char *src, unsigned char *dest, unsigned int numRows)
|
||||
{
|
||||
unsigned int srcPixelsOffset = 0;
|
||||
unsigned int srcPixelsOffset = 0;
|
||||
|
||||
for (unsigned int row = 0; row < numRows; row++) {
|
||||
for (unsigned int column = 0; column < 16; column++) {
|
||||
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
|
||||
unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8);
|
||||
for (unsigned int row = 0; row < numRows; row++) {
|
||||
for (unsigned int column = 0; column < 16; column++) {
|
||||
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
|
||||
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 destPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
|
||||
unsigned int destPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
|
||||
|
||||
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
|
||||
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
|
||||
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
|
||||
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
|
||||
|
||||
srcPixelsOffset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
srcPixelsOffset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ConvertToLatinFont(unsigned char *src, unsigned char *dest, unsigned int numRows)
|
||||
{
|
||||
unsigned int destPixelsOffset = 0;
|
||||
unsigned int destPixelsOffset = 0;
|
||||
|
||||
for (unsigned int row = 0; row < numRows; row++) {
|
||||
for (unsigned int column = 0; column < 16; column++) {
|
||||
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
|
||||
unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8);
|
||||
for (unsigned int row = 0; row < numRows; row++) {
|
||||
for (unsigned int column = 0; column < 16; column++) {
|
||||
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
|
||||
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 srcPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
|
||||
unsigned int srcPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
|
||||
|
||||
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
|
||||
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
|
||||
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
|
||||
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
|
||||
|
||||
destPixelsOffset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
destPixelsOffset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ConvertFromHalfwidthJapaneseFont(unsigned char *src, unsigned char *dest, unsigned int numRows)
|
||||
{
|
||||
for (unsigned int row = 0; row < numRows; row++) {
|
||||
for (unsigned int column = 0; column < 16; column++) {
|
||||
unsigned int glyphIndex = (row * 16) + column;
|
||||
for (unsigned int row = 0; row < numRows; row++) {
|
||||
for (unsigned int column = 0; column < 16; column++) {
|
||||
unsigned int glyphIndex = (row * 16) + column;
|
||||
|
||||
for (unsigned int glyphTile = 0; glyphTile < 2; glyphTile++) {
|
||||
unsigned int pixelsX = column * 8;
|
||||
unsigned int srcPixelsOffset = 512 * (glyphIndex >> 4) + 16 * (glyphIndex & 0xF) + 256 * glyphTile;
|
||||
for (unsigned int glyphTile = 0; glyphTile < 2; glyphTile++) {
|
||||
unsigned int pixelsX = column * 8;
|
||||
unsigned int srcPixelsOffset = 512 * (glyphIndex >> 4) + 16 * (glyphIndex & 0xF) + 256 * glyphTile;
|
||||
|
||||
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];
|
||||
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];
|
||||
|
||||
srcPixelsOffset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
srcPixelsOffset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ConvertToHalfwidthJapaneseFont(unsigned char *src, unsigned char *dest, unsigned int numRows)
|
||||
{
|
||||
for (unsigned int row = 0; row < numRows; row++) {
|
||||
for (unsigned int column = 0; column < 16; column++) {
|
||||
unsigned int glyphIndex = (row * 16) + column;
|
||||
for (unsigned int row = 0; row < numRows; row++) {
|
||||
for (unsigned int column = 0; column < 16; column++) {
|
||||
unsigned int glyphIndex = (row * 16) + column;
|
||||
|
||||
for (unsigned int glyphTile = 0; glyphTile < 2; glyphTile++) {
|
||||
unsigned int pixelsX = column * 8;
|
||||
unsigned int destPixelsOffset = 512 * (glyphIndex >> 4) + 16 * (glyphIndex & 0xF) + 256 * glyphTile;
|
||||
for (unsigned int glyphTile = 0; glyphTile < 2; glyphTile++) {
|
||||
unsigned int pixelsX = column * 8;
|
||||
unsigned int destPixelsOffset = 512 * (glyphIndex >> 4) + 16 * (glyphIndex & 0xF) + 256 * glyphTile;
|
||||
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
unsigned int pixelsY = (row * 16) + (glyphTile * 8) + i;
|
||||
unsigned int srcPixelsOffset = (pixelsY * 32) + (pixelsX / 4);
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
unsigned int pixelsY = (row * 16) + (glyphTile * 8) + i;
|
||||
unsigned int srcPixelsOffset = (pixelsY * 32) + (pixelsX / 4);
|
||||
|
||||
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
|
||||
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
|
||||
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
|
||||
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
|
||||
|
||||
destPixelsOffset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
destPixelsOffset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ConvertFromFullwidthJapaneseFont(unsigned char *src, unsigned char *dest, unsigned int numRows)
|
||||
{
|
||||
for (unsigned int row = 0; row < numRows; row++) {
|
||||
for (unsigned int column = 0; column < 16; column++) {
|
||||
unsigned int glyphIndex = (row * 16) + column;
|
||||
for (unsigned int row = 0; row < numRows; row++) {
|
||||
for (unsigned int column = 0; column < 16; column++) {
|
||||
unsigned int glyphIndex = (row * 16) + column;
|
||||
|
||||
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
|
||||
unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8);
|
||||
unsigned int srcPixelsOffset = 512 * (glyphIndex >> 3) + 32 * (glyphIndex & 7) + 256 * (glyphTile >> 1) + 16 * (glyphTile & 1);
|
||||
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
|
||||
unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8);
|
||||
unsigned int srcPixelsOffset = 512 * (glyphIndex >> 3) + 32 * (glyphIndex & 7) + 256 * (glyphTile >> 1) + 16 * (glyphTile & 1);
|
||||
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
|
||||
unsigned int destPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
|
||||
unsigned int destPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
|
||||
|
||||
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
|
||||
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
|
||||
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
|
||||
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
|
||||
|
||||
srcPixelsOffset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
srcPixelsOffset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ConvertToFullwidthJapaneseFont(unsigned char *src, unsigned char *dest, unsigned int numRows)
|
||||
{
|
||||
for (unsigned int row = 0; row < numRows; row++) {
|
||||
for (unsigned int column = 0; column < 16; column++) {
|
||||
unsigned int glyphIndex = (row * 16) + column;
|
||||
for (unsigned int row = 0; row < numRows; row++) {
|
||||
for (unsigned int column = 0; column < 16; column++) {
|
||||
unsigned int glyphIndex = (row * 16) + column;
|
||||
|
||||
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
|
||||
unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8);
|
||||
unsigned int destPixelsOffset = 512 * (glyphIndex >> 3) + 32 * (glyphIndex & 7) + 256 * (glyphTile >> 1) + 16 * (glyphTile & 1);
|
||||
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
|
||||
unsigned int pixelsX = (column * 16) + ((glyphTile & 1) * 8);
|
||||
unsigned int destPixelsOffset = 512 * (glyphIndex >> 3) + 32 * (glyphIndex & 7) + 256 * (glyphTile >> 1) + 16 * (glyphTile & 1);
|
||||
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
|
||||
unsigned int srcPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
unsigned int pixelsY = (row * 16) + ((glyphTile >> 1) * 8) + i;
|
||||
unsigned int srcPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
|
||||
|
||||
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
|
||||
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
|
||||
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
|
||||
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
|
||||
|
||||
destPixelsOffset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
destPixelsOffset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ConvertFromNitroFont(unsigned char *src, unsigned char *dest, unsigned int numRows, struct NtrFontMetadata *metadata)
|
||||
{
|
||||
unsigned int srcPixelsOffset = 0;
|
||||
unsigned int curGlyph = 0;
|
||||
|
||||
for (unsigned int row = 0; row < numRows; row++) {
|
||||
for (unsigned int column = 0; column < 16 && curGlyph < metadata->numGlyphs; column++, curGlyph++) {
|
||||
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
|
||||
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 destPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
|
||||
|
||||
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
|
||||
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
|
||||
|
||||
srcPixelsOffset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ConvertToNitroFont(unsigned char *src, unsigned char *dest, unsigned int numRows, struct NtrFontMetadata *metadata)
|
||||
{
|
||||
unsigned int destPixelsOffset = 0;
|
||||
unsigned int curGlyph = 0;
|
||||
|
||||
for (unsigned int row = 0; row < numRows; row++) {
|
||||
for (unsigned int column = 0; column < 16 && curGlyph < metadata->numGlyphs; column++, curGlyph++) {
|
||||
for (unsigned int glyphTile = 0; glyphTile < 4; glyphTile++) {
|
||||
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 srcPixelsOffset = (pixelsY * 64) + (pixelsX / 4);
|
||||
|
||||
dest[destPixelsOffset] = src[srcPixelsOffset + 1];
|
||||
dest[destPixelsOffset + 1] = src[srcPixelsOffset];
|
||||
|
||||
destPixelsOffset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SetFontPalette(struct Image *image)
|
||||
{
|
||||
image->hasPalette = true;
|
||||
image->hasPalette = true;
|
||||
|
||||
image->palette.numColors = 4;
|
||||
image->palette.numColors = 4;
|
||||
|
||||
for (int i = 0; i < image->palette.numColors; i++) {
|
||||
image->palette.colors[i].red = gFontPalette[i][0];
|
||||
image->palette.colors[i].green = gFontPalette[i][1];
|
||||
image->palette.colors[i].blue = gFontPalette[i][2];
|
||||
}
|
||||
for (int i = 0; i < image->palette.numColors; i++) {
|
||||
image->palette.colors[i].red = gFontPalette[i][0];
|
||||
image->palette.colors[i].green = gFontPalette[i][1];
|
||||
image->palette.colors[i].blue = gFontPalette[i][2];
|
||||
}
|
||||
|
||||
image->hasTransparency = false;
|
||||
image->hasTransparency = false;
|
||||
}
|
||||
|
||||
static void SetSubscreenFontPalette(struct Image *image)
|
||||
{
|
||||
image->hasPalette = true;
|
||||
|
||||
image->palette.numColors = 4;
|
||||
|
||||
for (int i = 0; i < image->palette.numColors; i++) {
|
||||
image->palette.colors[i].red = gFontPalette_Subscreen[i][0];
|
||||
image->palette.colors[i].green = gFontPalette_Subscreen[i][1];
|
||||
image->palette.colors[i].blue = gFontPalette_Subscreen[i][2];
|
||||
}
|
||||
|
||||
image->hasTransparency = false;
|
||||
}
|
||||
|
||||
void ReadLatinFont(char *path, struct Image *image)
|
||||
{
|
||||
int fileSize;
|
||||
unsigned char *buffer = ReadWholeFile(path, &fileSize);
|
||||
int fileSize;
|
||||
unsigned char *buffer = ReadWholeFile(path, &fileSize);
|
||||
|
||||
int numGlyphs = fileSize / 64;
|
||||
int numGlyphs = fileSize / 64;
|
||||
|
||||
if (numGlyphs % 16 != 0)
|
||||
FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs);
|
||||
if (numGlyphs % 16 != 0)
|
||||
FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs);
|
||||
|
||||
int numRows = numGlyphs / 16;
|
||||
int numRows = numGlyphs / 16;
|
||||
|
||||
image->width = 256;
|
||||
image->height = numRows * 16;
|
||||
image->bitDepth = 2;
|
||||
image->pixels = malloc(fileSize);
|
||||
image->width = 256;
|
||||
image->height = numRows * 16;
|
||||
image->bitDepth = 2;
|
||||
image->pixels = malloc(fileSize);
|
||||
|
||||
if (image->pixels == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for font.\n");
|
||||
if (image->pixels == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for font.\n");
|
||||
|
||||
ConvertFromLatinFont(buffer, image->pixels, numRows);
|
||||
ConvertFromLatinFont(buffer, image->pixels, numRows);
|
||||
|
||||
free(buffer);
|
||||
free(buffer);
|
||||
|
||||
SetFontPalette(image);
|
||||
SetFontPalette(image);
|
||||
}
|
||||
|
||||
void WriteLatinFont(char *path, struct Image *image)
|
||||
{
|
||||
if (image->width != 256)
|
||||
FATAL_ERROR("The width of the font image (%d) is not 256.\n", image->width);
|
||||
if (image->width != 256)
|
||||
FATAL_ERROR("The width of the font image (%d) is not 256.\n", image->width);
|
||||
|
||||
if (image->height % 16 != 0)
|
||||
FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height);
|
||||
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);
|
||||
int numRows = image->height / 16;
|
||||
int bufferSize = numRows * 16 * 64;
|
||||
unsigned char *buffer = malloc(bufferSize);
|
||||
|
||||
if (buffer == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for font.\n");
|
||||
if (buffer == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for font.\n");
|
||||
|
||||
ConvertToLatinFont(image->pixels, buffer, numRows);
|
||||
ConvertToLatinFont(image->pixels, buffer, numRows);
|
||||
|
||||
WriteWholeFile(path, buffer, bufferSize);
|
||||
WriteWholeFile(path, buffer, bufferSize);
|
||||
|
||||
free(buffer);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void ReadHalfwidthJapaneseFont(char *path, struct Image *image)
|
||||
{
|
||||
int fileSize;
|
||||
unsigned char *buffer = ReadWholeFile(path, &fileSize);
|
||||
int fileSize;
|
||||
unsigned char *buffer = ReadWholeFile(path, &fileSize);
|
||||
|
||||
int glyphSize = 32;
|
||||
int glyphSize = 32;
|
||||
|
||||
if (fileSize % glyphSize != 0)
|
||||
FATAL_ERROR("The file size (%d) is not a multiple of %d.\n", fileSize, glyphSize);
|
||||
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)
|
||||
FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs);
|
||||
int numGlyphs = fileSize / glyphSize;
|
||||
|
||||
if (numGlyphs % 16 != 0)
|
||||
FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs);
|
||||
|
||||
int numRows = numGlyphs / 16;
|
||||
int numRows = numGlyphs / 16;
|
||||
|
||||
image->width = 128;
|
||||
image->height = numRows * 16;
|
||||
image->bitDepth = 2;
|
||||
image->pixels = malloc(fileSize);
|
||||
image->width = 128;
|
||||
image->height = numRows * 16;
|
||||
image->bitDepth = 2;
|
||||
image->pixels = malloc(fileSize);
|
||||
|
||||
if (image->pixels == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for font.\n");
|
||||
if (image->pixels == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for font.\n");
|
||||
|
||||
ConvertFromHalfwidthJapaneseFont(buffer, image->pixels, numRows);
|
||||
ConvertFromHalfwidthJapaneseFont(buffer, image->pixels, numRows);
|
||||
|
||||
free(buffer);
|
||||
free(buffer);
|
||||
|
||||
SetFontPalette(image);
|
||||
SetFontPalette(image);
|
||||
}
|
||||
|
||||
void WriteHalfwidthJapaneseFont(char *path, struct Image *image)
|
||||
{
|
||||
if (image->width != 128)
|
||||
FATAL_ERROR("The width of the font image (%d) is not 128.\n", image->width);
|
||||
if (image->width != 128)
|
||||
FATAL_ERROR("The width of the font image (%d) is not 128.\n", image->width);
|
||||
|
||||
if (image->height % 16 != 0)
|
||||
FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height);
|
||||
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);
|
||||
int numRows = image->height / 16;
|
||||
int bufferSize = numRows * 16 * 32;
|
||||
unsigned char *buffer = malloc(bufferSize);
|
||||
|
||||
if (buffer == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for font.\n");
|
||||
if (buffer == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for font.\n");
|
||||
|
||||
ConvertToHalfwidthJapaneseFont(image->pixels, buffer, numRows);
|
||||
ConvertToHalfwidthJapaneseFont(image->pixels, buffer, numRows);
|
||||
|
||||
WriteWholeFile(path, buffer, bufferSize);
|
||||
WriteWholeFile(path, buffer, bufferSize);
|
||||
|
||||
free(buffer);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void ReadFullwidthJapaneseFont(char *path, struct Image *image)
|
||||
{
|
||||
int fileSize;
|
||||
unsigned char *buffer = ReadWholeFile(path, &fileSize);
|
||||
int fileSize;
|
||||
unsigned char *buffer = ReadWholeFile(path, &fileSize);
|
||||
|
||||
int numGlyphs = fileSize / 64;
|
||||
int numGlyphs = fileSize / 64;
|
||||
|
||||
if (numGlyphs % 16 != 0)
|
||||
FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs);
|
||||
if (numGlyphs % 16 != 0)
|
||||
FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs);
|
||||
|
||||
int numRows = numGlyphs / 16;
|
||||
int numRows = numGlyphs / 16;
|
||||
|
||||
image->width = 256;
|
||||
image->height = numRows * 16;
|
||||
image->bitDepth = 2;
|
||||
image->pixels = malloc(fileSize);
|
||||
image->width = 256;
|
||||
image->height = numRows * 16;
|
||||
image->bitDepth = 2;
|
||||
image->pixels = malloc(fileSize);
|
||||
|
||||
if (image->pixels == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for font.\n");
|
||||
if (image->pixels == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for font.\n");
|
||||
|
||||
ConvertFromFullwidthJapaneseFont(buffer, image->pixels, numRows);
|
||||
ConvertFromFullwidthJapaneseFont(buffer, image->pixels, numRows);
|
||||
|
||||
free(buffer);
|
||||
free(buffer);
|
||||
|
||||
SetFontPalette(image);
|
||||
SetFontPalette(image);
|
||||
}
|
||||
|
||||
void WriteFullwidthJapaneseFont(char *path, struct Image *image)
|
||||
{
|
||||
if (image->width != 256)
|
||||
FATAL_ERROR("The width of the font image (%d) is not 256.\n", image->width);
|
||||
if (image->width != 256)
|
||||
FATAL_ERROR("The width of the font image (%d) is not 256.\n", image->width);
|
||||
|
||||
if (image->height % 16 != 0)
|
||||
FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height);
|
||||
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);
|
||||
int numRows = image->height / 16;
|
||||
int bufferSize = numRows * 16 * 64;
|
||||
unsigned char *buffer = malloc(bufferSize);
|
||||
|
||||
if (buffer == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for font.\n");
|
||||
if (buffer == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for font.\n");
|
||||
|
||||
ConvertToFullwidthJapaneseFont(image->pixels, buffer, numRows);
|
||||
ConvertToFullwidthJapaneseFont(image->pixels, buffer, numRows);
|
||||
|
||||
WriteWholeFile(path, buffer, bufferSize);
|
||||
WriteWholeFile(path, buffer, bufferSize);
|
||||
|
||||
free(buffer);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int filesize;
|
||||
unsigned char *buffer = ReadWholeFile(path, &filesize);
|
||||
|
||||
metadata->size = ReadLittleEndianWord(buffer, 0x00);
|
||||
metadata->widthTableOffset = ReadLittleEndianWord(buffer, 0x04);
|
||||
metadata->numGlyphs = ReadLittleEndianWord(buffer, 0x08);
|
||||
metadata->maxWidth = buffer[0x0C];
|
||||
metadata->maxHeight = buffer[0x0D];
|
||||
metadata->glyphWidth = buffer[0x0E];
|
||||
metadata->glyphHeight = buffer[0x0F];
|
||||
|
||||
int numRows = (metadata->numGlyphs + 15) / 16; // Round up to next multiple of 16.
|
||||
|
||||
metadata->glyphWidthTable = malloc(metadata->numGlyphs);
|
||||
memcpy(metadata->glyphWidthTable, buffer + metadata->widthTableOffset, metadata->numGlyphs);
|
||||
|
||||
image->width = 256;
|
||||
image->height = numRows * 16;
|
||||
image->bitDepth = 2;
|
||||
image->pixels = malloc(filesize);
|
||||
|
||||
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)
|
||||
SetSubscreenFontPalette(image);
|
||||
else
|
||||
SetFontPalette(image);
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
FATAL_ERROR("Failed to allocate memory for font.\n");
|
||||
|
||||
buffer[0x00] = (metadata->size & 0x000000FF);
|
||||
buffer[0x01] = (metadata->size & 0x0000FF00) >> 8;
|
||||
buffer[0x02] = (metadata->size & 0x00FF0000) >> 16;
|
||||
buffer[0x03] = (metadata->size & 0xFF000000) >> 24;
|
||||
buffer[0x04] = (metadata->widthTableOffset & 0x000000FF);
|
||||
buffer[0x05] = (metadata->widthTableOffset & 0x0000FF00) >> 8;
|
||||
buffer[0x06] = (metadata->widthTableOffset & 0x00FF0000) >> 16;
|
||||
buffer[0x07] = (metadata->widthTableOffset & 0xFF000000) >> 24;
|
||||
buffer[0x08] = (metadata->numGlyphs & 0x000000FF);
|
||||
buffer[0x09] = (metadata->numGlyphs & 0x0000FF00) >> 8;
|
||||
buffer[0x0A] = (metadata->numGlyphs & 0x00FF0000) >> 16;
|
||||
buffer[0x0B] = (metadata->numGlyphs & 0xFF000000) >> 24;
|
||||
buffer[0x0C] = metadata->maxWidth;
|
||||
buffer[0x0D] = metadata->maxHeight;
|
||||
buffer[0x0E] = metadata->glyphWidth;
|
||||
buffer[0x0F] = metadata->glyphHeight;
|
||||
|
||||
ConvertToNitroFont(image->pixels, buffer + metadata->size, numRows, metadata);
|
||||
memcpy(buffer + metadata->widthTableOffset, metadata->glyphWidthTable, metadata->numGlyphs);
|
||||
|
||||
WriteWholeFile(path, buffer, bufferSize);
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void FreeNtrFontMetadata(struct NtrFontMetadata *metadata)
|
||||
{
|
||||
free(metadata->glyphWidthTable);
|
||||
free(metadata);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "gfx.h"
|
||||
#include "options.h"
|
||||
|
||||
void ReadLatinFont(char *path, struct Image *image);
|
||||
void WriteLatinFont(char *path, struct Image *image);
|
||||
@ -12,5 +13,8 @@ void ReadHalfwidthJapaneseFont(char *path, struct Image *image);
|
||||
void WriteHalfwidthJapaneseFont(char *path, struct Image *image);
|
||||
void ReadFullwidthJapaneseFont(char *path, struct Image *image);
|
||||
void WriteFullwidthJapaneseFont(char *path, struct Image *image);
|
||||
void ReadNtrFont(char *path, struct Image *image, struct NtrFontMetadata *metadata, bool useSubscreenPalette);
|
||||
void WriteNtrFont(char *path, struct Image *image, struct NtrFontMetadata *metadata);
|
||||
void FreeNtrFontMetadata(struct NtrFontMetadata *metadata);
|
||||
|
||||
#endif // FONT_H
|
||||
|
1372
tools/nitrogfx/gfx.c
1372
tools/nitrogfx/gfx.c
File diff suppressed because it is too large
Load Diff
@ -58,9 +58,9 @@ void WriteNtrImage(char *path, int numTiles, int bitDepth, int colsPerChunk, int
|
||||
uint32_t mappingType, uint32_t key, bool wrongSize);
|
||||
void FreeImage(struct Image *image);
|
||||
void ReadGbaPalette(char *path, struct Palette *palette);
|
||||
void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIndex);
|
||||
void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIndex, bool inverted);
|
||||
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);
|
||||
void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, int bitdepth, bool pad, int compNum, bool pcmp, bool inverted);
|
||||
void ReadNtrCell(char *path, struct JsonToCellOptions *options);
|
||||
void WriteNtrCell(char *path, struct JsonToCellOptions *options);
|
||||
void WriteNtrScreen(char *path, struct JsonToScreenOptions *options);
|
||||
|
@ -47,11 +47,13 @@ struct JsonToCellOptions *ParseNCERJson(char *path)
|
||||
}
|
||||
|
||||
cJSON *labelBool = cJSON_GetObjectItemCaseSensitive(json, "labelEnabled");
|
||||
cJSON *vramTransferBool = cJSON_GetObjectItemCaseSensitive(json, "vramTransferEnabled");
|
||||
cJSON *extended = cJSON_GetObjectItemCaseSensitive(json, "extended");
|
||||
cJSON *cellCount = cJSON_GetObjectItemCaseSensitive(json, "cellCount");
|
||||
cJSON *mappingType = cJSON_GetObjectItemCaseSensitive(json, "mappingType");
|
||||
|
||||
options->labelEnabled = GetBool(labelBool);
|
||||
options->vramTransferEnabled = GetBool(vramTransferBool);
|
||||
options->extended = GetBool(extended);
|
||||
options->cellCount = GetInt(cellCount);
|
||||
options->mappingType = GetInt(mappingType);
|
||||
@ -77,6 +79,30 @@ struct JsonToCellOptions *ParseNCERJson(char *path)
|
||||
}
|
||||
}
|
||||
|
||||
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 *vramTransferOffset = cJSON_GetObjectItemCaseSensitive(transfer, "offset");
|
||||
cJSON *vramTransferSize = cJSON_GetObjectItemCaseSensitive(transfer, "size");
|
||||
|
||||
options->transferData[j] = malloc(sizeof(struct CellVramTransferData));
|
||||
options->transferData[j]->sourceDataOffset = GetInt(vramTransferOffset);
|
||||
options->transferData[j]->size = GetInt(vramTransferSize);
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < options->cellCount; i++)
|
||||
{
|
||||
options->cells[i] = malloc(sizeof(struct Cell));
|
||||
@ -195,6 +221,7 @@ char *GetNCERJson(struct JsonToCellOptions *options)
|
||||
|
||||
cJSON_AddBoolToObject(ncer, "labelEnabled", options->labelEnabled);
|
||||
cJSON_AddBoolToObject(ncer, "extended", options->extended);
|
||||
cJSON_AddBoolToObject(ncer, "vramTransferEnabled", options->vramTransferEnabled);
|
||||
cJSON_AddNumberToObject(ncer, "cellCount", options->cellCount);
|
||||
cJSON_AddNumberToObject(ncer, "mappingType", options->mappingType);
|
||||
|
||||
@ -263,6 +290,20 @@ char *GetNCERJson(struct JsonToCellOptions *options)
|
||||
cJSON_AddNumberToObject(ncer, "labelCount", options->labelCount);
|
||||
}
|
||||
|
||||
if (options->vramTransferEnabled)
|
||||
{
|
||||
cJSON_AddNumberToObject(ncer, "vramTransferMaxSize", options->vramTransferMaxSize);
|
||||
cJSON *transfers = cJSON_AddArrayToObject(ncer, "transferData");
|
||||
|
||||
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);
|
||||
cJSON_AddItemToArray(transfers, transfer);
|
||||
}
|
||||
}
|
||||
|
||||
char *jsonString = cJSON_Print(ncer);
|
||||
cJSON_Delete(ncer);
|
||||
return jsonString;
|
||||
@ -600,6 +641,14 @@ void FreeNCERCell(struct JsonToCellOptions *options)
|
||||
}
|
||||
free(options->labels);
|
||||
}
|
||||
if (options->vramTransferEnabled)
|
||||
{
|
||||
for (int j = 0; j < options->cellCount; j++)
|
||||
{
|
||||
free(options->transferData[j]);
|
||||
}
|
||||
free(options->transferData);
|
||||
}
|
||||
free(options->cells);
|
||||
free(options);
|
||||
}
|
||||
@ -638,3 +687,79 @@ void FreeNANRAnimation(struct JsonToAnimationOptions *options)
|
||||
free(options->animationResults);
|
||||
free(options);
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
cJSON *width = cJSON_CreateNumber(metadata->glyphWidthTable[i]);
|
||||
cJSON_AddItemToArray(glyphWidths, width);
|
||||
}
|
||||
|
||||
char *jsonString = cJSON_Print(json);
|
||||
cJSON_Delete(json);
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
struct NtrFontMetadata *ParseNtrFontMetadataJson(char *path)
|
||||
{
|
||||
int fileLength;
|
||||
unsigned char *jsonString = ReadWholeFile(path, &fileLength);
|
||||
|
||||
cJSON *json = cJSON_Parse((const char *)jsonString);
|
||||
if (json == NULL)
|
||||
{
|
||||
const char *errorPtr = cJSON_GetErrorPtr();
|
||||
FATAL_ERROR("Error in line \"%s\"\n", errorPtr);
|
||||
}
|
||||
|
||||
cJSON *labelMaxGlyphWidth = cJSON_GetObjectItemCaseSensitive(json, "maxGlyphWidth");
|
||||
cJSON *labelMaxGlyphHeight = cJSON_GetObjectItemCaseSensitive(json, "maxGlyphHeight");
|
||||
cJSON *labelGlyphWidths = cJSON_GetObjectItemCaseSensitive(json, "glyphWidths");
|
||||
int numGlyphs = cJSON_GetArraySize(labelGlyphWidths);
|
||||
|
||||
struct NtrFontMetadata *metadata = malloc(sizeof(struct NtrFontMetadata));
|
||||
|
||||
metadata->size = NTR_FONT_HEADER_SIZE;
|
||||
metadata->numGlyphs = numGlyphs;
|
||||
metadata->maxWidth = GetInt(labelMaxGlyphWidth);
|
||||
metadata->maxHeight = GetInt(labelMaxGlyphHeight);
|
||||
|
||||
metadata->glyphWidth = TILES_FOR_PIXELS(metadata->maxWidth);
|
||||
metadata->glyphHeight = TILES_FOR_PIXELS(metadata->maxHeight);
|
||||
|
||||
int glyphBitmapSize = (PIXELS_FOR_DIMENSION(metadata->glyphWidth) * PIXELS_FOR_DIMENSION(metadata->glyphHeight)) / PIXELS_PER_BYTE_2BPP;
|
||||
metadata->widthTableOffset = metadata->size + (metadata->numGlyphs * glyphBitmapSize);
|
||||
|
||||
metadata->glyphWidthTable = malloc(metadata->numGlyphs);
|
||||
|
||||
uint8_t *glyphWidthCursor = metadata->glyphWidthTable;
|
||||
cJSON *glyphWidthIter = NULL;
|
||||
cJSON_ArrayForEach(glyphWidthIter, labelGlyphWidths)
|
||||
{
|
||||
if (!cJSON_IsNumber(glyphWidthIter))
|
||||
{
|
||||
const char *errorPtr = cJSON_GetErrorPtr();
|
||||
FATAL_ERROR("Error in line \"%s\"\n", errorPtr);
|
||||
}
|
||||
|
||||
*glyphWidthCursor = glyphWidthIter->valueint;
|
||||
glyphWidthCursor++;
|
||||
}
|
||||
|
||||
cJSON_Delete(json);
|
||||
free(jsonString);
|
||||
return metadata;
|
||||
}
|
||||
|
@ -13,5 +13,7 @@ char *GetNANRJson(struct JsonToAnimationOptions *options);
|
||||
void FreeNCERCell(struct JsonToCellOptions *options);
|
||||
void FreeNSCRScreen(struct JsonToScreenOptions *options);
|
||||
void FreeNANRAnimation(struct JsonToAnimationOptions *options);
|
||||
char *GetNtrFontMetadataJson(struct NtrFontMetadata *metadata);
|
||||
struct NtrFontMetadata *ParseNtrFontMetadataJson(char *path);
|
||||
|
||||
#endif //JSON_H
|
||||
|
@ -1,153 +1,188 @@
|
||||
// Copyright (c) 2015 YamaArashi
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "global.h"
|
||||
#include "lz.h"
|
||||
|
||||
unsigned char *LZDecompress(unsigned char *src, int srcSize, int *uncompressedSize)
|
||||
{
|
||||
if (srcSize < 4)
|
||||
goto fail;
|
||||
if (srcSize < 4)
|
||||
goto fail;
|
||||
|
||||
int destSize = (src[3] << 16) | (src[2] << 8) | src[1];
|
||||
int destSize = (src[3] << 16) | (src[2] << 8) | src[1];
|
||||
|
||||
unsigned char *dest = malloc(destSize);
|
||||
unsigned char *dest = malloc(destSize);
|
||||
|
||||
if (dest == NULL)
|
||||
goto fail;
|
||||
if (dest == NULL)
|
||||
goto fail;
|
||||
|
||||
int srcPos = 4;
|
||||
int destPos = 0;
|
||||
int srcPos = 4;
|
||||
int destPos = 0;
|
||||
|
||||
for (;;) {
|
||||
if (srcPos >= srcSize)
|
||||
goto fail;
|
||||
for (;;) {
|
||||
if (srcPos >= srcSize)
|
||||
goto fail;
|
||||
|
||||
unsigned char flags = src[srcPos++];
|
||||
unsigned char flags = src[srcPos++];
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (flags & 0x80) {
|
||||
if (srcPos + 1 >= srcSize)
|
||||
goto fail;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (flags & 0x80) {
|
||||
if (srcPos + 1 >= srcSize)
|
||||
goto fail;
|
||||
|
||||
int blockSize = (src[srcPos] >> 4) + 3;
|
||||
int blockDistance = (((src[srcPos] & 0xF) << 8) | src[srcPos + 1]) + 1;
|
||||
int blockSize = (src[srcPos] >> 4) + 3;
|
||||
int blockDistance = (((src[srcPos] & 0xF) << 8) | src[srcPos + 1]) + 1;
|
||||
|
||||
srcPos += 2;
|
||||
srcPos += 2;
|
||||
|
||||
int blockPos = destPos - blockDistance;
|
||||
int blockPos = destPos - blockDistance;
|
||||
|
||||
// Some Ruby/Sapphire tilesets overflow.
|
||||
if (destPos + blockSize > destSize) {
|
||||
blockSize = destSize - destPos;
|
||||
fprintf(stderr, "Destination buffer overflow.\n");
|
||||
}
|
||||
// Some Ruby/Sapphire tilesets overflow.
|
||||
if (destPos + blockSize > destSize) {
|
||||
blockSize = destSize - destPos;
|
||||
fprintf(stderr, "Destination buffer overflow.\n");
|
||||
}
|
||||
|
||||
if (blockPos < 0)
|
||||
goto fail;
|
||||
if (blockPos < 0)
|
||||
goto fail;
|
||||
|
||||
for (int j = 0; j < blockSize; j++)
|
||||
dest[destPos++] = dest[blockPos + j];
|
||||
} else {
|
||||
if (srcPos >= srcSize || destPos >= destSize)
|
||||
goto fail;
|
||||
for (int j = 0; j < blockSize; j++)
|
||||
dest[destPos++] = dest[blockPos + j];
|
||||
} else {
|
||||
if (srcPos >= srcSize || destPos >= destSize)
|
||||
goto fail;
|
||||
|
||||
dest[destPos++] = src[srcPos++];
|
||||
}
|
||||
dest[destPos++] = src[srcPos++];
|
||||
}
|
||||
|
||||
if (destPos == destSize) {
|
||||
*uncompressedSize = destSize;
|
||||
return dest;
|
||||
}
|
||||
if (destPos == destSize) {
|
||||
*uncompressedSize = destSize;
|
||||
return dest;
|
||||
}
|
||||
|
||||
flags <<= 1;
|
||||
}
|
||||
}
|
||||
flags <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
FATAL_ERROR("Fatal error while decompressing LZ file.\n");
|
||||
FATAL_ERROR("Fatal error while decompressing LZ file.\n");
|
||||
}
|
||||
|
||||
unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize, const int minDistance)
|
||||
static void FindBestBlockForwards(unsigned char *src, int srcPos, int srcSize, const int minDistance, int *outBestBlockDistance, int *outBestBlockSize)
|
||||
{
|
||||
if (srcSize <= 0)
|
||||
goto fail;
|
||||
int blockStart = srcPos < 0x1000 ? 0 : srcPos - 0x1000;
|
||||
while (blockStart != srcPos) {
|
||||
int blockSize = 0;
|
||||
|
||||
int worstCaseDestSize = 4 + srcSize + ((srcSize + 7) / 8);
|
||||
while (blockSize < 18
|
||||
&& srcPos + blockSize < srcSize
|
||||
&& src[blockStart + blockSize] == src[srcPos + blockSize])
|
||||
blockSize++;
|
||||
|
||||
// Round up to the next multiple of four.
|
||||
worstCaseDestSize = (worstCaseDestSize + 3) & ~3;
|
||||
if (blockSize > *outBestBlockSize
|
||||
&& srcPos - blockStart >= minDistance) {
|
||||
*outBestBlockDistance = srcPos - blockStart;
|
||||
*outBestBlockSize = blockSize;
|
||||
|
||||
unsigned char *dest = malloc(worstCaseDestSize);
|
||||
if (blockSize == 18)
|
||||
break;
|
||||
}
|
||||
|
||||
if (dest == NULL)
|
||||
goto fail;
|
||||
blockStart++;
|
||||
}
|
||||
}
|
||||
|
||||
// header
|
||||
dest[0] = 0x10; // LZ compression type
|
||||
dest[1] = (unsigned char)srcSize;
|
||||
dest[2] = (unsigned char)(srcSize >> 8);
|
||||
dest[3] = (unsigned char)(srcSize >> 16);
|
||||
static void FindBestBlockBackwards(unsigned char *src, int srcPos, int srcSize, const int minDistance, int *outBestBlockDistance, int *outBestBlockSize)
|
||||
{
|
||||
int blockDistance = minDistance;
|
||||
|
||||
int srcPos = 0;
|
||||
int destPos = 4;
|
||||
while (blockDistance <= srcPos && blockDistance <= 0x1000) {
|
||||
int blockStart = srcPos - blockDistance;
|
||||
int blockSize = 0;
|
||||
|
||||
for (;;) {
|
||||
unsigned char *flags = &dest[destPos++];
|
||||
*flags = 0;
|
||||
while (blockSize < 18
|
||||
&& srcPos + blockSize < srcSize
|
||||
&& src[blockStart + blockSize] == src[srcPos + blockSize])
|
||||
blockSize++;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int bestBlockDistance = 0;
|
||||
int bestBlockSize = 0;
|
||||
int blockDistance = minDistance;
|
||||
if (blockSize > *outBestBlockSize) {
|
||||
*outBestBlockDistance = blockDistance;
|
||||
*outBestBlockSize = blockSize;
|
||||
|
||||
while (blockDistance <= srcPos && blockDistance <= 0x1000) {
|
||||
int blockStart = srcPos - blockDistance;
|
||||
int blockSize = 0;
|
||||
if (blockSize == 18)
|
||||
break;
|
||||
}
|
||||
|
||||
while (blockSize < 18
|
||||
&& srcPos + blockSize < srcSize
|
||||
&& src[blockStart + blockSize] == src[srcPos + blockSize])
|
||||
blockSize++;
|
||||
blockDistance++;
|
||||
}
|
||||
}
|
||||
|
||||
if (blockSize > bestBlockSize) {
|
||||
bestBlockDistance = blockDistance;
|
||||
bestBlockSize = blockSize;
|
||||
typedef void (*FindBestBlockFunc)(unsigned char *src, int srcPos, int srcSize, const int minDistance, int *outBestBlockDistance, int *outBestBlockSize);
|
||||
|
||||
if (blockSize == 18)
|
||||
break;
|
||||
}
|
||||
unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize, const int minDistance, bool forwardIteration)
|
||||
{
|
||||
if (srcSize <= 0)
|
||||
goto fail;
|
||||
|
||||
blockDistance++;
|
||||
}
|
||||
int worstCaseDestSize = 4 + srcSize + ((srcSize + 7) / 8);
|
||||
|
||||
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++];
|
||||
}
|
||||
// Round up to the next multiple of four.
|
||||
worstCaseDestSize = (worstCaseDestSize + 3) & ~3;
|
||||
|
||||
if (srcPos == srcSize) {
|
||||
// Pad to multiple of 4 bytes.
|
||||
int remainder = destPos % 4;
|
||||
unsigned char *dest = malloc(worstCaseDestSize);
|
||||
|
||||
if (remainder != 0) {
|
||||
for (int i = 0; i < 4 - remainder; i++)
|
||||
dest[destPos++] = 0;
|
||||
}
|
||||
if (dest == NULL)
|
||||
goto fail;
|
||||
|
||||
*compressedSize = destPos;
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
}
|
||||
// header
|
||||
dest[0] = 0x10; // LZ compression type
|
||||
dest[1] = (unsigned char)srcSize;
|
||||
dest[2] = (unsigned char)(srcSize >> 8);
|
||||
dest[3] = (unsigned char)(srcSize >> 16);
|
||||
|
||||
int srcPos = 0;
|
||||
int destPos = 4;
|
||||
FindBestBlockFunc FindBestBlock = forwardIteration ? FindBestBlockForwards : FindBestBlockBackwards;
|
||||
|
||||
for (;;) {
|
||||
unsigned char *flags = &dest[destPos++];
|
||||
*flags = 0;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int bestBlockDistance = 0;
|
||||
int bestBlockSize = 0;
|
||||
|
||||
FindBestBlock(src, srcPos, srcSize, minDistance, &bestBlockDistance, &bestBlockSize);
|
||||
|
||||
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++];
|
||||
}
|
||||
|
||||
if (srcPos == srcSize) {
|
||||
// Pad to multiple of 4 bytes.
|
||||
int remainder = destPos % 4;
|
||||
|
||||
if (remainder != 0) {
|
||||
for (int i = 0; i < 4 - remainder; i++)
|
||||
dest[destPos++] = 0;
|
||||
}
|
||||
|
||||
*compressedSize = destPos;
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
FATAL_ERROR("Fatal error while compressing LZ file.\n");
|
||||
FATAL_ERROR("Fatal error while compressing LZ file.\n");
|
||||
}
|
||||
|
@ -3,7 +3,9 @@
|
||||
#ifndef LZ_H
|
||||
#define LZ_H
|
||||
|
||||
#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);
|
||||
unsigned char *LZCompress(unsigned char *src, int srcSize, int *compressedSize, const int minDistance, bool forwardIteration);
|
||||
|
||||
#endif // LZ_H
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -51,6 +51,11 @@ struct NtrToPngOptions {
|
||||
bool handleEmpty;
|
||||
};
|
||||
|
||||
struct CellVramTransferData {
|
||||
int sourceDataOffset;
|
||||
int size;
|
||||
};
|
||||
|
||||
struct Attr0 {
|
||||
int YCoordinate;
|
||||
bool Rotation;
|
||||
@ -100,9 +105,12 @@ struct Cell {
|
||||
struct JsonToCellOptions {
|
||||
bool labelEnabled;
|
||||
bool extended;
|
||||
bool vramTransferEnabled;
|
||||
int mappingType;
|
||||
int cellCount;
|
||||
struct Cell **cells;
|
||||
int vramTransferMaxSize;
|
||||
struct CellVramTransferData **transferData;
|
||||
char **labels;
|
||||
int labelCount;
|
||||
};
|
||||
@ -147,6 +155,7 @@ struct AnimationDataT {
|
||||
|
||||
struct AnimationResults {
|
||||
short resultType;
|
||||
bool padded;
|
||||
union {
|
||||
short index;
|
||||
struct AnimationDataSRT dataSrt;
|
||||
@ -166,4 +175,21 @@ struct JsonToAnimationOptions {
|
||||
short resultCount;
|
||||
};
|
||||
|
||||
struct NtrFontOptions {
|
||||
char *metadataFilePath;
|
||||
bool useSubscreenPalette;
|
||||
};
|
||||
|
||||
struct NtrFontMetadata {
|
||||
uint32_t size;
|
||||
uint32_t widthTableOffset;
|
||||
uint32_t numGlyphs;
|
||||
uint8_t maxWidth;
|
||||
uint8_t maxHeight;
|
||||
uint8_t glyphWidth;
|
||||
uint8_t glyphHeight;
|
||||
|
||||
uint8_t *glyphWidthTable;
|
||||
};
|
||||
|
||||
#endif // OPTIONS_H
|
||||
|
@ -12,129 +12,129 @@
|
||||
|
||||
bool ParseNumber(char *s, char **end, int radix, int *intValue)
|
||||
{
|
||||
char *localEnd;
|
||||
char *localEnd;
|
||||
|
||||
if (end == NULL)
|
||||
end = &localEnd;
|
||||
if (end == NULL)
|
||||
end = &localEnd;
|
||||
|
||||
errno = 0;
|
||||
errno = 0;
|
||||
|
||||
const long longValue = strtol(s, end, radix);
|
||||
const long longValue = strtol(s, end, radix);
|
||||
|
||||
if (*end == s)
|
||||
return false; // not a number
|
||||
if (*end == s)
|
||||
return false; // not a number
|
||||
|
||||
if ((longValue == LONG_MIN || longValue == LONG_MAX) && errno == ERANGE)
|
||||
return false;
|
||||
if ((longValue == LONG_MIN || longValue == LONG_MAX) && errno == ERANGE)
|
||||
return false;
|
||||
|
||||
if (longValue > INT_MAX)
|
||||
return false;
|
||||
if (longValue > INT_MAX)
|
||||
return false;
|
||||
|
||||
if (longValue < INT_MIN)
|
||||
return false;
|
||||
if (longValue < INT_MIN)
|
||||
return false;
|
||||
|
||||
*intValue = (int)longValue;
|
||||
*intValue = (int)longValue;
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
char *GetFileExtension(char *path)
|
||||
{
|
||||
char *extension = path;
|
||||
char *extension = path;
|
||||
|
||||
while (*extension != 0)
|
||||
extension++;
|
||||
while (*extension != 0)
|
||||
extension++;
|
||||
|
||||
while (extension > path && *extension != '.')
|
||||
extension--;
|
||||
while (extension > path && *extension != '.')
|
||||
extension--;
|
||||
|
||||
if (extension == path)
|
||||
return NULL;
|
||||
if (extension == path)
|
||||
return NULL;
|
||||
|
||||
extension++;
|
||||
extension++;
|
||||
|
||||
if (*extension == 0)
|
||||
return NULL;
|
||||
if (*extension == 0)
|
||||
return NULL;
|
||||
|
||||
return extension;
|
||||
return extension;
|
||||
}
|
||||
|
||||
unsigned char *ReadWholeFile(char *path, int *size)
|
||||
{
|
||||
FILE *fp = fopen(path, "rb");
|
||||
FILE *fp = fopen(path, "rb");
|
||||
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
fseek(fp, 0, SEEK_END);
|
||||
|
||||
*size = ftell(fp);
|
||||
*size = ftell(fp);
|
||||
|
||||
unsigned char *buffer = malloc(*size);
|
||||
unsigned char *buffer = malloc(*size);
|
||||
|
||||
if (buffer == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
|
||||
if (buffer == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
|
||||
|
||||
rewind(fp);
|
||||
rewind(fp);
|
||||
|
||||
if (fread(buffer, *size, 1, fp) != 1)
|
||||
FATAL_ERROR("Failed to read \"%s\".\n", path);
|
||||
if (fread(buffer, *size, 1, fp) != 1)
|
||||
FATAL_ERROR("Failed to read \"%s\".\n", path);
|
||||
|
||||
fclose(fp);
|
||||
fclose(fp);
|
||||
|
||||
return buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount)
|
||||
{
|
||||
FILE *fp = fopen(path, "rb");
|
||||
FILE *fp = fopen(path, "rb");
|
||||
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
fseek(fp, 0, SEEK_END);
|
||||
|
||||
*size = ftell(fp);
|
||||
*size = ftell(fp);
|
||||
|
||||
unsigned char *buffer = calloc(*size + padAmount, 1);
|
||||
unsigned char *buffer = calloc(*size + padAmount, 1);
|
||||
|
||||
if (buffer == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
|
||||
if (buffer == NULL)
|
||||
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
|
||||
|
||||
rewind(fp);
|
||||
rewind(fp);
|
||||
|
||||
if (fread(buffer, *size, 1, fp) != 1)
|
||||
FATAL_ERROR("Failed to read \"%s\".\n", path);
|
||||
if (fread(buffer, *size, 1, fp) != 1)
|
||||
FATAL_ERROR("Failed to read \"%s\".\n", path);
|
||||
|
||||
fclose(fp);
|
||||
fclose(fp);
|
||||
|
||||
return buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void WriteWholeStringToFile(char *path, char *string)
|
||||
{
|
||||
FILE *fp = fopen(path, "wb");
|
||||
FILE *fp = fopen(path, "wb");
|
||||
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
|
||||
|
||||
if (fputs(string, fp) == EOF)
|
||||
FATAL_ERROR("Failed to write to \"%s\".\n", path);
|
||||
if (fputs(string, fp) == EOF)
|
||||
FATAL_ERROR("Failed to write to \"%s\".\n", path);
|
||||
|
||||
fclose(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void WriteWholeFile(char *path, void *buffer, int bufferSize)
|
||||
{
|
||||
FILE *fp = fopen(path, "wb");
|
||||
FILE *fp = fopen(path, "wb");
|
||||
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
|
||||
|
||||
if (fwrite(buffer, bufferSize, 1, fp) != 1)
|
||||
FATAL_ERROR("Failed to write to \"%s\".\n", path);
|
||||
if (fwrite(buffer, bufferSize, 1, fp) != 1)
|
||||
FATAL_ERROR("Failed to write to \"%s\".\n", path);
|
||||
|
||||
fclose(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void WriteGenericNtrHeader(FILE* fp, const char* magicNumber, uint32_t size, bool byteorder, bool version101, uint16_t sectionCount)
|
||||
|
Loading…
Reference in New Issue
Block a user