예제 #1
0
        private IImage ExtractEmbeddedDXT5A(byte[] bytes,
                                            HWBinaryResourceChunk chunk)
        {
            // Get raw embedded DXT5 texture from resource file
            var width  = (int)Math.Sqrt(chunk.Size * 2);
            var height = width;

            // For some godforsaken reason, every pair of bytes is flipped so we need
            // to fix it here. This was really annoying to figure out, haha.
            for (var i = 0; i < chunk.Size; i += 2)
            {
                var offset = (int)chunk.Offset + i;

                var byte0 = bytes[offset + 0];
                var byte1 = bytes[offset + 1];

                bytes[offset + 0] = byte1;
                bytes[offset + 1] = byte0;
            }

            return(DxtDecoder.DecompressDxt5a(bytes,
                                              (int)chunk.Offset,
                                              width,
                                              height));
        }
예제 #2
0
        private IImage ExtractEmbeddedDXT1(byte[] bytes,
                                           HWBinaryResourceChunk chunk)
        {
            // Decompress DXT1 texture and turn it into a Bitmap
            var width =
                BinaryUtils.ReadInt32BigEndian(bytes, (int)chunk.Offset + 4);
            var height =
                BinaryUtils.ReadInt32BigEndian(bytes, (int)chunk.Offset + 8);

            return(DxtDecoder.DecompressDXT1(bytes,
                                             (int)chunk.Offset + 16,
                                             width,
                                             height));
        }
예제 #3
0
        protected override void Load(byte[] bytes)
        {
            uint   headerSize      = BinaryUtils.ReadUInt32BigEndian(bytes, 4);
            ushort numChunks       = BinaryUtils.ReadUInt16BigEndian(bytes, 16);
            int    chunkHeaderSize = 24;

            var chunks = new HWBinaryResourceChunk[numChunks];

            for (int i = 0; i < chunks.Length; i++)
            {
                int offset = (int)headerSize + i * chunkHeaderSize;

                chunks[i] = new HWBinaryResourceChunk()
                {
                    Type = ParseChunkType(
                        BinaryUtils.ReadUInt64BigEndian(bytes, offset)),
                    Offset = BinaryUtils.ReadUInt32BigEndian(bytes, offset + 8),
                    Size   = BinaryUtils.ReadUInt32BigEndian(bytes, offset + 12)
                };
            }

            this.Chunks = chunks;
        }
예제 #4
0
        private IModel ImportMesh(byte[] bytes)
        {
            int stride = 1;
            MeshNormalExportMode shadingMode = MeshNormalExportMode.Unchanged;

            HWBinaryResourceChunk headerChunk =
                GetFirstChunkOfType(HWBinaryResourceChunkType.XTD_XTDHeader);
            float tileScale =
                BinaryUtils.ReadFloatBigEndian(bytes,
                                               (int)headerChunk.Offset + 12);
            HWBinaryResourceChunk atlasChunk =
                GetFirstChunkOfType(HWBinaryResourceChunkType.XTD_AtlasChunk);

            int gridSize =
                (int)Math.Round(Math.Sqrt((atlasChunk.Size - 32) /
                                          8)); // Subtract the min/range vector sizes, divide by position + normal size, and sqrt for grid size
            int positionOffset = (int)atlasChunk.Offset + 32;
            int normalOffset   = positionOffset + gridSize * gridSize * 4;

            if (gridSize % stride != 0)
            {
                throw new Exception(
                          $"Grid size {gridSize} is not evenly divisible by stride {stride} - choose a different stride value.");
            }

            // These are stored as ZYX, 4 bytes per component
            Vector3 PosCompMin = BinaryUtils
                                 .ReadVector3BigEndian(
                bytes, (int)atlasChunk.Offset)
                                 .ReverseComponents();
            Vector3 PosCompRange =
                BinaryUtils
                .ReadVector3BigEndian(bytes, (int)atlasChunk.Offset + 16)
                .ReverseComponents();

            var finModel = new ModelImpl(gridSize * gridSize);
            var finMesh  = finModel.Skin.AddMesh();

            var finVertices = new IVertex[gridSize * gridSize];

            // Read vertex offsets/normals and add them to the mesh
            for (int x = 0; x < gridSize; x += stride)
            {
                for (int z = 0; z < gridSize; z += stride)
                {
                    int index =
                        ConvertGridPositionToIndex(new Tuple <int, int>(x, z), gridSize);
                    int offset = index * 4;


                    // Get offset position and normal for this vertex
                    Vector3 position =
                        ReadVector3Compressed(bytes, positionOffset + offset) *
                        PosCompRange -
                        PosCompMin;

                    // Positions are relative to the terrain grid, so shift them by the grid position
                    position += new Vector3(x, 0, z) * tileScale;

                    Vector3 normal =
                        ConvertDirectionVector(
                            Vector3.Normalize(
                                ReadVector3Compressed(bytes, normalOffset + offset) *
                                2.0f -
                                Vector3.One));

                    // Simple UV based on original, non-warped terrain grid
                    Vector3 texCoord = new Vector3(x / ((float)gridSize - 1),
                                                   z / ((float)gridSize - 1), 0);

                    var finVertex =
                        finModel.Skin
                        .AddVertex(position.X, position.Y, position.Z)
                        .SetLocalNormal(normal.X, normal.Y, normal.Z)
                        .SetUv(texCoord.X, texCoord.Y);
                    finVertices[GetVertexIndex(x, z, gridSize)] = finVertex;
                }
            }

            // Generate faces based on terrain grid
            for (int x = 0; x < gridSize - stride; x += stride)
            {
                var triangles = new List <(IVertex, IVertex, IVertex)>();

                for (int z = 0; z < gridSize - stride; z += stride)
                {
                    var a = finVertices[GetVertexIndex(x, z, gridSize)];
                    var b = finVertices[GetVertexIndex(x + stride, z, gridSize)];
                    var c = finVertices[GetVertexIndex(x, z + stride, gridSize)];
                    var d = finVertices[GetVertexIndex(x + stride, z + stride, gridSize)];

                    triangles.Add((a, b, c));
                    triangles.Add((d, c, b));
                }

                finMesh.AddTriangles(triangles.ToArray());
                triangles.Clear();
            }

            return(finModel);
        }