2015-07-12 21:57:05 +01:00
|
|
|
#include <cstdio>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cassert>
|
|
|
|
#include <new>
|
|
|
|
|
2015-09-06 12:31:42 +01:00
|
|
|
#include <rw.h>
|
2015-12-24 22:31:36 +00:00
|
|
|
#include <args.h>
|
2015-09-06 12:31:42 +01:00
|
|
|
#include <src/gtaplg.h>
|
2015-07-12 21:57:05 +01:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace rw;
|
|
|
|
|
2015-12-24 22:31:36 +00:00
|
|
|
struct {
|
|
|
|
char *str;
|
|
|
|
uint32 val;
|
|
|
|
} platforms[] = {
|
|
|
|
{ "mobile", PLATFORM_OGL },
|
|
|
|
{ "ps2", PLATFORM_PS2 },
|
|
|
|
{ "xbox", PLATFORM_XBOX },
|
|
|
|
{ "d3d8", PLATFORM_D3D8 },
|
|
|
|
{ "d3d9", PLATFORM_D3D9 },
|
|
|
|
{ NULL, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
char *argv0;
|
|
|
|
|
|
|
|
Frame*
|
|
|
|
findHierCB(Frame *f, void *p)
|
|
|
|
{
|
|
|
|
HAnimData *hanim = PLUGINOFFSET(HAnimData, f, hAnimOffset);
|
|
|
|
if(hanim->hierarchy){
|
|
|
|
*(HAnimHierarchy**)p = hanim->hierarchy;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
f->forAllChildren(findHierCB, p);
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
HAnimHierarchy*
|
|
|
|
getHierarchy(Clump *c)
|
|
|
|
{
|
|
|
|
HAnimHierarchy *hier = NULL;
|
|
|
|
findHierCB((Frame*)c->parent, &hier);
|
|
|
|
return hier;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fixLcsHier(HAnimHierarchy *hier)
|
|
|
|
{
|
|
|
|
hier->maxInterpKeyFrameSize = findAnimInterpolatorInfo(1)->keyFrameSize;
|
|
|
|
for(int32 i = 0; i < hier->numNodes; i++){
|
|
|
|
int32 id = hier->nodeInfo[i].id;
|
|
|
|
if(id == 255) hier->nodeInfo[i].id = -1;
|
|
|
|
else if(id > 0x80) hier->nodeInfo[i].id |= 0x1300;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
usage(void)
|
|
|
|
{
|
2015-12-27 17:45:37 +00:00
|
|
|
fprintf(stderr, "usage: %s [-u] [-i] [-s] [-v version] [-o platform] in.dff [out.dff]\n", argv0);
|
2015-12-24 22:31:36 +00:00
|
|
|
fprintf(stderr, "\t-u uninstance\n");
|
|
|
|
fprintf(stderr, "\t-i instance\n");
|
|
|
|
fprintf(stderr, "\t-v RW version, e.g. 33004 for 3.3.0.4\n");
|
|
|
|
fprintf(stderr, "\t-o output platform. ps2, xbox, mobile, d3d8, d3d9\n");
|
|
|
|
fprintf(stderr, "\t-s expect iOS LCS dff as input\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2015-07-12 21:57:05 +01:00
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
2015-09-09 22:26:16 +01:00
|
|
|
gta::attachPlugins();
|
2015-07-12 21:57:05 +01:00
|
|
|
|
2015-12-17 21:15:59 +00:00
|
|
|
rw::version = 0;
|
|
|
|
// rw::version = 0x34003;
|
2015-12-14 17:52:50 +00:00
|
|
|
// rw::version = 0x33002;
|
2015-12-24 22:31:36 +00:00
|
|
|
// rw::platform = rw::PLATFORM_PS2;
|
2015-09-06 12:31:42 +01:00
|
|
|
// rw::platform = rw::PLATFORM_OGL;
|
2015-12-14 17:52:50 +00:00
|
|
|
// rw::platform = rw::PLATFORM_XBOX;
|
2015-12-24 22:31:36 +00:00
|
|
|
rw::platform = rw::PLATFORM_D3D8;
|
2015-09-08 09:29:24 +01:00
|
|
|
// rw::platform = rw::PLATFORM_D3D9;
|
2015-07-12 21:57:05 +01:00
|
|
|
|
|
|
|
int uninstance = 0;
|
2015-12-24 22:31:36 +00:00
|
|
|
int instance = 0;
|
|
|
|
int lcs = 0;
|
|
|
|
int outplatform = rw::PLATFORM_D3D8;
|
2015-07-12 21:57:05 +01:00
|
|
|
|
2015-12-24 22:31:36 +00:00
|
|
|
char *s;
|
|
|
|
ARGBEGIN{
|
|
|
|
case 'u':
|
2015-07-12 21:57:05 +01:00
|
|
|
uninstance++;
|
2015-12-24 22:31:36 +00:00
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
instance++;
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
sscanf(EARGF(usage()), "%x", &rw::version);
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
s = EARGF(usage());
|
|
|
|
for(int i = 0; platforms[i].str; i++){
|
|
|
|
if(strcmp(platforms[i].str, s) == 0){
|
|
|
|
outplatform = platforms[i].val;
|
|
|
|
goto found;
|
|
|
|
}
|
2015-07-12 21:57:05 +01:00
|
|
|
}
|
2015-12-24 22:31:36 +00:00
|
|
|
printf("unknown platform %s\n", s);
|
|
|
|
outplatform = PLATFORM_D3D8;
|
|
|
|
found:
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
lcs++;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
}ARGEND;
|
|
|
|
|
|
|
|
if(uninstance && instance){
|
|
|
|
fprintf(stderr, "cannot both instance and uninstance, choose one!\n");
|
|
|
|
return 1;
|
2015-07-12 21:57:05 +01:00
|
|
|
}
|
|
|
|
|
2015-12-24 22:31:36 +00:00
|
|
|
matFXGlobals.hack = lcs;
|
|
|
|
skinGlobals.forceSkipUsedBones = lcs;
|
2015-09-09 22:26:16 +01:00
|
|
|
|
2015-12-24 22:31:36 +00:00
|
|
|
if(argc < 1)
|
|
|
|
usage();
|
|
|
|
|
|
|
|
Clump *c;
|
|
|
|
//uint32 len;
|
|
|
|
//uint8 *data = getFileContents(argv[0], &len);
|
|
|
|
//assert(data != NULL);
|
|
|
|
//StreamMemory in;
|
|
|
|
//in.open(data, len);
|
|
|
|
StreamFile in;
|
|
|
|
in.open(argv[0], "rb");
|
2015-09-09 22:26:16 +01:00
|
|
|
ChunkHeaderInfo header;
|
|
|
|
readChunkHeaderInfo(&in, &header);
|
|
|
|
if(header.type == ID_UVANIMDICT){
|
|
|
|
UVAnimDictionary *dict = UVAnimDictionary::streamRead(&in);
|
|
|
|
currentUVAnimDictionary = dict;
|
|
|
|
readChunkHeaderInfo(&in, &header);
|
|
|
|
}
|
|
|
|
assert(header.type == ID_CLUMP);
|
2015-12-24 22:31:36 +00:00
|
|
|
debugFile = argv[0];
|
|
|
|
if(lcs)
|
|
|
|
c = clumpStreamReadRsl(&in);
|
|
|
|
else
|
|
|
|
c = Clump::streamRead(&in);
|
2015-07-12 21:57:05 +01:00
|
|
|
assert(c != NULL);
|
2015-12-24 22:31:36 +00:00
|
|
|
in.close();
|
2015-07-12 21:57:05 +01:00
|
|
|
|
2015-08-01 22:03:10 +01:00
|
|
|
// printf("%s\n", argv[arg]);
|
|
|
|
|
2015-08-03 20:33:35 +01:00
|
|
|
/*
|
2015-08-01 22:03:10 +01:00
|
|
|
for(int32 i = 0; i < c->numAtomics; i++){
|
|
|
|
Atomic *a = c->atomicList[i];
|
|
|
|
Pipeline *ap = a->pipeline;
|
|
|
|
Geometry *g = a->geometry;
|
|
|
|
for(int32 j = 0; j < g->numMaterials; j++){
|
|
|
|
Pipeline *mp = g->materialList[j]->pipeline;
|
|
|
|
if(ap && mp)
|
|
|
|
printf("%s %x %x\n", argv[arg], ap->pluginData, mp->pluginData);
|
|
|
|
}
|
|
|
|
}
|
2015-08-03 20:33:35 +01:00
|
|
|
*/
|
2015-08-01 22:03:10 +01:00
|
|
|
|
2015-12-17 21:15:59 +00:00
|
|
|
int32 platform = findPlatform(c);
|
|
|
|
if(platform){
|
|
|
|
rw::platform = platform;
|
2015-12-24 22:31:36 +00:00
|
|
|
switchPipes(c, rw::platform);
|
2015-12-17 21:15:59 +00:00
|
|
|
}
|
|
|
|
|
2015-12-24 22:31:36 +00:00
|
|
|
if(lcs){
|
|
|
|
HAnimHierarchy *hier = getHierarchy(c);
|
|
|
|
if(hier)
|
|
|
|
fixLcsHier(hier);
|
|
|
|
for(int32 i = 0; i < c->numAtomics; i++){
|
|
|
|
Skin *skin = *PLUGINOFFSET(Skin*, c->atomicList[i]->geometry, skinGlobals.offset);
|
|
|
|
convertRslGeometry(c->atomicList[i]->geometry);
|
|
|
|
if(skin)
|
|
|
|
c->atomicList[i]->pipeline = skinGlobals.pipelines[rw::platform];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(uninstance)
|
|
|
|
for(int32 i = 0; i < c->numAtomics; i++){
|
|
|
|
Atomic *a = c->atomicList[i];
|
|
|
|
ObjPipeline *p = a->getPipeline();
|
2015-08-03 17:30:10 +01:00
|
|
|
p->uninstance(a);
|
2015-12-24 22:31:36 +00:00
|
|
|
if(outplatform != PLATFORM_PS2)
|
|
|
|
ps2::unconvertADC(a->geometry);
|
|
|
|
}
|
|
|
|
|
|
|
|
rw::platform = outplatform;
|
|
|
|
switchPipes(c, rw::platform);
|
|
|
|
|
|
|
|
if(instance)
|
|
|
|
for(int32 i = 0; i < c->numAtomics; i++){
|
|
|
|
Atomic *a = c->atomicList[i];
|
|
|
|
ObjPipeline *p = a->getPipeline();
|
2015-08-03 17:30:10 +01:00
|
|
|
p->instance(a);
|
2015-12-24 22:31:36 +00:00
|
|
|
if(outplatform != PLATFORM_PS2)
|
|
|
|
ps2::convertADC(a->geometry);
|
|
|
|
}
|
2015-07-12 21:57:05 +01:00
|
|
|
|
2015-12-17 21:15:59 +00:00
|
|
|
if(rw::version == 0){
|
|
|
|
rw::version = header.version;
|
|
|
|
rw::build = header.build;
|
|
|
|
}
|
|
|
|
|
2015-12-24 22:31:36 +00:00
|
|
|
StreamFile out;
|
|
|
|
if(argc > 1)
|
|
|
|
assert(out.open(argv[1], "wb"));
|
|
|
|
else
|
|
|
|
assert(out.open("out.dff", "wb"));
|
2015-09-09 22:26:16 +01:00
|
|
|
if(currentUVAnimDictionary)
|
|
|
|
currentUVAnimDictionary->streamWrite(&out);
|
2015-07-12 21:57:05 +01:00
|
|
|
c->streamWrite(&out);
|
|
|
|
out.close();
|
2015-12-24 22:31:36 +00:00
|
|
|
|
|
|
|
// data = new rw::uint8[1024*1024];
|
|
|
|
// rw::StreamMemory out;
|
|
|
|
// out.open(data, 0, 1024*1024);
|
|
|
|
// if(currentUVAnimDictionary)
|
|
|
|
// currentUVAnimDictionary->streamWrite(&out);
|
|
|
|
// c->streamWrite(&out);
|
|
|
|
//
|
|
|
|
// FILE *cf;
|
|
|
|
// if(argc > 1)
|
|
|
|
// cf = fopen(argv[1], "wb");
|
|
|
|
// else
|
|
|
|
// cf = fopen("out.dff", "wb");
|
|
|
|
// assert(cf != NULL);
|
|
|
|
// fwrite(data, out.getLength(), 1, cf);
|
|
|
|
// fclose(cf);
|
|
|
|
// out.close();
|
|
|
|
// delete[] data;
|
2015-07-12 21:57:05 +01:00
|
|
|
|
|
|
|
delete c;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|