internal static DebugShaderVariable Parse(DebugBytecodeReader reader,
                                                  DebugBytecodeReader variableReader, DebugShaderVersion target, bool isFirst)
        {
            uint nameOffset = variableReader.ReadUInt32("nameOffset");
            var  nameReader = reader.CopyAtOffset("nameReader", variableReader, (int)nameOffset);
            var  name       = nameReader.ReadString("name");

            var  startOffset = variableReader.ReadUInt32("startOffset");
            uint size        = variableReader.ReadUInt32("size");
            var  flags       = variableReader.ReadEnum32 <ShaderVariableFlags>("flags");

            var typeOffset = variableReader.ReadUInt32("typeOffset");
            var typeReader = reader.CopyAtOffset("typeReader", variableReader, (int)typeOffset);
            var shaderType = DebugShaderType.Parse(reader, typeReader, target, 2, isFirst, startOffset);

            var           defaultValueOffset = variableReader.ReadUInt32("defaultValueOffset");
            List <Number> defaultValue       = null;

            if (defaultValueOffset != 0)
            {
                defaultValue = new List <Number>();
                var defaultValueReader = reader.CopyAtOffset("defaultValueReader", variableReader, (int)defaultValueOffset);
                if (size % 4 != 0)
                {
                    throw new ParseException("Can only deal with 4-byte default values at the moment.");
                }
                for (int i = 0; i < size; i += 4)
                {
                    defaultValue.Add(new Number(defaultValueReader.ReadBytes($"defaultValue{i}", 4)));
                }
            }


            var result = new DebugShaderVariable
            {
                DefaultValue = defaultValue,
                Member       = new DebugShaderTypeMember(0)
                {
                    Name   = name,
                    Offset = startOffset,
                    Type   = shaderType
                },
                BaseType = name,
                Size     = size,
                Flags    = flags
            };

            if (target.MajorVersion >= 5 || target.ProgramType == ProgramType.LibraryShader)
            {
                result.StartTexture = variableReader.ReadInt32("startTexture");
                result.TextureSize  = variableReader.ReadInt32("textureSize");
                result.StartSampler = variableReader.ReadInt32("startSampler");
                result.SamplerSize  = variableReader.ReadInt32("samplerSize");
            }

            return(result);
        }
        public static DebugShaderType Parse(DebugBytecodeReader reader, DebugBytecodeReader typeReader, DebugShaderVersion target,
                                            int indent, bool isFirst, uint parentOffset)
        {
            var result = new DebugShaderType(indent, isFirst)
            {
                VariableClass = typeReader.ReadEnum16 <ShaderVariableClass>("VariableClass"),
                VariableType  = typeReader.ReadEnum16 <ShaderVariableType>("VariableType"),
                Rows          = typeReader.ReadUInt16("Rows"),
                Columns       = typeReader.ReadUInt16("Columns"),
                ElementCount  = typeReader.ReadUInt16("ElementCount")
            };

            var memberCount  = typeReader.ReadUInt16("memberCount");
            var memberOffset = typeReader.ReadUInt32("memberOffset");

            if (target.MajorVersion >= 5)
            {
                var subTypeOffset = typeReader.ReadInt32("subTypeOffset");                 // Guessing
                if (subTypeOffset != 0)
                {
                    var parentInterfaceReader = reader.CopyAtOffset("subtypeReader", typeReader, (int)subTypeOffset);
                    result.SubType = DebugShaderType.Parse(reader, parentInterfaceReader, target,
                                                           indent + 4, true, parentOffset);
                }

                var baseClassOffset = typeReader.ReadUInt32("baseClassOffset");
                if (baseClassOffset != 0)
                {
                    var baseClassReader = reader.CopyAtOffset("baseClassReader", typeReader, (int)baseClassOffset);
                    result.BaseClass = DebugShaderType.Parse(reader, baseClassReader, target,
                                                             indent + 4, true, parentOffset);
                }

                result.NumberOfInterfaces = typeReader.ReadUInt32("NumberOfInterfaces");

                var interfaceSectionOffset = typeReader.ReadUInt32("InterfaceSectionOffset");
                if (interfaceSectionOffset != 0)
                {
                    var interfaceSectionReader = reader.CopyAtOffset("interfaceSectionReader", typeReader, (int)interfaceSectionOffset);
                    for (int i = 0; i < result.NumberOfInterfaces; i++)
                    {
                        var interfaceTypeOffset = interfaceSectionReader.ReadUInt32($"UnkInterface{i}");
                        var interfaceReader     = reader.CopyAtOffset($"InterfaceReader {i}", typeReader, (int)interfaceTypeOffset);
                        result.Interfaces.Add(DebugShaderType.Parse(reader, interfaceReader,
                                                                    target, indent + 4, i == 0, parentOffset));
                    }
                }

                var parentNameOffset = typeReader.ReadUInt32("parentNameOffset");
                if (parentNameOffset > 0)
                {
                    var parentNameReader = reader.CopyAtOffset("parentNameOffset", typeReader, (int)parentNameOffset);
                    result.BaseTypeName = parentNameReader.ReadString("BaseTypeName");
                }
            }

            if (memberCount > 0)
            {
                var memberReader = reader.CopyAtOffset("memberReader", typeReader, (int)memberOffset);
                for (int i = 0; i < memberCount; i++)
                {
                    memberReader.AddIndent($"Member {i}");
                    result.Members.Add(DebugShaderTypeMember.Parse(reader, memberReader, target, indent + 4, i == 0,
                                                                   parentOffset));
                    memberReader.RemoveIndent();
                }
            }

            if (target.ProgramType == ProgramType.LibraryShader && target.MajorVersion == 4)
            {
                var unk1           = typeReader.ReadUInt32("Unk1");
                var unk2           = typeReader.ReadUInt32("Unk2");
                var unk3           = typeReader.ReadUInt32("Unk3");
                var unk4           = typeReader.ReadUInt32("Unk4");
                var typeNameOffset = typeReader.ReadUInt32("typeNameoffset");
                var typeNameReader = reader.CopyAtOffset("TypeNameReader", typeReader, (int)typeNameOffset);
                typeNameReader.ReadString("TypeName");
                Debug.Assert(unk1 == 0, $"ShaderType.Unk1={unk1}");
                Debug.Assert(unk2 == 0, $"ShaderType.Unk2={unk2}");
                Debug.Assert(unk3 == 0, $"ShaderType.Unk3={unk3}");
                Debug.Assert(unk4 == 0, $"ShaderType.Unk4={unk4}");
            }

            return(result);
        }