/// <summary> /// Deserializes file data from a stream. /// </summary> protected override void Read(BinaryReaderEx br) { br.BigEndian = false; Version = br.ReadEnum32 <CCMVer>(); if (Version == CCMVer.DemonsSouls) { br.BigEndian = true; } int fileSize = br.ReadInt32(); FullWidth = br.ReadInt16(); TexWidth = br.ReadInt16(); TexHeight = br.ReadInt16(); short codeGroupCount, texRegionCount, glyphCount; if (Version == CCMVer.DemonsSouls || Version == CCMVer.DarkSouls1) { Unk0E = br.ReadInt16(); codeGroupCount = br.ReadInt16(); texRegionCount = -1; glyphCount = br.ReadInt16(); } else { Unk0E = 0; codeGroupCount = -1; texRegionCount = br.ReadInt16(); glyphCount = br.ReadInt16(); br.AssertInt16(0); } br.AssertInt32(0x20); int glyphOffset = br.ReadInt32(); Unk1C = br.ReadByte(); Unk1D = br.ReadByte(); TexCount = br.ReadByte(); br.AssertByte(0); Glyphs = new Dictionary <int, Glyph>(glyphCount); if (Version == CCMVer.DemonsSouls || Version == CCMVer.DarkSouls1) { var codeGroups = new List <CodeGroup>(codeGroupCount); for (int i = 0; i < codeGroupCount; i++) { codeGroups.Add(new CodeGroup(br)); } var glyphs = new List <Glyph>(glyphCount); for (int i = 0; i < glyphCount; i++) { Vector2 uv1 = br.ReadVector2(); Vector2 uv2 = br.ReadVector2(); short preSpace = br.ReadInt16(); short width = br.ReadInt16(); short advance = br.ReadInt16(); short texIndex = br.ReadInt16(); glyphs.Add(new Glyph(uv1, uv2, preSpace, width, advance, texIndex)); } foreach (CodeGroup group in codeGroups) { int codeCount = group.EndCode - group.StartCode + 1; for (int i = 0; i < codeCount; i++) { Glyphs[group.StartCode + i] = glyphs[group.GlyphIndex + i]; } } } else if (Version == CCMVer.DarkSouls2) { var texRegions = new Dictionary <int, TexRegion>(texRegionCount); for (int i = 0; i < texRegionCount; i++) { texRegions[(int)br.Position] = new TexRegion(br); } for (int i = 0; i < glyphCount; i++) { int code = br.ReadInt32(); int texRegionOffset = br.ReadInt32(); short texIndex = br.ReadInt16(); short preSpace = br.ReadInt16(); short width = br.ReadInt16(); short advance = br.ReadInt16(); br.AssertInt32(0); br.AssertInt32(0); TexRegion texRegion = texRegions[texRegionOffset]; Vector2 uv1 = new Vector2(texRegion.X1 / (float)TexWidth, texRegion.Y1 / (float)TexHeight); Vector2 uv2 = new Vector2(texRegion.X2 / (float)TexWidth, texRegion.Y2 / (float)TexHeight); Glyphs[code] = new Glyph(uv1, uv2, preSpace, width, advance, texIndex); } } }
/// <summary> /// Serializes file data to a stream. /// </summary> protected override void Write(BinaryWriterEx bw) { bw.BigEndian = false; bw.WriteUInt32((uint)Version); bw.BigEndian = Version == CCMVer.DemonsSouls; bw.ReserveInt32("FileSize"); bw.WriteInt16(FullWidth); bw.WriteInt16(TexWidth); bw.WriteInt16(TexHeight); if (Version == CCMVer.DemonsSouls || Version == CCMVer.DarkSouls1) { bw.WriteInt16(Unk0E); bw.ReserveInt16("CodeGroupCount"); bw.WriteInt16((short)Glyphs.Count); } else if (Version == CCMVer.DarkSouls2) { bw.ReserveInt16("TexRegionCount"); bw.WriteInt16((short)Glyphs.Count); bw.WriteInt16(0); } bw.WriteInt32(0x20); bw.ReserveInt32("GlyphOffset"); bw.WriteByte(Unk1C); bw.WriteByte(Unk1D); bw.WriteByte(TexCount); bw.WriteByte(0); var codes = new List <int>(Glyphs.Keys); codes.Sort(); if (Version == CCMVer.DemonsSouls || Version == CCMVer.DarkSouls1) { var codeGroups = new List <CodeGroup>(); for (int i = 0; i < Glyphs.Count;) { int startCode = codes[i]; int glyphIndex = i; for (i++; i < Glyphs.Count && codes[i] == codes[i - 1] + 1; i++) { ; } int endCode = codes[i - 1]; codeGroups.Add(new CodeGroup(startCode, endCode, glyphIndex)); } bw.FillInt16("CodeGroupCount", (short)codeGroups.Count); foreach (CodeGroup group in codeGroups) { group.Write(bw); } bw.FillInt32("GlyphOffset", (int)bw.Position); foreach (int code in codes) { Glyph glyph = Glyphs[code]; bw.WriteVector2(glyph.UV1); bw.WriteVector2(glyph.UV2); bw.WriteInt16(glyph.PreSpace); bw.WriteInt16(glyph.Width); bw.WriteInt16(glyph.Advance); bw.WriteInt16(glyph.TexIndex); } } else if (Version == CCMVer.DarkSouls2) { var texRegionsByCode = new Dictionary <int, TexRegion>(Glyphs.Count); var texRegions = new HashSet <TexRegion>(); foreach (int code in codes) { Glyph glyph = Glyphs[code]; short x1 = (short)Math.Round(glyph.UV1.X * TexWidth); short y1 = (short)Math.Round(glyph.UV1.Y * TexHeight); short x2 = (short)Math.Round(glyph.UV2.X * TexWidth); short y2 = (short)Math.Round(glyph.UV2.Y * TexHeight); var region = new TexRegion(x1, y1, x2, y2); texRegionsByCode[code] = region; texRegions.Add(region); } bw.FillInt16("TexRegionCount", (short)texRegions.Count); var texRegionOffsets = new Dictionary <TexRegion, int>(texRegions.Count); foreach (TexRegion region in texRegions) { texRegionOffsets[region] = (int)bw.Position; region.Write(bw); } bw.FillInt32("GlyphOffset", (int)bw.Position); foreach (int code in codes) { Glyph glyph = Glyphs[code]; bw.WriteInt32(code); bw.WriteInt32(texRegionOffsets[texRegionsByCode[code]]); bw.WriteInt16(glyph.TexIndex); bw.WriteInt16(glyph.PreSpace); bw.WriteInt16(glyph.Width); bw.WriteInt16(glyph.Advance); bw.WriteInt32(0); bw.WriteInt32(0); } } bw.FillInt32("FileSize", (int)bw.Position); }