From 07d477fc70ef4a70c8c29d1aa51064803d454419 Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Tue, 18 Feb 2020 16:42:46 -0800 Subject: [PATCH] Improve Apple II hi-res visualizer Added a new category "sprite sheet", which is essentially a more generalized version of the bitmap font renderer. It has the full set of options for col/row/cell stride and colors. (Issue #74, issue #75) Added a flag that flips the high bits on bitmaps. Sometimes data is stored with the high bit clear, but the high bit is set as it's rendered. (Issue #76) Also, fixed the keyboard shortcuts in the Edit Visualization Set window, which were 'N' for both "New ___" items. (Issue #57) --- SourceGen/RuntimeData/Apple/VisHiRes.cs | 118 ++++++++++++++---- SourceGen/RuntimeData/Help/visualization.html | 54 +++++--- SourceGen/WpfGui/EditVisualizationSet.xaml | 4 +- 3 files changed, 133 insertions(+), 43 deletions(-) diff --git a/SourceGen/RuntimeData/Apple/VisHiRes.cs b/SourceGen/RuntimeData/Apple/VisHiRes.cs index 657e743..fd46f1c 100644 --- a/SourceGen/RuntimeData/Apple/VisHiRes.cs +++ b/SourceGen/RuntimeData/Apple/VisHiRes.cs @@ -30,6 +30,7 @@ namespace RuntimeData.Apple { // Visualization identifiers; DO NOT change or projects that use them will break. private const string VIS_GEN_BITMAP = "apple2-hi-res-bitmap"; + private const string VIS_GEN_BITMAP_GRID = "apple2-hi-res-bitmap-grid"; private const string VIS_GEN_BITMAP_FONT = "apple2-hi-res-bitmap-font"; private const string VIS_GEN_HR_SCREEN = "apple2-hi-res-screen"; @@ -38,8 +39,10 @@ namespace RuntimeData.Apple { private const string P_HEIGHT = "height"; private const string P_COL_STRIDE = "colStride"; private const string P_ROW_STRIDE = "rowStride"; + private const string P_CELL_STRIDE = "cellStride"; private const string P_IS_COLOR = "isColor"; private const string P_IS_FIRST_ODD = "isFirstOdd"; + private const string P_IS_HIGH_BIT_FLIPPED = "isHighBitFlipped"; private const string P_COLOR_CONV_MODE = "colorConvMode"; private const string P_ITEM_BYTE_WIDTH = "itemByteWidth"; private const string P_ITEM_HEIGHT = "itemHeight"; @@ -54,23 +57,48 @@ namespace RuntimeData.Apple { new VisParamDescr("File offset (hex)", P_OFFSET, typeof(int), 0, 0x00ffffff, VisParamDescr.SpecialMode.Offset, 0), new VisParamDescr("Width (in bytes)", - P_BYTE_WIDTH, typeof(int), 1, 40, 0, 1), + P_BYTE_WIDTH, typeof(int), 1, 256, 0, 1), new VisParamDescr("Height", - P_HEIGHT, typeof(int), 1, 192, 0, 1), + P_HEIGHT, typeof(int), 1, 1024, 0, 1), new VisParamDescr("Column stride (bytes)", - P_COL_STRIDE, typeof(int), 0, 256, 0, 0), + P_COL_STRIDE, typeof(int), 0, 1024, 0, 0), new VisParamDescr("Row stride (bytes)", - P_ROW_STRIDE, typeof(int), 0, 256, 0, 0), + P_ROW_STRIDE, typeof(int), 0, 1024, 0, 0), new VisParamDescr("Color", P_IS_COLOR, typeof(bool), 0, 0, 0, true), new VisParamDescr("First col odd", P_IS_FIRST_ODD, typeof(bool), 0, 0, 0, false), + new VisParamDescr("High bit flipped", + P_IS_HIGH_BIT_FLIPPED, typeof(bool), 0, 0, 0, false), //new VisParamDescr("Color conv mode", // P_COLOR_CONV_MODE, typeof(int), (int)ColorMode.SimpleColor, // (int)ColorMode.IIgsRGB, 0, (int)ColorMode.SimpleColor), //new VisParamDescr("Test Float", // "floaty", typeof(float), -5.0f, 5.0f, 0, 0.1f), }), + new VisDescr(VIS_GEN_BITMAP_GRID, "Apple II Hi-Res Sprite Sheet", VisDescr.VisType.Bitmap, + new VisParamDescr[] { + new VisParamDescr("File offset (hex)", + P_OFFSET, typeof(int), 0, 0x00ffffff, VisParamDescr.SpecialMode.Offset, 0), + new VisParamDescr("Cell width (in bytes)", + P_ITEM_BYTE_WIDTH, typeof(int), 1, 40, 0, 1), + new VisParamDescr("Cell height", + P_ITEM_HEIGHT, typeof(int), 1, 192, 0, 1), + new VisParamDescr("Column stride (bytes)", + P_COL_STRIDE, typeof(int), 0, 1024, 0, 0), + new VisParamDescr("Row stride (bytes)", + P_ROW_STRIDE, typeof(int), 0, 1024, 0, 0), + new VisParamDescr("Cell stride (bytes)", + P_CELL_STRIDE, typeof(int), 0, 4096, 0, 0), + new VisParamDescr("Number of items", + P_COUNT, typeof(int), 1, 1024, 0, 64), + new VisParamDescr("Color", + P_IS_COLOR, typeof(bool), 0, 0, 0, true), + new VisParamDescr("First col odd", + P_IS_FIRST_ODD, typeof(bool), 0, 0, 0, false), + new VisParamDescr("High bit flipped", + P_IS_HIGH_BIT_FLIPPED, typeof(bool), 0, 0, 0, false), + }), new VisDescr(VIS_GEN_BITMAP_FONT, "Apple II Hi-Res Bitmap Font", VisDescr.VisType.Bitmap, new VisParamDescr[] { new VisParamDescr("File offset (hex)", @@ -122,6 +150,8 @@ namespace RuntimeData.Apple { switch (descr.Ident) { case VIS_GEN_BITMAP: return GenerateBitmap(parms); + case VIS_GEN_BITMAP_GRID: + return GenerateBitmapGrid(parms); case VIS_GEN_BITMAP_FONT: return GenerateBitmapFont(parms); case VIS_GEN_HR_SCREEN: @@ -140,6 +170,7 @@ namespace RuntimeData.Apple { int rowStride = Util.GetFromObjDict(parms, P_ROW_STRIDE, 0); bool isColor = Util.GetFromObjDict(parms, P_IS_COLOR, true); bool isFirstOdd = Util.GetFromObjDict(parms, P_IS_FIRST_ODD, false); + bool isHighBitFlipped = Util.GetFromObjDict(parms, P_IS_HIGH_BIT_FLIPPED, false); int colorConvMode = !isColor ? (int)ColorMode.Mono : Util.GetFromObjDict(parms, P_COLOR_CONV_MODE, (int)ColorMode.SimpleColor); @@ -178,25 +209,74 @@ namespace RuntimeData.Apple { SetHiResPalette(vb); RenderBitmap(mFileData, offset, byteWidth, height, colStride, rowStride, - (ColorMode)colorConvMode, isFirstOdd, vb, 0, 0); + (ColorMode)colorConvMode, isFirstOdd, isHighBitFlipped, vb, 0, 0); return vb; } + private IVisualization2d GenerateBitmapGrid(ReadOnlyDictionary parms) { + int offset = Util.GetFromObjDict(parms, P_OFFSET, 0); + int itemByteWidth = Util.GetFromObjDict(parms, P_ITEM_BYTE_WIDTH, 1); + int itemHeight = Util.GetFromObjDict(parms, P_ITEM_HEIGHT, 8); + int colStride = Util.GetFromObjDict(parms, P_COL_STRIDE, 0); + int rowStride = Util.GetFromObjDict(parms, P_ROW_STRIDE, 0); + int cellStride = Util.GetFromObjDict(parms, P_CELL_STRIDE, 0); + int count = Util.GetFromObjDict(parms, P_COUNT, 96); + bool isColor = Util.GetFromObjDict(parms, P_IS_COLOR, true); + bool isFirstOdd = Util.GetFromObjDict(parms, P_IS_FIRST_ODD, false); + bool isHighBitFlipped = Util.GetFromObjDict(parms, P_IS_HIGH_BIT_FLIPPED, false); + + ColorMode colorConvMode = !isColor ? ColorMode.Mono : + (ColorMode)Util.GetFromObjDict(parms, P_COLOR_CONV_MODE, (int)ColorMode.SimpleColor); + + return GenerateGrid(offset, itemByteWidth, itemHeight, colStride, rowStride, + cellStride, count, colorConvMode, isFirstOdd, isHighBitFlipped); + } + private IVisualization2d GenerateBitmapFont(ReadOnlyDictionary parms) { int offset = Util.GetFromObjDict(parms, P_OFFSET, 0); int itemByteWidth = Util.GetFromObjDict(parms, P_ITEM_BYTE_WIDTH, 1); int itemHeight = Util.GetFromObjDict(parms, P_ITEM_HEIGHT, 8); int count = Util.GetFromObjDict(parms, P_COUNT, 96); + return GenerateGrid(offset, itemByteWidth, itemHeight, 0, 0, 0, count, + ColorMode.Mono, false, false); + } + + private IVisualization2d GenerateGrid(int offset, int itemByteWidth, int itemHeight, + int colStride, int rowStride, int cellStride, int count, + ColorMode colorConvMode, bool isFirstOdd, bool isHighBitFlipped) { + + // We allow the stride entries to be zero to indicate a "dense" bitmap. + if (colStride == 0) { + colStride = 1; + } + if (rowStride == 0) { + rowStride = itemByteWidth * colStride; + } + if (cellStride == 0) { + cellStride = rowStride * itemHeight; + } + if (offset < 0 || offset >= mFileData.Length || itemByteWidth <= 0 || itemByteWidth > MAX_DIM || - itemHeight <= 0 || itemHeight > MAX_DIM) { + itemHeight <= 0 || itemHeight > MAX_DIM || + count <= 0 || count > MAX_DIM) { // should be caught by editor mAppRef.ReportError("Invalid parameter"); return null; } - int lastOffset = offset + itemByteWidth * itemHeight * count - 1; + if (colStride <= 0 || colStride > MAX_DIM) { + mAppRef.ReportError("Invalid column stride"); + return null; + } + if (rowStride < itemByteWidth * colStride - (colStride - 1) || rowStride > MAX_DIM) { + mAppRef.ReportError("Invalid row stride"); + return null; + } + + int lastOffset = offset + (cellStride * (count - 1)) + + rowStride * itemHeight - (colStride - 1) - 1; if (lastOffset >= mFileData.Length) { mAppRef.ReportError("Bitmap runs off end of file (last offset +" + lastOffset.ToString("x6") + ")"); @@ -221,18 +301,10 @@ namespace RuntimeData.Apple { int cellx = 1; int celly = 1; - for (int idx = 0; idx < count; idx++) { - - //byte color = (byte)(1 + idx % 6); - //for (int y = 0; y < itemHeight; y++) { - // for (int x = 0; x < itemByteWidth * 7; x++) { - // vb.SetPixelIndex(cellx + x, celly + y, color); - // } - //} - RenderBitmap(mFileData, offset + idx * itemByteWidth * itemHeight, - itemByteWidth, itemHeight, 1, itemByteWidth, - ColorMode.Mono, false, + RenderBitmap(mFileData, offset + idx * cellStride, + itemByteWidth, itemHeight, colStride, rowStride, + colorConvMode, isFirstOdd, isHighBitFlipped, vb, cellx, celly); cellx += itemByteWidth * 7 + 1; @@ -296,7 +368,7 @@ namespace RuntimeData.Apple { VisBitmap8 vb = new VisBitmap8(HR_WIDTH, HR_HEIGHT); SetHiResPalette(vb); RenderBitmap(buf, 0, HR_BYTE_WIDTH, HR_HEIGHT, 1, HR_BYTE_WIDTH, - isColor ? ColorMode.SimpleColor : ColorMode.Mono, false, + isColor ? ColorMode.SimpleColor : ColorMode.Mono, false, false, vb, 0, 0); return vb; } @@ -319,12 +391,14 @@ namespace RuntimeData.Apple { /// Color conversion mode. /// If true, render as if we're starting on an odd column. /// This affects the colors. + /// If true, render as if the high bit has the + /// opposite value. This affects the colors. /// Output bitmap object. /// Initial X position in the output. /// Initial Y position in the output. private void RenderBitmap(byte[] data, int offset, int byteWidth, int height, int colStride, int rowStride, ColorMode colorMode, bool isFirstOdd, - VisBitmap8 vb, int xstart, int ystart) { + bool isHighBitFlipped, VisBitmap8 vb, int xstart, int ystart) { int bx = xstart; int by = ystart; switch (colorMode) { @@ -372,7 +446,7 @@ namespace RuntimeData.Apple { bool hiBitSet = (val & 0x80) != 0; for (int bit = 0; bit < 7; bit++) { - hiFlags[idx] = hiBitSet; + hiFlags[idx] = hiBitSet ^ isHighBitFlipped; lineBits[idx] = (val & 0x01) != 0; idx++; val >>= 1; @@ -448,7 +522,7 @@ namespace RuntimeData.Apple { bool hiBitSet = (val & 0x80) != 0; for (int bit = 0; bit < 7; bit++) { - hiFlags[idx] = hiBitSet; + hiFlags[idx] = hiBitSet ^ isHighBitFlipped; lineBits[idx] = (val & 0x01) != 0; idx++; val >>= 1; diff --git a/SourceGen/RuntimeData/Help/visualization.html b/SourceGen/RuntimeData/Help/visualization.html index d0d989a..7327663 100644 --- a/SourceGen/RuntimeData/Help/visualization.html +++ b/SourceGen/RuntimeData/Help/visualization.html @@ -131,15 +131,20 @@ height as parameters. Offsets are handled as they are elsewhere, i.e. always in hexadecimal, with a leading '+'. Some less-common parameters include:

    -
  • Row stride - number of bytes used to hold a row. This - is used when a row has padding on the end, e.g. a bitmap that's - 7 bytes wide might be padded to 8 for easy indexing. If you set - this to zero the visualizer will default to no padding - (stride == width).
  • Column stride - number of bytes used to hold a column. This is uncommon, but could be used if (say) a pair of bitmaps was stored with interleaved bytes. If you set this to zero the - visualizer will default to no interleave (stride == 1).
  • + visualizer will default to no interleave (col_stride = 1). +
  • Row stride - number of bytes between the start of each + row. This is used when a row has padding on the end, e.g. a + bitmap that's 7 bytes wide might be padded to 8 for easy indexing, + or when bitmap data is interleaved. If you set this to zero the + visualizer will default to no padding + (row_stride = width * column_stride).
  • +
  • Cell stride - for multi-bitmap data like a font or sprite + sheet, this determines the number of bytes between the start of + one item and the next. If set to zero a "dense" arrangement is + assumed (cell_stride = row_stride * item_height).

Remember that this is a disassembler, not an image converter. The @@ -147,19 +152,23 @@ results do not need to be perfectly accurate to be useful when disassembling code.

-

Apple II - Apple/VisHiRes

+

Apple II - Apple/VisHiRes and Apple/VisShapeTable

There is no standard format for small hi-res bitmaps, but certain -arrangements are common. The script defines three generators:

+arrangements are common. The VisHiRes script defines four generators:

  • Hi-Res Bitmap - converts an MxN row-major bitmap.
  • -
  • Hi-Res Bitmap Font - converts a series of MxN row-major - bitmaps. This is intended for hi-res fonts, which are typically - 8 bytes per entry, stored one after another. These are always - converted as monochrome, and have a 1-pixel transparent gap - between elements. (This also works for Apple /// fonts, but - currently ignores the high bit in each byte.)
  • +
  • Hi-Res Sprite Sheet - converts a series of bitmaps and + renders them in a grid. Useful for games that use cell + animation. The generated bitmap has a 1-pixel transparent gap + between elements.
  • +
  • Hi-Res Bitmap Font - a simplified version of the + Sprite Sheet, intended for the common 7x8 monochrome fonts. + Most fonts have 96 or 128 glyphs, though some drop the last + character. + (This also works for Apple /// fonts, but currently ignores + the high bit in each byte.)
  • Hi-Res Screen Image - used for 8KiB screen images. The data is linearized and converted to a 280x192 bitmap. Because images are relatively large, the generator does not require them @@ -172,12 +181,19 @@ arrangements are common. The script defines three generators:

    pixels (with some hand-waving).

    In addition to offset, dimensions, and stride values, the bitmap -converter has a checkbox for monochrome or color, and a checkbox that -will cause the first byte to be treated as an odd column rather than -an event one. The odd/even setting affects green/purple and orange/blue, -but has no effect on black or white.

    +converter has a checkbox for monochrome or color, and two checkboxes +that affect the color. The first causes the first byte to be treated +as being in an odd column rather than an even one, which affects +green vs. purple and orange vs. blue. The second flips the high bits +on every byte, switching green vs. orange and purple vs. blue. +Neither has any effect on black & white bitmaps.

    The converter generates one output pixel for every source pixel, so -half-pixel shifts are not rendered.

    +half-pixel shifts are not represented.

    + +

    The VisShapeTable script renders Applesoft shape tables, which can +have multiple vector shapes. The only parameter other than the offset +is the shape number.

    +

    Atari 2600 - Atari/Vis2600

    diff --git a/SourceGen/WpfGui/EditVisualizationSet.xaml b/SourceGen/WpfGui/EditVisualizationSet.xaml index cb438ab..64f1bc8 100644 --- a/SourceGen/WpfGui/EditVisualizationSet.xaml +++ b/SourceGen/WpfGui/EditVisualizationSet.xaml @@ -90,9 +90,9 @@ limitations under the License. -