private void ReadPmd(BinaryReader r) { // specifically check if the user passed in a // pmg file by accident r.BaseStream.Position = 1; var pmgSigCheck = ReadPmgSignature(r); if(pmgSigCheck == PmgSignature) { throw new ArgumentException("Pass a pmd file, not a pmg file."); } r.BaseStream.Position = 0; var version = r.ReadUInt32(); if (version != PmdVersion) { throw new NotSupportedException($"pmd version {version} is not supported."); } var materialCount = r.ReadUInt32(); var lookCount = r.ReadUInt32(); var pieceCount = r.ReadUInt32(); var variantCount = r.ReadUInt32(); var partCount = r.ReadUInt32(); var attribsCount = r.ReadUInt32(); var attribsValuesSize = r.ReadUInt32(); var materialBlockSize = r.ReadUInt32(); var lookOffset = r.ReadUInt32(); var variantOffset = r.ReadUInt32(); var partAttribsOffset = r.ReadUInt32(); var attribsValuesOffset = r.ReadUInt32(); var attribsHeaderOffset = r.ReadUInt32(); var materialOffsetsOffset = r.ReadUInt32(); var materialDataOffset = r.ReadUInt32(); // look names Looks.Clear(); for (int i = 0; i < lookCount; i++) { Looks.Add(new Look(r.ReadToken())); } // variant names Variants.Clear(); for (int i = 0; i < variantCount; i++) { Variants.Add(new Variant(r.ReadToken())); } // "partAttribs" // TODO: what is this? for (int i = 0; i < partCount; i++) { var from = r.ReadInt32(); var to = r.ReadInt32(); } // attribs header // each variant has the same attribs for (int i = 0; i < attribsCount; i++) { var name = r.ReadToken(); var type = r.ReadInt32(); var offset = r.ReadInt32(); foreach (var variant in Variants) { var attrib = new PartAttribute(); variant.Attributes.Add(attrib); attrib.Tag = name; attrib.Type = type; } } // attribs values // TODO: Find out if there are any files where a part has // more than one attrib or if "visible" is actually the only attrib // that exists for (int i = 0; i < variantCount; i++) { for (int j = 0; j < attribsCount; j++) { Variants[i].Attributes[j].Value = r.ReadUInt32(); } } // material offsets; I think we can get away with ignoring this? var materialsOffset = new List<uint>(); for (int i = 0; i < lookCount * materialCount; i++) { materialsOffset.Add(r.ReadUInt32()); } // look material paths var materialsData = r.ReadBytes((int)materialBlockSize); var materials = StringUtils.CStringBytesToList(materialsData); for(int i = 0; i < Looks.Count; i++) { Looks[i].Materials.AddRange( materials.GetRange(i * (int)materialCount, (int)materialCount) ); } }