NANR to json decoding

This commit is contained in:
red031000 2023-07-04 19:10:54 +01:00
parent f0ab32e9c8
commit c562885aa6
No known key found for this signature in database
GPG Key ID: D27E50C050AE0CE1
6 changed files with 275 additions and 2 deletions

View File

@ -1114,6 +1114,184 @@ void WriteNtrScreen(char *path, struct JsonToScreenOptions *options)
fclose(fp);
}
void ReadNtrAnimation(char *path, struct JsonToAnimationOptions *options)
{
int fileSize;
unsigned char *data = ReadWholeFile(path, &fileSize);
if (memcmp(data, "RNAN", 4) != 0 && memcmp(data, "RAMN", 4) != 0) //NANR/NMAR
{
FATAL_ERROR("Not a valid NANR/NMAR animation file.\n");
}
options->labelEnabled = data[0xE] != 1;
if (memcmp(data + 0x10, "KNBA", 4) != 0 ) //ABNK
{
FATAL_ERROR("Not a valid ABNK animation file.\n");
}
options->sequenceCount = data[0x18] | (data[0x19] << 8);
options->frameCount = data[0x1A] | (data[0x1B] << 8);
options->sequenceData = malloc(sizeof(struct SequenceData *) * options->sequenceCount);
for (int i = 0; i < options->sequenceCount; i++)
{
options->sequenceData[i] = malloc(sizeof(struct SequenceData));
}
int offset = 0x30;
unsigned int *frameOffsets = malloc(sizeof(unsigned int) * options->sequenceCount);
for (int i = 0; i < options->sequenceCount; i++, offset += 0x10)
{
options->sequenceData[i]->frameCount = data[offset] | (data[offset + 1] << 8);
options->sequenceData[i]->loopStartFrame = data[offset + 2] | (data[offset + 3] << 8);
options->sequenceData[i]->animationElement = data[offset + 4] | (data[offset + 5] << 8);
options->sequenceData[i]->animationType = data[offset + 6] | (data[offset + 7] << 8);
options->sequenceData[i]->playbackMode = data[offset + 8] | (data[offset + 9] << 8) | (data[offset + 10] << 16) | (data[offset + 11] << 24);
frameOffsets[i] = data[offset + 12] | (data[offset + 13] << 8) | (data[offset + 14] << 16) | (data[offset + 15] << 24);
options->sequenceData[i]->frameData = malloc(sizeof(struct FrameData *) * options->sequenceData[i]->frameCount);
for (int j = 0; j < options->sequenceData[i]->frameCount; j++)
{
options->sequenceData[i]->frameData[j] = malloc(sizeof(struct FrameData));
}
}
int *resultOffsets = malloc(sizeof(int) * options->frameCount);
memset(resultOffsets, -1, sizeof(int) * options->frameCount);
for (int i = 0; i < options->sequenceCount; i++)
{
for (int j = 0; j < options->sequenceData[i]->frameCount; j++)
{
int frameOffset = offset + frameOffsets[i] + j * 0x8;
options->sequenceData[i]->frameData[j]->resultOffset = data[frameOffset] | (data[frameOffset + 1] << 8) | (data[frameOffset + 2] << 16) | (data[frameOffset + 3] << 24);
options->sequenceData[i]->frameData[j]->frameDelay = data[frameOffset + 4] | (data[frameOffset + 5] << 8);
//0xBEEF
//the following is messy
bool present = false;
//check for offset in array
for (int k = 0; k < options->frameCount; k++)
{
if (resultOffsets[k] == options->sequenceData[i]->frameData[j]->resultOffset)
{
present = true;
break;
}
}
//add data if not present
if (!present)
{
for (int k = 0; i < options->frameCount; k++)
{
if (resultOffsets[k] == -1)
{
resultOffsets[k] = options->sequenceData[i]->frameData[j]->resultOffset;
break;
}
}
}
}
}
free(frameOffsets);
offset = 0x18 + (data[0x24] | (data[0x25] << 8) | (data[0x26] << 16) | (data[0x27] << 24)); //start of animation results
int k;
for (k = 0; k < options->frameCount; k++)
{
if (resultOffsets[k] == -1)
break;
}
options->resultCount = k;
free(resultOffsets);
options->animationResults = malloc(sizeof(struct AnimationResults *) * options->resultCount);
for (int i = 0; i < options->resultCount; i++)
{
options->animationResults[i] = malloc(sizeof(struct AnimationResults));
}
int resultOffset = 0;
for (int i = 0; i < options->resultCount; i++)
{
if (data[offset + 2] == 0xCC && data[offset + 3] == 0xCC)
{
options->animationResults[i]->resultType = 0;
}
else if (data[offset + 2] == 0xEF && data[offset + 3] == 0xBE)
{
options->animationResults[i]->resultType = 2;
}
else
{
options->animationResults[i]->resultType = 1;
}
for (int j = 0; j < options->sequenceCount; j++)
{
for (int k = 0; k < options->sequenceData[j]->frameCount; k++)
{
if (options->sequenceData[j]->frameData[k]->resultOffset == resultOffset)
{
options->sequenceData[j]->frameData[k]->resultId = i;
}
}
}
switch (options->animationResults[i]->resultType)
{
case 0: //index
options->animationResults[i]->index = data[offset] | (data[offset + 1] << 8);
resultOffset += 0x4;
offset += 0x4;
break;
case 1: //SRT
options->animationResults[i]->dataSrt.index = data[offset] | (data[offset + 1] << 8);
options->animationResults[i]->dataSrt.rotation = data[offset + 2] | (data[offset + 3] << 8);
options->animationResults[i]->dataSrt.scaleX = data[offset + 4] | (data[offset + 5] << 8) | (data[offset + 6] << 16) | (data[offset + 7] << 24);
options->animationResults[i]->dataSrt.scaleY = data[offset + 8] | (data[offset + 9] << 8) | (data[offset + 10] << 16) | (data[offset + 11] << 24);
options->animationResults[i]->dataSrt.positionX = data[offset + 12] | (data[offset + 13] << 8);
options->animationResults[i]->dataSrt.positionY = data[offset + 14] | (data[offset + 15] << 8);
resultOffset += 0x10;
offset += 0x10;
break;
case 2: //T
options->animationResults[i]->dataT.index = data[offset] | (data[offset + 1] << 8);
options->animationResults[i]->dataT.positionX = data[offset + 4] | (data[offset + 5] << 8);
options->animationResults[i]->dataT.positionY = data[offset + 6] | (data[offset + 7] << 8);
resultOffset += 0x8;
offset += 0x8;
break;
}
}
if (options->labelEnabled)
{
options->labelCount = options->sequenceCount; //*should* be the same
options->labels = malloc(sizeof(char *) * options->labelCount);
offset += 0x8 + options->labelCount * 0x4; //skip to label data
for (int i = 0; i < options->labelCount; i++)
{
options->labels[i] = malloc(strlen((char *)data + offset) + 1);
strcpy(options->labels[i], (char *)data + offset);
offset += strlen((char *)data + offset) + 1;
}
}
free(data);
}
void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options)
{
FILE *fp = fopen(path, "wb");
@ -1269,8 +1447,6 @@ void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options)
case 2:
KBNAContents[resPtrCounter] = options->animationResults[k]->dataT.index & 0xff;
KBNAContents[resPtrCounter + 1] = options->animationResults[k]->dataT.index >> 8;
//KBNAContents[resPtrCounter + 2] = options->animationResults[k]->dataT.rotation & 0xff;
//KBNAContents[resPtrCounter + 3] = options->animationResults[k]->dataT.rotation >> 8;
KBNAContents[resPtrCounter + 2] = 0xEF;
KBNAContents[resPtrCounter + 3] = 0xBE;
KBNAContents[resPtrCounter + 4] = options->animationResults[k]->dataT.positionX & 0xff;

View File

@ -43,6 +43,7 @@ void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, in
void ReadNtrCell(char *path, struct JsonToCellOptions *options);
void WriteNtrCell(char *path, struct JsonToCellOptions *options);
void WriteNtrScreen(char *path, struct JsonToScreenOptions *options);
void ReadNtrAnimation(char *path, struct JsonToAnimationOptions *options);
void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options);
#endif // GFX_H

View File

@ -481,6 +481,85 @@ struct JsonToAnimationOptions *ParseNANRJson(char *path)
return options;
}
char *GetNANRJson(struct JsonToAnimationOptions *options)
{
cJSON *nanr = cJSON_CreateObject();
cJSON_AddBoolToObject(nanr, "labelEnabled", options->labelEnabled);
cJSON_AddNumberToObject(nanr, "sequenceCount", options->sequenceCount);
cJSON_AddNumberToObject(nanr, "frameCount", options->frameCount);
cJSON *sequences = cJSON_AddArrayToObject(nanr, "sequences");
for (int i = 0; i < options->sequenceCount; i++)
{
cJSON *sequence = cJSON_CreateObject();
cJSON_AddNumberToObject(sequence, "frameCount", options->sequenceData[i]->frameCount);
cJSON_AddNumberToObject(sequence, "loopStartFrame", options->sequenceData[i]->loopStartFrame);
cJSON_AddNumberToObject(sequence, "animationElement", options->sequenceData[i]->animationElement);
cJSON_AddNumberToObject(sequence, "animationType", options->sequenceData[i]->animationType);
cJSON_AddNumberToObject(sequence, "playbackMode", options->sequenceData[i]->playbackMode);
cJSON *frameData = cJSON_AddArrayToObject(sequence, "frameData");
for (int j = 0; j < options->sequenceData[i]->frameCount; j++)
{
cJSON *frame = cJSON_CreateObject();
cJSON_AddNumberToObject(frame, "frameDelay", options->sequenceData[i]->frameData[j]->frameDelay);
cJSON_AddNumberToObject(frame, "resultId", options->sequenceData[i]->frameData[j]->resultId);
cJSON_AddItemToArray(frameData, frame);
}
cJSON_AddItemToArray(sequences, sequence);
}
cJSON *animationResults = cJSON_AddArrayToObject(nanr, "animationResults");
for (int i = 0; i < options->resultCount; i++)
{
cJSON *animationResult = cJSON_CreateObject();
cJSON_AddNumberToObject(animationResult, "resultType", options->animationResults[i]->resultType);
switch (options->animationResults[i]->resultType)
{
case 0: //index
cJSON_AddNumberToObject(animationResult, "index", options->animationResults[i]->index);
break;
case 1: //SRT
cJSON_AddNumberToObject(animationResult, "index", options->animationResults[i]->dataSrt.index);
cJSON_AddNumberToObject(animationResult, "rotation", options->animationResults[i]->dataSrt.rotation);
cJSON_AddNumberToObject(animationResult, "scaleX", options->animationResults[i]->dataSrt.scaleX);
cJSON_AddNumberToObject(animationResult, "scaleY", options->animationResults[i]->dataSrt.scaleY);
cJSON_AddNumberToObject(animationResult, "positionX", options->animationResults[i]->dataSrt.positionX);
cJSON_AddNumberToObject(animationResult, "positionY", options->animationResults[i]->dataSrt.positionY);
break;
case 2: //T
cJSON_AddNumberToObject(animationResult, "index", options->animationResults[i]->dataT.index);
cJSON_AddNumberToObject(animationResult, "positionX", options->animationResults[i]->dataT.positionX);
cJSON_AddNumberToObject(animationResult, "positionY", options->animationResults[i]->dataT.positionY);
break;
}
cJSON_AddItemToArray(animationResults, animationResult);
}
cJSON_AddNumberToObject(nanr, "resultCount", options->resultCount);
if (options->labelEnabled)
{
cJSON *labels = cJSON_CreateStringArray((const char * const*)options->labels, options->labelCount);
cJSON_AddItemToObject(nanr, "labels", labels);
cJSON_AddNumberToObject(nanr, "labelCount", options->labelCount);
}
char *jsonString = cJSON_Print(nanr);
cJSON_Delete(nanr);
return jsonString;
}
void FreeNCERCell(struct JsonToCellOptions *options)
{
for (int i = 0; i < options->cellCount; i++)

View File

@ -9,6 +9,7 @@ struct JsonToCellOptions *ParseNCERJson(char *path);
char *GetNCERJson(struct JsonToCellOptions *options);
struct JsonToScreenOptions *ParseNSCRJson(char *path);
struct JsonToAnimationOptions *ParseNANRJson(char *path);
char *GetNANRJson(struct JsonToAnimationOptions *options);
void FreeNCERCell(struct JsonToCellOptions *options);
void FreeNSCRScreen(struct JsonToScreenOptions *options);
void FreeNANRAnimation(struct JsonToAnimationOptions *options);

View File

@ -832,6 +832,19 @@ void HandleJsonToNtrAnimationCommand(char *inputPath, char *outputPath, int argc
FreeNANRAnimation(options);
}
void HandleNtrAnimationToJsonCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
struct JsonToAnimationOptions *options = malloc(sizeof(struct JsonToAnimationOptions));
ReadNtrAnimation(inputPath, options);
char *json = GetNANRJson(options);
WriteWholeStringToFile(outputPath, json);
FreeNANRAnimation(options);
}
void HandleJsonToNtrMulticellAnimationCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
struct JsonToAnimationOptions *options;
@ -1110,7 +1123,9 @@ int main(int argc, char **argv)
{ "NCER", "json", HandleNtrCellToJsonCommand },
{ "json", "NSCR", HandleJsonToNtrScreenCommand },
{ "json", "NANR", HandleJsonToNtrAnimationCommand },
{ "NANR", "json", HandleNtrAnimationToJsonCommand },
{ "json", "NMAR", HandleJsonToNtrMulticellAnimationCommand },
{ "NMAR", "json", HandleNtrAnimationToJsonCommand },
{ NULL, "huff", HandleHuffCompressCommand },
{ NULL, "lz", HandleLZCompressCommand },
{ "huff", NULL, HandleHuffDecompressCommand },

View File

@ -114,6 +114,7 @@ struct JsonToScreenOptions {
struct FrameData {
int resultId;
short frameDelay;
int resultOffset;
};
struct SequenceData {