update NANR parser to handle resultType better and handle padding

This commit is contained in:
Joshua Smith 2024-10-20 12:51:53 -05:00
parent f9a9fdc11b
commit d55fbd6ff4
3 changed files with 101 additions and 33 deletions

125
gfx.c
View File

@ -1327,8 +1327,8 @@ void ReadNtrAnimation(char *path, struct JsonToAnimationOptions *options)
{
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]->animationType = data[offset + 4] | (data[offset + 5] << 8);
options->sequenceData[i]->animationType2 = 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);
@ -1358,6 +1358,7 @@ void ReadNtrAnimation(char *path, struct JsonToAnimationOptions *options)
{
if (resultOffsets[k] == options->sequenceData[i]->frameData[j]->resultOffset)
{
options->sequenceData[i]->frameData[j]->resultId = k;
present = true;
break;
}
@ -1370,6 +1371,7 @@ void ReadNtrAnimation(char *path, struct JsonToAnimationOptions *options)
{
if (resultOffsets[k] == -1)
{
options->sequenceData[i]->frameData[j]->resultId = k;
resultOffsets[k] = options->sequenceData[i]->frameData[j]->resultOffset;
break;
}
@ -1400,37 +1402,49 @@ void ReadNtrAnimation(char *path, struct JsonToAnimationOptions *options)
options->animationResults[i] = malloc(sizeof(struct AnimationResults));
}
// store the animationType of the corresponding sequence as this result's resultType
for (int i = 0; i < options->sequenceCount; i++)
{
for (int j = 0; j < options->sequenceData[i]->frameCount; j++)
{
options->animationResults[options->sequenceData[i]->frameData[j]->resultId]->resultType = options->sequenceData[i]->animationType;
}
}
int resultOffset = 0;
int lastSequence = 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;
}
// find the earliest sequence matching this animation result,
// and add padding if the sequence changes + the total offset is not 4-byte aligned.
bool found = false;
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)
if (options->sequenceData[j]->frameData[k]->resultId == i)
{
options->sequenceData[j]->frameData[k]->resultId = i;
if (lastSequence != j)
{
lastSequence = j;
if (resultOffset % 4 != 0)
{
resultOffset += 0x2;
offset += 0x2;
}
}
found = true;
break;
}
}
if (found) break;
}
switch (options->animationResults[i]->resultType)
{
case 0: //index
options->animationResults[i]->index = data[offset] | (data[offset + 1] << 8);
resultOffset += 0x4;
offset += 0x4;
resultOffset += 0x2;
offset += 0x2;
break;
case 1: //SRT
@ -1454,6 +1468,9 @@ void ReadNtrAnimation(char *path, struct JsonToAnimationOptions *options)
}
}
// add any missed padding from the final frame before processing labels
if (offset % 4 != 0) offset += 2;
if (options->labelEnabled)
{
options->labelCount = options->sequenceCount; //*should* be the same
@ -1479,17 +1496,60 @@ void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options)
unsigned int totalSize = 0x20 + options->sequenceCount * 0x10 + options->frameCount * 0x8;
//todo: check these
for (int i = 0; i < options->resultCount; i++)
{
if (options->animationResults[i]->resultType == 0)
totalSize += 0x4;
totalSize += 0x2;
else if (options->animationResults[i]->resultType == 1)
totalSize += 0x10;
else if (options->animationResults[i]->resultType == 2)
totalSize += 0x8;
}
// foreach sequence, need to check whether padding is applied for its results
// then add 0x02 to totalSize if padding exists.
// padding exists if the animation results for that sequence are not 4-byte aligned.
// also flag the last result for the sequence with `padded` to save having to redo this same step later.
int *usedResults = malloc(sizeof(int) * options->frameCount);
memset(usedResults, -1, sizeof(int) * options->frameCount);
for (int i = 0; i < options->sequenceCount; i++)
{
int sequenceLen = 0;
int resultIndex = 0;
for (int j = 0; j < options->sequenceData[i]->frameCount; j++)
{
// check if the result has already been used
for (resultIndex = 0; resultIndex < options->resultCount; resultIndex++)
{
if (usedResults[resultIndex] == options->sequenceData[i]->frameData[j]->resultId)
{
break;
}
// if not already used, add it to the list
if (usedResults[resultIndex] == -1)
{
usedResults[resultIndex] = options->sequenceData[i]->frameData[j]->resultId;
break;
}
}
// if not already used, add it to the result size for the sequence
if (options->animationResults[resultIndex]->resultType == 0)
sequenceLen += 0x2;
else if (options->animationResults[resultIndex]->resultType == 1)
sequenceLen += 0x10;
else if (options->animationResults[resultIndex]->resultType == 2)
sequenceLen += 0x8;
}
if (sequenceLen % 4 != 0)
{
totalSize += 0x02;
// mark the last animationResult for the sequence as padded, this saves needing to check this again later
options->animationResults[resultIndex]->padded = true;
}
}
unsigned int KNBASize = totalSize;
if (options->labelEnabled)
@ -1547,10 +1607,10 @@ void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options)
KBNAContents[i + 1] = options->sequenceData[i / 0x10]->frameCount >> 8;
KBNAContents[i + 2] = options->sequenceData[i / 0x10]->loopStartFrame & 0xff;
KBNAContents[i + 3] = options->sequenceData[i / 0x10]->loopStartFrame >> 8;
KBNAContents[i + 4] = options->sequenceData[i / 0x10]->animationElement & 0xff;
KBNAContents[i + 5] = options->sequenceData[i / 0x10]->animationElement >> 8;
KBNAContents[i + 6] = options->sequenceData[i / 0x10]->animationType & 0xff;
KBNAContents[i + 7] = options->sequenceData[i / 0x10]->animationType >> 8;
KBNAContents[i + 4] = options->sequenceData[i / 0x10]->animationType & 0xff;
KBNAContents[i + 5] = (options->sequenceData[i / 0x10]->animationType >> 8) & 0xff;
KBNAContents[i + 6] = options->sequenceData[i / 0x10]->animationType2 & 0xff;
KBNAContents[i + 7] = (options->sequenceData[i / 0x10]->animationType2 >> 8) & 0xff;
KBNAContents[i + 8] = options->sequenceData[i / 0x10]->playbackMode & 0xff;
KBNAContents[i + 9] = (options->sequenceData[i / 0x10]->playbackMode >> 8) & 0xff;
KBNAContents[i + 10] = (options->sequenceData[i / 0x10]->playbackMode >> 16) & 0xff;
@ -1570,11 +1630,13 @@ void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options)
int resPtr = 0;
for (int l = 0; l < options->sequenceData[m]->frameData[k]->resultId; l++) {
if (options->animationResults[l]->resultType == 0)
resPtr += 0x4;
resPtr += 0x2;
else if (options->animationResults[l]->resultType == 1)
resPtr += 0x10;
else if (options->animationResults[l]->resultType == 2)
resPtr += 0x8;
if (options->animationResults[l]->padded) resPtr += 0x02;
}
KBNAContents[j + (k * 8)] = resPtr & 0xff;
KBNAContents[j + (k * 8) + 1] = (resPtr >> 8) & 0xff;
@ -1588,7 +1650,6 @@ void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options)
j += options->sequenceData[m]->frameCount * 8;
}
//todo: these are extrapolated, need confirming
int resPtrCounter = j;
for (int k = 0; k < options->resultCount; k++)
{
@ -1597,9 +1658,7 @@ void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options)
case 0:
KBNAContents[resPtrCounter] = options->animationResults[k]->index & 0xff;
KBNAContents[resPtrCounter + 1] = options->animationResults[k]->index >> 8;
KBNAContents[resPtrCounter + 2] = 0xCC;
KBNAContents[resPtrCounter + 3] = 0xCC;
resPtrCounter += 0x4;
resPtrCounter += 0x2;
break;
case 1:
@ -1634,6 +1693,14 @@ void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options)
resPtrCounter += 0x8;
break;
}
// use the `padded` flag which was stored earlier to inject padding
if (options->animationResults[k]->padded)
{
KBNAContents[resPtrCounter] = 0xCC;
KBNAContents[resPtrCounter + 1] = 0xCC;
resPtrCounter += 0x2;
}
}
fwrite(KBNAContents, 1, contentsSize, fp);

6
json.c
View File

@ -376,14 +376,14 @@ struct JsonToAnimationOptions *ParseNANRJson(char *path)
cJSON *frameCount = cJSON_GetObjectItemCaseSensitive(sequence, "frameCount");
cJSON *loopStartFrame = cJSON_GetObjectItemCaseSensitive(sequence, "loopStartFrame");
cJSON *animationElement = cJSON_GetObjectItemCaseSensitive(sequence, "animationElement");
cJSON *animationType = cJSON_GetObjectItemCaseSensitive(sequence, "animationType");
cJSON *animationType2 = cJSON_GetObjectItemCaseSensitive(sequence, "animationType2");
cJSON *playbackMode = cJSON_GetObjectItemCaseSensitive(sequence, "playbackMode");
options->sequenceData[i]->frameCount = GetInt(frameCount);
options->sequenceData[i]->loopStartFrame = GetInt(loopStartFrame);
options->sequenceData[i]->animationElement = GetInt(animationElement);
options->sequenceData[i]->animationType = GetInt(animationType);
options->sequenceData[i]->animationType2 = GetInt(animationType2);
options->sequenceData[i]->playbackMode = GetInt(playbackMode);
options->sequenceData[i]->frameData = malloc(sizeof(struct FrameData *) * options->sequenceData[i]->frameCount);
@ -521,8 +521,8 @@ char *GetNANRJson(struct JsonToAnimationOptions *options)
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, "animationType2", options->sequenceData[i]->animationType2);
cJSON_AddNumberToObject(sequence, "playbackMode", options->sequenceData[i]->playbackMode);
cJSON *frameData = cJSON_AddArrayToObject(sequence, "frameData");

View File

@ -123,8 +123,8 @@ struct FrameData {
struct SequenceData {
short frameCount;
short loopStartFrame;
short animationElement;
short animationType;
short animationType2;
int playbackMode;
struct FrameData **frameData;
};
@ -147,6 +147,7 @@ struct AnimationDataT {
struct AnimationResults {
short resultType;
bool padded;
union {
short index;
struct AnimationDataSRT dataSrt;