summaryrefslogtreecommitdiffstats
path: root/src/rw/ClumpRead.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rw/ClumpRead.cpp')
-rw-r--r--src/rw/ClumpRead.cpp230
1 files changed, 230 insertions, 0 deletions
diff --git a/src/rw/ClumpRead.cpp b/src/rw/ClumpRead.cpp
new file mode 100644
index 00000000..c9f027e7
--- /dev/null
+++ b/src/rw/ClumpRead.cpp
@@ -0,0 +1,230 @@
+#include "common.h"
+#include "patcher.h"
+
+struct rpGeometryList
+{
+ RpGeometry **geometries;
+ int32 numGeoms;
+};
+
+struct rpAtomicBinary
+{
+ RwInt32 frameIndex;
+ RwInt32 geomIndex;
+ RwInt32 flags;
+ RwInt32 unused;
+};
+
+static int32 numberGeometrys;
+static int32 streamPosition;
+static rpGeometryList gGeomList;
+static rwFrameList gFrameList;
+static RpClumpChunkInfo gClumpInfo;
+
+rpGeometryList*
+GeometryListStreamRead1(RwStream *stream, rpGeometryList *geomlist)
+{
+ int i;
+ RwUInt32 size, version;
+ RwInt32 numGeoms;
+
+ numberGeometrys = 0;
+ if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
+ return nil;
+ assert(size == 4);
+ if(RwStreamRead(stream, &numGeoms, 4) != 4)
+ return nil;
+
+ numberGeometrys = numGeoms/2;
+ geomlist->numGeoms = numGeoms;
+ if(geomlist->numGeoms > 0){
+ geomlist->geometries = (RpGeometry**)RwMalloc(geomlist->numGeoms * sizeof(RpGeometry*));
+ if(geomlist->geometries == nil)
+ return nil;
+ memset(geomlist->geometries, 0, geomlist->numGeoms * sizeof(RpGeometry*));
+ }else
+ geomlist->geometries = nil;
+
+ for(i = 0; i < numberGeometrys; i++){
+ if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version))
+ return nil;
+ geomlist->geometries[i] = RpGeometryStreamRead(stream);
+ if(geomlist->geometries[i] == nil)
+ return nil;
+ }
+
+ return geomlist;
+}
+
+rpGeometryList*
+GeometryListStreamRead2(RwStream *stream, rpGeometryList *geomlist)
+{
+ int i;
+ RwUInt32 version;
+
+ for(i = numberGeometrys; i < geomlist->numGeoms; i++){
+ if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version))
+ return nil;
+ geomlist->geometries[i] = RpGeometryStreamRead(stream);
+ if(geomlist->geometries[i] == nil)
+ return nil;
+ }
+
+ return geomlist;
+}
+
+void
+GeometryListDeinitialize(rpGeometryList *geomlist)
+{
+ int i;
+
+ for(i = 0; i < geomlist->numGeoms; i++)
+ if(geomlist->geometries[i])
+ RpGeometryDestroy(geomlist->geometries[i]);
+
+ if(geomlist->numGeoms){
+ RwFree(geomlist->geometries);
+ geomlist->numGeoms = 0;
+ }
+}
+
+RpAtomic*
+ClumpAtomicStreamRead(RwStream *stream, rwFrameList *frmList, rpGeometryList *geomList)
+{
+ RwUInt32 size, version;
+ rpAtomicBinary a;
+ RpAtomic *atomic;
+
+ numberGeometrys = 0;
+ if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
+ return nil;
+ assert(size <= sizeof(rpAtomicBinary));
+ if(RwStreamRead(stream, &a, size) != size)
+ return nil;
+
+ atomic = RpAtomicCreate();
+ if(atomic == nil)
+ return nil;
+
+ RpAtomicSetFlags(atomic, a.flags);
+
+ if(frmList->numFrames){
+ assert(a.frameIndex < frmList->numFrames);
+ RpAtomicSetFrame(atomic, frmList->frames[a.frameIndex]);
+ }
+
+ if(geomList->numGeoms){
+ assert(a.geomIndex < geomList->numGeoms);
+ RpAtomicSetGeometry(atomic, geomList->geometries[a.geomIndex], 0);
+ }else{
+ RpGeometry *geom;
+ if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version)){
+ RpAtomicDestroy(atomic);
+ return nil;
+ }
+ geom = RpGeometryStreamRead(stream);
+ if(geom == nil){
+ RpAtomicDestroy(atomic);
+ return nil;
+ }
+ RpAtomicSetGeometry(atomic, geom, 0);
+ RpGeometryDestroy(geom);
+ }
+
+ return atomic;
+}
+
+bool
+RpClumpGtaStreamRead1(RwStream *stream)
+{
+ RwUInt32 size, version;
+
+ if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version))
+ return false;
+ if(version >= 0x33000){
+ assert(size == 12);
+ if(RwStreamRead(stream, &gClumpInfo, 12) != 12)
+ return false;
+ }else{
+ assert(size == 4);
+ if(RwStreamRead(stream, &gClumpInfo, 4) != 4)
+ return false;
+ }
+
+ if(!RwStreamFindChunk(stream, rwID_FRAMELIST, nil, &version))
+ return false;
+ if(_rwFrameListStreamRead(stream, &gFrameList) == nil)
+ return false;
+
+ if(!RwStreamFindChunk(stream, rwID_GEOMETRYLIST, nil, &version)){
+ rwFrameListDeinitialize(&gFrameList);
+ return false;
+ }
+ if(GeometryListStreamRead1(stream, &gGeomList) == nil){
+ rwFrameListDeinitialize(&gFrameList);
+ return false;
+ }
+ streamPosition = stream->Type.memory.position;
+ return true;
+}
+
+RpClump*
+RpClumpGtaStreamRead2(RwStream *stream)
+{
+ int i;
+ RwUInt32 version;
+ RpAtomic *atomic;
+ RpClump *clump;
+
+ clump = RpClumpCreate();
+ if(clump == nil)
+ return nil;
+
+ RwStreamSkip(stream, streamPosition - stream->Type.memory.position);
+
+ if(GeometryListStreamRead2(stream, &gGeomList) == nil){
+ GeometryListDeinitialize(&gGeomList);
+ rwFrameListDeinitialize(&gFrameList);
+ RpClumpDestroy(clump);
+ return nil;
+ }
+
+ RpClumpSetFrame(clump, gFrameList.frames[0]);
+
+ for(i = 0; i < gClumpInfo.numAtomics; i++){
+ if(!RwStreamFindChunk(stream, rwID_ATOMIC, nil, &version)){
+ GeometryListDeinitialize(&gGeomList);
+ rwFrameListDeinitialize(&gFrameList);
+ RpClumpDestroy(clump);
+ return nil;
+ }
+
+ atomic = ClumpAtomicStreamRead(stream, &gFrameList, &gGeomList);
+ if(atomic == nil){
+ GeometryListDeinitialize(&gGeomList);
+ rwFrameListDeinitialize(&gFrameList);
+ RpClumpDestroy(clump);
+ return nil;
+ }
+
+ RpClumpAddAtomic(clump, atomic);
+ }
+
+ GeometryListDeinitialize(&gGeomList);
+ rwFrameListDeinitialize(&gFrameList);
+ return clump;
+}
+
+void
+RpClumpGtaCancelStream(void)
+{
+ GeometryListDeinitialize(&gGeomList);
+ rwFrameListDeinitialize(&gFrameList);
+ gFrameList.numFrames = 0;
+}
+
+STARTPATCHES
+ InjectHook(0x526060, RpClumpGtaStreamRead1, PATCH_JUMP);
+ InjectHook(0x526180, RpClumpGtaStreamRead2, PATCH_JUMP);
+ InjectHook(0x5262D0, RpClumpGtaCancelStream, PATCH_JUMP);
+ENDPATCHES