2015-08-08 22:36:39 -04:00
using System ;
using System.Collections.Generic ;
using System.ComponentModel ;
using System.Drawing ;
using System.Data ;
using System.Linq ;
using System.Text ;
using System.Threading.Tasks ;
using System.Windows.Forms ;
using System.Runtime.InteropServices ;
2016-12-11 14:25:29 -05:00
using Mesen.GUI.Controls ;
2015-08-08 22:36:39 -04:00
namespace Mesen.GUI.Debugger.Controls
{
2016-12-11 14:25:29 -05:00
public partial class ctrlChrViewer : BaseControl
2015-08-08 22:36:39 -04:00
{
2016-11-26 20:44:23 -05:00
private byte [ ] [ ] _chrPixelData = new byte [ 2 ] [ ] ;
private int _selectedPalette = 0 ;
private int _chrSelection = 0 ;
private CdlHighlightType _highlightType = CdlHighlightType . None ;
private bool _useLargeSprites = false ;
2017-03-04 21:50:19 -05:00
private Bitmap _tilePreview ;
private Bitmap [ ] _chrBanks = new Bitmap [ 2 ] ;
private bool _bottomBank = false ;
private int _tileIndex = 0 ;
private bool _hoverBottomBank = false ;
private int _hoverTileIndex = - 1 ;
private int _tilePosX = - 1 ;
private int _tilePosY = - 1 ;
2016-11-26 20:44:23 -05:00
2017-03-24 12:14:33 -04:00
private bool _forceChrRefresh = false ;
2015-08-08 22:36:39 -04:00
public ctrlChrViewer ( )
{
InitializeComponent ( ) ;
2016-11-29 20:44:22 -05:00
bool designMode = ( LicenseManager . UsageMode = = LicenseUsageMode . Designtime ) ;
if ( ! designMode ) {
this . cboPalette . SelectedIndex = 0 ;
this . cboHighlightType . SelectedIndex = 0 ;
2017-03-04 21:50:19 -05:00
this . picTile . Cursor = new Cursor ( Properties . Resources . Pencil . GetHicon ( ) ) ;
this . toolTip . SetToolTip ( this . picTileTooltip , "Click on the tile to draw with the selected color." + Environment . NewLine + "Right button draws the background color." ) ;
this . toolTip . SetToolTip ( this . picColorTooltip , "Click on a color (or press 1-4) to select it." ) ;
this . toolTip . SetToolTip ( this . picPaletteTooltip , "Press Shift-1 to Shift-8 to select the palette." ) ;
2017-08-15 22:01:54 -04:00
this . ctrlTilePalette . AllowSelection = true ;
this . ctrlTilePalette . HighlightMouseOver = true ;
this . ctrlTilePalette . DisplayIndexes = true ;
2016-11-29 20:44:22 -05:00
}
2015-08-08 22:36:39 -04:00
}
2016-11-26 20:44:23 -05:00
2017-08-20 12:06:45 -04:00
public int SelectedTileIndex
{
get { return cboChrSelection . SelectedIndex = = 0 ? ( _tileIndex + ( _bottomBank ? 256 : 0 ) ) : - 1 ; }
set
{
}
}
public int SelectedPaletteIndex
{
get { return cboPalette . SelectedIndex ; }
set
{
}
}
2016-11-26 20:44:23 -05:00
public void GetData ( )
2015-08-08 22:36:39 -04:00
{
2016-11-26 20:44:23 -05:00
for ( int i = 0 ; i < 2 ; i + + ) {
_chrPixelData [ i ] = InteropEmu . DebugGetChrBank ( i + _chrSelection * 2 , _selectedPalette , _useLargeSprites , _highlightType ) ;
2015-08-08 22:36:39 -04:00
}
}
2017-03-24 12:14:33 -04:00
public void RefreshViewer ( bool refreshPreview = false )
2015-08-08 22:36:39 -04:00
{
2017-03-24 12:14:33 -04:00
_forceChrRefresh = true ;
2016-09-05 12:09:14 -04:00
UpdateDropdown ( ) ;
2016-11-26 20:44:23 -05:00
PictureBox [ ] chrBanks = new PictureBox [ ] { this . picChrBank1 , this . picChrBank2 } ;
2015-08-08 22:36:39 -04:00
for ( int i = 0 ; i < 2 ; i + + ) {
2016-11-26 20:44:23 -05:00
byte [ ] pixelData = _chrPixelData [ i ] ;
2015-08-08 22:36:39 -04:00
GCHandle handle = GCHandle . Alloc ( pixelData , GCHandleType . Pinned ) ;
try {
Bitmap source = new Bitmap ( 128 , 128 , 4 * 128 , System . Drawing . Imaging . PixelFormat . Format32bppArgb , handle . AddrOfPinnedObject ( ) ) ;
Bitmap target = new Bitmap ( 256 , 256 ) ;
using ( Graphics g = Graphics . FromImage ( target ) ) {
g . InterpolationMode = System . Drawing . Drawing2D . InterpolationMode . NearestNeighbor ;
g . SmoothingMode = System . Drawing . Drawing2D . SmoothingMode . None ;
g . PixelOffsetMode = System . Drawing . Drawing2D . PixelOffsetMode . Half ;
2016-12-13 22:19:18 -05:00
g . ScaleTransform ( 2 , 2 ) ;
g . DrawImageUnscaled ( source , 0 , 0 ) ;
2015-08-08 22:36:39 -04:00
}
2017-03-04 21:50:19 -05:00
_chrBanks [ i ] = target ;
Bitmap chrBankImage = new Bitmap ( 256 , 256 ) ;
using ( Graphics g = Graphics . FromImage ( chrBankImage ) ) {
g . DrawImage ( _chrBanks [ i ] , 0 , 0 ) ;
if ( ( _bottomBank & & i = = 1 ) | | ( ! _bottomBank & & i = = 0 ) ) {
int tileX = _tileIndex % 16 ;
int tileY = _tileIndex / 16 ;
using ( Brush brush = new SolidBrush ( Color . FromArgb ( 192 , Color . White ) ) ) {
g . FillRectangle ( brush , tileX * 16 , tileY * 16 , 16 , 16 ) ;
g . DrawRectangle ( Pens . Black , tileX * 16 , tileY * 16 , 16 , 16 ) ;
}
}
if ( _hoverTileIndex > = 0 ) {
if ( ( _hoverBottomBank & & i = = 1 ) | | ( ! _hoverBottomBank & & i = = 0 ) ) {
int tileX = _hoverTileIndex % 16 ;
int tileY = _hoverTileIndex / 16 ;
using ( Brush brush = new SolidBrush ( Color . FromArgb ( 192 , Color . LightBlue ) ) ) {
g . FillRectangle ( brush , tileX * 16 , tileY * 16 , 16 , 16 ) ;
g . DrawRectangle ( Pens . Black , tileX * 16 - 1 , tileY * 16 - 1 , 18 , 18 ) ;
}
}
}
}
chrBanks [ i ] . Image = chrBankImage ;
2015-08-08 22:36:39 -04:00
} finally {
handle . Free ( ) ;
}
}
2017-03-04 21:50:19 -05:00
2017-03-24 12:14:33 -04:00
this . RefreshPreview ( _hoverTileIndex > = 0 ? _hoverTileIndex : _tileIndex , _hoverTileIndex > = 0 ? _hoverBottomBank : _bottomBank ) ;
2017-08-15 22:01:54 -04:00
ctrlTilePalette . RefreshPalette ( ) ;
2015-08-08 22:36:39 -04:00
}
2016-09-05 12:09:14 -04:00
private UInt32 _chrSize ;
private void UpdateDropdown ( )
{
DebugState state = new DebugState ( ) ;
InteropEmu . DebugGetState ( ref state ) ;
2016-09-05 16:34:01 -04:00
if ( state . Cartridge . ChrRomSize = = 0 ) {
this . flpHighlight . Visible = false ;
this . cboHighlightType . SelectedIndex = 0 ;
} else {
this . flpHighlight . Visible = true ;
}
2016-09-05 12:09:14 -04:00
UInt32 chrSize = state . Cartridge . ChrRomSize = = 0 ? state . Cartridge . ChrRamSize : state . Cartridge . ChrRomSize ;
if ( chrSize ! = _chrSize ) {
_chrSize = chrSize ;
int index = this . cboChrSelection . SelectedIndex ;
this . cboChrSelection . Items . Clear ( ) ;
this . cboChrSelection . Items . Add ( "PPU: $0000 - $1FFF" ) ;
for ( int i = 0 ; i < _chrSize / 0x2000 ; i + + ) {
this . cboChrSelection . Items . Add ( "CHR: $" + ( i * 0x2000 ) . ToString ( "X4" ) + " - $" + ( i * 0x2000 + 0x1FFF ) . ToString ( "X4" ) ) ;
}
this . cboChrSelection . SelectedIndex = this . cboChrSelection . Items . Count > index & & index > = 0 ? index : 0 ;
2017-08-13 20:45:36 -04:00
this . _chrSelection = this . cboChrSelection . SelectedIndex ;
2016-09-05 12:09:14 -04:00
}
}
private void cboChrSelection_DropDown ( object sender , EventArgs e )
{
UpdateDropdown ( ) ;
}
2015-08-08 22:36:39 -04:00
private void cboPalette_SelectedIndexChanged ( object sender , EventArgs e )
{
2016-11-26 20:44:23 -05:00
this . _selectedPalette = this . cboPalette . SelectedIndex ;
2017-08-15 22:01:54 -04:00
this . ctrlTilePalette . SelectedPalette = this . _selectedPalette ;
2017-03-04 21:50:19 -05:00
this . GetData ( ) ;
2015-08-08 22:36:39 -04:00
this . RefreshViewer ( ) ;
}
2016-08-29 18:10:55 -04:00
private void chkLargeSprites_Click ( object sender , EventArgs e )
{
2016-11-26 20:44:23 -05:00
this . _useLargeSprites = this . chkLargeSprites . Checked ;
2017-03-04 21:50:19 -05:00
this . GetData ( ) ;
2016-08-29 18:10:55 -04:00
this . RefreshViewer ( ) ;
}
2016-09-05 12:09:14 -04:00
private void cboHighlightType_SelectedIndexChanged ( object sender , EventArgs e )
{
2016-11-26 20:44:23 -05:00
this . _highlightType = ( CdlHighlightType ) this . cboHighlightType . SelectedIndex ;
2017-03-04 21:50:19 -05:00
this . GetData ( ) ;
2016-09-05 12:09:14 -04:00
this . RefreshViewer ( ) ;
}
private void cboChrSelection_SelectionChangeCommitted ( object sender , EventArgs e )
{
2016-11-26 20:44:23 -05:00
this . _chrSelection = this . cboChrSelection . SelectedIndex ;
2017-03-04 21:50:19 -05:00
this . GetData ( ) ;
2016-09-05 12:09:14 -04:00
this . RefreshViewer ( ) ;
}
2015-08-08 22:36:39 -04:00
private void picChrBank_MouseMove ( object sender , MouseEventArgs e )
{
2017-03-04 21:50:19 -05:00
int tileX = Math . Min ( e . X / 16 , 15 ) ;
int tileY = Math . Min ( e . Y / 16 , 15 ) ;
2017-03-24 12:14:33 -04:00
bool bottomBank = sender = = this . picChrBank2 ;
int tileIndex = tileY * 16 + tileX ;
if ( _forceChrRefresh | | bottomBank ! = _hoverBottomBank | | tileIndex ! = _hoverTileIndex ) {
_hoverBottomBank = sender = = this . picChrBank2 ;
_hoverTileIndex = tileY * 16 + tileX ;
RefreshViewer ( ) ;
RefreshPreview ( _hoverTileIndex , _hoverBottomBank ) ;
_forceChrRefresh = false ;
}
2017-03-04 21:50:19 -05:00
}
2015-08-08 22:36:39 -04:00
2017-03-04 21:50:19 -05:00
private void picChrBank_MouseDown ( object sender , MouseEventArgs e )
{
2015-08-08 22:36:39 -04:00
int tileX = Math . Min ( e . X / 16 , 15 ) ;
int tileY = Math . Min ( e . Y / 16 , 15 ) ;
2017-03-04 21:50:19 -05:00
_tileIndex = tileY * 16 + tileX ;
_bottomBank = sender = = this . picChrBank2 ;
}
2015-08-08 22:36:39 -04:00
2017-03-04 21:50:19 -05:00
private void picChrBank_MouseLeave ( object sender , EventArgs e )
{
_hoverTileIndex = - 1 ;
RefreshPreview ( _tileIndex , _bottomBank ) ;
}
2015-08-08 22:36:39 -04:00
2017-03-04 21:50:19 -05:00
private void RefreshPreview ( int tileIndex , bool bottomBank )
{
int baseAddress = bottomBank ? 0x1000 : 0x0000 ;
if ( this . cboChrSelection . SelectedIndex > 1 ) {
baseAddress + = ( this . cboChrSelection . SelectedIndex - 1 ) * 0x2000 ;
2016-12-13 22:19:18 -05:00
}
2017-03-04 21:50:19 -05:00
int tileX = tileIndex % 16 ;
int tileY = tileIndex / 16 ;
int realIndex = GetLargeSpriteIndex ( tileIndex ) ;
this . txtTileIndex . Text = realIndex . ToString ( "X2" ) ;
this . txtTileAddress . Text = ( baseAddress + realIndex * 16 ) . ToString ( "X4" ) ;
_tilePreview = new Bitmap ( 128 , 128 ) ;
Bitmap source = new Bitmap ( 16 , 16 ) ;
using ( Graphics g = Graphics . FromImage ( source ) ) {
g . DrawImage ( bottomBank ? this . _chrBanks [ 1 ] : this . _chrBanks [ 0 ] , new Rectangle ( 0 , 0 , 16 , 16 ) , new Rectangle ( tileX * 16 , tileY * 16 , 16 , 16 ) , GraphicsUnit . Pixel ) ;
}
using ( Graphics g = Graphics . FromImage ( _tilePreview ) ) {
2015-08-08 22:36:39 -04:00
g . InterpolationMode = System . Drawing . Drawing2D . InterpolationMode . NearestNeighbor ;
g . SmoothingMode = System . Drawing . Drawing2D . SmoothingMode . None ;
g . PixelOffsetMode = System . Drawing . Drawing2D . PixelOffsetMode . Half ;
2017-03-04 21:50:19 -05:00
g . ScaleTransform ( 8 , 8 ) ;
g . DrawImageUnscaled ( source , 0 , 0 ) ;
}
Bitmap tile = new Bitmap ( 128 , 128 ) ;
using ( Graphics g = Graphics . FromImage ( tile ) ) {
g . DrawImageUnscaled ( _tilePreview , 0 , 0 ) ;
using ( Brush brush = new SolidBrush ( Color . FromArgb ( 128 , Color . White ) ) ) {
g . FillRectangle ( brush , _tilePosX * 16 , _tilePosY * 16 , 16 , 16 ) ;
}
2015-08-08 22:36:39 -04:00
}
this . picTile . Image = tile ;
}
2017-03-04 21:50:19 -05:00
private void picTile_MouseMove ( object sender , MouseEventArgs e )
{
2017-03-24 12:14:33 -04:00
int x = Math . Max ( 0 , Math . Min ( e . X / 16 , 7 ) ) ;
int y = Math . Max ( 0 , Math . Min ( e . Y / 16 , 7 ) ) ;
2017-03-04 21:50:19 -05:00
2017-03-24 12:14:33 -04:00
if ( x ! = _tilePosX | | y ! = _tilePosY ) {
_tilePosX = x ;
_tilePosY = y ;
RefreshPreview ( _tileIndex , _bottomBank ) ;
2017-03-04 21:50:19 -05:00
2017-03-24 12:14:33 -04:00
if ( _drawing ) {
DrawPixel ( e . Button = = MouseButtons . Left , _tilePosX , _tilePosY ) ;
}
2017-03-04 21:50:19 -05:00
}
}
private void picTile_MouseLeave ( object sender , EventArgs e )
{
_tilePosX = - 1 ;
_tilePosY = - 1 ;
}
private int GetLargeSpriteIndex ( int tileIndex )
{
if ( chkLargeSprites . Checked ) {
int tileY = tileIndex / 16 ;
int tileX = tileIndex % 16 ;
int newX = ( tileX * 2 ) % 16 + ( ( tileY & 0x01 ) = = 0x01 ? 1 : 0 ) ;
int newY = ( tileY & 0xFE ) + ( ( tileX > = 8 ) ? 1 : 0 ) ;
return newY * 16 + newX ;
} else {
return tileIndex ;
}
}
private void DrawPixel ( bool leftButton , int x , int y )
{
int baseAddress = _bottomBank ? 0x1000 : 0x0000 ;
bool ppuMemory = this . cboChrSelection . SelectedIndex = = 0 ;
if ( this . cboChrSelection . SelectedIndex > 1 ) {
baseAddress + = ( this . cboChrSelection . SelectedIndex - 1 ) * 0x2000 ;
}
int tileIndex = GetLargeSpriteIndex ( _tileIndex ) ;
byte orgByte1 = InteropEmu . DebugGetMemoryValue ( ppuMemory ? DebugMemoryType . PpuMemory : DebugMemoryType . ChrRom , ( UInt32 ) ( baseAddress + tileIndex * 16 + y ) ) ;
byte orgByte2 = InteropEmu . DebugGetMemoryValue ( ppuMemory ? DebugMemoryType . PpuMemory : DebugMemoryType . ChrRom , ( UInt32 ) ( baseAddress + tileIndex * 16 + y + 8 ) ) ;
byte byte1 = ( byte ) ( orgByte1 & ~ ( 0x80 > > x ) ) ;
byte byte2 = ( byte ) ( orgByte2 & ~ ( 0x80 > > x ) ) ;
byte value = 0 ;
if ( leftButton ) {
2017-08-15 22:01:54 -04:00
value = ( byte ) ctrlTilePalette . SelectedColor ;
2017-03-04 21:50:19 -05:00
byte1 | = ( byte ) ( ( ( value < < 7 ) & 0x80 ) > > x ) ;
byte2 | = ( byte ) ( ( ( value < < 6 ) & 0x80 ) > > x ) ;
}
if ( byte1 ! = orgByte1 | | byte2 ! = orgByte2 ) {
InteropEmu . DebugSetMemoryValue ( ppuMemory ? DebugMemoryType . PpuMemory : DebugMemoryType . ChrRom , ( UInt32 ) ( baseAddress + tileIndex * 16 + y ) , byte1 ) ;
InteropEmu . DebugSetMemoryValue ( ppuMemory ? DebugMemoryType . PpuMemory : DebugMemoryType . ChrRom , ( UInt32 ) ( baseAddress + tileIndex * 16 + y + 8 ) , byte2 ) ;
GetData ( ) ;
RefreshViewer ( ) ;
}
}
private bool _drawing = false ;
private void picTile_MouseDown ( object sender , MouseEventArgs e )
{
_drawing = true ;
int x = Math . Max ( 0 , Math . Min ( e . X / 16 , 7 ) ) ;
int y = Math . Max ( 0 , Math . Min ( e . Y / 16 , 7 ) ) ;
DrawPixel ( e . Button = = MouseButtons . Left , x , y ) ;
}
private void picTile_MouseUp ( object sender , MouseEventArgs e )
{
_drawing = false ;
}
public void SelectPalette ( int palette )
{
cboPalette . SelectedIndex = palette ;
}
public void SelectColor ( int color )
{
2017-08-15 22:01:54 -04:00
ctrlTilePalette . SelectedColor = color ;
2017-03-04 21:50:19 -05:00
}
2017-06-28 19:00:08 -04:00
string _copyData ;
private void mnuCopyHdPack_Click ( object sender , EventArgs e )
{
Clipboard . SetText ( _copyData ) ;
}
private void ctxMenu_Opening ( object sender , CancelEventArgs e )
{
int baseAddress = _bottomBank ? 0x1000 : 0x0000 ;
bool ppuMemory = this . cboChrSelection . SelectedIndex = = 0 ;
if ( this . cboChrSelection . SelectedIndex > 1 ) {
baseAddress + = ( this . cboChrSelection . SelectedIndex - 1 ) * 0x2000 ;
}
int tileIndex = GetLargeSpriteIndex ( _tileIndex ) ;
2017-08-13 20:45:36 -04:00
bool isChrRam = InteropEmu . DebugGetMemorySize ( DebugMemoryType . ChrRom ) = = 0 ;
2017-06-28 19:00:08 -04:00
StringBuilder sb = new StringBuilder ( ) ;
2017-08-13 20:45:36 -04:00
if ( isChrRam ) {
for ( int i = 0 ; i < 16 ; i + + ) {
sb . Append ( InteropEmu . DebugGetMemoryValue ( ppuMemory ? DebugMemoryType . PpuMemory : DebugMemoryType . ChrRom , ( UInt32 ) ( baseAddress + tileIndex * 16 + i ) ) . ToString ( "X2" ) ) ;
}
} else {
int absoluteTileIndex = ppuMemory ? InteropEmu . DebugGetAbsoluteChrAddress ( ( uint ) ( baseAddress + tileIndex * 16 ) ) / 16 : ( baseAddress / 16 + tileIndex ) ;
sb . Append ( absoluteTileIndex . ToString ( ) ) ;
2017-06-28 19:00:08 -04:00
}
sb . Append ( "," ) ;
2017-08-07 22:52:27 -04:00
for ( int i = 0 ; i < 4 ; i + + ) {
2017-06-28 19:00:08 -04:00
sb . Append ( InteropEmu . DebugGetMemoryValue ( DebugMemoryType . PaletteMemory , ( uint ) ( this . _selectedPalette * 4 + i ) ) . ToString ( "X2" ) ) ;
}
_copyData = sb . ToString ( ) ;
}
2015-08-08 22:36:39 -04:00
}
}