some cleanup

This commit is contained in:
red031000 2023-07-03 18:15:33 +01:00
parent a4e194fc9b
commit 8906c349fd
No known key found for this signature in database
GPG Key ID: D27E50C050AE0CE1
4 changed files with 347 additions and 290 deletions

574
gfx.c
View File

@ -21,76 +21,76 @@
static void AdvanceMetatilePosition(int *subTileX, int *subTileY, int *metatileX, int *metatileY, int metatilesWide, int metatileWidth, int metatileHeight) static void AdvanceMetatilePosition(int *subTileX, int *subTileY, int *metatileX, int *metatileY, int metatilesWide, int metatileWidth, int metatileHeight)
{ {
(*subTileX)++; (*subTileX)++;
if (*subTileX == metatileWidth) { if (*subTileX == metatileWidth) {
*subTileX = 0; *subTileX = 0;
(*subTileY)++; (*subTileY)++;
if (*subTileY == metatileHeight) { if (*subTileY == metatileHeight) {
*subTileY = 0; *subTileY = 0;
(*metatileX)++; (*metatileX)++;
if (*metatileX == metatilesWide) { if (*metatileX == metatilesWide) {
*metatileX = 0; *metatileX = 0;
(*metatileY)++; (*metatileY)++;
} }
} }
} }
} }
static void ConvertFromTiles1Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) static void ConvertFromTiles1Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors)
{ {
int subTileX = 0; int subTileX = 0;
int subTileY = 0; int subTileY = 0;
int metatileX = 0; int metatileX = 0;
int metatileY = 0; int metatileY = 0;
int pitch = metatilesWide * metatileWidth; int pitch = metatilesWide * metatileWidth;
for (int i = 0; i < numTiles; i++) { for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) { for (int j = 0; j < 8; j++) {
int destY = (metatileY * metatileHeight + subTileY) * 8 + j; int destY = (metatileY * metatileHeight + subTileY) * 8 + j;
int destX = metatileX * metatileWidth + subTileX; int destX = metatileX * metatileWidth + subTileX;
unsigned char srcPixelOctet = *src++; unsigned char srcPixelOctet = *src++;
unsigned char *destPixelOctet = &dest[destY * pitch + destX]; unsigned char *destPixelOctet = &dest[destY * pitch + destX];
for (int k = 0; k < 8; k++) { for (int k = 0; k < 8; k++) {
*destPixelOctet <<= 1; *destPixelOctet <<= 1;
*destPixelOctet |= (srcPixelOctet & 1) ^ invertColors; *destPixelOctet |= (srcPixelOctet & 1) ^ invertColors;
srcPixelOctet >>= 1; srcPixelOctet >>= 1;
} }
} }
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight);
} }
} }
static void ConvertFromTiles4Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) static void ConvertFromTiles4Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors)
{ {
int subTileX = 0; int subTileX = 0;
int subTileY = 0; int subTileY = 0;
int metatileX = 0; int metatileX = 0;
int metatileY = 0; int metatileY = 0;
int pitch = (metatilesWide * metatileWidth) * 4; int pitch = (metatilesWide * metatileWidth) * 4;
for (int i = 0; i < numTiles; i++) { for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) { for (int j = 0; j < 8; j++) {
int destY = (metatileY * metatileHeight + subTileY) * 8 + j; int destY = (metatileY * metatileHeight + subTileY) * 8 + j;
for (int k = 0; k < 4; k++) { for (int k = 0; k < 4; k++) {
int destX = (metatileX * metatileWidth + subTileX) * 4 + k; int destX = (metatileX * metatileWidth + subTileX) * 4 + k;
unsigned char srcPixelPair = *src++; unsigned char srcPixelPair = *src++;
unsigned char leftPixel = srcPixelPair & 0xF; unsigned char leftPixel = srcPixelPair & 0xF;
unsigned char rightPixel = srcPixelPair >> 4; unsigned char rightPixel = srcPixelPair >> 4;
if (invertColors) { if (invertColors) {
leftPixel = 15 - leftPixel; leftPixel = 15 - leftPixel;
rightPixel = 15 - rightPixel; rightPixel = 15 - rightPixel;
} }
dest[destY * pitch + destX] = (leftPixel << 4) | rightPixel; dest[destY * pitch + destX] = (leftPixel << 4) | rightPixel;
} }
} }
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight);
} }
} }
static uint32_t ConvertFromScanned4Bpp(unsigned char *src, unsigned char *dest, int fileSize, bool invertColours, bool scanFrontToBack) static uint32_t ConvertFromScanned4Bpp(unsigned char *src, unsigned char *dest, int fileSize, bool invertColours, bool scanFrontToBack)
@ -137,86 +137,86 @@ static uint32_t ConvertFromScanned4Bpp(unsigned char *src, unsigned char *dest,
static void ConvertFromTiles8Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) static void ConvertFromTiles8Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors)
{ {
int subTileX = 0; int subTileX = 0;
int subTileY = 0; int subTileY = 0;
int metatileX = 0; int metatileX = 0;
int metatileY = 0; int metatileY = 0;
int pitch = (metatilesWide * metatileWidth) * 8; int pitch = (metatilesWide * metatileWidth) * 8;
for (int i = 0; i < numTiles; i++) { for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) { for (int j = 0; j < 8; j++) {
int destY = (metatileY * metatileHeight + subTileY) * 8 + j; int destY = (metatileY * metatileHeight + subTileY) * 8 + j;
for (int k = 0; k < 8; k++) { for (int k = 0; k < 8; k++) {
int destX = (metatileX * metatileWidth + subTileX) * 8 + k; int destX = (metatileX * metatileWidth + subTileX) * 8 + k;
unsigned char srcPixel = *src++; unsigned char srcPixel = *src++;
if (invertColors) if (invertColors)
srcPixel = 255 - srcPixel; srcPixel = 255 - srcPixel;
dest[destY * pitch + destX] = srcPixel; dest[destY * pitch + destX] = srcPixel;
} }
} }
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight);
} }
} }
static void ConvertToTiles1Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) static void ConvertToTiles1Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors)
{ {
int subTileX = 0; int subTileX = 0;
int subTileY = 0; int subTileY = 0;
int metatileX = 0; int metatileX = 0;
int metatileY = 0; int metatileY = 0;
int pitch = metatilesWide * metatileWidth; int pitch = metatilesWide * metatileWidth;
for (int i = 0; i < numTiles; i++) { for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) { for (int j = 0; j < 8; j++) {
int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; int srcY = (metatileY * metatileHeight + subTileY) * 8 + j;
int srcX = metatileX * metatileWidth + subTileX; int srcX = metatileX * metatileWidth + subTileX;
unsigned char srcPixelOctet = src[srcY * pitch + srcX]; unsigned char srcPixelOctet = src[srcY * pitch + srcX];
unsigned char *destPixelOctet = dest++; unsigned char *destPixelOctet = dest++;
for (int k = 0; k < 8; k++) { for (int k = 0; k < 8; k++) {
*destPixelOctet <<= 1; *destPixelOctet <<= 1;
*destPixelOctet |= (srcPixelOctet & 1) ^ invertColors; *destPixelOctet |= (srcPixelOctet & 1) ^ invertColors;
srcPixelOctet >>= 1; srcPixelOctet >>= 1;
} }
} }
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight);
} }
} }
static void ConvertToTiles4Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) static void ConvertToTiles4Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors)
{ {
int subTileX = 0; int subTileX = 0;
int subTileY = 0; int subTileY = 0;
int metatileX = 0; int metatileX = 0;
int metatileY = 0; int metatileY = 0;
int pitch = (metatilesWide * metatileWidth) * 4; int pitch = (metatilesWide * metatileWidth) * 4;
for (int i = 0; i < numTiles; i++) { for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) { for (int j = 0; j < 8; j++) {
int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; int srcY = (metatileY * metatileHeight + subTileY) * 8 + j;
for (int k = 0; k < 4; k++) { for (int k = 0; k < 4; k++) {
int srcX = (metatileX * metatileWidth + subTileX) * 4 + k; int srcX = (metatileX * metatileWidth + subTileX) * 4 + k;
unsigned char srcPixelPair = src[srcY * pitch + srcX]; unsigned char srcPixelPair = src[srcY * pitch + srcX];
unsigned char leftPixel = srcPixelPair >> 4; unsigned char leftPixel = srcPixelPair >> 4;
unsigned char rightPixel = srcPixelPair & 0xF; unsigned char rightPixel = srcPixelPair & 0xF;
if (invertColors) { if (invertColors) {
leftPixel = 15 - leftPixel; leftPixel = 15 - leftPixel;
rightPixel = 15 - rightPixel; rightPixel = 15 - rightPixel;
} }
*dest++ = (rightPixel << 4) | leftPixel; *dest++ = (rightPixel << 4) | leftPixel;
} }
} }
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight);
} }
} }
static void ConvertToScanned4Bpp(unsigned char *src, unsigned char *dest, int fileSize, bool invertColours, uint32_t encValue, uint32_t scanMode) static void ConvertToScanned4Bpp(unsigned char *src, unsigned char *dest, int fileSize, bool invertColours, uint32_t encValue, uint32_t scanMode)
@ -257,71 +257,71 @@ static void ConvertToScanned4Bpp(unsigned char *src, unsigned char *dest, int fi
static void ConvertToTiles8Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) static void ConvertToTiles8Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors)
{ {
int subTileX = 0; int subTileX = 0;
int subTileY = 0; int subTileY = 0;
int metatileX = 0; int metatileX = 0;
int metatileY = 0; int metatileY = 0;
int pitch = (metatilesWide * metatileWidth) * 8; int pitch = (metatilesWide * metatileWidth) * 8;
for (int i = 0; i < numTiles; i++) { for (int i = 0; i < numTiles; i++) {
for (int j = 0; j < 8; j++) { for (int j = 0; j < 8; j++) {
int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; int srcY = (metatileY * metatileHeight + subTileY) * 8 + j;
for (int k = 0; k < 8; k++) { for (int k = 0; k < 8; k++) {
int srcX = (metatileX * metatileWidth + subTileX) * 8 + k; int srcX = (metatileX * metatileWidth + subTileX) * 8 + k;
unsigned char srcPixel = src[srcY * pitch + srcX]; unsigned char srcPixel = src[srcY * pitch + srcX];
if (invertColors) if (invertColors)
srcPixel = 255 - srcPixel; srcPixel = 255 - srcPixel;
*dest++ = srcPixel; *dest++ = srcPixel;
} }
} }
AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight); AdvanceMetatilePosition(&subTileX, &subTileY, &metatileX, &metatileY, metatilesWide, metatileWidth, metatileHeight);
} }
} }
void ReadImage(char *path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors) void ReadImage(char *path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors)
{ {
int tileSize = bitDepth * 8; int tileSize = bitDepth * 8;
int fileSize; int fileSize;
unsigned char *buffer = ReadWholeFile(path, &fileSize); unsigned char *buffer = ReadWholeFile(path, &fileSize);
int numTiles = fileSize / tileSize; int numTiles = fileSize / tileSize;
int tilesHeight = (numTiles + tilesWidth - 1) / tilesWidth; int tilesHeight = (numTiles + tilesWidth - 1) / tilesWidth;
if (tilesWidth % metatileWidth != 0) if (tilesWidth % metatileWidth != 0)
FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth); FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth);
if (tilesHeight % metatileHeight != 0) if (tilesHeight % metatileHeight != 0)
FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight, metatileHeight); FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight, metatileHeight);
image->width = tilesWidth * 8; image->width = tilesWidth * 8;
image->height = tilesHeight * 8; image->height = tilesHeight * 8;
image->bitDepth = bitDepth; image->bitDepth = bitDepth;
image->pixels = calloc(tilesWidth * tilesHeight, tileSize); image->pixels = calloc(tilesWidth * tilesHeight, tileSize);
if (image->pixels == NULL) if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate memory for pixels.\n"); FATAL_ERROR("Failed to allocate memory for pixels.\n");
int metatilesWide = tilesWidth / metatileWidth; int metatilesWide = tilesWidth / metatileWidth;
switch (bitDepth) { switch (bitDepth) {
case 1: case 1:
ConvertFromTiles1Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); ConvertFromTiles1Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors);
break; break;
case 4: case 4:
ConvertFromTiles4Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); ConvertFromTiles4Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors);
break; break;
case 8: case 8:
ConvertFromTiles8Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); ConvertFromTiles8Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors);
break; break;
} }
free(buffer); free(buffer);
} }
uint32_t ReadNtrImage(char *path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors, bool scanFrontToBack) uint32_t ReadNtrImage(char *path, int tilesWidth, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors, bool scanFrontToBack)
@ -354,10 +354,18 @@ uint32_t ReadNtrImage(char *path, int tilesWidth, int bitDepth, int metatileWidt
int tileSize = bitDepth * 8; int tileSize = bitDepth * 8;
int numTiles = (charHeader[0x18] + (charHeader[0x19] << 8) + (charHeader[0x1A] << 16) + (charHeader[0x1B] << 24)) if (tilesWidth == 0) {
/ (64 / (8 / bitDepth)); tilesWidth = ReadS16(charHeader, 0xA);
if (tilesWidth < 0) {
tilesWidth = 1;
}
}
int tilesHeight = (numTiles + tilesWidth - 1) / tilesWidth; int numTiles = ReadS32(charHeader, 0x18) / (64 / (8 / bitDepth));
int tilesHeight = ReadS16(charHeader, 0x8);
if (tilesHeight < 0)
tilesHeight = (numTiles + tilesWidth - 1) / tilesWidth;
if (tilesWidth % metatileWidth != 0) if (tilesWidth % metatileWidth != 0)
FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth); FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth);
@ -373,7 +381,7 @@ uint32_t ReadNtrImage(char *path, int tilesWidth, int bitDepth, int metatileWidt
if (image->pixels == NULL) if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate memory for pixels.\n"); FATAL_ERROR("Failed to allocate memory for pixels.\n");
int metatilesWide = tilesWidth / metatileWidth; int metatilesWide = tilesWidth / metatileWidth;
uint32_t key = 0; uint32_t key = 0;
@ -410,53 +418,53 @@ uint32_t ReadNtrImage(char *path, int tilesWidth, int bitDepth, int metatileWidt
void WriteImage(char *path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors) void WriteImage(char *path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, bool invertColors)
{ {
int tileSize = bitDepth * 8; int tileSize = bitDepth * 8;
if (image->width % 8 != 0) if (image->width % 8 != 0)
FATAL_ERROR("The width in pixels (%d) isn't a multiple of 8.\n", image->width); FATAL_ERROR("The width in pixels (%d) isn't a multiple of 8.\n", image->width);
if (image->height % 8 != 0) if (image->height % 8 != 0)
FATAL_ERROR("The height in pixels (%d) isn't a multiple of 8.\n", image->height); FATAL_ERROR("The height in pixels (%d) isn't a multiple of 8.\n", image->height);
int tilesWidth = image->width / 8; int tilesWidth = image->width / 8;
int tilesHeight = image->height / 8; int tilesHeight = image->height / 8;
if (tilesWidth % metatileWidth != 0) if (tilesWidth % metatileWidth != 0)
FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth); FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth);
if (tilesHeight % metatileHeight != 0) if (tilesHeight % metatileHeight != 0)
FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight, metatileHeight); FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight, metatileHeight);
int maxNumTiles = tilesWidth * tilesHeight; int maxNumTiles = tilesWidth * tilesHeight;
if (numTiles == 0) if (numTiles == 0)
numTiles = maxNumTiles; numTiles = maxNumTiles;
else if (numTiles > maxNumTiles) else if (numTiles > maxNumTiles)
FATAL_ERROR("The specified number of tiles (%d) is greater than the maximum possible value (%d).\n", numTiles, maxNumTiles); FATAL_ERROR("The specified number of tiles (%d) is greater than the maximum possible value (%d).\n", numTiles, maxNumTiles);
int bufferSize = numTiles * tileSize; int bufferSize = numTiles * tileSize;
unsigned char *buffer = malloc(bufferSize); unsigned char *buffer = malloc(bufferSize);
if (buffer == NULL) if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for pixels.\n"); FATAL_ERROR("Failed to allocate memory for pixels.\n");
int metatilesWide = tilesWidth / metatileWidth; int metatilesWide = tilesWidth / metatileWidth;
switch (bitDepth) { switch (bitDepth) {
case 1: case 1:
ConvertToTiles1Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); ConvertToTiles1Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors);
break; break;
case 4: case 4:
ConvertToTiles4Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); ConvertToTiles4Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors);
break; break;
case 8: case 8:
ConvertToTiles8Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); ConvertToTiles8Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors);
break; break;
} }
WriteWholeFile(path, buffer, bufferSize); WriteWholeFile(path, buffer, bufferSize);
free(buffer); free(buffer);
} }
void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image, void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, int metatileHeight, struct Image *image,
@ -572,8 +580,8 @@ void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, in
fwrite(pixelBuffer, 1, bufferSize, fp); fwrite(pixelBuffer, 1, bufferSize, fp);
if (sopc) if (sopc)
{ {
unsigned char sopcBuffer[0x10] = { 0x53, 0x4F, 0x50, 0x43, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; unsigned char sopcBuffer[0x10] = { 0x53, 0x4F, 0x50, 0x43, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
sopcBuffer[12] = tilesWidth & 0xFF; sopcBuffer[12] = tilesWidth & 0xFF;
sopcBuffer[13] = (tilesWidth >> 8) & 0xFF; sopcBuffer[13] = (tilesWidth >> 8) & 0xFF;
@ -582,7 +590,7 @@ void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, in
sopcBuffer[15] = (tilesHeight >> 8) & 0xFF; sopcBuffer[15] = (tilesHeight >> 8) & 0xFF;
fwrite(sopcBuffer, 1, 0x10, fp); fwrite(sopcBuffer, 1, 0x10, fp);
} }
free(pixelBuffer); free(pixelBuffer);
fclose(fp); fclose(fp);
@ -590,28 +598,28 @@ void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, in
void FreeImage(struct Image *image) void FreeImage(struct Image *image)
{ {
free(image->pixels); free(image->pixels);
image->pixels = NULL; image->pixels = NULL;
} }
void ReadGbaPalette(char *path, struct Palette *palette) void ReadGbaPalette(char *path, struct Palette *palette)
{ {
int fileSize; int fileSize;
unsigned char *data = ReadWholeFile(path, &fileSize); unsigned char *data = ReadWholeFile(path, &fileSize);
if (fileSize % 2 != 0) if (fileSize % 2 != 0)
FATAL_ERROR("The file size (%d) is not a multiple of 2.\n", fileSize); FATAL_ERROR("The file size (%d) is not a multiple of 2.\n", fileSize);
palette->numColors = fileSize / 2; palette->numColors = fileSize / 2;
for (int i = 0; i < palette->numColors; i++) { for (int i = 0; i < palette->numColors; i++) {
uint16_t paletteEntry = (data[i * 2 + 1] << 8) | data[i * 2]; uint16_t paletteEntry = (data[i * 2 + 1] << 8) | data[i * 2];
palette->colors[i].red = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_RED(paletteEntry)); palette->colors[i].red = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_RED(paletteEntry));
palette->colors[i].green = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_GREEN(paletteEntry)); palette->colors[i].green = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_GREEN(paletteEntry));
palette->colors[i].blue = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_BLUE(paletteEntry)); palette->colors[i].blue = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_BLUE(paletteEntry));
} }
free(data); free(data);
} }
void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIndex) void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIndex)
@ -645,19 +653,19 @@ void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIn
for (int i = 0; i < 256; i++) for (int i = 0; i < 256; i++)
{ {
if (i < palette->numColors) if (i < palette->numColors)
{ {
uint16_t paletteEntry = (paletteData[(32 * palIndex) + i * 2 + 1] << 8) | paletteData[(32 * palIndex) + i * 2]; uint16_t paletteEntry = (paletteData[(32 * palIndex) + i * 2 + 1] << 8) | paletteData[(32 * palIndex) + i * 2];
palette->colors[i].red = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_RED(paletteEntry)); palette->colors[i].red = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_RED(paletteEntry));
palette->colors[i].green = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_GREEN(paletteEntry)); palette->colors[i].green = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_GREEN(paletteEntry));
palette->colors[i].blue = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_BLUE(paletteEntry)); palette->colors[i].blue = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_BLUE(paletteEntry));
} }
else else
{ {
palette->colors[i].red = 0; palette->colors[i].red = 0;
palette->colors[i].green = 0; palette->colors[i].green = 0;
palette->colors[i].blue = 0; palette->colors[i].blue = 0;
} }
} }
free(data); free(data);
@ -665,23 +673,23 @@ void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIn
void WriteGbaPalette(char *path, struct Palette *palette) void WriteGbaPalette(char *path, struct Palette *palette)
{ {
FILE *fp = fopen(path, "wb"); FILE *fp = fopen(path, "wb");
if (fp == NULL) if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path); FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
for (int i = 0; i < palette->numColors; i++) { for (int i = 0; i < palette->numColors; i++) {
unsigned char red = DOWNCONVERT_BIT_DEPTH(palette->colors[i].red); unsigned char red = DOWNCONVERT_BIT_DEPTH(palette->colors[i].red);
unsigned char green = DOWNCONVERT_BIT_DEPTH(palette->colors[i].green); unsigned char green = DOWNCONVERT_BIT_DEPTH(palette->colors[i].green);
unsigned char blue = DOWNCONVERT_BIT_DEPTH(palette->colors[i].blue); unsigned char blue = DOWNCONVERT_BIT_DEPTH(palette->colors[i].blue);
uint16_t paletteEntry = SET_GBA_PAL(red, green, blue); uint16_t paletteEntry = SET_GBA_PAL(red, green, blue);
fputc(paletteEntry & 0xFF, fp); fputc(paletteEntry & 0xFF, fp);
fputc(paletteEntry >> 8, fp); fputc(paletteEntry >> 8, fp);
} }
fclose(fp); fclose(fp);
} }
void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, int bitdepth, bool pad, int compNum) void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, int bitdepth, bool pad, int compNum)
@ -768,10 +776,10 @@ void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, in
void WriteNtrCell(char *path, struct JsonToCellOptions *options) void WriteNtrCell(char *path, struct JsonToCellOptions *options)
{ {
FILE *fp = fopen(path, "wb"); FILE *fp = fopen(path, "wb");
if (fp == NULL) if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path); FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
unsigned int totalSize = (options->labelEnabled > 0 ? 0x34 : 0x20) + options->cellCount * (options->extended ? 0x16 : 0xe); unsigned int totalSize = (options->labelEnabled > 0 ? 0x34 : 0x20) + options->cellCount * (options->extended ? 0x16 : 0xe);
@ -783,44 +791,44 @@ void WriteNtrCell(char *path, struct JsonToCellOptions *options)
} }
} }
WriteGenericNtrHeader(fp, "RECN", totalSize, true, false, options->labelEnabled ? 3 : 1); WriteGenericNtrHeader(fp, "RECN", totalSize, true, false, options->labelEnabled ? 3 : 1);
unsigned char KBECHeader[0x20] = unsigned char KBECHeader[0x20] =
{ {
0x4B, 0x42, 0x45, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4B, 0x42, 0x45, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}; };
KBECHeader[8] = options->cellCount; //cell count KBECHeader[8] = options->cellCount; //cell count
if (options->extended) if (options->extended)
{ {
KBECHeader[10] = 1; //extended KBECHeader[10] = 1; //extended
} }
unsigned int size = options->cellCount * (options->extended ? 0x16 : 0xe); unsigned int size = options->cellCount * (options->extended ? 0x16 : 0xe);
KBECHeader[4] = (size + 0x20) & 0xFF; //size KBECHeader[4] = (size + 0x20) & 0xFF; //size
KBECHeader[5] = (size + 0x20) >> 8; //unlikely to be more than 16 bits, but there are 32 allocated, change if necessary KBECHeader[5] = (size + 0x20) >> 8; //unlikely to be more than 16 bits, but there are 32 allocated, change if necessary
KBECHeader[16] = (options->mappingType & 0xFF); //not possible to be more than 8 bits, though 32 are allocated KBECHeader[16] = (options->mappingType & 0xFF); //not possible to be more than 8 bits, though 32 are allocated
fwrite(KBECHeader, 1, 0x20, fp); fwrite(KBECHeader, 1, 0x20, fp);
unsigned char *KBECContents = malloc(size); unsigned char *KBECContents = malloc(size);
memset(KBECContents, 0, size); memset(KBECContents, 0, size);
if (!options->extended) if (!options->extended)
{ {
FATAL_ERROR("Don't know how to deal with not extended yet, bug red031000.\n"); FATAL_ERROR("Don't know how to deal with not extended yet, bug red031000.\n");
} }
int i; int i;
for (i = 0; i < options->cellCount * 0x10; i += 0x10) for (i = 0; i < options->cellCount * 0x10; i += 0x10)
{ {
KBECContents[i] = 0x01; //number of images KBECContents[i] = 0x01; //number of images
KBECContents[i + 2] = options->cells[i / 0x10]->readOnly & 0xff; //unknown KBECContents[i + 2] = options->cells[i / 0x10]->readOnly & 0xff; //unknown
KBECContents[i + 3] = options->cells[i / 0x10]->readOnly >> 8; KBECContents[i + 3] = options->cells[i / 0x10]->readOnly >> 8;
KBECContents[i + 4] = (i / 0x10 * 6) & 0xff; //pointer to OAM data KBECContents[i + 4] = (i / 0x10 * 6) & 0xff; //pointer to OAM data
KBECContents[i + 5] = (i / 0x10 * 6) >> 8; //unlikely to be more than 16 bits, but there are 32 allocated, change if necessary KBECContents[i + 5] = (i / 0x10 * 6) >> 8; //unlikely to be more than 16 bits, but there are 32 allocated, change if necessary
@ -834,21 +842,21 @@ void WriteNtrCell(char *path, struct JsonToCellOptions *options)
KBECContents[i + 15] = options->cells[i / 0x10]->minY >> 8; KBECContents[i + 15] = options->cells[i / 0x10]->minY >> 8;
} }
//OAM data //OAM data
for (int j = i; j < options->cellCount * 6 + i; j += 6) for (int j = i; j < options->cellCount * 6 + i; j += 6)
{ {
//Attr0 //Attr0
//bits 0-7 Y coordinate //bits 0-7 Y coordinate
KBECContents[j] = options->cells[(j - i) / 6]->oam.attr0.YCoordinate & 0xff; KBECContents[j] = options->cells[(j - i) / 6]->oam.attr0.YCoordinate & 0xff;
//bit 8 rotation //bit 8 rotation
KBECContents[j + 1] = options->cells[(j - i) / 6]->oam.attr0.Rotation; KBECContents[j + 1] = options->cells[(j - i) / 6]->oam.attr0.Rotation;
//bit 9 Obj Size (if rotation) or Obj Disable (if not rotation) //bit 9 Obj Size (if rotation) or Obj Disable (if not rotation)
KBECContents[j + 1] |= options->cells[(j - i) / 6]->oam.attr0.SizeDisable << 1; KBECContents[j + 1] |= options->cells[(j - i) / 6]->oam.attr0.SizeDisable << 1;
//bits 10-11 Obj Mode //bits 10-11 Obj Mode
KBECContents[j + 1] |= options->cells[(j - i) / 6]->oam.attr0.Mode << 2; KBECContents[j + 1] |= options->cells[(j - i) / 6]->oam.attr0.Mode << 2;
//bit 12 Obj Mosaic //bit 12 Obj Mosaic
@ -885,12 +893,12 @@ void WriteNtrCell(char *path, struct JsonToCellOptions *options)
KBECContents[j + 5] |= options->cells[(j - i) / 6]->oam.attr2.Palette << 4; KBECContents[j + 5] |= options->cells[(j - i) / 6]->oam.attr2.Palette << 4;
} }
fwrite(KBECContents, 1, size, fp); fwrite(KBECContents, 1, size, fp);
free(KBECContents); free(KBECContents);
if (options->labelEnabled) if (options->labelEnabled)
{ {
unsigned int lablSize = 8; unsigned int lablSize = 8;
for (int j = 0; j < options->labelCount; j++) for (int j = 0; j < options->labelCount; j++)
{ {
@ -932,7 +940,7 @@ void WriteNtrCell(char *path, struct JsonToCellOptions *options)
fwrite(txeu, 1, 0xc, fp); fwrite(txeu, 1, 0xc, fp);
} }
fclose(fp); fclose(fp);
} }
void WriteNtrScreen(char *path, struct JsonToScreenOptions *options) void WriteNtrScreen(char *path, struct JsonToScreenOptions *options)
@ -1009,8 +1017,8 @@ void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options)
unsigned char KBNAHeader[0x20] = unsigned char KBNAHeader[0x20] =
{ {
0x4B, 0x4E, 0x42, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4B, 0x4E, 0x42, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}; };
KBNAHeader[4] = KNBASize & 0xff; KBNAHeader[4] = KNBASize & 0xff;
@ -1105,7 +1113,7 @@ void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options)
KBNAContents[resPtrCounter + 3] = 0xCC; KBNAContents[resPtrCounter + 3] = 0xCC;
resPtrCounter += 0x4; resPtrCounter += 0x4;
break; break;
case 1: case 1:
KBNAContents[resPtrCounter] = options->animationResults[k]->dataSrt.index & 0xff; KBNAContents[resPtrCounter] = options->animationResults[k]->dataSrt.index & 0xff;
KBNAContents[resPtrCounter + 1] = options->animationResults[k]->dataSrt.index >> 8; KBNAContents[resPtrCounter + 1] = options->animationResults[k]->dataSrt.index >> 8;
@ -1125,7 +1133,7 @@ void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options)
KBNAContents[resPtrCounter + 15] = options->animationResults[k]->dataSrt.positionY >> 8; KBNAContents[resPtrCounter + 15] = options->animationResults[k]->dataSrt.positionY >> 8;
resPtrCounter += 0x10; resPtrCounter += 0x10;
break; break;
case 2: case 2:
KBNAContents[resPtrCounter] = options->animationResults[k]->dataT.index & 0xff; KBNAContents[resPtrCounter] = options->animationResults[k]->dataT.index & 0xff;
KBNAContents[resPtrCounter + 1] = options->animationResults[k]->dataT.index >> 8; KBNAContents[resPtrCounter + 1] = options->animationResults[k]->dataT.index >> 8;
@ -1144,10 +1152,10 @@ void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options)
fwrite(KBNAContents, 1, contentsSize, fp); fwrite(KBNAContents, 1, contentsSize, fp);
free(KBNAContents); free(KBNAContents);
if (options->labelEnabled) if (options->labelEnabled)
{ {
unsigned int lablSize = 8; unsigned int lablSize = 8;
for (int j = 0; j < options->labelCount; j++) for (int j = 0; j < options->labelCount; j++)
{ {

20
main.c
View File

@ -1,5 +1,6 @@
// Copyright (c) 2015 YamaArashi, 2021-2023 red031000 // Copyright (c) 2015 YamaArashi, 2021-2023 red031000
#include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
@ -80,7 +81,7 @@ void ConvertNtrToPng(char *inputPath, char *outputPath, struct NtrToPngOptions *
{ {
image.hasPalette = false; image.hasPalette = false;
} }
uint32_t key = ReadNtrImage(inputPath, options->width, 0, options->metatileWidth, options->metatileHeight, &image, !image.hasPalette, options->scanFrontToBack); uint32_t key = ReadNtrImage(inputPath, options->width, 0, options->metatileWidth, options->metatileHeight, &image, !image.hasPalette, options->scanFrontToBack);
if (key) if (key)
@ -171,7 +172,10 @@ void HandleGbaToPngCommand(char *inputPath, char *outputPath, int argc, char **a
char *inputFileExtension = GetFileExtension(inputPath); char *inputFileExtension = GetFileExtension(inputPath);
struct GbaToPngOptions options; struct GbaToPngOptions options;
options.paletteFilePath = NULL; options.paletteFilePath = NULL;
options.bitDepth = inputFileExtension[0] - '0'; if (isdigit(inputFileExtension[0]))
options.bitDepth = inputFileExtension[0] - '0';
else
options.bitDepth = 4;
options.hasTransparency = false; options.hasTransparency = false;
options.width = 1; options.width = 1;
options.metatileWidth = 1; options.metatileWidth = 1;
@ -250,7 +254,7 @@ void HandleNtrToPngCommand(char *inputPath, char *outputPath, int argc, char **a
struct NtrToPngOptions options; struct NtrToPngOptions options;
options.paletteFilePath = NULL; options.paletteFilePath = NULL;
options.hasTransparency = false; options.hasTransparency = false;
options.width = 1; options.width = 0;
options.metatileWidth = 1; options.metatileWidth = 1;
options.metatileHeight = 1; options.metatileHeight = 1;
options.palIndex = 1; options.palIndex = 1;
@ -340,7 +344,7 @@ void HandleNtrToPngCommand(char *inputPath, char *outputPath, int argc, char **a
} }
} }
if (options.metatileWidth > options.width) if (options.width != 0 && options.metatileWidth > options.width)
options.width = options.metatileWidth; options.width = options.metatileWidth;
ConvertNtrToPng(inputPath, outputPath, &options); ConvertNtrToPng(inputPath, outputPath, &options);
@ -349,7 +353,11 @@ void HandleNtrToPngCommand(char *inputPath, char *outputPath, int argc, char **a
void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **argv) void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **argv)
{ {
char *outputFileExtension = GetFileExtension(outputPath); char *outputFileExtension = GetFileExtension(outputPath);
int bitDepth = outputFileExtension[0] - '0'; int bitDepth;
if (strcmp(outputFileExtension, "nbfc") == 0)
bitDepth = 4;
else
bitDepth = outputFileExtension[0] - '0';
struct PngToGbaOptions options; struct PngToGbaOptions options;
options.numTiles = 0; options.numTiles = 0;
options.bitDepth = bitDepth; options.bitDepth = bitDepth;
@ -814,7 +822,7 @@ void HandleJsonToNtrAnimationCommand(char *inputPath, char *outputPath, int argc
void HandleJsonToNtrMulticellAnimationCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) void HandleJsonToNtrMulticellAnimationCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{ {
struct JsonToAnimationOptions *options; struct JsonToAnimationOptions *options;
options = ParseNANRJson(inputPath); options = ParseNANRJson(inputPath);
options->multiCell = true; options->multiCell = true;

2
rl.c
View File

@ -101,7 +101,7 @@ unsigned char *RLCompress(unsigned char *src, int srcSize, int *compressedSize)
srcPos++; srcPos++;
uncompressedLength++; uncompressedLength++;
} }
if (uncompressedLength > 0) if (uncompressedLength > 0)
{ {
dest[destPos++] = uncompressedLength - 1; dest[destPos++] = uncompressedLength - 1;

41
util.h
View File

@ -13,4 +13,45 @@ unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount);
void WriteWholeFile(char *path, void *buffer, int bufferSize); void WriteWholeFile(char *path, void *buffer, int bufferSize);
void WriteGenericNtrHeader(FILE* fp, const char* magicNumber, uint32_t size, bool byteorder, bool version101, uint16_t sectionCount); void WriteGenericNtrHeader(FILE* fp, const char* magicNumber, uint32_t size, bool byteorder, bool version101, uint16_t sectionCount);
// Unaligned IO
static inline uint8_t ReadU8(const unsigned char *ptr, const size_t offset) {
return ptr[offset];
}
static inline uint16_t ReadU16(const unsigned char *ptr, const size_t offset) {
return ptr[offset] | (ptr[offset + 1] << 8);
}
static inline uint32_t ReadU32(const unsigned char *ptr, const size_t offset) {
return ptr[offset] | (ptr[offset + 1] << 8) | (ptr[offset + 2] << 16) | (ptr[offset + 3] << 24);
}
static inline int8_t ReadS8(const unsigned char *ptr, const size_t offset) {
return ptr[offset];
}
static inline int16_t ReadS16(const unsigned char *ptr, const size_t offset) {
return ptr[offset] | (ptr[offset + 1] << 8);
}
static inline int32_t ReadS32(const unsigned char *ptr, const size_t offset) {
return ptr[offset] | (ptr[offset + 1] << 8) | (ptr[offset + 2] << 16) | (ptr[offset + 3] << 24);
}
static inline void WriteU8(unsigned char *ptr, const size_t offset, uint8_t value) {
ptr[offset] = value;
}
static inline void WriteU16(unsigned char *ptr, const size_t offset, uint16_t value) {
ptr[offset] = value;
ptr[offset + 1] = value >> 8;
}
static inline void WriteU32(unsigned char *ptr, const size_t offset, uint32_t value) {
ptr[offset] = value;
ptr[offset + 1] = value >> 8;
ptr[offset + 2] = value >> 16;
ptr[offset + 3] = value >> 24;
}
#endif // UTIL_H #endif // UTIL_H