diff --git a/librw.vcxproj b/librw.vcxproj index 4376ed2..baf04fc 100644 --- a/librw.vcxproj +++ b/librw.vcxproj @@ -193,6 +193,7 @@ + @@ -202,6 +203,7 @@ + diff --git a/rw.h b/rw.h index e633a40..8f1c24e 100644 --- a/rw.h +++ b/rw.h @@ -8,3 +8,4 @@ #include "src/rwd3d8.h" #include "src/rwd3d9.h" #include "src/rwogl.h" +#include "src/mdl.h" diff --git a/src/clump.cpp b/src/clump.cpp index 9016a84..95e4989 100644 --- a/src/clump.cpp +++ b/src/clump.cpp @@ -157,7 +157,7 @@ sizeCB(Frame *f, void *size) return f; } -static Frame** +Frame** makeFrameList(Frame *frame, Frame **flist) { *flist++ = frame; diff --git a/src/gtaplg.cpp b/src/gtaplg.cpp index 71aeda7..61686c5 100644 --- a/src/gtaplg.cpp +++ b/src/gtaplg.cpp @@ -12,6 +12,7 @@ #include "rwps2.h" #include "rwd3d.h" #include "rwxbox.h" +#include "mdl.h" #include "gtaplg.h" using namespace std; @@ -81,6 +82,8 @@ attachPlugins(void) gta::register2dEffectPlugin(); gta::registerPipelinePlugin(); + registerRslPlugin(); + rw::Atomic::init(); } diff --git a/src/mdl.cpp b/src/mdl.cpp new file mode 100644 index 0000000..a267c03 --- /dev/null +++ b/src/mdl.cpp @@ -0,0 +1,358 @@ +#include +#include +#include +#include + +#include + +#include "rwbase.h" +#include "rwplugin.h" +#include "rwpipeline.h" +#include "rwobjects.h" +#include "rwps2.h" +#include "rwogl.h" +#include "rwxbox.h" +#include "rwd3d8.h" +#include "rwd3d9.h" +#include "mdl.h" + +using namespace std; +using namespace rw; + +enum { + ID_RSL = 0xf00d0000 +}; +int32 rslPluginOffset; + +struct RslMesh +{ + float32 bound[4]; // ? + float32 uvOff[2]; // ? + uint32 unknown; + uint32 dmaOffset; + uint16 numTriangles; + uint16 matID; + float32 pos[3]; // ? +}; + +struct RslGeometry +{ + float32 bound[4]; + uint32 size; + int32 type; + int32 unknown[4]; + float32 scale[3]; + float32 pos[3]; + + uint32 numMeshes; + RslMesh *meshes; + uint32 dataSize; + uint8 *data; +}; + +static uint32 +unpackSize(uint32 unpack) +{ + if((unpack&0x6F000000) == 0x6F000000) + return 2; + static uint32 size[] = { 32, 16, 8, 16 }; + return ((unpack>>26 & 3)+1)*size[unpack>>24 & 3]/8; +} + +void +analyzeData(uint8 *p) +{ + uint32 *w = (uint32*)p; + uint32 *end; + end = (uint32*)(p + ((w[0] & 0xFFFF) + 1)*0x10); // TODO: find out real mask + printf("start: %p end: %p\n", w, end); + w += 4; + while(w < end){ + if((w[0] & 0x60000000) == 0x60000000){ + printf("UNPACK %x %x\n", w[0], unpackSize(w[0])); + int32 n = (w[0] >> 16) & 0xFF; + p = (uint8*)(w+1); + p += n*unpackSize(w[0]); + w = (uint32*)p; + continue; + } + switch(w[0] & 0x7FFFFFFF){ + case 0x20000000: // STMASK + printf("STMASK %x\n", w[1]); + w++; + break; + case 0x30000000: + printf("STROW %x %x %x %x\n", w[1], w[2], w[3], w[4]); + w+=4; + break; + case 0x31000000: + printf("STCOL %x %x %x %x\n", w[1], w[2], w[3], w[4]); + w+=4; + break; + case 0: + break; + default: + printf("vif: %x\n", w[0]); + break; + } + w++; + } +} + +void +convertRslGeometry(Geometry *g) +{ + RslGeometry *rg = *PLUGINOFFSET(RslGeometry*, g, rslPluginOffset); + assert(rg != NULL); + RslMesh *m = rg->meshes; + for(int32 i = 0; i < rg->numMeshes; i++, m++) + analyzeData(rg->data + m->dmaOffset); +} + +Geometry* +geometryStreamReadRsl(Stream *stream) +{ + RslGeometry *rg = new RslGeometry; + stream->read(rg, 0x40); + rg->numMeshes = rg->size >> 20; + rg->size &= 0xFFFFF; + rg->meshes = new RslMesh[rg->numMeshes]; + rg->dataSize = rg->size - 0x40; + stream->read(rg->meshes, rg->numMeshes*sizeof(RslMesh)); + rg->dataSize -= rg->numMeshes*sizeof(RslMesh); + rg->data = new uint8[rg->dataSize]; + stream->read(rg->data, rg->dataSize); + + Geometry *g = new Geometry(0, 0, 0); + *PLUGINOFFSET(RslGeometry*, g, rslPluginOffset) = rg; + + assert(findChunk(stream, ID_MATLIST, NULL, NULL)); + assert(findChunk(stream, ID_STRUCT, NULL, NULL)); + g->numMaterials = stream->readI32(); + g->materialList = new Material*[g->numMaterials]; + stream->seek(g->numMaterials*4); // unused (-1) + for(int32 i = 0; i < g->numMaterials; i++){ + assert(findChunk(stream, ID_MATERIAL, NULL, NULL)); + g->materialList[i] = Material::streamRead(stream); + } + + g->streamReadPlugins(stream); + + return g; +} + +bool +geometryStreamWriteRsl(Stream *stream, Geometry *g) +{ + uint32 buf[3] = { ID_GEOMETRY, geometryStreamGetSizeRsl(g), 0xf00d }; + stream->write(&buf, 12); + + RslGeometry *rg = *PLUGINOFFSET(RslGeometry*, g, rslPluginOffset); + assert(rg != NULL); + rg->size |= rg->numMeshes << 20; + stream->write(rg, 0x40); + rg->numMeshes = rg->size >> 20; + rg->size &= 0xFFFFF; + stream->write(rg->meshes, rg->numMeshes*sizeof(RslMesh)); + stream->write(rg->data, rg->dataSize); + + uint32 size = 12 + 4; + for(int32 i = 0; i < g->numMaterials; i++) + size += 4 + 12 + g->materialList[i]->streamGetSize(); + writeChunkHeader(stream, ID_MATLIST, size); + writeChunkHeader(stream, ID_STRUCT, 4 + g->numMaterials*4); + stream->writeI32(g->numMaterials); + for(int32 i = 0; i < g->numMaterials; i++) + stream->writeI32(-1); + for(int32 i = 0; i < g->numMaterials; i++) + g->materialList[i]->streamWrite(stream); + + g->streamWritePlugins(stream); + return true; +} + +uint32 +geometryStreamGetSizeRsl(Geometry *g) +{ + RslGeometry *rg = *PLUGINOFFSET(RslGeometry*, g, rslPluginOffset); + assert(rg != NULL); + + uint32 size = rg->size; + size += 12 + 12 + 4; + for(int32 i = 0; i < g->numMaterials; i++) + size += 4 + 12 + g->materialList[i]->streamGetSize(); + size += 12 + g->streamGetPluginSize(); + return size; +} + +static uint32 atomicRights[2]; + +Atomic* +atomicStreamReadRsl(Stream *stream, Frame **frameList) +{ + int32 buf[4]; + uint32 version; + assert(findChunk(stream, ID_STRUCT, NULL, &version)); + stream->read(buf, 16); + Atomic *atomic = new Atomic; + atomic->frame = frameList[buf[0]]; + assert(findChunk(stream, ID_GEOMETRY, NULL, &version)); + assert(version == 0x00f00d00); + atomic->geometry = geometryStreamReadRsl(stream); + + atomicRights[0] = 0; + atomic->streamReadPlugins(stream); + if(atomicRights[0]) + atomic->assertRights(atomicRights[0], atomicRights[1]); + return atomic; +} + +bool +atomicStreamWriteRsl(Stream *stream, Atomic *a, Frame **frameList, int32 numFrames) +{ + int32 buf[4] = { 0, 0, 5, 0 }; + Clump *c = a->clump; + if(c == NULL) + return false; + writeChunkHeader(stream, ID_ATOMIC, atomicStreamGetSizeRsl(a)); + buf[0] = findPointer((void*)a->frame, (void**)frameList, numFrames); + writeChunkHeader(stream, ID_STRUCT, 16); + stream->write(buf, sizeof(buf)); + + geometryStreamWriteRsl(stream, a->geometry); + + a->streamWritePlugins(stream); + return true; +} + +uint32 +atomicStreamGetSizeRsl(Atomic *a) +{ + uint32 size = 12 + 12 + 12 + a->streamGetPluginSize(); + size += 16 + geometryStreamGetSizeRsl(a->geometry); + return size; +} + +Clump* +clumpStreamReadRsl(Stream *stream) +{ + uint32 length, version; + int32 buf[3]; + Clump *clump; + assert(findChunk(stream, ID_STRUCT, &length, &version)); + clump = new Clump; + stream->read(buf, length); + clump->numAtomics = buf[0]; + clump->numLights = 0; + clump->numCameras = 0; + + // Frame list + Frame **frameList; + int32 numFrames; + clump->frameListStreamRead(stream, &frameList, &numFrames); + clump->parent = (void*)frameList[0]; + + Geometry **geometryList = 0; + + // Atomics + if(clump->numAtomics) + clump->atomicList = new Atomic*[clump->numAtomics]; + for(int32 i = 0; i < clump->numAtomics; i++){ + assert(findChunk(stream, ID_ATOMIC, NULL, NULL)); + clump->atomicList[i] = atomicStreamReadRsl(stream, frameList); + clump->atomicList[i]->clump = clump; + } + + delete[] frameList; + + clump->streamReadPlugins(stream); + return clump; +} + +bool +clumpStreamWriteRsl(Stream *stream, Clump *c) +{ + int size = clumpStreamGetSizeRsl(c); + writeChunkHeader(stream, ID_CLUMP, size); + int buf[3] = { c->numAtomics, 0, 0 }; + writeChunkHeader(stream, ID_STRUCT, 4); + stream->write(buf, 4); + + int32 numFrames = ((Frame*)c->parent)->count(); + Frame **flist = new Frame*[numFrames]; + makeFrameList((Frame*)c->parent, flist); + + c->frameListStreamWrite(stream, flist, numFrames); + + for(int32 i = 0; i < c->numAtomics; i++) + atomicStreamWriteRsl(stream, c->atomicList[i], flist, numFrames); + + delete[] flist; + + c->streamWritePlugins(stream); + return true; +} + +static Frame* +sizeCB(Frame *f, void *size) +{ + *(int32*)size += f->streamGetPluginSize(); + f->forAllChildren(sizeCB, size); + return f; +} + +uint32 +clumpStreamGetSizeRsl(Clump *c) +{ + uint32 size = 0; + size += 12; // Struct + size += 4; // numAtomics + + // frame list + // TODO: make this into a function + int32 numFrames = ((Frame*)c->parent)->count(); + size += 12 + 12 + 4 + numFrames*(56+12); + sizeCB((Frame*)c->parent, (void*)&size); + + // atomics + for(int32 i = 0; i < c->numAtomics; i++) + size += 12 + atomicStreamGetSizeRsl(c->atomicList[i]); + + size += 12 + c->streamGetPluginSize(); + return size; +} + + +static void* +createRslGeo(void *object, int32 offset, int32) +{ + *PLUGINOFFSET(RslGeometry*, object, offset) = NULL; + return object; +} + +static void* +destroyRslGeo(void *object, int32 offset, int32) +{ + RslGeometry *rg = *PLUGINOFFSET(RslGeometry*, object, offset); + delete rg->data; + delete rg->meshes; + delete rg; + *PLUGINOFFSET(RslGeometry*, object, offset) = NULL; + return object; +} + +static void* +copyRslGeo(void *dst, void *src, int32 offset, int32) +{ + // TODO + return dst; +} + +void +registerRslPlugin(void) +{ + rslPluginOffset = Geometry::registerPlugin(sizeof(RslGeometry*), ID_RSL, + createRslGeo, + destroyRslGeo, + copyRslGeo); +} diff --git a/src/mdl.h b/src/mdl.h new file mode 100644 index 0000000..7125685 --- /dev/null +++ b/src/mdl.h @@ -0,0 +1,13 @@ +rw::Clump *clumpStreamReadRsl(rw::Stream *stream); +bool clumpStreamWriteRsl(rw::Stream *stream, rw::Clump *c); +rw::uint32 clumpStreamGetSizeRsl(rw::Clump *c); + +rw::Atomic *atomicStreamReadRsl(rw::Stream *stream, rw::Frame **frameList); +rw::uint32 atomicStreamGetSizeRsl(rw::Atomic *a); + +rw::Geometry *geometryStreamReadRsl(rw::Stream *stream); +rw::uint32 geometryStreamGetSizeRsl(rw::Geometry *g); + +void convertRslGeometry(rw::Geometry *g); + +void registerRslPlugin(void); \ No newline at end of file diff --git a/src/plugins.cpp b/src/plugins.cpp index 0b145c5..af7db34 100644 --- a/src/plugins.cpp +++ b/src/plugins.cpp @@ -882,7 +882,8 @@ readMaterialMatFX(Stream *stream, int32, void *object, int32 offset, int32) *PLUGINOFFSET(MatFX*, object, offset) = matfx; matfx->setEffects(stream->readU32()); - for(int i = 0; i < 2; i++){ + int32 n = matFXGlobals.hack ? 1 : 2; + for(int i = 0; i < n; i++){ uint32 type = stream->readU32(); switch(type){ case MatFX::BUMPMAP: @@ -907,7 +908,10 @@ readMaterialMatFX(Stream *stream, int32, void *object, int32 offset, int32) case MatFX::ENVMAP: coefficient = stream->readF32(); - fbAlpha = stream->readI32(); + if(matFXGlobals.hack) + fbAlpha = 0; + else + fbAlpha = stream->readI32(); tex = NULL; if(stream->readI32()){ assert(findChunk(stream, ID_TEXTURE, diff --git a/src/rwobjects.h b/src/rwobjects.h index 0aec5b2..8967d74 100644 --- a/src/rwobjects.h +++ b/src/rwobjects.h @@ -33,6 +33,8 @@ struct Frame : PluginBase, Object void setDirty(void); }; +Frame **makeFrameList(Frame *frame, Frame **flist); + struct HAnimKeyFrame { HAnimKeyFrame *prev; @@ -268,6 +270,7 @@ struct MatFXGlobals int32 atomicOffset; int32 materialOffset; ObjPipeline *pipelines[NUM_PLATFORMS]; + bool32 hack; }; extern MatFXGlobals matFXGlobals; void registerMatFXPlugin(void); @@ -436,7 +439,6 @@ struct Clump : PluginBase, Object bool streamWrite(Stream *stream); uint32 streamGetSize(void); -private: void frameListStreamRead(Stream *stream, Frame ***flp, int32 *nf); void frameListStreamWrite(Stream *stream, Frame **flp, int32 nf); }; diff --git a/tools/dffwrite/dffwrite.cpp b/tools/dffwrite/dffwrite.cpp index 33fad1c..2455dca 100644 --- a/tools/dffwrite/dffwrite.cpp +++ b/tools/dffwrite/dffwrite.cpp @@ -21,6 +21,9 @@ main(int argc, char *argv[]) rw::platform = PLATFORM_D3D8; // rw::version = 0x30200; + int lcs = 1; + matFXGlobals.hack = lcs; + gta::attachPlugins(); rw::Clump *c; @@ -62,10 +65,16 @@ main(int argc, char *argv[]) readChunkHeaderInfo(&in, &header); } assert(header.type == ID_CLUMP); - c = Clump::streamRead(&in); + if(lcs) + c = clumpStreamReadRsl(&in); + else + c = Clump::streamRead(&in); assert(c != NULL); } + if(lcs) + for(int32 i = 0; i < c->numAtomics; i++) + convertRslGeometry(c->atomicList[i]->geometry); // rw::Image::setSearchPath("./;/home/aap/gamedata/ps2/gtavc/MODELS/gta3_archive/txd_extracted/"); @@ -76,14 +85,6 @@ main(int argc, char *argv[]) rw::writeTGA(tga, "out.tga"); */ - for(int32 i = 0; i < c->numAtomics; i++){ - Geometry *g = c->atomicList[i]->geometry; - for(int32 j = 0; j < g->numMaterials; j++) - if(g->materialList[j]->texture) - g->materialList[j]->texture->filterAddressing = - (g->materialList[j]->texture->filterAddressing&~0xF) | 2; - } - // for(rw::int32 i = 0; i < c->numAtomics; i++) // rw::Gl::Instance(c->atomicList[i]); @@ -106,7 +107,10 @@ main(int argc, char *argv[]) out.open(argv[2], "wb"); else out.open("out.dff", "wb"); - c->streamWrite(&out); + if(lcs) + clumpStreamWriteRsl(&out, c); + else + c->streamWrite(&out); out.close(); }