diff --git a/Core/PpuTools.cpp b/Core/PpuTools.cpp index a167263..f5aed6e 100644 --- a/Core/PpuTools.cpp +++ b/Core/PpuTools.cpp @@ -225,6 +225,8 @@ void PpuTools::GetTilemap(GetTilemapOptions options, uint8_t* vram, uint8_t* cgr } } } else { + int tileHeight = largeTileHeight ? 16 : 8; + int tileWidth = largeTileWidth ? 16 : 8; for(int row = 0; row < (layer.DoubleHeight ? 64 : 32); row++) { uint16_t addrVerticalScrollingOffset = layer.DoubleHeight ? ((row & 0x20) << (layer.DoubleWidth ? 6 : 5)) : 0; uint16_t baseOffset = (layer.TilemapAddress >> 1) + addrVerticalScrollingOffset + ((row & 0x1F) << 5); @@ -234,28 +236,25 @@ void PpuTools::GetTilemap(GetTilemapOptions options, uint8_t* vram, uint8_t* cgr bool vMirror = (vram[addr + 1] & 0x80) != 0; bool hMirror = (vram[addr + 1] & 0x40) != 0; - uint16_t tileIndex = ((vram[addr + 1] & 0x03) << 8) | vram[addr]; - uint16_t tileStart = layer.ChrAddress + tileIndex * 8 * bpp; - if(largeTileWidth || largeTileHeight) { - tileIndex = ( - tileIndex + - (largeTileHeight ? ((row & 0x01) ? (vMirror ? 0 : 16) : (vMirror ? 16 : 0)) : 0) + - (largeTileWidth ? ((column & 0x01) ? (hMirror ? 0 : 1) : (hMirror ? 1 : 0)) : 0) - ) & 0x3FF; - } + for(int y = 0; y < tileHeight; y++) { + uint8_t yOffset = vMirror ? (7 - (y & 0x07)) : (y & 0x07); - for(int y = 0; y < 8; y++) { - uint8_t yOffset = vMirror ? (7 - y) : y; - uint16_t pixelStart = tileStart + yOffset * 2; + for(int x = 0; x < tileWidth; x++) { + uint16_t tileOffset = ( + (largeTileHeight ? ((y & 0x08) ? (vMirror ? 0 : 16) : (vMirror ? 16 : 0)) : 0) + + (largeTileWidth ? ((x & 0x08) ? (hMirror ? 0 : 1) : (hMirror ? 1 : 0)) : 0) + ); - for(int x = 0; x < 8; x++) { - uint8_t shift = hMirror ? x : (7 - x); + uint16_t tileStart = layer.ChrAddress + ((tileIndex + tileOffset) & 0x3FF) * 8 * bpp; + uint16_t pixelStart = tileStart + yOffset * 2; + + uint8_t shift = hMirror ? (x & 0x07) : (7 - (x & 0x07)); uint8_t color = GetTilePixelColor(vram, Ppu::VideoRamSize - 1, bpp, pixelStart, shift); if(color != 0) { uint8_t palette = bpp == 8 ? 0 : (vram[addr + 1] >> 2) & 0x07; - outBuffer[((row * 8) + y) * 1024 + column * 8 + x] = GetRgbPixelColor(cgram, color, palette, bpp, directColor, basePaletteOffset); + outBuffer[((row * tileHeight) + y) * 1024 + column * tileWidth + x] = GetRgbPixelColor(cgram, color, palette, bpp, directColor, basePaletteOffset); } } } @@ -274,8 +273,25 @@ void PpuTools::GetTilemap(GetTilemapOptions options, uint8_t* vram, uint8_t* cgr if(options.ShowScrollOverlay) { constexpr uint32_t overlayColor = 0x40FFFFFF; - int widthMask = options.BgMode == 7 ? 0x3FF : (layer.DoubleWidth ? 0x1FF : 0xFF); - int heightMask = options.BgMode == 7 ? 0x3FF : (layer.DoubleHeight ? 0x1FF : 0xFF); + int widthMask = 0xFF; + int heightMask = 0xFF; + if(options.BgMode == 7) { + widthMask = 0x3FF; + heightMask = 0x3FF; + } else { + if(layer.DoubleWidth && largeTileWidth) { + widthMask = 0x3FF; + } else if(layer.DoubleWidth || largeTileWidth) { + widthMask = 0x1FF; + } + + if(layer.DoubleHeight && largeTileHeight) { + heightMask = 0x3FF; + } else if(layer.DoubleHeight || largeTileHeight) { + heightMask = 0x1FF; + } + } + int hScroll = options.BgMode == 7 ? state.Mode7.HScroll : layer.HScroll; int vScroll = options.BgMode == 7 ? state.Mode7.VScroll : layer.VScroll; for(int y = 0; y < 240; y++) { diff --git a/UI/Debugger/PpuViewer/frmTilemapViewer.Designer.cs b/UI/Debugger/PpuViewer/frmTilemapViewer.Designer.cs index cd57b3a..e48e800 100644 --- a/UI/Debugger/PpuViewer/frmTilemapViewer.Designer.cs +++ b/UI/Debugger/PpuViewer/frmTilemapViewer.Designer.cs @@ -38,6 +38,35 @@ this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); this.chkShowScrollOverlay = new System.Windows.Forms.CheckBox(); this.chkShowTileGrid = new System.Windows.Forms.CheckBox(); + this.grpTileInfo = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); + this.txtPalette = new System.Windows.Forms.TextBox(); + this.txtTileNumber = new System.Windows.Forms.TextBox(); + this.txtAddress = new System.Windows.Forms.TextBox(); + this.txtPosition = new System.Windows.Forms.TextBox(); + this.lblMap = new System.Windows.Forms.Label(); + this.lblPosition = new System.Windows.Forms.Label(); + this.lblAddress = new System.Windows.Forms.Label(); + this.lblValue = new System.Windows.Forms.Label(); + this.lblTileNumber = new System.Windows.Forms.Label(); + this.lblPalette = new System.Windows.Forms.Label(); + this.chkPriorityFlag = new System.Windows.Forms.CheckBox(); + this.chkHorizontalMirror = new System.Windows.Forms.CheckBox(); + this.chkVerticalMirror = new System.Windows.Forms.CheckBox(); + this.txtMapNumber = new System.Windows.Forms.TextBox(); + this.txtValue = new System.Windows.Forms.TextBox(); + this.grpLayerInfo = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel5 = new System.Windows.Forms.TableLayoutPanel(); + this.lblMapAddress = new System.Windows.Forms.Label(); + this.lblMapSize = new System.Windows.Forms.Label(); + this.lblBitDepth = new System.Windows.Forms.Label(); + this.lblTileSize = new System.Windows.Forms.Label(); + this.lblTilesetAddress = new System.Windows.Forms.Label(); + this.txtMapSize = new System.Windows.Forms.TextBox(); + this.txtMapAddress = new System.Windows.Forms.TextBox(); + this.txtTileSize = new System.Windows.Forms.TextBox(); + this.txtTilesetAddress = new System.Windows.Forms.TextBox(); + this.txtBitDepth = new System.Windows.Forms.TextBox(); this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); this.lblLayer = new System.Windows.Forms.Label(); this.ctrlMesenMenuStrip1 = new Mesen.GUI.Controls.ctrlMesenMenuStrip(); @@ -54,6 +83,10 @@ this.pnlTilemap.SuspendLayout(); this.tableLayoutPanel1.SuspendLayout(); this.tableLayoutPanel2.SuspendLayout(); + this.grpTileInfo.SuspendLayout(); + this.tableLayoutPanel4.SuspendLayout(); + this.grpLayerInfo.SuspendLayout(); + this.tableLayoutPanel5.SuspendLayout(); this.tableLayoutPanel3.SuspendLayout(); this.ctrlMesenMenuStrip1.SuspendLayout(); this.SuspendLayout(); @@ -63,10 +96,11 @@ this.picTilemap.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; this.picTilemap.Location = new System.Drawing.Point(0, 0); this.picTilemap.Name = "picTilemap"; - this.picTilemap.Size = new System.Drawing.Size(512, 512); + this.picTilemap.Size = new System.Drawing.Size(512, 471); this.picTilemap.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; this.picTilemap.TabIndex = 0; this.picTilemap.TabStop = false; + this.picTilemap.MouseClick += new System.Windows.Forms.MouseEventHandler(this.picTilemap_MouseClick); // // btnLayer1 // @@ -119,9 +153,9 @@ // ctrlScanlineCycleSelect // this.ctrlScanlineCycleSelect.Dock = System.Windows.Forms.DockStyle.Bottom; - this.ctrlScanlineCycleSelect.Location = new System.Drawing.Point(0, 546); + this.ctrlScanlineCycleSelect.Location = new System.Drawing.Point(0, 532); this.ctrlScanlineCycleSelect.Name = "ctrlScanlineCycleSelect"; - this.ctrlScanlineCycleSelect.Size = new System.Drawing.Size(667, 28); + this.ctrlScanlineCycleSelect.Size = new System.Drawing.Size(668, 28); this.ctrlScanlineCycleSelect.TabIndex = 5; // // pnlTilemap @@ -131,7 +165,7 @@ this.pnlTilemap.Dock = System.Windows.Forms.DockStyle.Fill; this.pnlTilemap.Location = new System.Drawing.Point(3, 31); this.pnlTilemap.Name = "pnlTilemap"; - this.pnlTilemap.Size = new System.Drawing.Size(512, 488); + this.pnlTilemap.Size = new System.Drawing.Size(513, 474); this.pnlTilemap.TabIndex = 6; // // tableLayoutPanel1 @@ -148,7 +182,7 @@ this.tableLayoutPanel1.RowCount = 2; this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel1.Size = new System.Drawing.Size(667, 522); + this.tableLayoutPanel1.Size = new System.Drawing.Size(668, 508); this.tableLayoutPanel1.TabIndex = 7; // // tableLayoutPanel2 @@ -157,14 +191,19 @@ this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel2.Controls.Add(this.chkShowScrollOverlay, 0, 1); this.tableLayoutPanel2.Controls.Add(this.chkShowTileGrid, 0, 0); - this.tableLayoutPanel2.Location = new System.Drawing.Point(521, 3); + this.tableLayoutPanel2.Controls.Add(this.grpTileInfo, 0, 3); + this.tableLayoutPanel2.Controls.Add(this.grpLayerInfo, 0, 2); + this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Right; + this.tableLayoutPanel2.Location = new System.Drawing.Point(522, 3); this.tableLayoutPanel2.Name = "tableLayoutPanel2"; - this.tableLayoutPanel2.RowCount = 3; + this.tableLayoutPanel2.RowCount = 5; this.tableLayoutPanel1.SetRowSpan(this.tableLayoutPanel2, 2); this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel2.Size = new System.Drawing.Size(143, 320); + this.tableLayoutPanel2.Size = new System.Drawing.Size(143, 502); this.tableLayoutPanel2.TabIndex = 7; // // chkShowScrollOverlay @@ -189,6 +228,328 @@ this.chkShowTileGrid.UseVisualStyleBackColor = true; this.chkShowTileGrid.Click += new System.EventHandler(this.chkShowTileGrid_Click); // + // grpTileInfo + // + this.grpTileInfo.Controls.Add(this.tableLayoutPanel4); + this.grpTileInfo.Dock = System.Windows.Forms.DockStyle.Fill; + this.grpTileInfo.Location = new System.Drawing.Point(3, 203); + this.grpTileInfo.Name = "grpTileInfo"; + this.grpTileInfo.Size = new System.Drawing.Size(137, 268); + this.grpTileInfo.TabIndex = 2; + this.grpTileInfo.TabStop = false; + this.grpTileInfo.Text = "Tile Information"; + // + // tableLayoutPanel4 + // + this.tableLayoutPanel4.ColumnCount = 2; + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel4.Controls.Add(this.txtPalette, 1, 7); + this.tableLayoutPanel4.Controls.Add(this.txtTileNumber, 1, 6); + this.tableLayoutPanel4.Controls.Add(this.txtAddress, 1, 3); + this.tableLayoutPanel4.Controls.Add(this.txtPosition, 1, 1); + this.tableLayoutPanel4.Controls.Add(this.lblMap, 0, 0); + this.tableLayoutPanel4.Controls.Add(this.lblPosition, 0, 1); + this.tableLayoutPanel4.Controls.Add(this.lblAddress, 0, 3); + this.tableLayoutPanel4.Controls.Add(this.lblValue, 0, 4); + this.tableLayoutPanel4.Controls.Add(this.lblTileNumber, 0, 6); + this.tableLayoutPanel4.Controls.Add(this.lblPalette, 0, 7); + this.tableLayoutPanel4.Controls.Add(this.chkPriorityFlag, 0, 8); + this.tableLayoutPanel4.Controls.Add(this.chkHorizontalMirror, 0, 9); + this.tableLayoutPanel4.Controls.Add(this.chkVerticalMirror, 0, 10); + this.tableLayoutPanel4.Controls.Add(this.txtMapNumber, 1, 0); + this.tableLayoutPanel4.Controls.Add(this.txtValue, 1, 4); + this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel4.Name = "tableLayoutPanel4"; + this.tableLayoutPanel4.RowCount = 12; + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 10F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 10F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel4.Size = new System.Drawing.Size(131, 249); + this.tableLayoutPanel4.TabIndex = 0; + // + // txtPalette + // + this.txtPalette.Location = new System.Drawing.Point(76, 153); + this.txtPalette.Name = "txtPalette"; + this.txtPalette.ReadOnly = true; + this.txtPalette.Size = new System.Drawing.Size(30, 20); + this.txtPalette.TabIndex = 14; + // + // txtTileNumber + // + this.txtTileNumber.Location = new System.Drawing.Point(76, 127); + this.txtTileNumber.Name = "txtTileNumber"; + this.txtTileNumber.ReadOnly = true; + this.txtTileNumber.Size = new System.Drawing.Size(42, 20); + this.txtTileNumber.TabIndex = 13; + // + // txtAddress + // + this.txtAddress.Location = new System.Drawing.Point(76, 65); + this.txtAddress.Name = "txtAddress"; + this.txtAddress.ReadOnly = true; + this.txtAddress.Size = new System.Drawing.Size(43, 20); + this.txtAddress.TabIndex = 11; + // + // txtPosition + // + this.txtPosition.Location = new System.Drawing.Point(76, 29); + this.txtPosition.Name = "txtPosition"; + this.txtPosition.ReadOnly = true; + this.txtPosition.Size = new System.Drawing.Size(52, 20); + this.txtPosition.TabIndex = 10; + // + // lblMap + // + this.lblMap.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblMap.AutoSize = true; + this.lblMap.Location = new System.Drawing.Point(3, 6); + this.lblMap.Name = "lblMap"; + this.lblMap.Size = new System.Drawing.Size(31, 13); + this.lblMap.TabIndex = 0; + this.lblMap.Text = "Map:"; + // + // lblPosition + // + this.lblPosition.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblPosition.AutoSize = true; + this.lblPosition.Location = new System.Drawing.Point(3, 32); + this.lblPosition.Name = "lblPosition"; + this.lblPosition.Size = new System.Drawing.Size(47, 13); + this.lblPosition.TabIndex = 1; + this.lblPosition.Text = "Position:"; + // + // lblAddress + // + this.lblAddress.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblAddress.AutoSize = true; + this.lblAddress.Location = new System.Drawing.Point(3, 68); + this.lblAddress.Name = "lblAddress"; + this.lblAddress.Size = new System.Drawing.Size(48, 13); + this.lblAddress.TabIndex = 2; + this.lblAddress.Text = "Address:"; + // + // lblValue + // + this.lblValue.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblValue.AutoSize = true; + this.lblValue.Location = new System.Drawing.Point(3, 94); + this.lblValue.Name = "lblValue"; + this.lblValue.Size = new System.Drawing.Size(37, 13); + this.lblValue.TabIndex = 3; + this.lblValue.Text = "Value:"; + // + // lblTileNumber + // + this.lblTileNumber.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblTileNumber.AutoSize = true; + this.lblTileNumber.Location = new System.Drawing.Point(3, 130); + this.lblTileNumber.Name = "lblTileNumber"; + this.lblTileNumber.Size = new System.Drawing.Size(67, 13); + this.lblTileNumber.TabIndex = 4; + this.lblTileNumber.Text = "Tile Number:"; + // + // lblPalette + // + this.lblPalette.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblPalette.AutoSize = true; + this.lblPalette.Location = new System.Drawing.Point(3, 156); + this.lblPalette.Name = "lblPalette"; + this.lblPalette.Size = new System.Drawing.Size(43, 13); + this.lblPalette.TabIndex = 5; + this.lblPalette.Text = "Palette:"; + // + // chkPriorityFlag + // + this.chkPriorityFlag.AutoCheck = false; + this.chkPriorityFlag.AutoSize = true; + this.tableLayoutPanel4.SetColumnSpan(this.chkPriorityFlag, 2); + this.chkPriorityFlag.Location = new System.Drawing.Point(3, 179); + this.chkPriorityFlag.Name = "chkPriorityFlag"; + this.chkPriorityFlag.Size = new System.Drawing.Size(57, 17); + this.chkPriorityFlag.TabIndex = 6; + this.chkPriorityFlag.Text = "Priority"; + this.chkPriorityFlag.UseVisualStyleBackColor = true; + // + // chkHorizontalMirror + // + this.chkHorizontalMirror.AutoCheck = false; + this.chkHorizontalMirror.AutoSize = true; + this.tableLayoutPanel4.SetColumnSpan(this.chkHorizontalMirror, 2); + this.chkHorizontalMirror.Location = new System.Drawing.Point(3, 202); + this.chkHorizontalMirror.Name = "chkHorizontalMirror"; + this.chkHorizontalMirror.Size = new System.Drawing.Size(102, 17); + this.chkHorizontalMirror.TabIndex = 8; + this.chkHorizontalMirror.Text = "Horizontal Mirror"; + this.chkHorizontalMirror.UseVisualStyleBackColor = true; + // + // chkVerticalMirror + // + this.chkVerticalMirror.AutoCheck = false; + this.chkVerticalMirror.AutoSize = true; + this.tableLayoutPanel4.SetColumnSpan(this.chkVerticalMirror, 2); + this.chkVerticalMirror.Location = new System.Drawing.Point(3, 225); + this.chkVerticalMirror.Name = "chkVerticalMirror"; + this.chkVerticalMirror.Size = new System.Drawing.Size(90, 17); + this.chkVerticalMirror.TabIndex = 7; + this.chkVerticalMirror.Text = "Vertical Mirror"; + this.chkVerticalMirror.UseVisualStyleBackColor = true; + // + // txtMapNumber + // + this.txtMapNumber.Location = new System.Drawing.Point(76, 3); + this.txtMapNumber.Name = "txtMapNumber"; + this.txtMapNumber.ReadOnly = true; + this.txtMapNumber.Size = new System.Drawing.Size(30, 20); + this.txtMapNumber.TabIndex = 9; + // + // txtValue + // + this.txtValue.Location = new System.Drawing.Point(76, 91); + this.txtValue.Name = "txtValue"; + this.txtValue.ReadOnly = true; + this.txtValue.Size = new System.Drawing.Size(43, 20); + this.txtValue.TabIndex = 12; + // + // grpLayerInfo + // + this.grpLayerInfo.Controls.Add(this.tableLayoutPanel5); + this.grpLayerInfo.Location = new System.Drawing.Point(3, 49); + this.grpLayerInfo.Name = "grpLayerInfo"; + this.grpLayerInfo.Size = new System.Drawing.Size(137, 148); + this.grpLayerInfo.TabIndex = 3; + this.grpLayerInfo.TabStop = false; + this.grpLayerInfo.Text = "Layer Information"; + // + // tableLayoutPanel5 + // + this.tableLayoutPanel5.ColumnCount = 2; + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel5.Controls.Add(this.lblMapAddress, 0, 1); + this.tableLayoutPanel5.Controls.Add(this.lblMapSize, 0, 0); + this.tableLayoutPanel5.Controls.Add(this.lblBitDepth, 0, 4); + this.tableLayoutPanel5.Controls.Add(this.lblTileSize, 0, 2); + this.tableLayoutPanel5.Controls.Add(this.lblTilesetAddress, 0, 3); + this.tableLayoutPanel5.Controls.Add(this.txtMapSize, 1, 0); + this.tableLayoutPanel5.Controls.Add(this.txtMapAddress, 1, 1); + this.tableLayoutPanel5.Controls.Add(this.txtTileSize, 1, 2); + this.tableLayoutPanel5.Controls.Add(this.txtTilesetAddress, 1, 3); + this.tableLayoutPanel5.Controls.Add(this.txtBitDepth, 1, 4); + this.tableLayoutPanel5.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel5.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel5.Name = "tableLayoutPanel5"; + this.tableLayoutPanel5.RowCount = 6; + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel5.Size = new System.Drawing.Size(131, 129); + this.tableLayoutPanel5.TabIndex = 0; + // + // lblMapAddress + // + this.lblMapAddress.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblMapAddress.AutoSize = true; + this.lblMapAddress.Location = new System.Drawing.Point(3, 32); + this.lblMapAddress.Name = "lblMapAddress"; + this.lblMapAddress.Size = new System.Drawing.Size(48, 13); + this.lblMapAddress.TabIndex = 2; + this.lblMapAddress.Text = "Address:"; + // + // lblMapSize + // + this.lblMapSize.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblMapSize.AutoSize = true; + this.lblMapSize.Location = new System.Drawing.Point(3, 6); + this.lblMapSize.Name = "lblMapSize"; + this.lblMapSize.Size = new System.Drawing.Size(30, 13); + this.lblMapSize.TabIndex = 1; + this.lblMapSize.Text = "Size:"; + // + // lblBitDepth + // + this.lblBitDepth.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblBitDepth.AutoSize = true; + this.lblBitDepth.Location = new System.Drawing.Point(3, 110); + this.lblBitDepth.Name = "lblBitDepth"; + this.lblBitDepth.Size = new System.Drawing.Size(54, 13); + this.lblBitDepth.TabIndex = 3; + this.lblBitDepth.Text = "Bit Depth:"; + // + // lblTileSize + // + this.lblTileSize.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblTileSize.AutoSize = true; + this.lblTileSize.Location = new System.Drawing.Point(3, 58); + this.lblTileSize.Name = "lblTileSize"; + this.lblTileSize.Size = new System.Drawing.Size(50, 13); + this.lblTileSize.TabIndex = 4; + this.lblTileSize.Text = "Tile Size:"; + // + // lblTilesetAddress + // + this.lblTilesetAddress.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblTilesetAddress.AutoSize = true; + this.lblTilesetAddress.Location = new System.Drawing.Point(3, 84); + this.lblTilesetAddress.Name = "lblTilesetAddress"; + this.lblTilesetAddress.Size = new System.Drawing.Size(66, 13); + this.lblTilesetAddress.TabIndex = 5; + this.lblTilesetAddress.Text = "Tileset Addr:"; + // + // txtMapSize + // + this.txtMapSize.Location = new System.Drawing.Point(75, 3); + this.txtMapSize.Name = "txtMapSize"; + this.txtMapSize.ReadOnly = true; + this.txtMapSize.Size = new System.Drawing.Size(52, 20); + this.txtMapSize.TabIndex = 13; + // + // txtMapAddress + // + this.txtMapAddress.Location = new System.Drawing.Point(75, 29); + this.txtMapAddress.Name = "txtMapAddress"; + this.txtMapAddress.ReadOnly = true; + this.txtMapAddress.Size = new System.Drawing.Size(43, 20); + this.txtMapAddress.TabIndex = 14; + // + // txtTileSize + // + this.txtTileSize.Location = new System.Drawing.Point(75, 55); + this.txtTileSize.Name = "txtTileSize"; + this.txtTileSize.ReadOnly = true; + this.txtTileSize.Size = new System.Drawing.Size(43, 20); + this.txtTileSize.TabIndex = 15; + // + // txtTilesetAddress + // + this.txtTilesetAddress.Location = new System.Drawing.Point(75, 81); + this.txtTilesetAddress.Name = "txtTilesetAddress"; + this.txtTilesetAddress.ReadOnly = true; + this.txtTilesetAddress.Size = new System.Drawing.Size(43, 20); + this.txtTilesetAddress.TabIndex = 16; + // + // txtBitDepth + // + this.txtBitDepth.Location = new System.Drawing.Point(75, 107); + this.txtBitDepth.Name = "txtBitDepth"; + this.txtBitDepth.ReadOnly = true; + this.txtBitDepth.Size = new System.Drawing.Size(30, 20); + this.txtBitDepth.TabIndex = 17; + // // tableLayoutPanel3 // this.tableLayoutPanel3.ColumnCount = 6; @@ -228,7 +589,7 @@ this.mnuView}); this.ctrlMesenMenuStrip1.Location = new System.Drawing.Point(0, 0); this.ctrlMesenMenuStrip1.Name = "ctrlMesenMenuStrip1"; - this.ctrlMesenMenuStrip1.Size = new System.Drawing.Size(667, 24); + this.ctrlMesenMenuStrip1.Size = new System.Drawing.Size(668, 24); this.ctrlMesenMenuStrip1.TabIndex = 8; this.ctrlMesenMenuStrip1.Text = "ctrlMesenMenuStrip1"; // @@ -244,7 +605,7 @@ // this.mnuClose.Image = global::Mesen.GUI.Properties.Resources.Exit; this.mnuClose.Name = "mnuClose"; - this.mnuClose.Size = new System.Drawing.Size(152, 22); + this.mnuClose.Size = new System.Drawing.Size(103, 22); this.mnuClose.Text = "Close"; this.mnuClose.Click += new System.EventHandler(this.mnuClose_Click); // @@ -267,38 +628,38 @@ this.mnuAutoRefresh.CheckOnClick = true; this.mnuAutoRefresh.CheckState = System.Windows.Forms.CheckState.Checked; this.mnuAutoRefresh.Name = "mnuAutoRefresh"; - this.mnuAutoRefresh.Size = new System.Drawing.Size(152, 22); + this.mnuAutoRefresh.Size = new System.Drawing.Size(141, 22); this.mnuAutoRefresh.Text = "Auto-refresh"; // // toolStripMenuItem2 // this.toolStripMenuItem2.Name = "toolStripMenuItem2"; - this.toolStripMenuItem2.Size = new System.Drawing.Size(149, 6); + this.toolStripMenuItem2.Size = new System.Drawing.Size(138, 6); // // mnuRefresh // this.mnuRefresh.Image = global::Mesen.GUI.Properties.Resources.Refresh; this.mnuRefresh.Name = "mnuRefresh"; - this.mnuRefresh.Size = new System.Drawing.Size(152, 22); + this.mnuRefresh.Size = new System.Drawing.Size(141, 22); this.mnuRefresh.Text = "Refresh"; this.mnuRefresh.Click += new System.EventHandler(this.mnuRefresh_Click); // // toolStripMenuItem1 // this.toolStripMenuItem1.Name = "toolStripMenuItem1"; - this.toolStripMenuItem1.Size = new System.Drawing.Size(149, 6); + this.toolStripMenuItem1.Size = new System.Drawing.Size(138, 6); // // mnuZoomIn // this.mnuZoomIn.Name = "mnuZoomIn"; - this.mnuZoomIn.Size = new System.Drawing.Size(152, 22); + this.mnuZoomIn.Size = new System.Drawing.Size(141, 22); this.mnuZoomIn.Text = "Zoom In"; this.mnuZoomIn.Click += new System.EventHandler(this.mnuZoomIn_Click); // // mnuZoomOut // this.mnuZoomOut.Name = "mnuZoomOut"; - this.mnuZoomOut.Size = new System.Drawing.Size(152, 22); + this.mnuZoomOut.Size = new System.Drawing.Size(141, 22); this.mnuZoomOut.Text = "Zoom Out"; this.mnuZoomOut.Click += new System.EventHandler(this.mnuZoomOut_Click); // @@ -306,7 +667,7 @@ // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(667, 574); + this.ClientSize = new System.Drawing.Size(668, 560); this.Controls.Add(this.tableLayoutPanel1); this.Controls.Add(this.ctrlScanlineCycleSelect); this.Controls.Add(this.ctrlMesenMenuStrip1); @@ -318,6 +679,12 @@ this.tableLayoutPanel1.ResumeLayout(false); this.tableLayoutPanel2.ResumeLayout(false); this.tableLayoutPanel2.PerformLayout(); + this.grpTileInfo.ResumeLayout(false); + this.tableLayoutPanel4.ResumeLayout(false); + this.tableLayoutPanel4.PerformLayout(); + this.grpLayerInfo.ResumeLayout(false); + this.tableLayoutPanel5.ResumeLayout(false); + this.tableLayoutPanel5.PerformLayout(); this.tableLayoutPanel3.ResumeLayout(false); this.tableLayoutPanel3.PerformLayout(); this.ctrlMesenMenuStrip1.ResumeLayout(false); @@ -352,5 +719,34 @@ private System.Windows.Forms.ToolStripMenuItem mnuZoomOut; private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2; private System.Windows.Forms.ToolStripMenuItem mnuRefresh; + private System.Windows.Forms.GroupBox grpTileInfo; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; + private System.Windows.Forms.TextBox txtPalette; + private System.Windows.Forms.TextBox txtTileNumber; + private System.Windows.Forms.TextBox txtAddress; + private System.Windows.Forms.TextBox txtPosition; + private System.Windows.Forms.Label lblMap; + private System.Windows.Forms.Label lblPosition; + private System.Windows.Forms.Label lblAddress; + private System.Windows.Forms.Label lblValue; + private System.Windows.Forms.Label lblTileNumber; + private System.Windows.Forms.Label lblPalette; + private System.Windows.Forms.CheckBox chkPriorityFlag; + private System.Windows.Forms.CheckBox chkHorizontalMirror; + private System.Windows.Forms.CheckBox chkVerticalMirror; + private System.Windows.Forms.TextBox txtMapNumber; + private System.Windows.Forms.TextBox txtValue; + private System.Windows.Forms.GroupBox grpLayerInfo; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel5; + private System.Windows.Forms.Label lblMapAddress; + private System.Windows.Forms.Label lblMapSize; + private System.Windows.Forms.Label lblBitDepth; + private System.Windows.Forms.Label lblTileSize; + private System.Windows.Forms.Label lblTilesetAddress; + private System.Windows.Forms.TextBox txtMapSize; + private System.Windows.Forms.TextBox txtMapAddress; + private System.Windows.Forms.TextBox txtTileSize; + private System.Windows.Forms.TextBox txtTilesetAddress; + private System.Windows.Forms.TextBox txtBitDepth; } } \ No newline at end of file diff --git a/UI/Debugger/PpuViewer/frmTilemapViewer.cs b/UI/Debugger/PpuViewer/frmTilemapViewer.cs index 11a4754..f6bfcd8 100644 --- a/UI/Debugger/PpuViewer/frmTilemapViewer.cs +++ b/UI/Debugger/PpuViewer/frmTilemapViewer.cs @@ -16,6 +16,8 @@ namespace Mesen.GUI.Debugger { public partial class frmTilemapViewer : BaseForm { + private int[,] _layerBpp = new int[8, 4] { { 2,2,2,2 }, { 4,4,2,0 }, { 4,4,0,0 }, { 8,4,0,0 }, { 8,2,0,0 }, { 4,2,0,0 }, { 4,0,0,0 }, { 8,0,0,0 } }; + private NotificationListener _notifListener; private GetTilemapOptions _options; private DebugState _state; @@ -24,6 +26,8 @@ namespace Mesen.GUI.Debugger private byte[] _tilemapData; private Bitmap _tilemapImage; private int _scale = 1; + private int _selectedRow = 0; + private int _selectedColumn = 0; public frmTilemapViewer() { @@ -88,18 +92,60 @@ namespace Mesen.GUI.Debugger _cgram = DebugApi.GetMemoryState(SnesMemoryType.CGRam); } + private bool IsLargeTileWidth + { + get { return _state.Ppu.Layers[_options.Layer].LargeTiles || _state.Ppu.BgMode == 5 || _state.Ppu.BgMode == 6; } + } + + private bool IsLargeTileHeight + { + get { return _state.Ppu.Layers[_options.Layer].LargeTiles; } + } + private int GetWidth() { - return _state.Ppu.BgMode == 7 ? 1024 : _state.Ppu.Layers[_options.Layer].DoubleWidth ? 512 : 256; + if(_state.Ppu.BgMode == 7) { + return 1024; + } + + LayerConfig layer = _state.Ppu.Layers[_options.Layer]; + bool largeTileWidth = layer.LargeTiles || _state.Ppu.BgMode == 5 || _state.Ppu.BgMode == 6; + bool largeTileHeight = layer.LargeTiles; + + int width = 256; + if(layer.DoubleWidth) { + width *= 2; + } + if(largeTileWidth) { + width *= 2; + } + return width; } private int GetHeight() { - return _state.Ppu.BgMode == 7 ? 1024 : _state.Ppu.Layers[_options.Layer].DoubleHeight ? 512 : 256; + if(_state.Ppu.BgMode == 7) { + return 1024; + } + + LayerConfig layer = _state.Ppu.Layers[_options.Layer]; + + int height = 256; + if(layer.DoubleHeight) { + height *= 2; + } + if(layer.LargeTiles) { + height *= 2; + } + return height; } private void RefreshViewer() { + if(_layerBpp[_state.Ppu.BgMode, _options.Layer] == 0) { + _options.Layer = 0; + } + DebugApi.GetTilemap(_options, _vram, _cgram, _tilemapData); int mapWidth = GetWidth(); @@ -111,20 +157,28 @@ namespace Mesen.GUI.Debugger using(Graphics g = Graphics.FromImage(_tilemapImage)) { GCHandle handle = GCHandle.Alloc(_tilemapData, GCHandleType.Pinned); Bitmap source = new Bitmap(mapWidth, mapHeight, 4 * 1024, PixelFormat.Format32bppArgb, handle.AddrOfPinnedObject()); - try { - g.DrawImage(source, 0, 0); - } finally { - handle.Free(); - } + g.DrawImage(source, 0, 0); + + g.DrawRectangle(Pens.Gray, _selectedColumn * 8 - 2, _selectedRow * 8 - 2, IsLargeTileWidth ? 19 : 11, IsLargeTileHeight ? 19 : 11); + g.DrawRectangle(Pens.White, _selectedColumn * 8 - 1, _selectedRow * 8 - 1, IsLargeTileWidth ? 17 : 9, IsLargeTileHeight ? 17 : 9); + + handle.Free(); } - btnLayer1.BackColor = _options.Layer == 0 ? SystemColors.GradientActiveCaption : SystemColors.ControlLight; - btnLayer2.BackColor = _options.Layer == 1 ? SystemColors.GradientActiveCaption : SystemColors.ControlLight; - btnLayer3.BackColor = _options.Layer == 2 ? SystemColors.GradientActiveCaption : SystemColors.ControlLight; - btnLayer4.BackColor = _options.Layer == 3 ? SystemColors.GradientActiveCaption : SystemColors.ControlLight; + btnLayer1.BackColor = _options.Layer == 0 ? SystemColors.GradientActiveCaption : Color.Empty; + btnLayer2.BackColor = _options.Layer == 1 ? SystemColors.GradientActiveCaption : Color.Empty; + btnLayer3.BackColor = _options.Layer == 2 ? SystemColors.GradientActiveCaption : Color.Empty; + btnLayer4.BackColor = _options.Layer == 3 ? SystemColors.GradientActiveCaption : Color.Empty; + + btnLayer1.Enabled = _layerBpp[_state.Ppu.BgMode, 0] > 0; + btnLayer2.Enabled = _layerBpp[_state.Ppu.BgMode, 1] > 0; + btnLayer3.Enabled = _layerBpp[_state.Ppu.BgMode, 2] > 0; + btnLayer4.Enabled = _layerBpp[_state.Ppu.BgMode, 3] > 0; UpdateMapSize(); picTilemap.Invalidate(); + + UpdateFields(); } private void UpdateMapSize() @@ -133,6 +187,59 @@ namespace Mesen.GUI.Debugger picTilemap.Height = GetHeight() * _scale; } + private void UpdateFields() + { + if(_state.Ppu.BgMode == 7) { + //Selected tile + txtMapNumber.Text = "0"; + txtPosition.Text = _selectedColumn.ToString() + ", " + _selectedRow.ToString(); + int address = _selectedRow * 128 + _selectedColumn; + int value = _vram[address] | (_vram[address + 1] << 8); + txtAddress.Text = address.ToString("X4"); + txtValue.Text = value.ToString("X4"); + txtTileNumber.Text = (value & 0xFF).ToString(); + + txtPalette.Text = "0"; + chkPriorityFlag.Checked = false; + chkHorizontalMirror.Checked = false; + chkVerticalMirror.Checked = false; + + //Tilemap + txtMapSize.Text = "128x128"; + txtMapAddress.Text = "0000"; + txtTilesetAddress.Text = "0000"; + txtTileSize.Text = "8x8"; + txtBitDepth.Text = "8"; + } else { + int row = (IsLargeTileHeight ? _selectedRow / 2 : _selectedRow); + int column = (IsLargeTileWidth ? _selectedColumn / 2 : _selectedColumn); + + LayerConfig layer = _state.Ppu.Layers[_options.Layer]; + int addrVerticalScrollingOffset = layer.DoubleHeight ? ((row & 0x20) << (layer.DoubleWidth ? 6 : 5)) : 0; + int baseOffset = (layer.TilemapAddress >> 1) + addrVerticalScrollingOffset + ((row & 0x1F) << 5); + int address = (baseOffset + (column & 0x1F) + (layer.DoubleWidth ? ((column & 0x20) << 5) : 0)) << 1; + int value = _vram[address] | (_vram[address + 1] << 8); + + //Selected tile + txtMapNumber.Text = ((column >= 32 ? 1 : 0) + (row >= 32 ? 1 : 0)).ToString(); + txtPosition.Text = (column & 0x1F).ToString() + ", " + (row & 0x1F).ToString(); + txtAddress.Text = address.ToString("X4"); + txtValue.Text = value.ToString("X4"); + txtTileNumber.Text = (value & 0x3FF).ToString(); + txtPalette.Text = ((value >> 10) & 0x07).ToString(); + chkPriorityFlag.Checked = (value & 0x2000) != 0; + chkHorizontalMirror.Checked = (value & 0x4000) != 0; + chkVerticalMirror.Checked = (value & 0x8000) != 0; + + //Tilemap + txtMapSize.Text = (layer.DoubleWidth ? "64" : "32") + "x" + (layer.DoubleHeight ? "64" : "32"); + txtMapAddress.Text = layer.TilemapAddress.ToString("X4"); + txtTilesetAddress.Text = layer.ChrAddress.ToString("X4"); + txtTileSize.Text = (IsLargeTileWidth ? "16" : "8") + "x" + (IsLargeTileHeight ? "16" : "8"); + txtBitDepth.Text = _layerBpp[_state.Ppu.BgMode, _options.Layer].ToString(); + } + } + private void btnLayer1_Click(object sender, EventArgs e) { _options.Layer = 0; @@ -160,11 +267,13 @@ namespace Mesen.GUI.Debugger private void chkShowTileGrid_Click(object sender, EventArgs e) { _options.ShowTileGrid = chkShowTileGrid.Checked; + RefreshViewer(); } private void chkShowScrollOverlay_Click(object sender, EventArgs e) { _options.ShowScrollOverlay = chkShowScrollOverlay.Checked; + RefreshViewer(); } private void mnuRefresh_Click(object sender, EventArgs e) @@ -189,5 +298,20 @@ namespace Mesen.GUI.Debugger { Close(); } + + private void picTilemap_MouseClick(object sender, MouseEventArgs e) + { + _selectedColumn = e.X / (8 * _scale); + _selectedRow = e.Y / (8 * _scale); + + if(IsLargeTileWidth) { + _selectedColumn &= 0xFE; + } + if(IsLargeTileHeight) { + _selectedRow &= 0xFE; + } + + RefreshViewer(); + } } }