/// <summary> /// コンストラクタ /// </summary> /// <param name="rom"></param> public Nes(byte[] rom) { this.Cartridge = NesCartridge.Load(rom); this.Controller = new NesGameController(); this.Ppu = new Ppu.NesPpu(this.Cartridge.GetCopyChrRom1(), this.Cartridge.GetCopyChrRom2(), this.Cartridge.IsHMirror, this.Cartridge.IsVMirror, x => this.Image = x); this.MemoryMap = new Cpu.NesCpuMemoryMap(this.Cartridge.GetCopyPgRom1(), this.Cartridge.GetCopyPgRom2(), this.Ppu,this.Controller); this.Cpu = new Cpu.NesCpu(this.MemoryMap, this.Ppu); }
/// <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(); } } } }