diff --git a/gfx.c b/gfx.c index 5278122..a87dae4 100644 --- a/gfx.c +++ b/gfx.c @@ -21,76 +21,76 @@ static void AdvanceMetatilePosition(int *subTileX, int *subTileY, int *metatileX, int *metatileY, int metatilesWide, int metatileWidth, int metatileHeight) { - (*subTileX)++; - if (*subTileX == metatileWidth) { - *subTileX = 0; - (*subTileY)++; - if (*subTileY == metatileHeight) { - *subTileY = 0; - (*metatileX)++; - if (*metatileX == metatilesWide) { - *metatileX = 0; - (*metatileY)++; - } - } - } + (*subTileX)++; + if (*subTileX == metatileWidth) { + *subTileX = 0; + (*subTileY)++; + if (*subTileY == metatileHeight) { + *subTileY = 0; + (*metatileX)++; + if (*metatileX == metatilesWide) { + *metatileX = 0; + (*metatileY)++; + } + } + } } static void ConvertFromTiles1Bpp(unsigned char *src, unsigned char *dest, int numTiles, int metatilesWide, int metatileWidth, int metatileHeight, bool invertColors) { - int subTileX = 0; - int subTileY = 0; - int metatileX = 0; - int metatileY = 0; - int pitch = metatilesWide * metatileWidth; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = metatilesWide * metatileWidth; - for (int i = 0; i < numTiles; i++) { - for (int j = 0; j < 8; j++) { - int destY = (metatileY * metatileHeight + subTileY) * 8 + j; - int destX = metatileX * metatileWidth + subTileX; - unsigned char srcPixelOctet = *src++; - unsigned char *destPixelOctet = &dest[destY * pitch + destX]; + for (int i = 0; i < numTiles; i++) { + for (int j = 0; j < 8; j++) { + int destY = (metatileY * metatileHeight + subTileY) * 8 + j; + int destX = metatileX * metatileWidth + subTileX; + unsigned char srcPixelOctet = *src++; + unsigned char *destPixelOctet = &dest[destY * pitch + destX]; - for (int k = 0; k < 8; k++) { - *destPixelOctet <<= 1; - *destPixelOctet |= (srcPixelOctet & 1) ^ invertColors; - srcPixelOctet >>= 1; - } - } + for (int k = 0; k < 8; k++) { + *destPixelOctet <<= 1; + *destPixelOctet |= (srcPixelOctet & 1) ^ invertColors; + 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) { - int subTileX = 0; - int subTileY = 0; - int metatileX = 0; - int metatileY = 0; - int pitch = (metatilesWide * metatileWidth) * 4; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = (metatilesWide * metatileWidth) * 4; - for (int i = 0; i < numTiles; i++) { - for (int j = 0; j < 8; j++) { - int destY = (metatileY * metatileHeight + subTileY) * 8 + j; + for (int i = 0; i < numTiles; i++) { + for (int j = 0; j < 8; j++) { + int destY = (metatileY * metatileHeight + subTileY) * 8 + j; - for (int k = 0; k < 4; k++) { - int destX = (metatileX * metatileWidth + subTileX) * 4 + k; - unsigned char srcPixelPair = *src++; - unsigned char leftPixel = srcPixelPair & 0xF; - unsigned char rightPixel = srcPixelPair >> 4; + for (int k = 0; k < 4; k++) { + int destX = (metatileX * metatileWidth + subTileX) * 4 + k; + unsigned char srcPixelPair = *src++; + unsigned char leftPixel = srcPixelPair & 0xF; + unsigned char rightPixel = srcPixelPair >> 4; - if (invertColors) { - leftPixel = 15 - leftPixel; - rightPixel = 15 - rightPixel; - } + if (invertColors) { + leftPixel = 15 - leftPixel; + 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) @@ -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) { - int subTileX = 0; - int subTileY = 0; - int metatileX = 0; - int metatileY = 0; - int pitch = (metatilesWide * metatileWidth) * 8; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = (metatilesWide * metatileWidth) * 8; - for (int i = 0; i < numTiles; i++) { - for (int j = 0; j < 8; j++) { - int destY = (metatileY * metatileHeight + subTileY) * 8 + j; + for (int i = 0; i < numTiles; i++) { + for (int j = 0; j < 8; j++) { + int destY = (metatileY * metatileHeight + subTileY) * 8 + j; - for (int k = 0; k < 8; k++) { - int destX = (metatileX * metatileWidth + subTileX) * 8 + k; - unsigned char srcPixel = *src++; + for (int k = 0; k < 8; k++) { + int destX = (metatileX * metatileWidth + subTileX) * 8 + k; + unsigned char srcPixel = *src++; - if (invertColors) - srcPixel = 255 - srcPixel; + if (invertColors) + 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) { - int subTileX = 0; - int subTileY = 0; - int metatileX = 0; - int metatileY = 0; - int pitch = metatilesWide * metatileWidth; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = metatilesWide * metatileWidth; - for (int i = 0; i < numTiles; i++) { - for (int j = 0; j < 8; j++) { - int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; - int srcX = metatileX * metatileWidth + subTileX; - unsigned char srcPixelOctet = src[srcY * pitch + srcX]; - unsigned char *destPixelOctet = dest++; + for (int i = 0; i < numTiles; i++) { + for (int j = 0; j < 8; j++) { + int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; + int srcX = metatileX * metatileWidth + subTileX; + unsigned char srcPixelOctet = src[srcY * pitch + srcX]; + unsigned char *destPixelOctet = dest++; - for (int k = 0; k < 8; k++) { - *destPixelOctet <<= 1; - *destPixelOctet |= (srcPixelOctet & 1) ^ invertColors; - srcPixelOctet >>= 1; - } - } + for (int k = 0; k < 8; k++) { + *destPixelOctet <<= 1; + *destPixelOctet |= (srcPixelOctet & 1) ^ invertColors; + 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) { - int subTileX = 0; - int subTileY = 0; - int metatileX = 0; - int metatileY = 0; - int pitch = (metatilesWide * metatileWidth) * 4; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = (metatilesWide * metatileWidth) * 4; - for (int i = 0; i < numTiles; i++) { - for (int j = 0; j < 8; j++) { - int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; + for (int i = 0; i < numTiles; i++) { + for (int j = 0; j < 8; j++) { + int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; - for (int k = 0; k < 4; k++) { - int srcX = (metatileX * metatileWidth + subTileX) * 4 + k; - unsigned char srcPixelPair = src[srcY * pitch + srcX]; - unsigned char leftPixel = srcPixelPair >> 4; - unsigned char rightPixel = srcPixelPair & 0xF; + for (int k = 0; k < 4; k++) { + int srcX = (metatileX * metatileWidth + subTileX) * 4 + k; + unsigned char srcPixelPair = src[srcY * pitch + srcX]; + unsigned char leftPixel = srcPixelPair >> 4; + unsigned char rightPixel = srcPixelPair & 0xF; - if (invertColors) { - leftPixel = 15 - leftPixel; - rightPixel = 15 - rightPixel; - } + if (invertColors) { + leftPixel = 15 - leftPixel; + 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) @@ -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) { - int subTileX = 0; - int subTileY = 0; - int metatileX = 0; - int metatileY = 0; - int pitch = (metatilesWide * metatileWidth) * 8; + int subTileX = 0; + int subTileY = 0; + int metatileX = 0; + int metatileY = 0; + int pitch = (metatilesWide * metatileWidth) * 8; - for (int i = 0; i < numTiles; i++) { - for (int j = 0; j < 8; j++) { - int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; + for (int i = 0; i < numTiles; i++) { + for (int j = 0; j < 8; j++) { + int srcY = (metatileY * metatileHeight + subTileY) * 8 + j; - for (int k = 0; k < 8; k++) { - int srcX = (metatileX * metatileWidth + subTileX) * 8 + k; - unsigned char srcPixel = src[srcY * pitch + srcX]; + for (int k = 0; k < 8; k++) { + int srcX = (metatileX * metatileWidth + subTileX) * 8 + k; + unsigned char srcPixel = src[srcY * pitch + srcX]; - if (invertColors) - srcPixel = 255 - srcPixel; + if (invertColors) + 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) { - int tileSize = bitDepth * 8; + int tileSize = bitDepth * 8; - int fileSize; - unsigned char *buffer = ReadWholeFile(path, &fileSize); + int 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) - FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth); + if (tilesWidth % metatileWidth != 0) + FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth); - if (tilesHeight % metatileHeight != 0) - FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight, metatileHeight); + if (tilesHeight % metatileHeight != 0) + FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight, metatileHeight); - image->width = tilesWidth * 8; - image->height = tilesHeight * 8; - image->bitDepth = bitDepth; - image->pixels = calloc(tilesWidth * tilesHeight, tileSize); + image->width = tilesWidth * 8; + image->height = tilesHeight * 8; + image->bitDepth = bitDepth; + image->pixels = calloc(tilesWidth * tilesHeight, tileSize); - if (image->pixels == NULL) - FATAL_ERROR("Failed to allocate memory for pixels.\n"); + if (image->pixels == NULL) + FATAL_ERROR("Failed to allocate memory for pixels.\n"); - int metatilesWide = tilesWidth / metatileWidth; + int metatilesWide = tilesWidth / metatileWidth; - switch (bitDepth) { - case 1: - ConvertFromTiles1Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); - break; - case 4: - ConvertFromTiles4Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); - break; - case 8: - ConvertFromTiles8Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); - break; - } + switch (bitDepth) { + case 1: + ConvertFromTiles1Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); + break; + case 4: + ConvertFromTiles4Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); + break; + case 8: + ConvertFromTiles8Bpp(buffer, image->pixels, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); + 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) @@ -354,10 +354,18 @@ uint32_t ReadNtrImage(char *path, int tilesWidth, int bitDepth, int metatileWidt int tileSize = bitDepth * 8; - int numTiles = (charHeader[0x18] + (charHeader[0x19] << 8) + (charHeader[0x1A] << 16) + (charHeader[0x1B] << 24)) - / (64 / (8 / bitDepth)); + if (tilesWidth == 0) { + 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) 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) FATAL_ERROR("Failed to allocate memory for pixels.\n"); - + int metatilesWide = tilesWidth / metatileWidth; 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) { - int tileSize = bitDepth * 8; + int tileSize = bitDepth * 8; - if (image->width % 8 != 0) - FATAL_ERROR("The width in pixels (%d) isn't a multiple of 8.\n", image->width); + if (image->width % 8 != 0) + FATAL_ERROR("The width in pixels (%d) isn't a multiple of 8.\n", image->width); - if (image->height % 8 != 0) - FATAL_ERROR("The height in pixels (%d) isn't a multiple of 8.\n", image->height); + if (image->height % 8 != 0) + FATAL_ERROR("The height in pixels (%d) isn't a multiple of 8.\n", image->height); - int tilesWidth = image->width / 8; - int tilesHeight = image->height / 8; + int tilesWidth = image->width / 8; + int tilesHeight = image->height / 8; - if (tilesWidth % metatileWidth != 0) - FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth); + if (tilesWidth % metatileWidth != 0) + FATAL_ERROR("The width in tiles (%d) isn't a multiple of the specified metatile width (%d)", tilesWidth, metatileWidth); - if (tilesHeight % metatileHeight != 0) - FATAL_ERROR("The height in tiles (%d) isn't a multiple of the specified metatile height (%d)", tilesHeight, metatileHeight); + if (tilesHeight % metatileHeight != 0) + 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) - 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); + if (numTiles == 0) + 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); - int bufferSize = numTiles * tileSize; - unsigned char *buffer = malloc(bufferSize); + int bufferSize = numTiles * tileSize; + unsigned char *buffer = malloc(bufferSize); - if (buffer == NULL) - FATAL_ERROR("Failed to allocate memory for pixels.\n"); + if (buffer == NULL) + FATAL_ERROR("Failed to allocate memory for pixels.\n"); - int metatilesWide = tilesWidth / metatileWidth; + int metatilesWide = tilesWidth / metatileWidth; - switch (bitDepth) { - case 1: - ConvertToTiles1Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); - break; - case 4: - ConvertToTiles4Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); - break; - case 8: - ConvertToTiles8Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); - break; - } + switch (bitDepth) { + case 1: + ConvertToTiles1Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); + break; + case 4: + ConvertToTiles4Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); + break; + case 8: + ConvertToTiles8Bpp(image->pixels, buffer, numTiles, metatilesWide, metatileWidth, metatileHeight, invertColors); + 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, @@ -572,8 +580,8 @@ void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, in fwrite(pixelBuffer, 1, bufferSize, fp); 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[13] = (tilesWidth >> 8) & 0xFF; @@ -582,7 +590,7 @@ void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, in sopcBuffer[15] = (tilesHeight >> 8) & 0xFF; fwrite(sopcBuffer, 1, 0x10, fp); - } + } free(pixelBuffer); fclose(fp); @@ -590,28 +598,28 @@ void WriteNtrImage(char *path, int numTiles, int bitDepth, int metatileWidth, in void FreeImage(struct Image *image) { - free(image->pixels); - image->pixels = NULL; + free(image->pixels); + image->pixels = NULL; } void ReadGbaPalette(char *path, struct Palette *palette) { - int fileSize; - unsigned char *data = ReadWholeFile(path, &fileSize); + int fileSize; + unsigned char *data = ReadWholeFile(path, &fileSize); - if (fileSize % 2 != 0) - FATAL_ERROR("The file size (%d) is not a multiple of 2.\n", fileSize); + if (fileSize % 2 != 0) + 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++) { - 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].green = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_GREEN(paletteEntry)); - palette->colors[i].blue = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_BLUE(paletteEntry)); - } + for (int i = 0; i < palette->numColors; i++) { + 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].green = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_GREEN(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) @@ -645,19 +653,19 @@ void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIn for (int i = 0; i < 256; i++) { - if (i < palette->numColors) - { - 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].green = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_GREEN(paletteEntry)); - palette->colors[i].blue = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_BLUE(paletteEntry)); - } - else - { - palette->colors[i].red = 0; - palette->colors[i].green = 0; - palette->colors[i].blue = 0; - } + if (i < palette->numColors) + { + 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].green = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_GREEN(paletteEntry)); + palette->colors[i].blue = UPCONVERT_BIT_DEPTH(GET_GBA_PAL_BLUE(paletteEntry)); + } + else + { + palette->colors[i].red = 0; + palette->colors[i].green = 0; + palette->colors[i].blue = 0; + } } free(data); @@ -665,23 +673,23 @@ void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIn void WriteGbaPalette(char *path, struct Palette *palette) { - 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); - for (int i = 0; i < palette->numColors; i++) { - unsigned char red = DOWNCONVERT_BIT_DEPTH(palette->colors[i].red); - unsigned char green = DOWNCONVERT_BIT_DEPTH(palette->colors[i].green); - unsigned char blue = DOWNCONVERT_BIT_DEPTH(palette->colors[i].blue); + for (int i = 0; i < palette->numColors; i++) { + unsigned char red = DOWNCONVERT_BIT_DEPTH(palette->colors[i].red); + unsigned char green = DOWNCONVERT_BIT_DEPTH(palette->colors[i].green); + 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 >> 8, fp); - } + fputc(paletteEntry & 0xFF, 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) @@ -768,10 +776,10 @@ void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, in void WriteNtrCell(char *path, struct JsonToCellOptions *options) { - 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); 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, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 }; - 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[5] = (size + 0x20) >> 8; //unlikely to be more than 16 bits, but there are 32 allocated, change if necessary + 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[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; - for (i = 0; i < options->cellCount * 0x10; i += 0x10) + int i; + for (i = 0; i < options->cellCount * 0x10; i += 0x10) { - KBECContents[i] = 0x01; //number of images - KBECContents[i + 2] = options->cells[i / 0x10]->readOnly & 0xff; //unknown + KBECContents[i] = 0x01; //number of images + KBECContents[i + 2] = options->cells[i / 0x10]->readOnly & 0xff; //unknown KBECContents[i + 3] = options->cells[i / 0x10]->readOnly >> 8; 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 @@ -834,21 +842,21 @@ void WriteNtrCell(char *path, struct JsonToCellOptions *options) KBECContents[i + 15] = options->cells[i / 0x10]->minY >> 8; } - //OAM data - for (int j = i; j < options->cellCount * 6 + i; j += 6) + //OAM data + for (int j = i; j < options->cellCount * 6 + i; j += 6) { - //Attr0 + //Attr0 - //bits 0-7 Y coordinate - KBECContents[j] = options->cells[(j - i) / 6]->oam.attr0.YCoordinate & 0xff; + //bits 0-7 Y coordinate + KBECContents[j] = options->cells[(j - i) / 6]->oam.attr0.YCoordinate & 0xff; - //bit 8 rotation - KBECContents[j + 1] = options->cells[(j - i) / 6]->oam.attr0.Rotation; + //bit 8 rotation + KBECContents[j + 1] = options->cells[(j - i) / 6]->oam.attr0.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; + //bit 9 Obj Size (if rotation) or Obj Disable (if not rotation) + 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; //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; } - fwrite(KBECContents, 1, size, fp); + fwrite(KBECContents, 1, size, fp); - free(KBECContents); + free(KBECContents); - if (options->labelEnabled) - { + if (options->labelEnabled) + { unsigned int lablSize = 8; for (int j = 0; j < options->labelCount; j++) { @@ -932,7 +940,7 @@ void WriteNtrCell(char *path, struct JsonToCellOptions *options) fwrite(txeu, 1, 0xc, fp); } - fclose(fp); + fclose(fp); } void WriteNtrScreen(char *path, struct JsonToScreenOptions *options) @@ -1009,8 +1017,8 @@ void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options) unsigned char KBNAHeader[0x20] = { - 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 + 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 }; KBNAHeader[4] = KNBASize & 0xff; @@ -1105,7 +1113,7 @@ void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options) KBNAContents[resPtrCounter + 3] = 0xCC; resPtrCounter += 0x4; break; - + case 1: KBNAContents[resPtrCounter] = options->animationResults[k]->dataSrt.index & 0xff; 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; resPtrCounter += 0x10; break; - + case 2: KBNAContents[resPtrCounter] = options->animationResults[k]->dataT.index & 0xff; 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); - free(KBNAContents); + free(KBNAContents); if (options->labelEnabled) - { + { unsigned int lablSize = 8; for (int j = 0; j < options->labelCount; j++) { diff --git a/main.c b/main.c index 09bd022..adc93b8 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,6 @@ // Copyright (c) 2015 YamaArashi, 2021-2023 red031000 +#include #include #include #include @@ -80,7 +81,7 @@ void ConvertNtrToPng(char *inputPath, char *outputPath, struct NtrToPngOptions * { image.hasPalette = false; } - + uint32_t key = ReadNtrImage(inputPath, options->width, 0, options->metatileWidth, options->metatileHeight, &image, !image.hasPalette, options->scanFrontToBack); if (key) @@ -171,7 +172,10 @@ void HandleGbaToPngCommand(char *inputPath, char *outputPath, int argc, char **a char *inputFileExtension = GetFileExtension(inputPath); struct GbaToPngOptions options; 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.width = 1; options.metatileWidth = 1; @@ -250,7 +254,7 @@ void HandleNtrToPngCommand(char *inputPath, char *outputPath, int argc, char **a struct NtrToPngOptions options; options.paletteFilePath = NULL; options.hasTransparency = false; - options.width = 1; + options.width = 0; options.metatileWidth = 1; options.metatileHeight = 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; 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) { 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; options.numTiles = 0; 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) { struct JsonToAnimationOptions *options; - + options = ParseNANRJson(inputPath); options->multiCell = true; diff --git a/rl.c b/rl.c index 968c934..993ac64 100644 --- a/rl.c +++ b/rl.c @@ -101,7 +101,7 @@ unsigned char *RLCompress(unsigned char *src, int srcSize, int *compressedSize) srcPos++; uncompressedLength++; } - + if (uncompressedLength > 0) { dest[destPos++] = uncompressedLength - 1; diff --git a/util.h b/util.h index b757aa4..080dd4b 100644 --- a/util.h +++ b/util.h @@ -13,4 +13,45 @@ unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount); 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); +// 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