void readStringtable(int pos, FILE* f, std::vector<std::string>& dest) { long oldPos = ftell(f); fseek(f, pos, SEEK_SET); u16 count; fread(&count, 2, 1, f); toWORD(count); fseek(f, 2, SEEK_CUR); //skip pad bytes for(int i = 0; i < count; ++i) { u16 unknown, stringOffset; fread(&unknown, 2, 1, f); toWORD(unknown); fread(&stringOffset, 2, 1, f); toWORD(stringOffset); std::string s = getString(pos + stringOffset, f); dest.push_back(s); } fseek(f, oldPos, SEEK_SET); }
void writeStringtable(std::ostream& out, FILE* f, int offset) { int p = ftell(f); fseek(f, offset, SEEK_SET); u16 count; fread(&count, 2, 1, f); toWORD(count); fseek(f, 2, SEEK_CUR); //skip pad bytes out << "String table (" << count << " entries)" << std::endl; for(int i = 0; i < count; ++i) { u16 unknown, stringOffset; fread(&unknown, 2, 1, f); toWORD(unknown); fread(&stringOffset, 2, 1, f); toWORD(stringOffset); std::string s = getString(offset + stringOffset, f); out << " 0x" << std::hex << unknown << " - " << s << std::endl; } fseek(f, p, SEEK_SET); }
void clsMaterialHeader::ReadMaterialSegment(int index){ u32 ReadBytes=0; u32 i=0; unsigned char* pnt=&MaterialSegments[index].front(); mGroup* ThisSegment=&MaterialSegment[index]; memcpy(&ThisSegment->groupheader,&pnt[ReadBytes],4); toDWORD((u32&)ThisSegment->groupheader); ReadBytes+=4; ReadBytes+=ReadTextureInfo(&ThisSegment->info,&pnt[ReadBytes]); if(fVersion==MP1){ memcpy(&ThisSegment->unknown0,&pnt[ReadBytes],4); toDWORD((u32&)ThisSegment->unknown0); ReadBytes+=4; memcpy(&ThisSegment->unknown1,&pnt[ReadBytes],4); toDWORD((u32&)ThisSegment->unknown1); ReadBytes+=4; /* if ((unknown0x00 & 0xF) == 0xB) { } leaving this segment from the bt out and just adding the sizes together to the current function you can implement if you want */ if ((ThisSegment->groupheader & 0x4000) != 0x0000) { memcpy(&ThisSegment->unknown0a[0],&pnt[ReadBytes],4); toDWORD((u32&)ThisSegment->unknown1); ReadBytes+=4; memcpy(&ThisSegment->unknown0a[1],&pnt[ReadBytes],4); toDWORD((u32&)ThisSegment->unknown1); ReadBytes+=4; } if ((ThisSegment->groupheader & 0xD00) == 0xD00) { memcpy(&ThisSegment->unknown1a,&pnt[ReadBytes],4); toDWORD((u32&)ThisSegment->unknown1); ReadBytes+=4; } // unsure, this is just a hack for now // need to determine if this is present under any other circumstances if ((ThisSegment->groupheader & 0x08) != 0x00){ memcpy(&ThisSegment->unknownCount0,&pnt[ReadBytes],4); toDWORD((u32&)ThisSegment->unknownCount0); ThisSegment->unknownData0.resize(ThisSegment->unknownCount0); ReadBytes+=4; for(i=0;i<ThisSegment->unknownCount0;i++){ memcpy(&ThisSegment->unknownData0[i],&pnt[ReadBytes],4); toDWORD((u32&)ThisSegment->unknownData0[i]); ReadBytes+=4; } } for(i=0;i<3;i++){ memcpy(&ThisSegment->unknown2[i],&pnt[ReadBytes],4); toDWORD((u32&)ThisSegment->unknown2[i]); ReadBytes+=4; } //Read Attribute info memcpy(&ThisSegment->AttribCount,&pnt[ReadBytes],4); toDWORD((u32&)ThisSegment->AttribCount); ReadBytes+=4; ThisSegment->Attributes.resize(ThisSegment->AttribCount); if(ThisSegment->AttribCount<10)ThisSegment->unknown4.resize(ThisSegment->AttribCount); for(i=0;i<ThisSegment->AttribCount;i++){ memcpy(&ThisSegment->Attributes[i],&pnt[ReadBytes],20);//Struct size is 20 bytes //u8 Unknown0; //u8 Blend; //u8 Unknown1; //u8 Unknown2; toWORD((u16&)ThisSegment->Attributes[i].BlendNumber); toWORD((u16&)ThisSegment->Attributes[i].BlendType); ReadBytes+=20; } for(i=0;i<ThisSegment->AttribCount;i++){ memcpy(&ThisSegment->unknown4[i],&pnt[ReadBytes],4); ReadBytes+=4; } memcpy(&ThisSegment->LayerInfo,&pnt[ReadBytes],4); ReadBytes+=4; toDWORD((u32&)ThisSegment->LayerInfo); ThisSegment->LayerData.resize(ThisSegment->LayerInfo); for(i=0;i<ThisSegment->LayerInfo;i++){ memcpy(&ThisSegment->LayerData[i],&pnt[ReadBytes],4); toDWORD((u32&)ThisSegment->LayerData[i]); ReadBytes+=4; } memcpy(&ThisSegment->unknownsize,&pnt[ReadBytes],4); toDWORD((u32&)ThisSegment->unknownsize); ReadBytes+=4; memcpy(&ThisSegment->unknown5,&pnt[ReadBytes],4); toDWORD((u32&)ThisSegment->unknown5); ReadBytes+=4; memcpy(&ThisSegment->unknown6,&pnt[ReadBytes],4); toDWORD((u32&)ThisSegment->unknown6); } return; }
int MREAData::ReadSubMesh(FILE* fp, MeshData & meshData) { unsigned int maxVert = 0; unsigned int maxNorm = 0; unsigned int maxUV = 0; int startPos = ftell(fp); long GroupId = 0; fseek(fp,startPos + 0xC,SEEK_SET); fread(&GroupId,1,4,fp); toDWORD((u32&)GroupId); int dataFormat = 0;// MaterialHeader[0].MaterialSegment[GroupId].info.count-1; fseek(fp,startPos + 0x12,SEEK_SET); u16 dataSize = 0; fread(&dataSize,sizeof(u16),1,fp); toWORD((u16&)dataSize); fseek(fp,startPos + 0x60,SEEK_SET); meshData.subMeshes.push_back(struct_Mesh()); struct_Mesh & mesh = meshData.subMeshes.back(); mesh.GroupId = GroupId; mesh.format = 0; u32 const vertexcount = (u32)meshData.vertices.size(); u32 const normalcount = (u32)meshData.normals.size(); uint32 readBytes = 0; while (readBytes < dataSize) { mesh.subMeshes.push_back(struct_SubMesh()); struct_SubMesh & submesh = mesh.subMeshes.back(); fread(&(submesh.primitiveFlags), sizeof(unsigned char), 1, fp); readBytes += sizeof(unsigned char); submesh.indexCount = 0; if (submesh.primitiveFlags == 0 || submesh.primitiveFlags < 0x80 || submesh.primitiveFlags > 0xBF || (readBytes + 2) >= dataSize) { submesh.primitiveFlags = 0; break; } fread(&(submesh.indexCount), sizeof(unsigned short), 1, fp); readBytes += sizeof(unsigned short); toWORD((u16&)submesh.indexCount); if (submesh.indexCount <= 0 || readBytes >= dataSize) { submesh.primitiveFlags = 0; break; } submesh.indices.resize(submesh.indexCount); struct_Faces * pFaces = &submesh.indices.front(); uint32 startReadBytes = readBytes; int currentPos = ftell(fp); bool bValid = false; //((0 == dataFormat) || (3 == dataFormat)); int i=0; while (!bValid && (struct_Faces::MAX_UV_INDICES >= dataFormat)) { fseek(fp, currentPos, SEEK_SET); readBytes = startReadBytes; bValid = true; for (i=0; (readBytes < dataSize) && (i < submesh.indexCount); i++) { fread(&(pFaces[i].vertexIndex), sizeof(unsigned short), 1, fp); readBytes += sizeof(unsigned short); fread(&(pFaces[i].normalIndex), sizeof(unsigned short), 1, fp); readBytes += sizeof(unsigned short); toWORD((u16&)pFaces[i].vertexIndex); toWORD((u16&)pFaces[i].normalIndex); if (maxVert < pFaces[i].vertexIndex) { maxVert = pFaces[i].vertexIndex; } if (maxNorm < pFaces[i].normalIndex) { maxNorm = pFaces[i].normalIndex; } for (int iUV = 0; iUV < dataFormat; ++iUV) { fread(&(pFaces[i].uvIndex[iUV]), sizeof(unsigned short), 1, fp); readBytes += sizeof(unsigned short); toWORD((u16&)pFaces[i].uvIndex[iUV]); if (maxUV < pFaces[i].uvIndex[iUV]) { maxUV = pFaces[i].uvIndex[iUV]; } } if (pFaces[i].vertexIndex >= vertexcount || pFaces[i].normalIndex >= normalcount || readBytes > dataSize ) { bValid = false; break; } } if (bValid) { unsigned char peekByte = 0; unsigned short peekShort = 0; fread(&(peekByte), sizeof(unsigned char), 1, fp); fread(&(peekShort), sizeof(unsigned short), 1, fp); fseek(fp, ftell(fp) - 3, SEEK_SET); if (((readBytes + 3) < dataSize && ((peekByte == 0 && peekShort != 0) || (peekByte != 0 && (peekByte < 0x80 || peekByte > 0xBF || peekShort == 0)))) || (readBytes < (dataSize - 32) && peekByte == 0 && peekShort == 0)) { bValid = false; } } if (!bValid) { ++dataFormat; maxVert = 0; maxNorm = 0; maxUV = 0; } } if (!bValid) { dataFormat = 0; readBytes = dataSize; submesh.primitiveFlags = 0; submesh.indexCount = 0; break; } mesh.format = (dataFormat & 0x7FFF); } fseek(fp, startPos + dataSize, SEEK_SET); char buff[256] = {0}; sprintf(buff, "Max Vertex Index: %4d - Max Normal Index: %4d - Max UV Index: %4d\n", maxVert, maxNorm, maxUV); OutputDebugStr(buff); return 0; }
int MREAData::ReadMesh(FILE* fp, int index, int segmentNum) { MeshData & mesh = m_meshes[index]; mesh.glList = 0; u32 nextOffset = ftell(fp) + m_sectionSizes[segmentNum]; fread(&mesh.header.unknown0x00, 4, 1, fp); toDWORD(mesh.header.unknown0x00); fread(mesh.header.transformMatrix, 4, 12, fp); for (u32 i = 0; i < 12; ++i) { toDWORD((u32&)mesh.header.transformMatrix[i]); } fread(mesh.header.boundingBox, 4, 6, fp); for (u32 i = 0; i < 6; ++i) { toDWORD((u32&)mesh.header.boundingBox[i]); } if (0 == index) { // minimum if (mesh.header.boundingBox[0] < minBounds.X) { minBounds.X = mesh.header.boundingBox[0]; } if (mesh.header.boundingBox[1] < minBounds.Y) { minBounds.Y = mesh.header.boundingBox[1]; } if (mesh.header.boundingBox[2] < minBounds.Z) { minBounds.Z = mesh.header.boundingBox[2]; } // maximum bounds if (mesh.header.boundingBox[3] > maxBounds.X) { maxBounds.X = mesh.header.boundingBox[3]; } if (mesh.header.boundingBox[4] > maxBounds.Y) { maxBounds.Y = mesh.header.boundingBox[4]; } if (mesh.header.boundingBox[5] > maxBounds.Z) { maxBounds.Z = mesh.header.boundingBox[5]; } } // move to next section data fseek(fp, nextOffset, SEEK_SET); ++segmentNum; nextOffset += m_sectionSizes[segmentNum]; u32 dataCount = m_sectionSizes[segmentNum] / 0x0C; u32 dataNum = 0; mesh.vertices.resize(dataCount); for(dataNum=0; dataNum<dataCount; ++dataNum) { fread(&mesh.vertices[dataNum].X, sizeof(float), 1, fp); fread(&mesh.vertices[dataNum].Y, sizeof(float), 1, fp); fread(&mesh.vertices[dataNum].Z, sizeof(float), 1, fp); toDWORD((u32&)mesh.vertices[dataNum].X); toDWORD((u32&)mesh.vertices[dataNum].Y); toDWORD((u32&)mesh.vertices[dataNum].Z); const tex vert = mesh.vertices[dataNum]; if (0) // == index) { // minimum bounds if (vert.X < minBounds.X) { minBounds.X = vert.X; } if (vert.Y < minBounds.Y) { minBounds.Y = vert.Y; } if (vert.Z < minBounds.Z) { minBounds.Z = vert.Z; } // maximum bounds if (vert.X > maxBounds.X) { maxBounds.X = vert.X; } if (vert.Y > maxBounds.Y) { maxBounds.Y = vert.Y; } if (vert.Z > maxBounds.Z) { maxBounds.Z = vert.Z; } } } // move to next section data fseek(fp, nextOffset, SEEK_SET); ++segmentNum; nextOffset += m_sectionSizes[segmentNum]; signed short x, y, z; dataCount = m_sectionSizes[segmentNum] / 0x06; mesh.normals.resize(dataCount); for(dataNum=0; dataNum<dataCount; ++dataNum) { fread(&x,sizeof(signed short),1,fp); fread(&y,sizeof(signed short),1,fp); fread(&z,sizeof(signed short),1,fp); toWORD((u16&)x); toWORD((u16&)y); toWORD((u16&)z); mesh.normals[dataNum].X = float(x) / 16834.0f; mesh.normals[dataNum].Y = float(y) / 16834.0f; mesh.normals[dataNum].Z = float(z) / 16834.0f; } // move to next section data fseek(fp, nextOffset, SEEK_SET); ++segmentNum; nextOffset += m_sectionSizes[segmentNum]; // read zero data // move to next section data fseek(fp, nextOffset, SEEK_SET); ++segmentNum; nextOffset += m_sectionSizes[segmentNum]; // read texture coordinate data dataCount = m_sectionSizes[segmentNum] / 0x08; mesh.uvs.resize(dataCount); for(dataNum=0; dataNum<dataCount; ++dataNum) { fread(&mesh.uvs[dataNum].U, sizeof(float), 1, fp); fread(&mesh.uvs[dataNum].V, sizeof(float), 1, fp); toDWORD((u32&)mesh.uvs[dataNum].U); toDWORD((u32&)mesh.uvs[dataNum].V); } // move to next section data fseek(fp, nextOffset, SEEK_SET); ++segmentNum; nextOffset += m_sectionSizes[segmentNum]; // read unknown data // move to next section data fseek(fp, nextOffset, SEEK_SET); ++segmentNum; nextOffset += m_sectionSizes[segmentNum]; // read sub mesh info data fread(&mesh.subMeshInfo.subMeshCount, 4, 1, fp); toDWORD(mesh.subMeshInfo.subMeshCount); mesh.subMeshInfo.subMeshOffsets.resize(mesh.subMeshInfo.subMeshCount); fread(&mesh.subMeshInfo.subMeshOffsets.front(), 4, mesh.subMeshInfo.subMeshCount, fp); for (u32 i = 0; i < mesh.subMeshInfo.subMeshCount; ++i) { toDWORD(mesh.subMeshInfo.subMeshOffsets[i]); } // move to next section data fseek(fp, nextOffset, SEEK_SET); ++segmentNum; nextOffset += m_sectionSizes[segmentNum]; // read sub mesh data for (u32 i = 0; i < mesh.subMeshInfo.subMeshCount; ++i) { ReadSubMesh(fp, mesh); // move to next section data fseek(fp, nextOffset, SEEK_SET); ++segmentNum; nextOffset += m_sectionSizes[segmentNum]; } return segmentNum; }