/// <summary> /// 指定ラインの画像情報を作成 /// </summary> /// <param name="yLine"></param> internal void CreateLine(int yLine, NesPpu ppu) { if(yLine >= NesPpuScreenSize.MaxHeight) return; int? disp1PointY = null; int? disp2PointY = null; if (yLine + ppu.Scroll.VScroll >= NesPpuScreenSize.MaxHeight) { if (ppu.VMirror) disp1PointY = disp2PointY = (yLine + ppu.Scroll.VScroll) - NesPpuScreenSize.MaxHeight; else disp2PointY = (yLine + ppu.Scroll.VScroll) - NesPpuScreenSize.MaxHeight; } else if (ppu.Scroll.VScroll > 0) { if (ppu.VMirror) disp1PointY = disp2PointY = yLine + ppu.Scroll.VScroll; else disp1PointY = yLine + ppu.Scroll.VScroll; } else { if (ppu.VMirror) disp1PointY = disp2PointY = yLine; else disp1PointY = yLine; } Func<NesPpu, int, NameTableType, byte[]> createBgFunc = (p, y, t) => { var namePoint = new NameTablePoint(0, y / Pattern.MaxHeight); var nameIndex = NameTablePoint.ConvertIndex(namePoint); var patternTable = p.PatternTables[p.ControlRegister1.BgPatternTableAdress]; return p.NameAttributePairTables[t].Item1 .Skip(nameIndex) .Take(NameTable.MaxWidth) .Select((x, i) => { var pointTuple = NameTablePoint.ConvertPoint(i + nameIndex, NameTable.MaxWidth); var point = new NameTablePoint(pointTuple.Item1, pointTuple.Item2); var high2Bit = p.NameAttributePairTables[t].Item2.GetAttributeHigh2Bit(point); return new { Data = x, HighBitData = high2Bit }; }) .Select(x => patternTable[x.Data].Select(xx => (byte)((x.HighBitData << 2) | xx)).ToArray()) .Buffer(32) .SelectMany(x => { var data = x; byte[] buf = new byte[(Pattern.MaxWidth * Pattern.MaxHeight) * NameTable.MaxWidth]; for (int line = 0; line < 8; line++) { for (int i = 0; i < 32; i++) { for (int j = 0; j < 8; j++) { var index = i * 8 + j + (line * 256); buf[index] = data[i][j + (line * 8)]; } } } return buf; }) .ToArray(); }; Func<int, byte[], byte[]> getLineFunc = (y, t) => { var index = 0 + (y % Pattern.MaxHeight) * NesPpuScreenSize.MaxWidth; return t.Skip(index).Take(NesPpuScreenSize.MaxWidth).ToArray(); }; // 画面1 if (disp1PointY != null) { if (!this.cacheDictionary.ContainsKey(Tuple.Create(NameTableType.Table0, disp1PointY.Value / Pattern.MaxHeight))) { var lineImage = createBgFunc(ppu, disp1PointY.Value, NameTableType.Table0); this.cacheDictionary[Tuple.Create(NameTableType.Table0, disp1PointY.Value / Pattern.MaxHeight)] = lineImage; } } // 画面2 if (disp2PointY != null) { if (!this.cacheDictionary.ContainsKey(Tuple.Create(NameTableType.Table1, disp2PointY.Value / Pattern.MaxHeight))) { var lineImage = createBgFunc(ppu, disp2PointY.Value, NameTableType.Table1); this.cacheDictionary[Tuple.Create(NameTableType.Table1, disp2PointY.Value / Pattern.MaxHeight)] = lineImage; } } // 横2画面 if (disp1PointY != null && disp2PointY != null) { var disp1Image = this.cacheDictionary[Tuple.Create(NameTableType.Table0, disp1PointY.Value / Pattern.MaxHeight)]; var disp2Image = this.cacheDictionary[Tuple.Create(NameTableType.Table1, disp2PointY.Value / Pattern.MaxHeight)]; if (ppu.Scroll.HScroll == 0) { this.lineDictionary[yLine] = getLineFunc(disp1PointY.Value, disp1Image); } else if (ppu.Scroll.HScroll >= NesPpuScreenSize.MaxWidth) { this.lineDictionary[yLine] = getLineFunc(disp2PointY.Value, disp2Image); } else { this.lineDictionary[yLine] = getLineFunc(disp1PointY.Value, disp1Image) .Skip(ppu.Scroll.HScroll) .Concat( getLineFunc(disp2PointY.Value, disp2Image) .Take(ppu.Scroll.HScroll) ) .ToArray(); } } // 縦2画面 else { if (disp1PointY != null) { var disp1Image = this.cacheDictionary[Tuple.Create(NameTableType.Table0, disp1PointY.Value / Pattern.MaxHeight)]; if (ppu.Scroll.HScroll == 0 || ppu.Scroll.HScroll >= NesPpuScreenSize.MaxWidth) { this.lineDictionary[yLine] = getLineFunc(disp1PointY.Value, disp1Image); } else { this.lineDictionary[yLine] = getLineFunc(disp1PointY.Value, disp1Image) .Skip(ppu.Scroll.HScroll) .Concat( getLineFunc(disp1PointY.Value, disp1Image) .Take(ppu.Scroll.HScroll) ) .ToArray(); } } else { var disp2Image = this.cacheDictionary[Tuple.Create(NameTableType.Table1, disp2PointY.Value / Pattern.MaxHeight)]; if (ppu.Scroll.HScroll == 0 || ppu.Scroll.HScroll >= NesPpuScreenSize.MaxWidth) { this.lineDictionary[yLine] = getLineFunc(disp2PointY.Value, disp2Image); } else { this.lineDictionary[yLine] = getLineFunc(disp2PointY.Value, disp2Image) .Skip(ppu.Scroll.HScroll) .Concat( getLineFunc(disp2PointY.Value, disp2Image) .Take(ppu.Scroll.HScroll) ) .ToArray(); } } } }
/// <summary> /// BGイメージ情報をネーム・属性・パターンテーブルから作成 /// </summary> /// <param name="p"></param> /// <param name="t"></param> /// <returns></returns> private IEnumerable<byte> ExpandBgImage(Tuple<NameTable, AttributeTable> p, PatternTable t) { //var bgImage = p.Item1 // .Select((x, i) => // { // var point = PointAbstract.ConvertPoint<NameTablePoint>(i); // var high2Bit = p.Item2.GetAttributeHigh2Bit(point); // return new { Data = x, HighBitData = high2Bit }; // }) // .SelectMany(x => t[x.Data].Select(xx => (byte)((x.HighBitData << 2) | xx))) // .Buffer(64) // .Buffer(32) // .SelectMany(x => // { // var data = x.ToArray(); // byte[] buf = new byte[64 * 32]; // for (int line = 0; line < 8; line++) // { // for (int i = 0; i < 32; i++) // { // for (int j = 0; j < 8; j++) // { // var index = i * 8 + j + (line * 256); // buf[index] = data[i][j + (line * 8)]; // } // } // } // return buf; // //return x.SelectMany(xx => xx.Select((xxx, i) => new { Data = xxx, PointY = i / 8 })) // // .GroupBy(xx => xx.PointY) // // .SelectMany(xx => xx.Select(xxx => xxx.Data)); // }) // .ToArray(); var bgImage = p.Item1 .Select((x, i) => { var pointTuple = NameTablePoint.ConvertPoint(i, NameTable.MaxWidth); var point = new NameTablePoint(pointTuple.Item1, pointTuple.Item2); var high2Bit = p.Item2.GetAttributeHigh2Bit(point); return new { Data = x, HighBitData = high2Bit }; }) .Select(x => t[x.Data].Select(xx => (byte)((x.HighBitData << 2) | xx)).ToArray()) .Buffer(32) .SelectMany(x => { var data = x; byte[] buf = new byte[64 * 32]; for (int line = 0; line < 8; line++) { for (int i = 0; i < 32; i++) { for (int j = 0; j < 8; j++) { var index = i * 8 + j + (line * 256); buf[index] = data[i][j + (line * 8)]; } } } return buf; // forループの処理に置き換えたのでコメントアウト //return x.SelectMany(xx => xx.Select((xxx, i) => new { Data = xxx, PointY = i / 8 })) // .GroupBy(xx => xx.PointY) // .SelectMany(xx => xx.Select(xxx => xxx.Data)); }); return bgImage; }