I wrote this to cut up a couple of animations that I use piecemeal in two Blend Space 1Ds because I got tired of having to re-clip frames every time I changed the underlying animation. Now I can run a script to cut out the frames I want after changing the animation and just re-import the individual keyframes.
This only works on ASCII FBX files, and I’ve only tried it on a file exported from Blender 2.79 (2.8 doesn’t even have ASCII FBX export now). I know it doesn’t produce exactly the same coordinates but the difference doesn’t seem to be significant.
There are a lot of sharp edges, use at your own risk. It only reads the source file but overwrites any previously-generated files.
See the usage text for more details on how to use.
// A quick and dirty C program to take in an ASCII 6.1 FBX file and create
// ASCII FBX files for each keyframe. I'm tossing this into the public domain.
// brian at westley period org
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
int main(int argc, char *argv])
{
char line[256], line2[256], line3[256], line4[256], line5[256];
char *p, *q, fname[256];
FILE *fbx, *fbxout;
int i, j, k, m, n;
int frame, kf, ki;
long long ll, keys[256];
char allkeys;
int didakey;
float percent;
char *suffix = "_", pchar = 'p', dotchar = '.', minuschar = '-';
char *format = "%03d";
if (argc < 2 ||
!((p=strstr(argv[1], ".fbx")) != NULL && strlen(p) == 4))
{
printf("Usage: %s file.fbx [arg1] [arg2] ...
", argv[0]);
printf("This program takes an ASCII FBX animation file and creates FBX
");
printf("files that contain a single frame of the original animation.
");
printf("If no arguments other than the filename are given, all frames
");
printf("are output in files named file_000.fbx file_001.fbx etc.
");
printf("Arguments can be frame numbers (0 based) or percents.
");
printf("Negative frame numbers are counted from the end, e.g. -0 is
");
printf("the last frame, -1 is second to last, etc.
");
printf("Percents are arguments with a '%%' or a '.' and will contain
");
printf("the closest frame.
");
printf("-f<format> changes the frame numbering to <format> (default %%03d).
");
printf("-s<suffix> changes the suffix to <suffix> (default _).
");
printf("file names are generated directly from arguments with the
");
printf("following single-character substitutions:
");
printf("--x will substitute x in place of - for frame arguments (default -)
");
printf("-.x will substitute x in place of . for percent arguments (default .)
");
printf("-%%x will substitute x in place of %% for percent arguments (default p)
");
printf("Special cases for -%%:
");
printf("-%%# will output the frame format instead of copying the arguments.
");
printf("-%%s will ONLY use the current suffix for the new filename.
");
printf("Examples:
");
printf("keyframefbx file.fbx 0 7 14
");
printf("This will create file_0.fbx, file_7.fbx, and file_14.fbx
");
printf("keyframefbx file.fbx 0%% -f_FRAME%%04d 50%% -%%# 100%%
");
printf("This will create file_0p.fbx, file_50p.fbx, and file_FRAMENNNN.fbx
");
printf("where NNNN is the last (zero-filled) frame number.
");
printf("keyframefbx file.fbx -%%s -s_start 0 -s_middle 50%% -s_end -0
");
printf("This will create file_start.fbx, file_middle.fbx, and file_end.fbx
");
exit(-1);
}
for (i = 0; i < sizeof(keys)/sizeof(keys[0]); i++)
keys* = -1;
k = 0;
fbx = fopen(argv[1], "r");
while (fgets(line, sizeof(line), fbx) != NULL)
{
if ((p=strstr(line, "KeyCount: ")) != NULL)
{
i = atoi(p+10);
fgets(line, sizeof(line), fbx);
while (i-- > 0)
{
fgets(line, sizeof(line), fbx);
ll = atoll(line);
j = 0;
while (j < k && keys[j] < ll)
j++;
if (keys[j] != ll)
{
m = j;
n = k;
while (j < k)
{
keys[n] = keys[n-1];
j++;
n--;
}
keys[m] = ll;
k++;
}
}
}
}
fclose(fbx);
// k = total key frames
//for (i = 0; i < k; i++)
//printf("%lld
", keys*);
// If list of frames to use is given, use those, otherwise do all
allkeys = (argc == 2);
if (allkeys)
{
kf = k;
}
else
{
kf = argc - 2;
}
didakey = 0;
for (ki = 0; ki < kf; ki++)
{
if (allkeys)
{
frame = ki;
sprintf(line, format, frame);
}
else
{
strcpy(line, argv[ki+2]);
if (line[0] == '-')
{
switch (line[1])
{
case 's':
suffix = argv[ki+2]+2;
break;
case 'f':
format = argv[ki+2]+2;
break;
case '%':
pchar = line[2];
break;
case '.':
dotchar = line[2];
break;
case '-':
minuschar = line[2];
break;
}
// if we've only done switches and have no explicit keyframes,
// reset the numbers and allkeys
if (ki+1 == kf && didakey == 0)
{
allkeys = 1;
ki = 0;
kf = k;
continue;
}
}
didakey = 1;
q = NULL;
if ((p=index(line, '%')) != NULL ||
(q=index(line, '.')) != NULL)
{
percent = atof(line);
if (p != NULL)
p[0] = pchar;
if (q != NULL)
q[0] = dotchar;
frame = percent * (float)k / 100.0 + 0.5;
}
else
{
frame = strtol(line, NULL, 10);
if (line[0] == '-')
{
frame = k - 1 + frame;
p[0] = minuschar;
}
}
if (frame < 0)
frame = 0;
if (frame >= k)
frame = k-1;
if (pchar == 's')
line[0] = '\0';
else if (pchar == '#')
sprintf(line, format, frame);
}
fbx = fopen(argv[1], "r");
snprintf(fname, sizeof(fname), "%s", argv[1]);
i = strlen(fname)-4;
snprintf(fname+i, sizeof(fname)-i, "%s%s.fbx", suffix, line);
fbxout = fopen(fname, "w");
while (fgets(line, sizeof(line), fbx) != NULL)
{
if (strstr(line, "LocalTime: ") != NULL ||
strstr(line, "ReferenceTime: ") != NULL)
{
if ((p=index(line, ',')) != NULL)
{
p[1] = '0';
p[2] = '
';
p[3] = '\0';
}
fputs(line, fbxout);
}
else if ((p=strstr(line, "TimeLineStopTime: ")) != NULL)
{
p[18] = '0';
p[19] = '
';
p[20] = '\0';
fputs(line, fbxout);
}
else if ((p=strstr(line, "Default: ")) != NULL)
{
p[9] = '\0';
fprintf(fbxout, "%s", line);
fgets(line2, sizeof(line2), fbx);
fgets(line3, sizeof(line3), fbx);
if ((p=strstr(line3, "KeyCount: ")) != NULL)
{
i = atoi(p+10);
p[10] = '1';
p[11] = '
';
p[12] = '\0';
fgets(line4, sizeof(line4), fbx);
while (i-- > 0)
{
fgets(line5, sizeof(line5), fbx);
ll = atoll(line5);
if (keys[frame] <= ll || i == 0)
{
if (line5[strlen(line5)-2] == ',')
{
line5[strlen(line5)-2] = '
';
line5[strlen(line5)-1] = '\0';
}
if ((q=index(line5, ',')) != NULL)
q[0] = '\0';
else
q = "??
";
if ((p=rindex(line5, ' ')) != NULL)
p[1] = '\0';
break;
}
}
if ((p=index(q+1, ',')) != NULL)
{
p[0] = '\0';
fprintf(fbxout, "%s
", q+1);
p[0] = ',';
}
else
{
fprintf(fbxout, "%s", q+1);
}
fputs(line2, fbxout);
fputs(line3, fbxout);
fputs(line4, fbxout);
fprintf(fbxout, "%s%lld,%s", line5, keys[frame], q+1);
while (i-- > 0)
fgets(line, sizeof(line), fbx);
}
}
else
{
fputs(line, fbxout);
}
}
fclose(fbx);
fclose(fbxout);
}
return (0);
}