コード例 #1
0
        /// <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);
        }
コード例 #2
0
        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();
        }