diff --git a/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs b/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs index 00e7ed4430..c82115abc4 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs @@ -78,8 +78,30 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES } } + public enum BGMode + { + Unavailable, Text, Mode7, Mode7Ext, Mode7DC + } + + /// + /// this class is not 'smart' - it wont recompute values for you. it's meant to be read only (we should find some way to protect write access to make that clear) + /// public class BGInfo { + public BGInfo(int num) + { + } + + /// + /// what type of BG is it? + /// + public BGMode BGMode; + + /// + /// is this BGMode a mode7 type (mode7, mode7ext, mode7DC) + /// + public bool BGModeIsMode7Type { get { return BGMode == SNESGraphicsDecoder.BGMode.Mode7 || BGMode == SNESGraphicsDecoder.BGMode.Mode7DC || BGMode == SNESGraphicsDecoder.BGMode.Mode7Ext; } } + /// /// Is the layer even enabled? /// @@ -103,12 +125,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES /// /// the address of the screen data /// - public int ScreenAddr { get { return SCADDR << 9; } } + public int ScreenAddr; /// /// the address of the tile data /// - public int TiledataAddr { get { return TDADDR << 13; } } + public int TiledataAddr; /// /// Screen size (shape, really.) @@ -148,7 +170,15 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES /// /// The size of the layer, in tiles /// - public Dimensions ScreenSizeInTiles { get { return SizeInTilesForBGSize(ScreenSize); } } + public Dimensions ScreenSizeInTiles + { + get + { + if (BGMode == SNESGraphicsDecoder.BGMode.Text) + return SizeInTilesForBGSize(ScreenSize); + else return new Dimensions(128, 128); + } + } /// /// The size of the layer, in pixels. This has factored in the selection of 8x8 or 16x16 tiles @@ -170,7 +200,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES public class BGInfos { - BGInfo[] bgs = new BGInfo[4] { new BGInfo(), new BGInfo(), new BGInfo(), new BGInfo() }; + BGInfo[] bgs = new BGInfo[4] { new BGInfo(1), new BGInfo(2), new BGInfo(3), new BGInfo(4) }; public BGInfo BG1 { get { return bgs[0]; } } public BGInfo BG2 { get { return bgs[1]; } } public BGInfo BG3 { get { return bgs[2]; } } @@ -296,8 +326,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES si.BG.BG3.Bpp = ModeBpps[si.Mode.MODE, 2]; si.BG.BG4.Bpp = ModeBpps[si.Mode.MODE, 3]; - if (si.Mode.MODE == 7 && si.SETINI_Mode7ExtBG) - si.BG.BG2.Bpp = 7; + //initial setting of mode type (derived from bpp table.. mode7 bg types will be fixed up later) + for(int i=1;i<=4;i++) + si.BG[i].BGMode = si.BG[i].Bpp == 0 ? BGMode.Unavailable : BGMode.Text; si.BG.BG1.TILESIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG1_TILESIZE); si.BG.BG2.TILESIZE = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.BG2_TILESIZE); @@ -331,7 +362,33 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES si.BG.BG4.MathEnabled = LibsnesDll.snes_peek_logical_register(LibsnesDll.SNES_REG.CGADSUB_BG4) == 1; for (int i = 1; i <= 4; i++) + { si.BG[i].Mode = si.Mode.MODE; + si.BG[i].TiledataAddr = si.BG[i].TDADDR << 13; + si.BG[i].ScreenAddr = si.BG[i].SCADDR << 9; + } + + //fixup irregular things for mode 7 + if (si.Mode.MODE == 7) + { + si.BG.BG1.TiledataAddr = 0; + si.BG.BG1.ScreenAddr = 0; + + if (si.CGWSEL_DirectColor) + { + si.BG.BG1.BGMode = BGMode.Mode7DC; + } + else + si.BG.BG1.BGMode = BGMode.Mode7; + + if (si.SETINI_Mode7ExtBG) + { + si.BG.BG2.BGMode = BGMode.Mode7Ext; + si.BG.BG2.Bpp = 7; + si.BG.BG2.TiledataAddr = 0; + si.BG.BG2.ScreenAddr = 0; + } + } //determine which colors each BG could use switch (si.Mode.MODE) @@ -452,7 +509,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES public enum TileEntryFlags : byte { - Priority = 1, Horz = 2, Vert = 4, + None = 0, Priority = 1, Horz = 2, Vert = 4, } /// @@ -563,6 +620,23 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES } } + public TileEntry[] FetchMode7Tilemap() + { + TileEntry[] buf = new TileEntry[128*128]; + for (int ty = 0, tidx = 0; ty < 128; ty++) + { + for (int tx = 0; tx < 128; tx++, tidx++) + { + int tileEntry = vram[tidx * 2]; + buf[tidx].address = tidx * 2; + buf[tidx].tilenum = (ushort)tileEntry; + //palette and flags are ok defaulting to 0 + } + } + + return buf; + } + /// /// fetches a tilemap. this is simple; apparently only the screen size (shape) is a factor (not the tile size) /// @@ -732,17 +806,18 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES /// /// renders the mode7 tiles to a screen with the predefined size. /// - public void RenderMode7TilesToScreen(int* screen, int stride, bool ext, bool directColor) + public void RenderMode7TilesToScreen(int* screen, int stride, bool ext, bool directColor, int tilesWide = 16, int startTile = 0, int numTiles = 256) { - int numTiles = 256; - int tilesWide = 16; int[] tilebuf = _tileCache[ext?17:7]; for (int i = 0; i < numTiles; i++) { + int tnum = startTile + i; + //TODO - mask by possible number of tiles? only in OBJ rendering mode? + int ty = i / tilesWide; int tx = i % tilesWide; int dstOfs = (ty * 8) * stride + tx * 8; - int srcOfs = i * 64; + int srcOfs = tnum * 64; for (int y = 0, p = 0; y < 8; y++) { for (int x = 0; x < 8; x++, p++) @@ -758,6 +833,38 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES Colorize(screen, 0, numPixels); } + + /// + /// renders the tiles to a screen of the crudely specified size. + /// we might need 16x16 unscrambling and some other perks here eventually. + /// provide a start color to use as the basis for the palette + /// + public void RenderTilesToScreen(int* screen, int tilesWide, int tilesTall, int stride, int bpp, int startcolor, int startTile = 0, int numTiles = -1, bool descramble16 = false) + { + if (numTiles == -1) + numTiles = 8192 / bpp; + int[] tilebuf = _tileCache[bpp]; + for (int i = 0; i < numTiles; i++) + { + int tnum = startTile + i; + //TODO - mask by possible number of tiles? only in OBJ rendering mode? + int ty = i / tilesWide; + int tx = i % tilesWide; + int dstOfs = (ty * 8) * stride + tx * 8; + int srcOfs = tnum * 64; + for (int y = 0, p = 0; y < 8; y++) + for (int x = 0; x < 8; x++, p++) + { + screen[dstOfs + y * stride + x] = tilebuf[srcOfs + p]; + } + } + + int numPixels = numTiles * 8 * 8; + Paletteize(screen, 0, startcolor, numPixels); + Colorize(screen, 0, numPixels); + } + + public void RenderSpriteToScreen(int* screen, int stride, int destx, int desty, ScreenInfo si, int spritenum) { var dims = new[] { SNESGraphicsDecoder.ObjSizes[si.OBSEL_Size, 0], SNESGraphicsDecoder.ObjSizes[si.OBSEL_Size, 1] }; @@ -794,36 +901,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES } } - /// - /// renders the tiles to a screen of the crudely specified size. - /// we might need 16x16 unscrambling and some other perks here eventually. - /// provide a start color to use as the basis for the palette - /// - public void RenderTilesToScreen(int* screen, int tilesWide, int tilesTall, int stride, int bpp, int startcolor, int startTile = 0, int numTiles = -1, bool descramble16 = false) - { - if(numTiles == -1) - numTiles = 8192 / bpp; - int[] tilebuf = _tileCache[bpp]; - for (int i = 0; i < numTiles; i++) - { - int tnum = startTile + i; - //TODO - mask by possible number of tiles? only in OBJ rendering mode? - int ty = i / tilesWide; - int tx = i % tilesWide; - int dstOfs = (ty * 8) * stride + tx * 8; - int srcOfs = tnum * 64; - for (int y = 0,p=0; y < 8; y++) - for (int x = 0; x < 8; x++,p++) - { - screen[dstOfs+y*stride+x] = tilebuf[srcOfs + p]; - } - } - - int numPixels = numTiles * 8 * 8; - Paletteize(screen, 0, startcolor, numPixels); - Colorize(screen, 0, numPixels); - } - public int Colorize(int rgb555) { return colortable[491520 + rgb555]; diff --git a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.Designer.cs b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.Designer.cs index 98a6a8fb1d..9d03296d98 100644 --- a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.Designer.cs +++ b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.Designer.cs @@ -43,18 +43,8 @@ this.panel1 = new System.Windows.Forms.Panel(); this.groupFreeze = new System.Windows.Forms.GroupBox(); this.pnGroupFreeze = new System.Windows.Forms.Panel(); + this.labelMemory = new System.Windows.Forms.Label(); this.check2x = new System.Windows.Forms.CheckBox(); - this.groupBox8 = new System.Windows.Forms.GroupBox(); - this.radioButton6 = new System.Windows.Forms.RadioButton(); - this.radioButton1 = new System.Windows.Forms.RadioButton(); - this.radioButton10 = new System.Windows.Forms.RadioButton(); - this.radioButton15 = new System.Windows.Forms.RadioButton(); - this.radioButton5 = new System.Windows.Forms.RadioButton(); - this.radioButton14 = new System.Windows.Forms.RadioButton(); - this.radioButton4 = new System.Windows.Forms.RadioButton(); - this.radioButton3 = new System.Windows.Forms.RadioButton(); - this.radioButton13 = new System.Windows.Forms.RadioButton(); - this.radioButton2 = new System.Windows.Forms.RadioButton(); this.comboDisplayType = new System.Windows.Forms.ComboBox(); this.label47 = new System.Windows.Forms.Label(); this.pnBackdropColor = new System.Windows.Forms.Panel(); @@ -71,6 +61,17 @@ this.groupBox2 = new System.Windows.Forms.GroupBox(); this.label26 = new System.Windows.Forms.Label(); this.txtOBSELT1OfsBits = new System.Windows.Forms.TextBox(); + this.groupBox8 = new System.Windows.Forms.GroupBox(); + this.radioButton6 = new System.Windows.Forms.RadioButton(); + this.radioButton1 = new System.Windows.Forms.RadioButton(); + this.radioButton10 = new System.Windows.Forms.RadioButton(); + this.radioButton15 = new System.Windows.Forms.RadioButton(); + this.radioButton5 = new System.Windows.Forms.RadioButton(); + this.radioButton14 = new System.Windows.Forms.RadioButton(); + this.radioButton4 = new System.Windows.Forms.RadioButton(); + this.radioButton3 = new System.Windows.Forms.RadioButton(); + this.radioButton13 = new System.Windows.Forms.RadioButton(); + this.radioButton2 = new System.Windows.Forms.RadioButton(); this.label41 = new System.Windows.Forms.Label(); this.txtOBSELT1OfsDescr = new System.Windows.Forms.TextBox(); this.checkEN1_OBJ = new System.Windows.Forms.CheckBox(); @@ -159,6 +160,7 @@ this.label4 = new System.Windows.Forms.Label(); this.label5 = new System.Windows.Forms.Label(); this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.txtBG1MapSizeBytes = new System.Windows.Forms.TextBox(); this.txtBGPaletteInfo = new System.Windows.Forms.TextBox(); this.rbBG4 = new System.Windows.Forms.RadioButton(); this.rbBG3 = new System.Windows.Forms.RadioButton(); @@ -219,18 +221,17 @@ this.viewerTile = new BizHawk.MultiClient.SNESGraphicsViewer(); this.viewerMapEntryTile = new BizHawk.MultiClient.SNESGraphicsViewer(); this.viewer = new BizHawk.MultiClient.SNESGraphicsViewer(); - this.labelMemory = new System.Windows.Forms.Label(); this.menuStrip1.SuspendLayout(); this.tableLayoutPanel1.SuspendLayout(); this.panel1.SuspendLayout(); this.groupFreeze.SuspendLayout(); this.pnGroupFreeze.SuspendLayout(); - this.groupBox8.SuspendLayout(); this.groupBox3.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.nudScanline)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.sliderScanline)).BeginInit(); this.groupBox6.SuspendLayout(); this.groupBox2.SuspendLayout(); + this.groupBox8.SuspendLayout(); this.groupBox1.SuspendLayout(); this.groupBox5.SuspendLayout(); this.tabctrlDetails.SuspendLayout(); @@ -372,6 +373,15 @@ this.pnGroupFreeze.Size = new System.Drawing.Size(208, 94); this.pnGroupFreeze.TabIndex = 0; // + // labelMemory + // + this.labelMemory.AutoSize = true; + this.labelMemory.Location = new System.Drawing.Point(3, 2); + this.labelMemory.Name = "labelMemory"; + this.labelMemory.Size = new System.Drawing.Size(176, 13); + this.labelMemory.TabIndex = 1; + this.labelMemory.Text = "Right-click an item to display it here."; + // // check2x // this.check2x.Appearance = System.Windows.Forms.Appearance.Button; @@ -386,145 +396,6 @@ this.check2x.UseVisualStyleBackColor = true; this.check2x.CheckedChanged += new System.EventHandler(this.check2x_CheckedChanged); // - // groupBox8 - // - this.groupBox8.Controls.Add(this.radioButton6); - this.groupBox8.Controls.Add(this.radioButton1); - this.groupBox8.Controls.Add(this.radioButton10); - this.groupBox8.Controls.Add(this.radioButton15); - this.groupBox8.Controls.Add(this.radioButton5); - this.groupBox8.Controls.Add(this.radioButton14); - this.groupBox8.Controls.Add(this.radioButton4); - this.groupBox8.Controls.Add(this.radioButton3); - this.groupBox8.Controls.Add(this.radioButton13); - this.groupBox8.Controls.Add(this.radioButton2); - this.groupBox8.Location = new System.Drawing.Point(273, 247); - this.groupBox8.Name = "groupBox8"; - this.groupBox8.Size = new System.Drawing.Size(15, 22); - this.groupBox8.TabIndex = 54; - this.groupBox8.TabStop = false; - this.groupBox8.Text = "groupBox8"; - // - // radioButton6 - // - this.radioButton6.AutoSize = true; - this.radioButton6.Enabled = false; - this.radioButton6.Location = new System.Drawing.Point(77, 115); - this.radioButton6.Name = "radioButton6"; - this.radioButton6.Size = new System.Drawing.Size(73, 17); - this.radioButton6.TabIndex = 49; - this.radioButton6.TabStop = true; - this.radioButton6.Text = "Mode7Ext"; - this.radioButton6.UseVisualStyleBackColor = true; - // - // radioButton1 - // - this.radioButton1.AutoSize = true; - this.radioButton1.Enabled = false; - this.radioButton1.Location = new System.Drawing.Point(27, 51); - this.radioButton1.Name = "radioButton1"; - this.radioButton1.Size = new System.Drawing.Size(46, 17); - this.radioButton1.TabIndex = 19; - this.radioButton1.TabStop = true; - this.radioButton1.Text = "BG1"; - this.radioButton1.UseVisualStyleBackColor = true; - // - // radioButton10 - // - this.radioButton10.AutoSize = true; - this.radioButton10.Enabled = false; - this.radioButton10.Location = new System.Drawing.Point(77, 67); - this.radioButton10.Name = "radioButton10"; - this.radioButton10.Size = new System.Drawing.Size(49, 17); - this.radioButton10.TabIndex = 28; - this.radioButton10.TabStop = true; - this.radioButton10.Text = "4bpp"; - this.radioButton10.UseVisualStyleBackColor = true; - // - // radioButton15 - // - this.radioButton15.AutoSize = true; - this.radioButton15.Enabled = false; - this.radioButton15.Location = new System.Drawing.Point(77, 99); - this.radioButton15.Name = "radioButton15"; - this.radioButton15.Size = new System.Drawing.Size(58, 17); - this.radioButton15.TabIndex = 33; - this.radioButton15.TabStop = true; - this.radioButton15.Text = "Mode7"; - this.radioButton15.UseVisualStyleBackColor = true; - // - // radioButton5 - // - this.radioButton5.AutoSize = true; - this.radioButton5.Enabled = false; - this.radioButton5.Location = new System.Drawing.Point(77, 51); - this.radioButton5.Name = "radioButton5"; - this.radioButton5.Size = new System.Drawing.Size(49, 17); - this.radioButton5.TabIndex = 23; - this.radioButton5.TabStop = true; - this.radioButton5.Text = "2bpp"; - this.radioButton5.UseVisualStyleBackColor = true; - // - // radioButton14 - // - this.radioButton14.AutoSize = true; - this.radioButton14.Enabled = false; - this.radioButton14.Location = new System.Drawing.Point(27, 116); - this.radioButton14.Name = "radioButton14"; - this.radioButton14.Size = new System.Drawing.Size(45, 17); - this.radioButton14.TabIndex = 32; - this.radioButton14.TabStop = true; - this.radioButton14.Text = "OBJ"; - this.radioButton14.UseVisualStyleBackColor = true; - // - // radioButton4 - // - this.radioButton4.AutoSize = true; - this.radioButton4.Enabled = false; - this.radioButton4.Location = new System.Drawing.Point(27, 99); - this.radioButton4.Name = "radioButton4"; - this.radioButton4.Size = new System.Drawing.Size(46, 17); - this.radioButton4.TabIndex = 22; - this.radioButton4.TabStop = true; - this.radioButton4.Text = "BG4"; - this.radioButton4.UseVisualStyleBackColor = true; - // - // radioButton3 - // - this.radioButton3.AutoSize = true; - this.radioButton3.Enabled = false; - this.radioButton3.Location = new System.Drawing.Point(27, 83); - this.radioButton3.Name = "radioButton3"; - this.radioButton3.Size = new System.Drawing.Size(46, 17); - this.radioButton3.TabIndex = 21; - this.radioButton3.TabStop = true; - this.radioButton3.Text = "BG3"; - this.radioButton3.UseVisualStyleBackColor = true; - // - // radioButton13 - // - this.radioButton13.AutoSize = true; - this.radioButton13.Enabled = false; - this.radioButton13.Location = new System.Drawing.Point(77, 83); - this.radioButton13.Name = "radioButton13"; - this.radioButton13.Size = new System.Drawing.Size(49, 17); - this.radioButton13.TabIndex = 31; - this.radioButton13.TabStop = true; - this.radioButton13.Text = "8bpp"; - this.radioButton13.UseVisualStyleBackColor = true; - // - // radioButton2 - // - this.radioButton2.AutoSize = true; - this.radioButton2.Enabled = false; - this.radioButton2.Location = new System.Drawing.Point(27, 67); - this.radioButton2.Name = "radioButton2"; - this.radioButton2.Size = new System.Drawing.Size(46, 17); - this.radioButton2.TabIndex = 20; - this.radioButton2.TabStop = true; - this.radioButton2.Text = "BG2"; - this.radioButton2.UseVisualStyleBackColor = true; - // // comboDisplayType // this.comboDisplayType.DisplayMember = "descr"; @@ -568,6 +439,7 @@ this.comboPalette.Name = "comboPalette"; this.comboPalette.Size = new System.Drawing.Size(70, 21); this.comboPalette.TabIndex = 52; + this.toolTip1.SetToolTip(this.comboPalette, resources.GetString("comboPalette.ToolTip")); this.comboPalette.ValueMember = "type"; this.comboPalette.SelectedIndexChanged += new System.EventHandler(this.comboPalette_SelectedIndexChanged); // @@ -789,6 +661,145 @@ this.txtOBSELT1OfsBits.TabIndex = 55; this.txtOBSELT1OfsBits.Text = "00"; // + // groupBox8 + // + this.groupBox8.Controls.Add(this.radioButton6); + this.groupBox8.Controls.Add(this.radioButton1); + this.groupBox8.Controls.Add(this.radioButton10); + this.groupBox8.Controls.Add(this.radioButton15); + this.groupBox8.Controls.Add(this.radioButton5); + this.groupBox8.Controls.Add(this.radioButton14); + this.groupBox8.Controls.Add(this.radioButton4); + this.groupBox8.Controls.Add(this.radioButton3); + this.groupBox8.Controls.Add(this.radioButton13); + this.groupBox8.Controls.Add(this.radioButton2); + this.groupBox8.Location = new System.Drawing.Point(273, 247); + this.groupBox8.Name = "groupBox8"; + this.groupBox8.Size = new System.Drawing.Size(15, 22); + this.groupBox8.TabIndex = 54; + this.groupBox8.TabStop = false; + this.groupBox8.Text = "groupBox8"; + // + // radioButton6 + // + this.radioButton6.AutoSize = true; + this.radioButton6.Enabled = false; + this.radioButton6.Location = new System.Drawing.Point(77, 115); + this.radioButton6.Name = "radioButton6"; + this.radioButton6.Size = new System.Drawing.Size(73, 17); + this.radioButton6.TabIndex = 49; + this.radioButton6.TabStop = true; + this.radioButton6.Text = "Mode7Ext"; + this.radioButton6.UseVisualStyleBackColor = true; + // + // radioButton1 + // + this.radioButton1.AutoSize = true; + this.radioButton1.Enabled = false; + this.radioButton1.Location = new System.Drawing.Point(27, 51); + this.radioButton1.Name = "radioButton1"; + this.radioButton1.Size = new System.Drawing.Size(46, 17); + this.radioButton1.TabIndex = 19; + this.radioButton1.TabStop = true; + this.radioButton1.Text = "BG1"; + this.radioButton1.UseVisualStyleBackColor = true; + // + // radioButton10 + // + this.radioButton10.AutoSize = true; + this.radioButton10.Enabled = false; + this.radioButton10.Location = new System.Drawing.Point(77, 67); + this.radioButton10.Name = "radioButton10"; + this.radioButton10.Size = new System.Drawing.Size(49, 17); + this.radioButton10.TabIndex = 28; + this.radioButton10.TabStop = true; + this.radioButton10.Text = "4bpp"; + this.radioButton10.UseVisualStyleBackColor = true; + // + // radioButton15 + // + this.radioButton15.AutoSize = true; + this.radioButton15.Enabled = false; + this.radioButton15.Location = new System.Drawing.Point(77, 99); + this.radioButton15.Name = "radioButton15"; + this.radioButton15.Size = new System.Drawing.Size(58, 17); + this.radioButton15.TabIndex = 33; + this.radioButton15.TabStop = true; + this.radioButton15.Text = "Mode7"; + this.radioButton15.UseVisualStyleBackColor = true; + // + // radioButton5 + // + this.radioButton5.AutoSize = true; + this.radioButton5.Enabled = false; + this.radioButton5.Location = new System.Drawing.Point(77, 51); + this.radioButton5.Name = "radioButton5"; + this.radioButton5.Size = new System.Drawing.Size(49, 17); + this.radioButton5.TabIndex = 23; + this.radioButton5.TabStop = true; + this.radioButton5.Text = "2bpp"; + this.radioButton5.UseVisualStyleBackColor = true; + // + // radioButton14 + // + this.radioButton14.AutoSize = true; + this.radioButton14.Enabled = false; + this.radioButton14.Location = new System.Drawing.Point(27, 116); + this.radioButton14.Name = "radioButton14"; + this.radioButton14.Size = new System.Drawing.Size(45, 17); + this.radioButton14.TabIndex = 32; + this.radioButton14.TabStop = true; + this.radioButton14.Text = "OBJ"; + this.radioButton14.UseVisualStyleBackColor = true; + // + // radioButton4 + // + this.radioButton4.AutoSize = true; + this.radioButton4.Enabled = false; + this.radioButton4.Location = new System.Drawing.Point(27, 99); + this.radioButton4.Name = "radioButton4"; + this.radioButton4.Size = new System.Drawing.Size(46, 17); + this.radioButton4.TabIndex = 22; + this.radioButton4.TabStop = true; + this.radioButton4.Text = "BG4"; + this.radioButton4.UseVisualStyleBackColor = true; + // + // radioButton3 + // + this.radioButton3.AutoSize = true; + this.radioButton3.Enabled = false; + this.radioButton3.Location = new System.Drawing.Point(27, 83); + this.radioButton3.Name = "radioButton3"; + this.radioButton3.Size = new System.Drawing.Size(46, 17); + this.radioButton3.TabIndex = 21; + this.radioButton3.TabStop = true; + this.radioButton3.Text = "BG3"; + this.radioButton3.UseVisualStyleBackColor = true; + // + // radioButton13 + // + this.radioButton13.AutoSize = true; + this.radioButton13.Enabled = false; + this.radioButton13.Location = new System.Drawing.Point(77, 83); + this.radioButton13.Name = "radioButton13"; + this.radioButton13.Size = new System.Drawing.Size(49, 17); + this.radioButton13.TabIndex = 31; + this.radioButton13.TabStop = true; + this.radioButton13.Text = "8bpp"; + this.radioButton13.UseVisualStyleBackColor = true; + // + // radioButton2 + // + this.radioButton2.AutoSize = true; + this.radioButton2.Enabled = false; + this.radioButton2.Location = new System.Drawing.Point(27, 67); + this.radioButton2.Name = "radioButton2"; + this.radioButton2.Size = new System.Drawing.Size(46, 17); + this.radioButton2.TabIndex = 20; + this.radioButton2.TabStop = true; + this.radioButton2.Text = "BG2"; + this.radioButton2.UseVisualStyleBackColor = true; + // // label41 // this.label41.AutoSize = true; @@ -1649,6 +1660,7 @@ // // groupBox1 // + this.groupBox1.Controls.Add(this.txtBG1MapSizeBytes); this.groupBox1.Controls.Add(this.txtBGPaletteInfo); this.groupBox1.Controls.Add(this.rbBG4); this.groupBox1.Controls.Add(this.rbBG3); @@ -1681,6 +1693,16 @@ this.groupBox1.TabStop = false; this.groupBox1.Text = "BG"; // + // txtBG1MapSizeBytes + // + this.txtBG1MapSizeBytes.Location = new System.Drawing.Point(34, 112); + this.txtBG1MapSizeBytes.Multiline = true; + this.txtBG1MapSizeBytes.Name = "txtBG1MapSizeBytes"; + this.txtBG1MapSizeBytes.ReadOnly = true; + this.txtBG1MapSizeBytes.Size = new System.Drawing.Size(33, 17); + this.txtBG1MapSizeBytes.TabIndex = 40; + this.txtBG1MapSizeBytes.Text = "(32K)"; + // // txtBGPaletteInfo // this.txtBGPaletteInfo.Location = new System.Drawing.Point(5, 181); @@ -1893,7 +1915,7 @@ // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(124, 95); + this.label3.Location = new System.Drawing.Point(134, 96); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(32, 13); this.label3.TabIndex = 7; @@ -1916,9 +1938,9 @@ this.txtBG1SizeInTiles.Multiline = true; this.txtBG1SizeInTiles.Name = "txtBG1SizeInTiles"; this.txtBG1SizeInTiles.ReadOnly = true; - this.txtBG1SizeInTiles.Size = new System.Drawing.Size(48, 17); + this.txtBG1SizeInTiles.Size = new System.Drawing.Size(59, 17); this.txtBG1SizeInTiles.TabIndex = 6; - this.txtBG1SizeInTiles.Text = "64x64"; + this.txtBG1SizeInTiles.Text = "128x128 (32K)"; // // label2 // @@ -2196,9 +2218,9 @@ this.txtMapEntryTileAddr.Multiline = true; this.txtMapEntryTileAddr.Name = "txtMapEntryTileAddr"; this.txtMapEntryTileAddr.ReadOnly = true; - this.txtMapEntryTileAddr.Size = new System.Drawing.Size(42, 18); + this.txtMapEntryTileAddr.Size = new System.Drawing.Size(45, 18); this.txtMapEntryTileAddr.TabIndex = 57; - this.txtMapEntryTileAddr.Text = "@FFFF"; + this.txtMapEntryTileAddr.Text = "@0D00"; // // txtMapEntryPrio // @@ -2306,15 +2328,6 @@ this.viewer.MouseMove += new System.Windows.Forms.MouseEventHandler(this.viewer_MouseMove); this.viewer.MouseUp += new System.Windows.Forms.MouseEventHandler(this.viewer_MouseUp); // - // labelMemory - // - this.labelMemory.AutoSize = true; - this.labelMemory.Location = new System.Drawing.Point(3, 2); - this.labelMemory.Name = "labelMemory"; - this.labelMemory.Size = new System.Drawing.Size(176, 13); - this.labelMemory.TabIndex = 1; - this.labelMemory.Text = "Right-click an item to display it here."; - // // SNESGraphicsDebugger // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -2337,8 +2350,6 @@ this.groupFreeze.ResumeLayout(false); this.pnGroupFreeze.ResumeLayout(false); this.pnGroupFreeze.PerformLayout(); - this.groupBox8.ResumeLayout(false); - this.groupBox8.PerformLayout(); this.groupBox3.ResumeLayout(false); this.groupBox3.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.nudScanline)).EndInit(); @@ -2347,6 +2358,8 @@ this.groupBox6.PerformLayout(); this.groupBox2.ResumeLayout(false); this.groupBox2.PerformLayout(); + this.groupBox8.ResumeLayout(false); + this.groupBox8.PerformLayout(); this.groupBox1.ResumeLayout(false); this.groupBox1.PerformLayout(); this.groupBox5.ResumeLayout(false); @@ -2414,7 +2427,6 @@ private System.Windows.Forms.TextBox txtBG1SizeInPixels; private System.Windows.Forms.Label label3; private System.Windows.Forms.TextBox txtBG1SCAddrBits; - private System.Windows.Forms.TextBox txtBG1SizeInTiles; private System.Windows.Forms.Label label2; private System.Windows.Forms.TextBox txtBG1SizeBits; private System.Windows.Forms.Label label19; @@ -2554,5 +2566,7 @@ private System.Windows.Forms.RadioButton radioButton2; private System.Windows.Forms.Panel pnGroupFreeze; private System.Windows.Forms.Label labelMemory; + private System.Windows.Forms.TextBox txtBG1MapSizeBytes; + private System.Windows.Forms.TextBox txtBG1SizeInTiles; } } \ No newline at end of file diff --git a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs index 87487351a7..2d726bb170 100644 --- a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs +++ b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.cs @@ -4,6 +4,7 @@ //TODO - maybe draw a label (in lieu of above, also) showing what scale the content is at: 2x or 1x or 1/2x //TODO - add eDisplayType for BG1-Tiles, BG2-Tiles, etc. which show the tiles available to a BG. more concise than viewing all tiles and illustrating the relevant accessible areas // . could this apply to the palette too? +//TODO - show the priority list for the current mode. make the priority list have checkboxes, and use that to control whether that item displays (does bsnes have that granularity? maybe) //http://stackoverflow.com/questions/1101149/displaying-thumbnail-icons-128x128-pixels-or-larger-in-a-grid-in-listview @@ -57,9 +58,9 @@ namespace BizHawk.MultiClient comboDisplayType.SelectedIndex = 0; var paletteTypeItems = new List(); - paletteTypeItems.Add(new PaletteTypeItem("BizHawk Palette", SnesColors.ColorType.BizHawk)); - paletteTypeItems.Add(new PaletteTypeItem("bsnes Palette", SnesColors.ColorType.BSNES)); - paletteTypeItems.Add(new PaletteTypeItem("Snes9X Palette", SnesColors.ColorType.Snes9x)); + paletteTypeItems.Add(new PaletteTypeItem("BizHawk", SnesColors.ColorType.BizHawk)); + paletteTypeItems.Add(new PaletteTypeItem("bsnes", SnesColors.ColorType.BSNES)); + paletteTypeItems.Add(new PaletteTypeItem("Snes9X", SnesColors.ColorType.Snes9x)); suppression = true; comboPalette.DataSource = paletteTypeItems; comboPalette.SelectedIndex = 0; @@ -87,13 +88,6 @@ namespace BizHawk.MultiClient else return bpp.ToString(); } - string FormatScreenSizeInTiles(SNESGraphicsDecoder.ScreenSize screensize) - { - var dims = SNESGraphicsDecoder.SizeInTilesForBGSize(screensize); - int size = dims.Width * dims.Height * 2 / 1024; - return string.Format("{0} ({1}K)", dims, size); - } - string FormatVramAddress(int address) { int excess = address & 1023; @@ -179,6 +173,8 @@ namespace BizHawk.MultiClient SNESGraphicsDecoder gd = new SNESGraphicsDecoder(SnesColors.ColorType.BizHawk); SNESGraphicsDecoder.ScreenInfo si; + SNESGraphicsDecoder.TileEntry[] map; + SNESGraphicsDecoder.BGMode viewBgMode; void RegenerateData() { @@ -234,13 +230,15 @@ namespace BizHawk.MultiClient txtBG1TSizeDescr.Text = string.Format("{0}x{0}", bg.TileSize); txtBG1Bpp.Text = FormatBpp(bg.Bpp); txtBG1SizeBits.Text = bg.SCSIZE.ToString(); - txtBG1SizeInTiles.Text = FormatScreenSizeInTiles(bg.ScreenSize); + txtBG1SizeInTiles.Text = bg.ScreenSizeInTiles.ToString(); + int size = bg.ScreenSizeInTiles.Width * bg.ScreenSizeInTiles.Height * 2 / 1024; + txtBG1MapSizeBytes.Text = string.Format("({0}K)", size); txtBG1SCAddrBits.Text = bg.SCADDR.ToString(); - txtBG1SCAddrDescr.Text = FormatVramAddress(bg.SCADDR << 9); + txtBG1SCAddrDescr.Text = FormatVramAddress(bg.ScreenAddr); txtBG1Colors.Text = (1 << bg.Bpp).ToString(); if (bg.Bpp == 8 && si.CGWSEL_DirectColor) txtBG1Colors.Text = "(Direct Color)"; txtBG1TDAddrBits.Text = bg.TDADDR.ToString(); - txtBG1TDAddrDescr.Text = FormatVramAddress(bg.TDADDR << 13); + txtBG1TDAddrDescr.Text = FormatVramAddress(bg.TiledataAddr); if (bg.Bpp != 0) { @@ -249,9 +247,7 @@ namespace BizHawk.MultiClient } else txtBGPaletteInfo.Text = ""; - var sizeInPixels = SNESGraphicsDecoder.SizeInTilesForBGSize(bg.ScreenSize); - sizeInPixels.Width *= si.BG[bgnum].TileSize; - sizeInPixels.Height *= si.BG[bgnum].TileSize; + var sizeInPixels = bg.ScreenSizeInPixels; txtBG1SizeInPixels.Text = string.Format("{0}x{1}", sizeInPixels.Width, sizeInPixels.Height); checkTMOBJ.Checked = si.OBJ_MainEnabled; @@ -290,7 +286,6 @@ namespace BizHawk.MultiClient RenderPalette(); RenderTileView(); UpdateColorDetails(); - UpdateMapEntryDetails(); } eDisplayType CurrDisplaySelection { get { return (comboDisplayType.SelectedValue as eDisplayType?).Value; } } @@ -377,12 +372,16 @@ namespace BizHawk.MultiClient var si = gd.ScanScreenInfo(); var bg = si.BG[bgnum]; + map = new SNESGraphicsDecoder.TileEntry[0]; + viewBgMode = bg.BGMode; + bool handled = false; if (bg.Enabled) { //TODO - directColor in normal BG renderer bool DirectColor = si.CGWSEL_DirectColor && bg.Bpp == 8; //any exceptions? int numPixels = 0; + //TODO - could use BGMode property on BG... too much chaos to deal with it now if (si.Mode.MODE == 7) { bool mode7 = bgnum == 1; @@ -395,6 +394,9 @@ namespace BizHawk.MultiClient numPixels = 128 * 128 * 8 * 8; if (DirectColor) gd.DirectColorify(pixelptr, numPixels); else gd.Paletteize(pixelptr, 0, 0, numPixels); + + //get a fake map, since mode7 doesnt really have a map + map = gd.FetchMode7Tilemap(); } } else @@ -406,7 +408,7 @@ namespace BizHawk.MultiClient numPixels = dims.Width * dims.Height; System.Diagnostics.Debug.Assert(stride / 4 == dims.Width); - var map = gd.FetchTilemap(bg.ScreenAddr, bg.ScreenSize); + map = gd.FetchTilemap(bg.ScreenAddr, bg.ScreenSize); int paletteStart = 0; gd.DecodeBG(pixelptr, stride / 4, map, bg.TiledataAddr, bg.ScreenSize, bg.Bpp, bg.TileSize, paletteStart); gd.Paletteize(pixelptr, 0, 0, numPixels); @@ -689,6 +691,11 @@ namespace BizHawk.MultiClient int baseTileNum = tiledataBaseAddr / tileSizeBytes; int tileNum = baseTileNum + currMapEntryState.entry.tilenum; int addr = tileNum * tileSizeBytes; + + //mode7 takes up 128 bytes per tile because its interleaved with the screen data + if (bg.BGModeIsMode7Type) + addr *= 2; + addr &= 0xFFFF; txtMapEntryTileAddr.Text = "@" + addr.ToHexString(4); } @@ -860,26 +867,33 @@ namespace BizHawk.MultiClient public Point Location; } MapEntryState currMapEntryState; - int currViewingTile = -1; - int currViewingTileBpp = -1; - int currViewingSprite = -1; - void RenderTileView(bool force=false) - { - //TODO - blech - handle invalid some other way with a dedicated black-setter - bool valid = currViewingTile != -1; - valid |= (currMapEntryState != null); - if (!valid && !force) return; + class TileDataState + { + public eDisplayType Type; + public int Bpp; + public int Tile; + } + TileDataState tileDataState; + + void RenderTileView() + { if (currMapEntryState != null) { - //view a BG tile (no mode7 support yet) - itd be nice if we could generalize this code a bit - //TODO - choose correct palette (commonize that code) + //view a BG tile int paletteStart = 0; var bmp = new Bitmap(8, 8, System.Drawing.Imaging.PixelFormat.Format32bppArgb); var bmpdata = bmp.LockBits(new Rectangle(0, 0, 8, 8), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); var bgs = currMapEntryState; var oneTileEntry = new SNESGraphicsDecoder.TileEntry[] { bgs.entry }; - if (valid) + + if (viewBgMode == SNESGraphicsDecoder.BGMode.Mode7) + gd.RenderMode7TilesToScreen((int*)bmpdata.Scan0, bmpdata.Stride / 4, false, false, 1, currMapEntryState.entry.tilenum, 1); + else if (viewBgMode == SNESGraphicsDecoder.BGMode.Mode7Ext) + gd.RenderMode7TilesToScreen((int*)bmpdata.Scan0, bmpdata.Stride / 4, true, false, 1, currMapEntryState.entry.tilenum, 1); + else if (viewBgMode == SNESGraphicsDecoder.BGMode.Mode7DC) + gd.RenderMode7TilesToScreen((int*)bmpdata.Scan0, bmpdata.Stride / 4, false, true, 1, currMapEntryState.entry.tilenum, 1); + else { gd.DecodeBG((int*)bmpdata.Scan0, bmpdata.Stride / 4, oneTileEntry, si.BG[bgs.bgnum].TiledataAddr, SNESGraphicsDecoder.ScreenSize.Hacky_1x1, si.BG[bgs.bgnum].Bpp, 8, paletteStart); gd.Paletteize((int*)bmpdata.Scan0, 0, 0, 64); @@ -889,24 +903,48 @@ namespace BizHawk.MultiClient bmp.UnlockBits(bmpdata); viewerMapEntryTile.SetBitmap(bmp); } - else + else if (tileDataState != null) { //view a tileset tile - int bpp = currViewingTileBpp; + int bpp = tileDataState.Bpp; var bmp = new Bitmap(8, 8, System.Drawing.Imaging.PixelFormat.Format32bppArgb); var bmpdata = bmp.LockBits(new Rectangle(0, 0, 8, 8), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - if (valid) gd.RenderTilesToScreen((int*)bmpdata.Scan0, 1, 1, bmpdata.Stride / 4, bpp, currPaletteSelection.start, currViewingTile, 1); + if (tileDataState.Type == eDisplayType.TilesMode7) + gd.RenderMode7TilesToScreen((int*)bmpdata.Scan0, bmpdata.Stride / 4, false, false, 1, tileDataState.Tile, 1); + else if (tileDataState.Type == eDisplayType.TilesMode7Ext) + gd.RenderMode7TilesToScreen((int*)bmpdata.Scan0, bmpdata.Stride / 4, true, false, 1, tileDataState.Tile, 1); + else if (tileDataState.Type == eDisplayType.TilesMode7DC) + gd.RenderMode7TilesToScreen((int*)bmpdata.Scan0, bmpdata.Stride / 4, false, true, 1, tileDataState.Tile, 1); + else gd.RenderTilesToScreen((int*)bmpdata.Scan0, 1, 1, bmpdata.Stride / 4, bpp, currPaletteSelection.start, tileDataState.Tile, 1); + bmp.UnlockBits(bmpdata); viewerTile.SetBitmap(bmp); } + else + { + var bmp = new Bitmap(8, 8, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + viewerTile.SetBitmap(bmp); + } + } + + void HandleTileViewMouseOver(int pxacross, int pxtall, int bpp, int tx, int ty) + { + int tilestride = pxacross / 8; + int tilesTall = pxtall / 8; + if (tx < 0 || ty < 0 || tx >= tilestride || ty >= tilesTall) + return; + tileDataState = new TileDataState(); + tileDataState.Bpp = bpp; + tileDataState.Type = CurrDisplaySelection; + tileDataState.Tile = ty * tilestride + tx; + tabctrlDetails.SelectedTab = tpTile; } void UpdateViewerMouseover(Point loc) { currMapEntryState = null; - currViewingTile = -1; - currViewingTileBpp = -1; + tileDataState = null; int tx = loc.X / 8; int ty = loc.Y / 8; switch (CurrDisplaySelection) @@ -915,12 +953,19 @@ namespace BizHawk.MultiClient //currViewingSprite = tx + ty * 16; RenderView(); break; + case eDisplayType.Tiles2bpp: + HandleTileViewMouseOver(512, 512, 2, tx, ty); + break; case eDisplayType.Tiles4bpp: - currViewingTileBpp = 4; - currViewingTile = ty * 64 + tx; - if (currViewingTile < 0 || currViewingTile >= (8192 / currViewingTileBpp)) - currViewingTile = -1; - tabctrlDetails.SelectedTab = tpTile; + HandleTileViewMouseOver(512, 256, 4, tx, ty); + break; + case eDisplayType.Tiles8bpp: + HandleTileViewMouseOver(256, 256, 8, tx, ty); + break; + case eDisplayType.TilesMode7: + case eDisplayType.TilesMode7Ext: + case eDisplayType.TilesMode7DC: + HandleTileViewMouseOver(128, 128, 8, tx, ty); break; case eDisplayType.BG1: case eDisplayType.BG2: @@ -928,7 +973,7 @@ namespace BizHawk.MultiClient case eDisplayType.BG4: { var bg = si.BG[(int)CurrDisplaySelection]; - var map = gd.FetchTilemap(bg.ScreenAddr, bg.ScreenSize); + if (bg.TileSize == 16) { tx /= 2; ty /= 2; } //worry about this later. need to pass a different flag into `currViewingTile` int tloc = ty * bg.ScreenSizeInTiles.Width + tx; @@ -952,7 +997,8 @@ namespace BizHawk.MultiClient break; } - RenderTileView(true); + RenderTileView(); + UpdateMapEntryDetails(); } private void viewer_MouseEnter(object sender, EventArgs e) diff --git a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.resx b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.resx index 416878dadc..e795b29e7a 100644 --- a/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.resx +++ b/BizHawk.MultiClient/SNESTools/SNESGraphicsDebugger.resx @@ -123,6 +123,14 @@ 126, 17 + + Colors can be converted from the snes 555 format to PC standard 888 in several ways. +Snes9x really didnt make any effort to make sense; +bsnes seemed to make an effort but didnt make sense to us; +and bizhawk of course makes sense to us. +The different palettes are provided here so that you can achieve uniformity with +old data while using bizhawk to rip art. The differences are slight. + Enable the scanline controls. Leaving this disabled will be fine for most users and