/// <summary> /// Read mesh data to record array. /// </summary> /// <param name="record">Destination record index.</param> private bool ReadMesh(int record) { // Create empty mesh records[record].PureMesh = new PureMesh(); // Create plane array int faceCount = records[record].Header.PlaneCount; records[record].PureMesh.Planes = new PurePlane[faceCount]; // Get reader for normal data long normalPosition = records[record].Header.NormalListOffset; BinaryReader normalReader = records[record].MemoryFile.GetReader(normalPosition); // Read native data into plane array int uniqueTextureCount = 0; MeshVersions version = records[record].Version; long position = records[record].Header.PlaneListOffset; BinaryReader reader = records[record].MemoryFile.GetReader(position); BinaryReader pointReader = records[record].MemoryFile.GetReader(); BinaryReader planeDataReader = records[record].MemoryFile.GetReader(); int minX = 0, maxX = 0, minY = 0, maxY = 0, minZ = 0, maxZ = 0; for (int plane = 0; plane < faceCount; plane++) { // Read plane header records[record].PureMesh.Planes[plane].Header.Position = reader.BaseStream.Position; records[record].PureMesh.Planes[plane].Header.PlanePointCount = reader.ReadByte(); records[record].PureMesh.Planes[plane].Header.Unknown1 = reader.ReadByte(); records[record].PureMesh.Planes[plane].Header.Texture = reader.ReadUInt16(); records[record].PureMesh.Planes[plane].Header.Unknown2 = reader.ReadUInt32(); // Read the normal data for this plane Int32 nx = normalReader.ReadInt32(); Int32 ny = normalReader.ReadInt32(); Int32 nz = normalReader.ReadInt32(); // Build list of unique textures across all planes - this will be used later to create submesh buffers UInt16 textureBitfield = records[record].PureMesh.Planes[plane].Header.Texture; int textureArchive = textureBitfield >> 7; int textureRecord = textureBitfield & 0x7f; bool foundTexture = false; for (int i = 0; i < uniqueTextureCount; i++) { if (uniqueTextureBuffer[i].Archive == textureArchive && uniqueTextureBuffer[i].Record == textureRecord) { foundTexture = true; break; } } if (!foundTexture) { uniqueTextureBuffer[uniqueTextureCount].Archive = textureArchive; uniqueTextureBuffer[uniqueTextureCount].Record = textureRecord; uniqueTextureCount++; } // Store texture index for this plane records[record].PureMesh.Planes[plane].TextureIndex.Archive = textureArchive; records[record].PureMesh.Planes[plane].TextureIndex.Record = textureRecord; // Read plane points int pointCount = records[record].PureMesh.Planes[plane].Header.PlanePointCount; records[record].PureMesh.Planes[plane].Points = new FaceUVTool.DFPurePoint[pointCount]; for (int point = 0; point < pointCount; point++) { // Read offset int pointOffset = reader.ReadInt32(); // Read UV data Int16 u = reader.ReadInt16(); Int16 v = reader.ReadInt16(); // Fix certain UV coordinates that are // packed oddly, or aligned outside of poly. int threshold = 14335; while (u > threshold) { u = (Int16)(0x4000 - u); } while (u < -threshold) { u = (Int16)(0x4000 + u); } while (v > threshold) { v = (Int16)(0x4000 - v); } while (v < -threshold) { v = (Int16)(0x4000 + v); } // Fix some remaining special-case textures if (u == 7168) { u = 1024; } if (u == -7168) { u = -1024; } // Store UV coordinates records[record].PureMesh.Planes[plane].Points[point].u = u; records[record].PureMesh.Planes[plane].Points[point].v = v; // Get point position long pointPosition = records[record].Header.PointListOffset; switch (version) { case MeshVersions.Version27: case MeshVersions.Version26: pointPosition += pointOffset; break; case MeshVersions.Version25: pointPosition += (pointOffset * 3); break; } // Read native point values pointReader.BaseStream.Position = pointPosition; int x = pointReader.ReadInt32(); int y = pointReader.ReadInt32(); int z = pointReader.ReadInt32(); // Find min/max values of native points so far // This can be used to construct a tight box around mesh if (x < minX) { minX = x; } if (x > maxX) { maxX = x; } if (y < minY) { minY = y; } if (y > maxY) { maxY = y; } if (z < minZ) { minZ = z; } if (z > maxZ) { maxZ = z; } // Store native point values records[record].PureMesh.Planes[plane].Points[point].x = x; records[record].PureMesh.Planes[plane].Points[point].y = y; records[record].PureMesh.Planes[plane].Points[point].z = z; // Store native normal values for each vertex records[record].PureMesh.Planes[plane].Points[point].nx = nx; records[record].PureMesh.Planes[plane].Points[point].ny = ny; records[record].PureMesh.Planes[plane].Points[point].nz = nz; } // Read unknown plane data planeDataReader.BaseStream.Position = records[record].Header.PlaneDataOffset + plane * 24; records[record].PureMesh.Planes[plane].PlaneData = planeDataReader.ReadBytes(24); // Store size of mesh DFMesh.DFPoint size = new DFMesh.DFPoint(); size.X = (maxX / pointDivisor - minX / pointDivisor); size.Y = (maxY / pointDivisor - minY / pointDivisor); size.Z = (maxZ / pointDivisor - minZ / pointDivisor); records[record].PureMesh.Size = size; // Store centre of mesh DFMesh.DFPoint centre = new DFMesh.DFPoint(); centre.X = size.X / 2; centre.Y = size.Y / 2; centre.Z = size.Z / 2; records[record].PureMesh.Centre = centre; } //// Read unknown object data, but ignore known non-conforming objects //if (records[record].Header.ObjectDataCount > 0 && // records[record].ObjectId != 4722 && // records[record].ObjectId != 7614) //{ // // Create object data record array // records[record].ObjectDataRecords = new ObjectDataRecord[records[record].Header.ObjectDataCount]; // // Start reading // reader.BaseStream.Position = records[record].Header.ObjectDataOffset; // for (int i = 0; i < records[record].Header.ObjectDataCount; i++) // { // // Read object data record header // records[record].ObjectDataRecords[i].Header.N1 = reader.ReadInt32(); // records[record].ObjectDataRecords[i].Header.N2 = reader.ReadInt32(); // records[record].ObjectDataRecords[i].Header.N3 = reader.ReadInt32(); // records[record].ObjectDataRecords[i].Header.N4 = reader.ReadInt32(); // records[record].ObjectDataRecords[i].Header.SubRecordCount = reader.ReadInt16(); // // Read unknown sub-records // records[record].ObjectDataRecords[i].SubRecords = new ObjectDataSubRecord[records[record].ObjectDataRecords[i].Header.SubRecordCount]; // for (int j = 0; j < records[record].ObjectDataRecords[i].Header.SubRecordCount; j++) // { // records[record].ObjectDataRecords[i].SubRecords[j].Unknown1 = reader.ReadBytes(6); // } // } //} // Copy valid part of unique texture list into pureMesh data and create plane buffer for decomposition records[record].PureMesh.UniqueTextures = new TextureIndex[uniqueTextureCount]; for (int i = 0; i < uniqueTextureCount; i++) { records[record].PureMesh.UniqueTextures[i] = uniqueTextureBuffer[i]; subMeshBuffer[i].TextureArchive = uniqueTextureBuffer[i].Archive; subMeshBuffer[i].TextureRecord = uniqueTextureBuffer[i].Record; subMeshBuffer[i].planeCount = 0; subMeshBuffer[i].PlaneBuffer = new DFPlaneBuffer[planeBufferLength]; } return(true); }
private void LoadVertices(ref ModelData model, float scale) { const int BuildingDoors = 74; const int DungeonEnterDoors = 56; const int DungeonRuinEnterDoors = 331; const int DungeonExitDoors = 95; //const int dungeonFloorRecord = 2; // Allocate arrays model.Vertices = new Vector3[model.DFMesh.TotalVertices]; model.Normals = new Vector3[model.DFMesh.TotalVertices]; model.UVs = new Vector2[model.DFMesh.TotalVertices]; // Static door and dungeon floor lists List <ModelDoor> modelDoors = new List <ModelDoor>(); //List<DFMesh.DFPlane> dungeonFloors = new List<DFMesh.DFPlane>(); // Loop through all submeshes int vertexCount = 0; foreach (DFMesh.DFSubMesh dfSubMesh in model.DFMesh.SubMeshes) { // Get cached material data CachedMaterial cm; dfUnity.MaterialReader.GetCachedMaterial(dfSubMesh.TextureArchive, dfSubMesh.TextureRecord, 0, out cm); Vector2 sz = cm.recordSizes[0]; // Get texture archive for this submesh as base climate int submeshTextureArchive = dfSubMesh.TextureArchive; int baseTextureArchive = (submeshTextureArchive - (submeshTextureArchive / 100) * 100); // Get base climate archive for door check // All base door textures are > 100, except dungeon ruins doors int doorArchive = submeshTextureArchive; if (doorArchive > 100 && doorArchive != DungeonRuinEnterDoors) { doorArchive = baseTextureArchive; } // Check if this is a door archive bool doorFound = false; DoorTypes doorType = DoorTypes.None; switch (doorArchive) { case BuildingDoors: doorFound = true; doorType = DoorTypes.Building; break; case DungeonEnterDoors: doorFound = true; doorType = DoorTypes.DungeonEntrance; break; case DungeonRuinEnterDoors: if (dfSubMesh.TextureRecord > 0) // Dungeon ruins index 0 is just a stone texture { doorFound = true; doorType = DoorTypes.DungeonEntrance; } break; case DungeonExitDoors: doorFound = true; doorType = DoorTypes.DungeonExit; break; } //// Check if this is a dungeon floor //bool dungeonFloorFound = false; //if (baseTextureArchive >= 19 && baseTextureArchive <= 24 && dfSubMesh.TextureRecord == dungeonFloorRecord) // dungeonFloorFound = true; // Loop through all planes in this submesh int doorCount = 0; foreach (DFMesh.DFPlane dfPlane in dfSubMesh.Planes) { // If this is a door then each plane is a single door if (doorFound) { // Set door verts DFMesh.DFPoint p0 = dfPlane.Points[0]; DFMesh.DFPoint p1 = dfPlane.Points[1]; DFMesh.DFPoint p2 = dfPlane.Points[2]; ModelDoor modelDoor = new ModelDoor() { Index = doorCount++, Type = doorType, Vert0 = new Vector3(p0.X, -p0.Y, p0.Z) * scale, Vert1 = new Vector3(p1.X, -p1.Y, p1.Z) * scale, Vert2 = new Vector3(p2.X, -p2.Y, p2.Z) * scale, }; // Set door normal Vector3 u = modelDoor.Vert0 - modelDoor.Vert2; Vector3 v = modelDoor.Vert0 - modelDoor.Vert1; modelDoor.Normal = Vector3.Normalize(Vector3.Cross(u, v)); // Add door to list modelDoors.Add(modelDoor); } //// If this a floor then store the polygon //if (dungeonFloorFound) // dungeonFloors.Add(dfPlane); // Copy each point in this plane to vertex buffer foreach (DFMesh.DFPoint dfPoint in dfPlane.Points) { // Position and normal Vector3 position = new Vector3(dfPoint.X, -dfPoint.Y, dfPoint.Z) * scale; Vector3 normal = new Vector3(dfPoint.NX, -dfPoint.NY, dfPoint.NZ); // Store vertex data model.Vertices[vertexCount] = position; model.Normals[vertexCount] = Vector3.Normalize(normal); model.UVs[vertexCount] = new Vector2((dfPoint.U / sz.x), -(dfPoint.V / sz.y)); // Inrement count vertexCount++; } } } // Assign found doors model.Doors = modelDoors.ToArray(); //model.DungeonFloors = dungeonFloors.ToArray(); }