Beispiel #1
0
        public static LmNodeInfo Unpack(LmMsgPck msg)
        {
            var matrix = LmMatrix.Unpack(msg);
            var name   = msg.ReadString();

            return(new LmNodeInfo(matrix, name));
        }
Beispiel #2
0
        public static LmAABB Unpack(LmMsgPck msg)
        {
            var min = LmVector3.Unpack(msg);
            var max = LmVector3.Unpack(msg);

            return(new LmAABB(min, max));
        }
Beispiel #3
0
        // Converts .json file from parsing arguments into...
        // TODO: Refactor to remove references to fbx files as they are no
        // longer a part of the Luminaire workflow.
        private static void ConvertFile(string gfxbin, string gpubin)
        {
            DefaultPrintFunction.SetDefaultPrintFunction(Console.WriteLine);

            var readData       = File.ReadAllBytes(gfxbin);
            var gpubinReadData = File.ReadAllBytes(gpubin);

            // TODO don't hardcode
            var dependencies = new Dictionary <string, byte[]>
            {
                { /* "data://character/nh/nh00/model_010/nh00_010.gpubin"*/ gpubin, gpubinReadData }
            };

            var unpackContext = new LmGfxBinUnpackContext
            {
                // Shorthand initialization for auto-implemented properties
                GpuBuffer = gpubinReadData // TODO don't hardcode
            };

            var msgPck = new LmMsgPck(readData, unpackContext);

            var gmtlLoader = new LmGfxBinMaterialAssetLoader();
            var gmdlLoader = new LmGfxBinAssetLoader();

            // After tracing this dependencies variable as its passed through
            // various functions, it seems that the dictionary isn't actually
            // used anywhere. The reference in the deepest level of function
            // calls the place where this variable is used is commented out.
            gmdlLoader.BuildDependencyTable(unpackContext, msgPck, dependencies);
            var modelResourceNode = LmGfxBinAssetLoader.Convert(msgPck);

            var fbx = gpubin.Replace(gpubinExtension, fbxExtension);

            GmdlUnityAssetConverter.Convert(modelResourceNode, gfxbin, "");
        }
Beispiel #4
0
        public static LmBoneInfo Unpack(LmMsgPck msg)
        {
            var name = msg.ReadString();
            var id   = msg.Read();

            uint unboxedId;

            if (id is ushort x)
            {
                unboxedId = x;
            }
            else
            {
                unboxedId = (uint)id;
            }

            if (msg.Version < 20160407)
            {
                return(new LmBoneInfo(name, unboxedId, 0xFFFFu));
            }
            else
            {
                return(new LmBoneInfo(name, unboxedId, unboxedId >> 16));
            }
        }
Beispiel #5
0
        public static LmBoneTable Unpack(LmMsgPck msg)
        {
            // i_shaderInfo is seemingly always empty
            var instanceNameFormat = msg.ReadByte();

            Debug.Assert((byte)instanceNameFormat == (byte)LmPackFormat.FixStrStart);

            var shaderClassFormat = msg.ReadByte();

            Debug.Assert((byte)shaderClassFormat == (byte)LmPackFormat.FixStrStart);

            var shaderSamplerDescFormat = msg.ReadByte();

            Debug.Assert((byte)shaderSamplerDescFormat == (byte)LmPackFormat.FixArrayStart);

            var shaderParametersListFormat = msg.ReadByte();

            Debug.Assert((byte)shaderParametersListFormat == (byte)LmPackFormat.FixArrayStart);

            var childClassesFormat = msg.ReadByte();

            Debug.Assert((byte)childClassesFormat == (byte)LmPackFormat.FixArrayStart);

            var result    = new LmBoneTable();
            var boneCount = msg.ReadUint();

            for (var _ = 0; _ < boneCount; _++)
            {
                var boneInfo = LmBoneInfo.Unpack(msg);
                result.BoneInfos.Add(boneInfo);
            }

            return(result);
        }
Beispiel #6
0
        public static LmVertexStreamDesc Unpack(LmMsgPck msg)
        {
            var slot = (LmEVertexStreamSlot)msg.ReadUint();
            var type = (LmEVertexStreamType)msg.ReadUint();
            var desc = LmStructuredVertexBufferDesc.Unpack(msg);

            return(new LmVertexStreamDesc(slot, type, desc));
        }
Beispiel #7
0
        public static LmVertexElementDesc Unpack(LmMsgPck msg)
        {
            var offset   = msg.ReadUint();
            var semantic = msg.ReadString();
            var format   = (LmEVertexElementFormat)msg.ReadUint();

            return(new LmVertexElementDesc(offset, semantic, format));
        }
Beispiel #8
0
        public static GmdlMeshPartsData Unpack(LmMsgPck msg)
        {
            var partsId    = msg.ReadInt();
            var startIndex = msg.ReadInt();
            var indexCount = msg.ReadInt();

            return(new GmdlMeshPartsData(partsId, startIndex, indexCount));
        }
Beispiel #9
0
        public static LmVector3 Unpack(LmMsgPck msg)
        {
            var x = msg.ReadFloat();
            var y = msg.ReadFloat();
            var z = msg.ReadFloat();

            return(new LmVector3(x, y, z));
        }
Beispiel #10
0
        public static GmdlPartsData Unpack(LmMsgPck msg)
        {
            var name = msg.ReadString();
            var id   = msg.ReadUint();
            var str  = msg.ReadString();
            var flag = msg.ReadBool();

            return(new GmdlPartsData(name, id, flag));
        }
Beispiel #11
0
        public static LmOrientedBB Unpack(LmMsgPck msg)
        {
            var center      = LmVector3.Unpack(msg);
            var xHalfExtent = LmVector3.Unpack(msg);
            var yHalfExtent = LmVector3.Unpack(msg);
            var zHalfExtent = LmVector3.Unpack(msg);

            return(new LmOrientedBB(center, xHalfExtent, yHalfExtent, zHalfExtent));
        }
Beispiel #12
0
        public static LmMatrix Unpack(LmMsgPck msg)
        {
            var row0 = LmVector3.Unpack(msg);
            var row1 = LmVector3.Unpack(msg);
            var row2 = LmVector3.Unpack(msg);
            var row3 = LmVector3.Unpack(msg);

            return(new LmMatrix(row0, row1, row2, row3));
        }
Beispiel #13
0
        public static LmSubGeometry Unpack(LmMsgPck msg)
        {
            var aabb              = LmAABB.Unpack(msg);
            var startIdx          = msg.ReadUint();
            var primCount         = msg.ReadUint();
            var clusterIdxBitFlag = msg.ReadUint();
            var drawOrder         = msg.ReadUint();

            return(new LmSubGeometry(aabb, startIdx, primCount, clusterIdxBitFlag, drawOrder));
        }
Beispiel #14
0
        public static LmVertexStreamGroupDesc Unpack(LmMsgPck msg)
        {
            var result = new LmVertexStreamGroupDesc();
            var count  = msg.ReadUint();

            for (var _ = 0; _ < count; _++)
            {
                var desc = LmVertexStreamDesc.Unpack(msg);
                result.VtxStreamDescs.Add(desc);
            }

            return(result);
        }
Beispiel #15
0
        public static LmNodeTable Unpack(LmMsgPck msg)
        {
            var result = new LmNodeTable();

            var nodeCount = msg.ReadUint();

            for (var _ = 0; _ < nodeCount; _++)
            {
                var nodeInfo = LmNodeInfo.Unpack(msg);
                result.NodeInfos.Add(nodeInfo);
            }

            return(result);
        }
Beispiel #16
0
        public static LmStructuredVertexBufferDesc Unpack(LmMsgPck msg)
        {
            var stride      = msg.ReadUint();
            var startOffset = msg.ReadUint();
            var result      = new LmStructuredVertexBufferDesc(stride, startOffset);

            var elementCount = msg.ReadUint();

            for (var _ = 0; _ < elementCount; _++)
            {
                var desc = LmVertexElementDesc.Unpack(msg);
                result.VtxElementDescs.Add(desc);
            }

            return(result);
        }
Beispiel #17
0
        // This function takes a gmtl file name as input and converts to
        // contents of that file to json format. It then writes that json
        // to a file in the same directory as the input file. The output
        // file will have the same name as the input file but with the
        // .json extension.
        private static void ConvertMaterial(string gfxbin)
        {
            DefaultPrintFunction.SetDefaultPrintFunction(Console.WriteLine);
            // Reads contents of gfxbin file (which is binary) into a
            // bytearray. This implies that readData is a byte[].
            var readData = File.ReadAllBytes(gfxbin);

            var unpackContext = new LmGfxBinUnpackContext();
            var msgPck        = new LmMsgPck(readData, unpackContext);

            // Loads the unpacked message data into a MaterialGmtl.
            var gmtlLoader = new LmGfxBinMaterialAssetLoader();
            var gmtl       = gmtlLoader.Initialize(unpackContext, msgPck, null);

            // Make a string for the file path of the input file, but with
            // a .json file extension. The output file should be stored in
            // the same directory as the input file.
            var jsonPath = gfxbin.Replace(gmtlExtension, "json");

            JsonConvert.Convert(gmtl, jsonPath);
        }
Beispiel #18
0
        public static MeshContainer Convert(LmMsgPck pck)
        {
            var name   = pck.ReadString();
            var result = new MeshContainer(name);

            var clusterCount = pck.Read();

            Debug.Assert((int)clusterCount == 1);

            // Where are these stored? Seemingly nowhere?
            var clusterName = pck.ReadString();

            var meshCount = pck.ReadUint();

            for (var _ = 0; _ < meshCount; _++)
            {
                var mesh = Mesh.Convert(pck);
                result.Meshes.Add(mesh);
            }

            // TODO Setup
            return(result);
        }
Beispiel #19
0
        public static LmBoneIdTable Unpack(LmMsgPck msg)
        {
            var result      = new LmBoneIdTable();
            var boneIdCount = msg.ReadUint();

            for (var _ = 0; _ < boneIdCount; _++)
            {
                var boneId = msg.Read();
                if (boneId is byte x)
                {
                    result.BoneIds.Add(x);
                }
                else if (boneId is ushort y)
                {
                    result.BoneIds.Add(y);
                }
                else
                {
                    result.BoneIds.Add((uint)boneId);
                }
            }

            return(result);
        }
Beispiel #20
0
        public static Mesh Convert(LmMsgPck msg)
        {
            var name             = msg.ReadString();
            var u0               = msg.ReadByte();
            var boneIdTable      = LmBoneIdTable.Unpack(msg);
            var vertexLayoutType = (VertexLayoutType)msg.ReadInt();
            var geometry         = LmGeometry.Unpack(msg);

            var mesh = new Mesh(name, geometry);

            mesh.Setup(geometry);

            // TODO get Material
            var defaultMaterialHash = msg.ReadUint64();

            var gmdlMeshData = new GmdlMeshData();

            mesh.GmdlMeshData = gmdlMeshData;

            if (msg.Version >= 20140623)
            {
                gmdlMeshData.DrawPriorityOffset = msg.ReadInt();
                if (msg.ReadBool())
                {
                    gmdlMeshData.Flags |= 1;
                }

                if (msg.ReadBool())
                {
                    gmdlMeshData.Flags |= 2;
                }

                gmdlMeshData.LodNear = msg.ReadFloat();
                gmdlMeshData.LodFar  = msg.ReadFloat();
                gmdlMeshData.LodFade = msg.ReadFloat();

                if (gmdlMeshData.LodNear < gmdlMeshData.LodFar && (gmdlMeshData.LodNear > 0.0 || gmdlMeshData.LodFar < 3.4028235e38))
                {
                    gmdlMeshData.Flags |= 4u;
                }

                if (gmdlMeshData.LodFade > 0.0)
                {
                    gmdlMeshData.Flags |= 0x100u;
                }
            }

            if (msg.Version >= 20140814)
            {
                msg.ReadBool();
            }

            if (msg.Version >= 20141112 && msg.ReadBool())
            {
                gmdlMeshData.Flags |= 0x10u;
            }

            if (msg.Version >= 20140815)
            {
                gmdlMeshData.PartsId = msg.ReadUint();
            }

            if (msg.Version >= 20141115)
            {
                var gmdlMeshPartsDataCount = msg.ReadInt();
                for (var _ = 0; _ < gmdlMeshPartsDataCount; _++)
                {
                    var gmdlMeshPartData = GmdlMeshPartsData.Unpack(msg);
                    gmdlMeshData.GmdlMeshPartsDatas.Add(gmdlMeshPartData);
                }
            }

            if (msg.Version >= 20150413 && msg.ReadBool())
            {
                gmdlMeshData.Flags |= 0x20u;
            }

            if (msg.Version >= 20150430)
            {
                var flag = msg.ReadUint();
                if (msg.Version < 20151217)
                {
                    gmdlMeshData.Flags |= 0x200u;
                    if (boneIdTable.BoneIds.Count == 0)
                    {
                        gmdlMeshData.Flags |= 0x400u;
                    }
                }

                gmdlMeshData.Flags |= flag;
            }

            if (msg.Version >= 20150512 && msg.ReadBool())
            {
                gmdlMeshData.Flags |= 0x80u;
            }

            if (msg.Version < 20160420)
            {
                gmdlMeshData.BreakableBoneIndex    = 0xFFFFFFFF;
                gmdlMeshData.LowLodShadowCascadeNo = 2;
            }
            else
            {
                gmdlMeshData.BreakableBoneIndex    = msg.ReadUint();
                gmdlMeshData.LowLodShadowCascadeNo = (sbyte)msg.ReadUint();
            }

            gmdlMeshData.VertexLayoutType = vertexLayoutType;
            if ((gmdlMeshData.Flags & 0x80000) != 0)
            {
                var unk0 = msg.ReadBool();
                var unk1 = msg.ReadUint();
                var unk2 = msg.ReadUint();
            }

            // TODO SetupMeshLod

            return(mesh);
        }
Beispiel #21
0
        public static LmGeometry Unpack(LmMsgPck msg)
        {
            // Probably an unnecessary isOBB check
            var bValue1  = msg.Read();
            var geometry = new LmGeometry
            {
                AABB = LmAABB.Unpack(msg)
            };

            if (msg.Version >= 20160705)
            {
                var isOBB = (bool)msg.Read();
                Debug.Assert(isOBB);

                geometry.OBB = LmOrientedBB.Unpack(msg);
            }

            geometry.PrimType = (LmEPrimitiveType)msg.ReadByte();
            geometry.IdxNum   = msg.ReadUint();
            geometry.IdxType  = (LmEIndexType)msg.ReadByte();

            if (msg.Version < 20141113)
            {
                Debug.Fail("Unsupported version");
            }

            var idxBufferOffset = msg.ReadUint();

            geometry.IdxBufferSize = msg.ReadUint();
            geometry.IdxBuffer     = new int[geometry.IdxNum];

            for (var i = 0; i < geometry.IdxNum; i++)
            {
                if (geometry.IdxType == LmEIndexType.IndexType32)
                {
                    geometry.IdxBuffer[i] = BitConverter.ToInt32(msg.UserData.GpuBuffer, (int)idxBufferOffset + (4 * i));
                }
                else if (geometry.IdxType == LmEIndexType.IndexType16)
                {
                    geometry.IdxBuffer[i] = BitConverter.ToInt16(msg.UserData.GpuBuffer, (int)idxBufferOffset + (2 * i));
                }
                else
                {
                    Debug.Fail("Unsupported index type");
                }
            }

            geometry.VtxNum             = msg.ReadUint();
            geometry.VtxStreamGroupDesc = LmVertexStreamGroupDesc.Unpack(msg);

            var vtxBufferOffset = msg.ReadUint();

            geometry.VtxBufferSize = msg.ReadUint();

            geometry.VtxBuffer = new byte[geometry.VtxBufferSize];
            Array.Copy(msg.UserData.GpuBuffer, (int)vtxBufferOffset, geometry.VtxBuffer, 0, (int)geometry.VtxBufferSize);

            if (msg.Version < 20150413)
            {
                geometry.InstanceNum = 0;
            }
            else
            {
                geometry.InstanceNum = msg.ReadUint();
                //var instanceNumOffset = msg.ReadUint();
                //var unknown = (float)msg.Read();
                //geometry.InstanceBuffer = new ArraySegment<byte>(msg.UserData.GpuBuffer, (int)instanceNumOffset, (int)unknown);
            }

            // TODO subgeometries
            var subgeometryCount = msg.ReadUint();

            for (var _ = 0; _ < subgeometryCount; _++)
            {
                geometry.SubGeometries.Add(LmSubGeometry.Unpack(msg));
            }

            return(geometry);
        }
Beispiel #22
0
        public static MaterialGmtl Unpack(LmMsgPck msg)
        {
            var reflectionMaterial = new ReflectionMaterial();

            msg.UnpackUInt64(out ulong materialName);

            msg.UnpackUInt16(out ushort matUniformCount);
            msg.UnpackUInt16(out ushort matBufferCount);
            msg.UnpackUInt16(out ushort matTextureCount);
            msg.UnpackUInt16(out ushort matSamplerCount);
            msg.UnpackUInt16(out ushort totalUniformCount);
            msg.UnpackUInt16(out ushort totalBufferCount);
            msg.UnpackUInt16(out ushort totalTextureCount);

            msg.UnpackUInt16(out ushort totalSamplerCount);
            msg.UnpackUInt16(out ushort shaderBinaryCount);
            msg.UnpackUInt16(out ushort shaderProgramCount);

            msg.UnpackUInt32(out uint gpuDataSize);
            msg.UnpackUInt32(out uint stringBufferSize);
            msg.UnpackUInt32(out uint hashMaterialName);
            msg.UnpackUInt32(out uint blendType);

            msg.UnpackFloat32(out float blendFactor);

            msg.UnpackUInt32(out uint renderStateBits);
            msg.UnpackUInt16(out ushort skinVsMaxBoneCount);
            msg.UnpackUInt16(out ushort brdfType);

            reflectionMaterial.MaterialNameOffset = materialName;
            reflectionMaterial.MatUniformCount    = matUniformCount;
            reflectionMaterial.MatBufferCount     = matBufferCount;
            reflectionMaterial.MatTextureCount    = matTextureCount;
            reflectionMaterial.MatSamplerCount    = matSamplerCount;
            reflectionMaterial.TotalUniformCount  = totalUniformCount;
            reflectionMaterial.TotalBufferCount   = totalBufferCount;
            reflectionMaterial.TotalTextureCount  = totalTextureCount;
            reflectionMaterial.TotalSamplerCount  = totalSamplerCount;
            reflectionMaterial.ShaderBinaryCount  = shaderBinaryCount;
            reflectionMaterial.ShaderProgramCount = shaderProgramCount;
            reflectionMaterial.GpuDataSize        = gpuDataSize;
            reflectionMaterial.StringBufferSize   = stringBufferSize;
            reflectionMaterial.HashMaterialName   = hashMaterialName;
            reflectionMaterial.BlendType          = blendType;
            reflectionMaterial.BlendFactor        = blendFactor;
            reflectionMaterial.RenderStateBits    = renderStateBits;
            reflectionMaterial.SkinVsMaxBoneCount = skinVsMaxBoneCount;
            reflectionMaterial.BrdfType           = brdfType;

            if (msg.Version >= 20150403)
            {
                msg.UnpackUInt16(out ushort highTexturePackAssetId);
                reflectionMaterial.HighTexturePackAssetIdOffset = highTexturePackAssetId;
            }

            for (var _ = 0; _ < totalUniformCount; _++)
            {
                msg.UnpackUInt64(out ulong name);
                msg.UnpackUInt64(out ulong shaderGenName);
                msg.UnpackUInt32(out uint hashName);
                msg.UnpackUInt32(out uint hashShaderGenName);
                msg.UnpackUInt16(out ushort offset);
                msg.UnpackUInt16(out ushort size);
                msg.UnpackUInt16(out ushort bufferIndex);
                msg.UnpackUInt16(out ushort type);
                msg.UnpackUInt32(out uint flags);

                reflectionMaterial.Uniforms.Add(new ReflectionUniform(name, shaderGenName, hashName, hashShaderGenName, offset, size, bufferIndex, type, flags));
            }

            for (var _ = 0; _ < totalBufferCount; _++)
            {
                msg.UnpackUInt64(out ulong name);
                msg.UnpackUInt64(out ulong shaderGenName);
                msg.UnpackUInt64(out ulong u1);
                msg.UnpackUInt32(out uint hashName);
                msg.UnpackUInt32(out uint hashShaderGenName);
                msg.UnpackUInt32(out uint u2);
                msg.UnpackUInt32(out uint gpuOffset);
                msg.UnpackUInt16(out ushort size);
                msg.UnpackUInt16(out ushort uniformCount);
                msg.UnpackUInt32(out uint flags);

                reflectionMaterial.UniformBuffers.Add(new ReflectionUniformBuffer(name, shaderGenName, hashName, hashShaderGenName, gpuOffset, size, uniformCount, flags));
            }

            for (var _ = 0; _ < totalTextureCount; _++)
            {
                msg.UnpackUInt64(out ulong resourceFileHash);
                msg.UnpackUInt64(out ulong name);
                msg.UnpackUInt64(out ulong shaderGenName);
                msg.UnpackUInt64(out ulong u1);
                msg.UnpackUInt64(out ulong path);
                msg.UnpackUInt32(out uint hashName);
                msg.UnpackUInt32(out uint hashShaderGenName);
                msg.UnpackUInt32(out uint u2);
                msg.UnpackUInt32(out uint hashPath);
                msg.UnpackUInt32(out uint flags);

                sbyte highTextureStreamingLevels = -1;
                if (msg.Version > 20150508)
                {
                    msg.UnpackInt8(out highTextureStreamingLevels);
                }

                reflectionMaterial.Textures.Add(new ReflectionTexture(resourceFileHash, name, shaderGenName, path, hashName, hashShaderGenName, hashPath, flags, highTextureStreamingLevels));
            }

            var material = new MaterialGmtl();

            material.Reflection = reflectionMaterial;
            for (var _ = 0; _ < totalSamplerCount; _++)
            {
                msg.UnpackUInt64(out ulong reflectionSamplerName);
                msg.UnpackUInt64(out ulong reflectionSamplerShaderGenName);
                msg.UnpackUInt64(out ulong u1); // reflectionSamplerHashName?
                msg.UnpackInt8(out sbyte samplerStateMagFilter);

                msg.UnpackInt8(out sbyte samplerStateMinFilter);
                msg.UnpackInt8(out sbyte samplerStateMipFilter);
                msg.UnpackInt8(out sbyte samplerStateWrapS);
                msg.UnpackInt8(out sbyte samplerStateWrapT);
                msg.UnpackInt8(out sbyte samplerStateWrapR);

                msg.UnpackFloat32(out float mipmapLodBias);
                msg.UnpackInt8(out sbyte maxAniso);

                msg.UnpackInt8(out sbyte u2);
                msg.UnpackInt8(out sbyte u3);
                msg.UnpackInt8(out sbyte u4);

                // BorderColor shenanigans
                msg.UnpackFloat32(out float ur);
                msg.UnpackFloat32(out float ug);
                msg.UnpackFloat32(out float ub);
                msg.UnpackFloat32(out float ua);

                msg.UnpackUInt16(out ushort minLod);
                msg.UnpackUInt16(out ushort maxLod);

                msg.UnpackUInt32(out uint reflectionSamplerFlags);

                // TODO a bunch of bit twiddling for borderColor

                var minLodBytes  = BitConverter.GetBytes(minLod);
                var minLoadFloat = Half.ToHalf(minLodBytes, 0);

                var maxLodBytes  = BitConverter.GetBytes(maxLod);
                var maxLoadFloat = Half.ToHalf(maxLodBytes, 0);

                reflectionMaterial.Samplers.Add(new ReflectionSampler(reflectionSamplerName, reflectionSamplerShaderGenName, 0, 0, reflectionSamplerFlags));
                material.Samplers.Add(new SamplerState(mipmapLodBias, new Color4B(0xFFFFFFFF), samplerStateWrapS, samplerStateWrapT, samplerStateWrapR, minLoadFloat, maxLoadFloat, maxAniso, samplerStateMinFilter, samplerStateMagFilter, samplerStateMipFilter, 0));
            }

            for (var _ = 0; _ < shaderBinaryCount; _++)
            {
                msg.UnpackUInt64(out ulong resourceFileHash);
                msg.UnpackUInt64(out ulong path);

                reflectionMaterial.ShaderBinaries.Add(new ReflectionShaderBinary(resourceFileHash, path));
            }

            for (var _ = 0; _ < shaderProgramCount; _++)
            {
                msg.UnpackUInt16(out ushort lowKey);
                msg.UnpackUInt16(out ushort highKey);
                msg.UnpackUInt16(out ushort csBinaryIndex);
                msg.UnpackUInt16(out ushort vsBinaryIndex);
                msg.UnpackUInt16(out ushort hsBinaryIndex);
                msg.UnpackUInt16(out ushort dsBinaryIndex);
                msg.UnpackUInt16(out ushort gsBinaryIndex);
                msg.UnpackUInt16(out ushort psBinaryIndex);

                reflectionMaterial.ShaderPrograms.Add(new ReflectionShaderProgram(lowKey, highKey, csBinaryIndex, vsBinaryIndex, hsBinaryIndex, dsBinaryIndex, gsBinaryIndex, psBinaryIndex));
            }

            if (gpuDataSize > 0)
            {
                msg.UnpackBlob(out byte[] gpuData, out gpuDataSize);
                reflectionMaterial.GpuData = gpuData;
            }

            if (stringBufferSize > 0)
            {
                msg.UnpackBlob(out byte[] stringBuffer, out stringBufferSize);
                reflectionMaterial.StringBuffer = stringBuffer;
            }

            // Read strings
            reflectionMaterial.MaterialName = reflectionMaterial.GetStringFromBuffer((int)reflectionMaterial.MaterialNameOffset);

            foreach (var reflectionUniform in reflectionMaterial.Uniforms)
            {
                reflectionUniform.Name          = reflectionMaterial.GetStringFromBuffer((int)reflectionUniform.NameOffset);
                reflectionUniform.ShaderGenName = reflectionMaterial.GetStringFromBuffer((int)reflectionUniform.ShaderGenNameOffset);
            }

            foreach (var uniformBuffer in reflectionMaterial.UniformBuffers)
            {
                uniformBuffer.Name          = reflectionMaterial.GetStringFromBuffer((int)uniformBuffer.NameOffset);
                uniformBuffer.ShaderGenName = reflectionMaterial.GetStringFromBuffer((int)uniformBuffer.ShaderGenNameOffset);
            }

            foreach (var texture in reflectionMaterial.Textures)
            {
                texture.Name          = reflectionMaterial.GetStringFromBuffer((int)texture.NameOffset);
                texture.ShaderGenName = reflectionMaterial.GetStringFromBuffer((int)texture.ShaderGenNameOffset);
                texture.Path          = reflectionMaterial.GetStringFromBuffer((int)texture.PathOffset);
            }

            foreach (var sampler in reflectionMaterial.Samplers)
            {
                sampler.Name          = reflectionMaterial.GetStringFromBuffer((int)sampler.NameOffset);
                sampler.ShaderGenName = reflectionMaterial.GetStringFromBuffer((int)sampler.ShaderGenNameOffset);
            }

            foreach (var shaderBinary in reflectionMaterial.ShaderBinaries)
            {
                shaderBinary.Path = reflectionMaterial.GetStringFromBuffer((int)shaderBinary.PathOffset);
            }

            if (reflectionMaterial.HighTexturePackAssetIdOffset != 0)
            {
                reflectionMaterial.HighTexturePackAssetId = reflectionMaterial.GetStringFromBuffer((int)reflectionMaterial.HighTexturePackAssetIdOffset);
            }

            return(material);
        }