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();
}