#include #include #include #include "rwcore.h" #include "rpworld.h" RwUInt32 oc, fc, gc, mc; /* object, frame, geometry, and material counter */ void CalcNormal(RwReal *n, RwReal *v0, RwReal *v1, RwReal *v2) { RwReal a[3], b[3]; RwReal len; /* Calculate the normal */ a[0] = v1[0]-v0[0]; a[1] = v1[1]-v0[1]; a[2] = v1[2]-v0[2]; b[0] = v2[0]-v0[0]; b[1] = v2[1]-v0[1]; b[2] = v2[2]-v0[2]; n[0] = a[1]*b[2] - a[2]*b[1]; n[1] = a[2]*b[0] - a[0]*b[2]; n[2] = a[0]*b[1] - a[1]*b[0]; /* Make it 1 unit long */ len = sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]); if (len == 0) len = 1; n[0] /= len; n[1] /= len; n[2] /= len; } RpClump *RpClumpStreamRead(RwStream *dff) { RpClump *Clump; RwChunkHeaderInfo rwh; Clump = RpClumpCreate(); RwStreamReadChunkHeaderInfo(dff, &rwh); if (rwh.type == rwID_CLUMP) { ParseChunk(*Clump, &rwh, 0, dff); } else { free(Clump); return NULL; } return Clump; } void ParseChunk(RpClump &c, RwChunkHeaderInfo *rwh, RwUInt32 parent, RwStream *dff) { RwUInt32 i; RpGeometry *geo; switch (rwh->type) { case rwID_CLUMP: oc = fc = gc = 0; ReadChunk(c, rwh, dff); break; case rwID_STRUCT: ReadStruct(c, rwh, parent, dff); break; case rwID_FRAME: ReadFrame(c.Frm[fc], rwh->length, dff); fc++; break; case rwID_GEOMETRY: ReadChunk(c, rwh, dff); gc++; break; case rwID_MATERIAL: ReadChunk(c, rwh, dff); mc++; break; case rwID_ATOMIC: /* It is necessary to read all atomics at once. * The clump size of gta3 ps2 dffs is often not correct and we * would miss two atomics if we read them when we see them */ for (i = 0; i < (RwUInt32) c.numAtomics; i++) { ReadChunk(c, rwh, dff); RwStreamReadChunkHeaderInfo(dff, rwh); oc++; } break; case rwID_BINMESH: { RwUInt32 buffer[3]; geo = &c.Geo[gc]; // RwStreamReadInt32(dff, buffer, 3*sizeof(RwUInt32)); RwStreamRead(dff, buffer, 3*sizeof(RwUInt32)); geo->FaceType = buffer[0]; geo->numSplits = buffer[1]; geo->numIndices = buffer[2]; geo->Split = new RpMesh[geo->numSplits]; for (i = 0; i < geo->numSplits; i++) { RpMesh *s; s = &geo->Split[i]; // RwStreamReadInt32(dff, buffer, 2*sizeof(RwUInt32)); RwStreamRead(dff, buffer, 2*sizeof(RwUInt32)); s->numIndices = buffer[0]; s->MatIndex = buffer[1]; if (!geo->isPs2) { s->Indices = new RwUInt32[s->numIndices]; // RwStreamReadInt32(dff, s->Indices, RwStreamRead(dff, s->Indices, sizeof(RwUInt32) * s->numIndices); } } break; } case rwID_MATERIALEFFECTS: ReadMatfx(c, rwh, parent, dff); break; case rwID_SPECULARMAT: RwStreamReadReal(dff, &c.Geo[gc].Mat[mc].SpecLevel, sizeof(RwReal)); c.Geo[gc].Mat[mc].SpecName = new char[rwh->length-8]; RwStreamRead(dff, c.Geo[gc].Mat[mc].SpecName, rwh->length-8); RwStreamSkip(dff, 4); break; case rwID_REFLECTIONMAT: { RwReal buffer[5]; RwStreamReadReal(dff, buffer, 5*sizeof(RwReal)); c.Geo[gc].Mat[mc].RefImageAmount[0] = buffer[0]; c.Geo[gc].Mat[mc].RefImageAmount[1] = buffer[1]; c.Geo[gc].Mat[mc].RefImageAmount[2] = buffer[2]; c.Geo[gc].Mat[mc].RefImageAmount[3] = buffer[3]; c.Geo[gc].Mat[mc].RefIntensity = buffer[4]; RwStreamSkip(dff, 4); break; } case rwID_MATLIST: case rwID_EXTENSION: case rwID_FRAMELIST: case rwID_GEOMETRYLIST: case rwID_TEXTURE: ReadChunk(c, rwh, dff); break; case rwID_NATIVEDATA: /* * Actually there is no such thing as SA compression or * optimization. SA just uses by convention a little * different format that could probably be also read by * Vice City (it uses it in fact for skinning if I'm not * mistaken). * SA can read VC dffs (weapons in SA use that format) */ /* These should be combined when I have uncovered the secrets * of PS2 optimization */ if (IsSaCompression(c.Geo[gc], dff)) ReadNativeDataSaPs2(c.Geo[gc], dff); else ReadNativeDataVcPs2(c.Geo[gc], dff); break; case rwID_NIGHTVERTEXCOLOR: { RpGeometry *g; g = &c.Geo[gc]; if (g->isPs2) { RwStreamSkip(dff, rwh->length); } else { RwStreamSkip(dff, 4); g->NightVColor = new Color4b[g->numVertices]; RwStreamRead(dff, g->NightVColor, g->numVertices*sizeof(Color4b)); } break; } default: RwStreamSkip(dff, rwh->length); break; } } void ReadChunk(RpClump &c, RwChunkHeaderInfo *rwh, RwStream *dff) { RwChunkHeaderInfo child; RwUInt32 end; end = rwh->length + RwStreamTell(dff); while (RwStreamTell(dff) < end) { RwStreamReadChunkHeaderInfo(dff, &child); ParseChunk(c, &child, rwh->type, dff); } } void ReadFrame(RwFrame &f, RwUInt32 size, RwStream *dff) { f.Name = new char[size+1]; RwStreamRead(dff, f.Name, size); f.Name[size] = '\0'; } void ReadMatfx(RpClump &c, RwChunkHeaderInfo *rwh, RwUInt32 parent, RwStream *dff) { RwInt32 type; RwChunkHeaderInfo texh; // RwStreamReadInt32(dff, &type, sizeof(RwUInt32)); RwStreamRead(dff, &type, sizeof(RwUInt32)); if (type != 2) return; RwStreamSkip(dff, 16); RwStreamPeekInt32(dff, &type, sizeof(RwUInt32)); if (type == 0) { RwStreamSkip(dff, 4); return; } c.Geo[gc].Mat[mc].HasRef = 1; RwStreamReadChunkHeaderInfo(dff, &texh); ReadChunk(c, &texh, dff); RwStreamSkip(dff, 4); } void ReadStruct(RpClump &c, RwChunkHeaderInfo *rwh, RwUInt32 parent, RwStream *dff) { RwUInt32 i; RpGeometry *g; RpMaterial *m; RwTexture *t; switch (parent) { case rwID_CLUMP: { RwInt32 buffer[2]; if (c.Atm != NULL) { /* Light Chunk */ RwStreamSkip(dff, 4); return; } if (rwh->version == 0x302) { /* GTA3_1 */ printf("Sorry, can't read such an old file format\n"); exit(1); } // RwStreamReadInt32(dff, buffer, sizeof(RwInt32)); RwStreamRead(dff, buffer, sizeof(RwInt32)); c.numAtomics = buffer[0]; if (rwh->version != GTA3_1 && rwh->version != GTA3_2 && rwh->version != GTA3_3 && rwh->version != GTA3_4) { // RwStreamReadInt32(dff, buffer, 2*sizeof(RwInt32)); RwStreamRead(dff, buffer, 2*sizeof(RwInt32)); c.numLights = buffer[0]; c.numCameras = buffer[1]; } c.Atm = new RpAtomic[c.numAtomics]; break; } case rwID_FRAMELIST: { // RwStreamReadInt32(dff, &c.numFrames, sizeof(RwInt32)); RwStreamRead(dff, &c.numFrames, sizeof(RwInt32)); c.Frm = new RwFrame[c.numFrames]; for (i = 0; i < (RwUInt32) c.numFrames; i++) { RwInt32 buffer[2]; RwFrame *f; f = &c.Frm[i]; // RwStreamReadReal(dff, f->Rotation, sizeof(RwReal)*9); // RwStreamReadReal(dff, f->Position, sizeof(RwReal)*3); RwStreamRead(dff, f->Rotation, sizeof(RwReal)*9); RwStreamRead(dff, f->Position, sizeof(RwReal)*3); // RwStreamReadInt32(dff, buffer, sizeof(RwInt32)); RwStreamRead(dff, buffer, 2*sizeof(RwInt32)); f->Parent = buffer[0]; f->Unknown = buffer[1]; f->Name = NULL; } break; } case rwID_GEOMETRYLIST: // RwStreamReadInt32(dff, &c.numGeometries, sizeof(RwInt32)); RwStreamRead(dff, &c.numGeometries, sizeof(RwInt32)); c.Geo = new RpGeometry[c.numGeometries]; break; case rwID_GEOMETRY: { RwInt32 buffer[4]; g = &c.Geo[gc]; mc = 0; // RwStreamReadInt32(dff, buffer, 4*sizeof(RwInt32)); RwStreamRead(dff, buffer, 4*sizeof(RwInt32)); g->Flags = buffer[0] & 0xFFFF; g->numUVs = (buffer[0] & 0xFF0000) >> 16; g->isPs2 = (buffer[0] & 0xFF000000) >> 24; g->numTriangles = buffer[1]; g->numVertices = buffer[2]; g->numMorphTargets = buffer[3]; if (rwh->version == GTA3_1 || rwh->version == GTA3_2 || rwh->version == GTA3_3 || rwh->version == GTA3_4 || rwh->version == VCPS2) { RwStreamSkip(dff, 12); } g->VColor = NULL; g->NightVColor = NULL; g->UV = NULL; g->UV2 = NULL; g->Face = NULL; g->Vertex = NULL; g->Normal = NULL; if (!g->isPs2) { if ((g->Flags & rpGEOMETRYPRELIT) != 0) { g->VColor = new Color4b[g->numVertices]; RwStreamRead(dff, g->VColor, g->numVertices*sizeof(Color4b)); } if ((g->Flags & rpGEOMETRYTEXTURED) != 0) { g->UV = new Vector2f[g->numVertices]; // RwStreamReadReal(dff, g->UV, // g->numVertices*sizeof(Vector2f)); RwStreamRead(dff, g->UV, g->numVertices*sizeof(Vector2f)); } if ((g->Flags & rpGEOMETRYTEXTURED2) != 0) { g->UV = new Vector2f[g->numVertices]; g->UV2 = new Vector2f[g->numVertices]; // RwStreamReadReal(dff, g->UV, // g->numVertices*sizeof(Vector2f)); // RwStreamReadReal(dff, g->UV2, // g->numVertices*sizeof(Vector2f)); RwStreamRead(dff, g->UV, g->numVertices*sizeof(Vector2f)); RwStreamRead(dff, g->UV2, g->numVertices*sizeof(Vector2f)); } g->Face = new Face4i[g->numTriangles]; // RwStreamReadReal(dff, g->Face, // g->numTriangles*sizeof(Face4i)); RwStreamRead(dff, g->Face, g->numTriangles*sizeof(Face4i)); } RwStreamRead(dff, &g->BoundingSphere, 4*sizeof(RwReal)); // RwStreamReadInt32(dff, buffer, 2*sizeof(RwInt32)); RwStreamRead(dff, buffer, 2*sizeof(RwInt32)); g->BsPos = buffer[0]; g->BsNor = buffer[1]; if (!g->isPs2) { g->Vertex = new Vector3f[g->numVertices]; // RwStreamReadReal(dff, g->Vertex, // g->numVertices*sizeof(Vector3f)); RwStreamRead(dff, g->Vertex, g->numVertices*sizeof(Vector3f)); if ((g->Flags & rpGEOMETRYNORMALS) != 0) { g->Normal = new Vector3f[g->numVertices]; // RwStreamReadReal(dff, g->Normal, // g->numVertices*sizeof(Vector3f)); RwStreamRead(dff, g->Normal, g->numVertices*sizeof(Vector3f)); } } break; } case rwID_MATLIST: RwStreamRead(dff, &c.Geo[gc].numMaterials, sizeof(RwUInt32)); c.Geo[gc].Mat = new RpMaterial[c.Geo[gc].numMaterials]; RwStreamSkip(dff, 4*c.Geo[gc].numMaterials); break; case rwID_MATERIAL: { RwInt32 ibuffer[2]; RwReal rbuffer[3]; m = &c.Geo[gc].Mat[mc]; // RwStreamReadInt32(dff, &m->Flags, sizeof(RwInt32)); RwStreamRead(dff, &m->Flags, sizeof(RwInt32)); // RwStreamReadInt32(dff, &m->Color, 4*sizeof(RwUInt8)); RwStreamRead(dff, &m->Color, 4*sizeof(RwUInt8)); // RwStreamReadInt32(dff, ibuffer, 2*sizeof(RwInt32)); RwStreamRead(dff, ibuffer, 2*sizeof(RwInt32)); m->Unused = ibuffer[0]; m->HasTex = ibuffer[1]; RwStreamReadReal(dff, rbuffer, 3*sizeof(RwReal)); m->SurfaceProps[0] = rbuffer[0]; m->SurfaceProps[1] = rbuffer[1]; m->SurfaceProps[2] = rbuffer[2]; m->TexRead = FALSE; m->HasRef = FALSE; m->SpecName = NULL; break; } case rwID_TEXTURE: { RwInt16 buffer[2]; m = &c.Geo[gc].Mat[mc]; t = &m->Tex; /* If the texture has already been read, or there has been * no texture, read reflection map. */ if (m->TexRead || !m->HasTex) t = &m->Reflection; // RwStreamReadInt16(dff, buffer, 2*sizeof(RwInt16)); RwStreamRead(dff, buffer, 2*sizeof(RwInt16)); t->FilterFlags = buffer[0]; // t->Unknown = buffer[1]; /* texture name */ RwStreamReadChunkHeaderInfo(dff, rwh); // t->Name = new char[rwh->length+1]; RwStreamRead(dff, t->Name, rwh->length); t->Name[rwh->length] = '\0'; /* alpha name */ RwStreamReadChunkHeaderInfo(dff, rwh); // t->Alpha = new char[rwh->length+1]; RwStreamRead(dff, t->MaskName, rwh->length); t->MaskName[rwh->length] = '\0'; m->TexRead = TRUE; break; } case rwID_ATOMIC: { RwInt32 buffer[4]; RwStreamRead(dff, buffer, 4*sizeof(RwInt32)); c.Atm[oc].FrmIndex = buffer[0]; c.Atm[oc].GeoIndex = buffer[1]; c.Atm[oc].Unknown0 = buffer[2]; c.Atm[oc].Unknown1 = buffer[3]; break; } default: RwStreamSkip(dff, rwh->length); } } RwReal GetSaVertScale(RpGeometry &g) { /* This seems to work but is probably only coincidental */ /* if (g.Flags & rpGEOMETRYNORMALS) return SAVERTSCALE2; else return SAVERTSCALE1; */ return SAVERTSCALE1; } RwBool IsSameVert(RwReal *v0, RwReal *v1) { if (v0[0] == v1[0] && v0[1] == v1[1] && v0[2] == v1[2]) return TRUE; else return FALSE; } void Ps2ToPc(RpGeometry &g, struct ps2split *splits) { RwUInt32 i, j, k; RwUInt32 faceinc; /* Correct index count for each split */ for (i = 0; i < g.numSplits; i++) g.Split[i].numIndices = splits[i].vertexc+splits[i].extraverts; /* Correct index count for the whole mesh */ g.numIndices = 0; for (i = 0; i < g.numSplits; i++) g.numIndices += g.Split[i].numIndices; /* Calculate vertex count */ g.numVertices = 0; for (i = 0; i < g.numSplits; i++) g.numVertices += g.Split[i].numIndices; /* Write Vertices into Geometry struct */ g.Vertex = new Vector3f[g.numVertices]; for (i = k = 0; i < g.numSplits; i++) { for (j = 0; j < splits[i].vertexc; j++) { g.Vertex[j+k][0] = splits[i].vertices[j][0]; g.Vertex[j+k][1] = splits[i].vertices[j][1]; g.Vertex[j+k][2] = splits[i].vertices[j][2]; } k += j; } /* Write UV Coordinates into Geometry Struct if we have any */ if (g.Flags & rpGEOMETRYTEXTURED) { g.UV = new Vector2f[g.numVertices]; for (i = k = 0; i < g.numSplits; i++) { for (j = 0; j < splits[i].vertexc; j++) { g.UV[j+k][0] = splits[i].uv[j][0]; g.UV[j+k][1] = splits[i].uv[j][1]; } k += j; } } else if (g.Flags & rpGEOMETRYTEXTURED2) { g.UV = new Vector2f[g.numVertices]; g.UV2 = new Vector2f[g.numVertices]; for (i = k = 0; i < g.numSplits; i++) { for (j = 0; j < splits[i].vertexc; j++) { g.UV[j+k][0] = splits[i].uv[j][0]; g.UV[j+k][1] = splits[i].uv[j][1]; } for (j = 0; j < splits[i].vertexc; j++) { g.UV2[j+k][0] = splits[i].uv[j][0]; g.UV2[j+k][1] = splits[i].uv[j][1]; } k += j; } } /* Write Vertex colors into Geometry Struct if we have any */ if (g.Flags & rpGEOMETRYPRELIT) { g.VColor = new Color4b[g.numVertices]; if (splits[0].hasNVC) g.NightVColor = new Color4b[g.numVertices]; for (i = k = 0; i < g.numSplits; i++) { for (j = 0; j < splits[i].vertexc; j++) { g.VColor[j+k][0] = splits[i].vc[j][0]; g.VColor[j+k][1] = splits[i].vc[j][1]; g.VColor[j+k][2] = splits[i].vc[j][2]; g.VColor[j+k][3] = splits[i].vc[j][3]; if (splits[i].hasNVC) { g.NightVColor[j+k][0] = splits[i].vc[j][4]; g.NightVColor[j+k][1] = splits[i].vc[j][5]; g.NightVColor[j+k][2] = splits[i].vc[j][6]; g.NightVColor[j+k][3] = splits[i].vc[j][7]; } } k += j; } } /* Write Normals into Geometry struct if we have any */ k = 0; if (g.Flags & rpGEOMETRYNORMALS) { g.Normal = new Vector3f[g.numVertices]; for (i = k = 0; i < g.numSplits; i++) { for (j = 0; j < splits[i].vertexc; j++) { g.Normal[j+k][0] = splits[i].normals[j][0]; g.Normal[j+k][1] = splits[i].normals[j][1]; g.Normal[j+k][2] = splits[i].normals[j][2]; } k += j; } } /* Write an index list */ faceinc = 0; for (i = 0; i < g.numSplits; i++) { RwUInt32 k; g.Split[i].Indices = new RwUInt32[g.Split[i].numIndices]; for (j = k = 0; j < splits[i].vertexc; j++, k++) { g.Split[i].Indices[k] = j+faceinc; if (splits[i].flags && splits[i].flags[j+1] == 0x8000) { k++; g.Split[i].Indices[k] = j+faceinc; } } faceinc += j; } /* Write Faces. Note: This is not elegant, but useless anyhow */ if (g.FaceType == 1) { g.numTriangles = g.numIndices - 2*g.numSplits; g.Face = new Face4i[g.numTriangles]; faceinc = 0; for (i = 0; i < g.numSplits; i++) { for (j = 0; j < g.Split[i].numIndices-2; j++) { g.Face[j+faceinc][0] = g.Split[i].Indices[j]; g.Face[j+faceinc][1] = g.Split[i].Indices[j+1]; g.Face[j+faceinc][2] = 0; g.Face[j+faceinc][3] = g.Split[i].Indices[j+2]; } faceinc += j; } } else { g.numTriangles = g.Split[i].numIndices/3; g.Face = NULL; } /* Free everything */ for (i = 0; i < g.numSplits; i++) { for (j = 0; j < splits[i].vertexc; j++) { free(splits[i].vertices[j]); free(splits[i].uv[j]); free(splits[i].uv2[j]); free(splits[i].vc[j]); free(splits[i].normals[j]); } free(splits[i].vertices); free(splits[i].uv); free(splits[i].uv2); free(splits[i].vc); free(splits[i].normals); free(splits[i].flags); } } void ReadNativeDataVcPs2(RpGeometry &g, RwStream *dff) { RwUInt32 i, k; RwUInt32 blockvertcount, oldvertcount; RwBool isnotactor, islast; RwUInt32 subsecthdr; RwUInt32 splitsize, nextsplit; RwInt8 compnormal[3]; struct ps2split *splits; struct ps2split *cursplit; splits = (struct ps2split*) malloc(g.numSplits*sizeof(struct ps2split)); /* Skip header and platform */ RwStreamSkip(dff, 16); for (i = 0; i < g.numSplits; i++) { cursplit = &splits[i]; // RwStreamReadInt32(dff, &splitsize, sizeof(RwUInt32)); RwStreamRead(dff, &splitsize, sizeof(RwUInt32)); nextsplit = splitsize + 4 + RwStreamTell(dff); // RwStreamReadInt32(dff, &isnotactor, sizeof(RwUInt32)); RwStreamRead(dff, &isnotactor, sizeof(RwUInt32)); if (isnotactor) RwStreamSkip(dff, 16); cursplit->vertices = NULL; cursplit->uv = NULL; cursplit->uv2 = NULL; cursplit->vc = NULL; cursplit->normals = NULL; cursplit->hasNVC = 0; /* Loop through blocks */ cursplit->vertexc = 0; islast = 0; while (!islast) { if (!isnotactor) RwStreamSkip(dff, 48); /* Vertices */ RwStreamSkip(dff, 12); // RwStreamReadInt32(dff, &subsecthdr, sizeof(RwUInt32)); RwStreamRead(dff, &subsecthdr, sizeof(RwUInt32)); blockvertcount = (subsecthdr & 0x00ff0000) >> 16; oldvertcount = cursplit->vertexc; cursplit->vertexc += blockvertcount; cursplit->vertices = (RwReal **) realloc(cursplit->vertices, cursplit->vertexc*4); cursplit->flags = NULL; cursplit->extraverts = 0; for (k = oldvertcount; k < cursplit->vertexc; k++) { cursplit->vertices[k] = (RwReal *) malloc(3*4); RwStreamReadReal(dff, cursplit->vertices[k], 3*sizeof(RwUInt32)); } /* Skip padding */ if ((blockvertcount*12 % 16) != 0) RwStreamSkip(dff, 16-(blockvertcount*12%16)); /* UV Coordinates */ RwStreamSkip(dff, 16); cursplit->uv = (RwReal **) realloc(cursplit->uv, cursplit->vertexc*4); cursplit->uv2 = (RwReal **) realloc(cursplit->uv2, cursplit->vertexc*4); for (k = oldvertcount; k < cursplit->vertexc; k++) { cursplit->uv[k] = (RwReal *) malloc(2*4); cursplit->uv2[k] = (RwReal *) malloc(2*4); RwStreamReadReal(dff, cursplit->uv[k], 2*sizeof(RwUInt32)); } /* Skip padding */ if ((blockvertcount*8 % 16) != 0) RwStreamSkip(dff, 16-(blockvertcount*8%16)); /* Vertex colors */ RwStreamSkip(dff, 16); cursplit->vc = (RwUInt8 **) realloc(cursplit->vc, cursplit->vertexc*4); for (k = oldvertcount; k < cursplit->vertexc; k++) { cursplit->vc[k] = (RwUInt8 *) malloc(1*4); RwStreamRead(dff, cursplit->vc[k], 4*sizeof(RwUInt8)); } /* Skip padding */ if ((blockvertcount*4 % 16) != 0) RwStreamSkip(dff, 16-(blockvertcount*4%16)); /* Normals */ RwStreamSkip(dff, 16); cursplit->normals = (RwReal **) realloc(cursplit->normals, cursplit->vertexc*4); for (k = oldvertcount; k < cursplit->vertexc; k++) { cursplit->normals[k] = (RwReal *) malloc(3*4); RwStreamRead(dff, compnormal, 3*sizeof(RwInt8)); cursplit->normals[k][0] = compnormal[0] * VCNORMSCALE; cursplit->normals[k][1] = compnormal[1] * VCNORMSCALE; cursplit->normals[k][2] = compnormal[2] * VCNORMSCALE; } /* Skip padding */ if ((blockvertcount*3 % 16) != 0) RwStreamSkip(dff, 16-(blockvertcount*3%16)); /* Skip end of block and see whether it was the last */ RwStreamSkip(dff, 8); // RwStreamReadInt32(dff, &islast, sizeof(RwInt32)); RwStreamRead(dff, &islast, sizeof(RwInt32)); if (islast == 0x11000000) islast = 1; else islast = 0; RwStreamSkip(dff, 4); } /* Jump to next split and skip unknowns (probably skin data) */ RwStreamSeek(dff, nextsplit); } Ps2ToPc(g, splits); free(splits); } void ReadNativeDataSaPs2(RpGeometry &g, RwStream *dff) { RwUInt32 i, j; RwUInt32 splitsize, nextsplit; RwUInt32 vertexpos, uvpos, normalpos, vcpos; RwUInt32 startaddress; RwInt16 compvert[4]; RwInt16 compuv[2]; RwUInt8 compnormal[4]; RwInt8 compcolor[8]; RwReal vertscale; struct ps2split *splits; struct ps2split *cursplit; splits = (struct ps2split*) malloc(g.numSplits*sizeof(struct ps2split)); /* Skip header and platform */ RwStreamSkip(dff, 16); vertscale = GetSaVertScale(g); for (i = 0; i < g.numSplits; i++) { cursplit = &splits[i]; // RwStreamReadInt32(dff, &splitsize, sizeof(RwUInt32)); RwStreamRead(dff, &splitsize, sizeof(RwUInt32)); nextsplit = splitsize + 4 + RwStreamTell(dff); RwStreamSkip(dff, 4); startaddress = RwStreamTell(dff); RwStreamSkip(dff, 4); // RwStreamReadInt32(dff, &vertexpos, sizeof(RwUInt32)); RwStreamRead(dff, &vertexpos, sizeof(RwUInt32)); vertexpos = vertexpos*0x10 + startaddress; if ((g.Flags & rpGEOMETRYTEXTURED) || (g.Flags & rpGEOMETRYTEXTURED2)) { RwStreamSkip(dff, 28); // RwStreamReadInt32(dff, &uvpos, sizeof(RwUInt32)); RwStreamRead(dff, &uvpos, sizeof(RwUInt32)); uvpos = uvpos*0x10 + startaddress; } if (g.Flags & rpGEOMETRYPRELIT) { RwStreamSkip(dff, 28); // RwStreamReadInt32(dff, &vcpos, sizeof(RwUInt32)); RwStreamRead(dff, &vcpos, sizeof(RwUInt32)); vcpos = vcpos*0x10 + startaddress; } if (g.Flags & rpGEOMETRYNORMALS) { RwStreamSkip(dff, 28); // RwStreamReadInt32(dff, &normalpos, sizeof(RwUInt32)); RwStreamRead(dff, &normalpos, sizeof(RwUInt32)); normalpos = normalpos*0x10 + startaddress; } cursplit->vertexc = g.Split[i].numIndices; cursplit->vertices = (RwReal **) malloc(cursplit->vertexc*4); cursplit->flags = (RwUInt16 *) malloc(cursplit->vertexc*sizeof(RwUInt16)); cursplit->uv = (RwReal **) malloc(cursplit->vertexc*4); cursplit->uv2 = (RwReal **) malloc(cursplit->vertexc*4); cursplit->vc = (RwUInt8 **) malloc(cursplit->vertexc*4); cursplit->normals = (RwReal **) malloc(cursplit->vertexc*4); cursplit->hasNVC = 1; /* Read Vertices */ RwStreamSeek(dff, vertexpos); cursplit->extraverts = 0; /* How can I determine the correct scaling factor? * Vehicles use 1/1024 every other object uses 1/128 */ for (j = 0; j < cursplit->vertexc; j++) { cursplit->vertices[j] = (RwReal *) malloc(3*4); RwStreamRead(dff, compvert, 4*sizeof(RwInt16)); cursplit->vertices[j][0] = compvert[0] * vertscale; cursplit->vertices[j][1] = compvert[1] * vertscale; cursplit->vertices[j][2] = compvert[2] * vertscale; if ((cursplit->flags[j] = compvert[3]) == 0x8000) cursplit->extraverts++; } /* Read UV coordinates */ if (g.Flags & rpGEOMETRYTEXTURED) { RwStreamSeek(dff, uvpos); for (j = 0; j < cursplit->vertexc; j++) { cursplit->uv[j] = (RwReal *) malloc(2*4); RwStreamRead(dff, compuv, 2*sizeof(RwInt16)); cursplit->uv[j][0] = compuv[0] * SAUVSCALE; cursplit->uv[j][1] = compuv[1] * SAUVSCALE; } for (j = 0; j < cursplit->vertexc; j++) cursplit->uv2[j] = (RwReal *) malloc(2*4); } else if (g.Flags & rpGEOMETRYTEXTURED2) { /* Note that this is incorrect */ RwStreamSeek(dff, uvpos); for (j = 0; j < cursplit->vertexc; j++) { cursplit->uv[j] = (RwReal *) malloc(2*4); cursplit->uv2[j] = (RwReal *) malloc(2*4); RwStreamRead(dff, compuv, 2*sizeof(RwInt16)); cursplit->uv[j][0] = compuv[0] * SAUVSCALE; cursplit->uv[j][1] = compuv[1] * SAUVSCALE; RwStreamRead(dff, compuv, 2*sizeof(RwInt16)); cursplit->uv2[j][0] = compuv[0] * SAUVSCALE; cursplit->uv2[j][1] = compuv[1] * SAUVSCALE; } } else { for (j = 0; j < cursplit->vertexc; j++) { cursplit->uv[j] = (RwReal *) malloc(2*4); cursplit->uv2[j] = (RwReal *) malloc(2*4); } } /* Read Vertex colors */ if (g.Flags & rpGEOMETRYPRELIT) { RwStreamSeek(dff, vcpos); for (j = 0; j < cursplit->vertexc; j++) { cursplit->vc[j] = (RwUInt8 *) malloc(8*1); RwStreamRead(dff, compcolor, 8*sizeof(RwUInt8)); cursplit->vc[j][0] = compcolor[0]; cursplit->vc[j][1] = compcolor[2]; cursplit->vc[j][2] = compcolor[4]; cursplit->vc[j][3] = compcolor[6]; cursplit->vc[j][4] = compcolor[1]; cursplit->vc[j][5] = compcolor[3]; cursplit->vc[j][6] = compcolor[5]; cursplit->vc[j][7] = compcolor[7]; } } else { for (j = 0; j < cursplit->vertexc; j++) cursplit->vc[j] = (RwUInt8 *) malloc(8*1); } /* Read Normals (incorrect) */ if (g.Flags & rpGEOMETRYNORMALS) { RwStreamSeek(dff, normalpos); for (j = 0; j < cursplit->vertexc; j++) { cursplit->normals[j] = (RwReal *) malloc(3*4); RwStreamRead(dff, compnormal, 4*sizeof(RwInt8)); cursplit->normals[j][0] = compnormal[0] * SANORMSCALE; cursplit->normals[j][1] = compnormal[1] * SANORMSCALE; cursplit->normals[j][2] = compnormal[2] * SANORMSCALE; } } else { for (j = 0; j < cursplit->vertexc; j++) cursplit->normals[j] = (RwReal *) malloc(3*4); } RwStreamSeek(dff, nextsplit); } Ps2ToPc(g, splits); // free(splits); } RwBool IsSaCompression(RpGeometry &g, RwStream *dff) { RwUInt32 isnotactor; RwUInt32 oldpos; RwChunkHeaderInfo rwh; oldpos = RwStreamTell(dff); RwStreamReadChunkHeaderInfo(dff, &rwh); RwStreamSkip(dff, 8); // RwStreamReadInt32(dff, &isnotactor, sizeof(RwUInt32)); RwStreamRead(dff, &isnotactor, sizeof(RwUInt32)); RwStreamSeek(dff, oldpos); if ((rwh.version == SA) && (isnotactor == 0)) return TRUE; else return FALSE; } RwUInt32 RpClumpGetNumAtomics(RpClump *Clump) { return Clump->numAtomics; } RpClump *RpClumpCreate() { RpClump *c; c = new RpClump; c->numAtomics = 0; c->numFrames = 0; c->numGeometries = 0; c->Atm = NULL; c->Frm = NULL; c->Geo = NULL; return c; } void RpClumpDestroy(RpClump *Clp) { RwUInt32 j, k; RpGeometry *g; RpMaterial *m; RpMesh *s; for (j = 0; j < (RwUInt32) Clp->numFrames; j++) if (Clp->Frm[j].Name != NULL) delete[] Clp->Frm[j].Name; delete[] Clp->Frm; for (j = 0; j < (RwUInt32) Clp->numGeometries; j++) { g = &Clp->Geo[j]; for (k = 0; k < g->numMaterials; k++) { m = &g->Mat[k]; if (m->SpecName != NULL) delete[] m->SpecName; } delete[] g->Mat; delete[] g->Vertex; delete[] g->Face; if (g->Flags & rpGEOMETRYTEXTURED) delete[] g->UV; if (g->Flags & rpGEOMETRYTEXTURED2) { delete[] g->UV; delete[] g->UV2; } if (g->Flags & rpGEOMETRYPRELIT) delete[] g->VColor; if (g->NightVColor != NULL) delete[] g->NightVColor; if (g->Flags & rpGEOMETRYNORMALS) delete[] g->Normal; for (k = 0; k < g->numSplits; k++) { s = &g->Split[k]; delete[] s->Indices; } delete[] g->Split; } delete[] Clp->Geo; delete[] Clp->Atm; delete Clp; }