mirror of
https://github.com/fadden/6502bench.git
synced 2024-10-31 19:04:44 +00:00
Expand C64 sprite visualizer
Added fonts and sprite sheets. Updated documentation.
This commit is contained in:
parent
663a3d0230
commit
8b1e70fa58
@ -13,12 +13,23 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
//#define SHOW_BORDER
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
using PluginCommon;
|
using PluginCommon;
|
||||||
|
|
||||||
|
|
||||||
namespace RuntimeData.Commodore {
|
namespace RuntimeData.Commodore {
|
||||||
|
/// <summary>
|
||||||
|
/// Visualizer for C64 sprites and fonts.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// References:
|
||||||
|
/// https://www.c64-wiki.com/wiki/Sprite
|
||||||
|
/// http://sta.c64.org/cbm64disp.html
|
||||||
|
/// http://unusedino.de/ec64/technical/misc/vic656x/colors/
|
||||||
|
/// </remarks>
|
||||||
public class VisC64 : MarshalByRefObject, IPlugin, IPlugin_Visualizer {
|
public class VisC64 : MarshalByRefObject, IPlugin, IPlugin_Visualizer {
|
||||||
// IPlugin
|
// IPlugin
|
||||||
public string Identifier {
|
public string Identifier {
|
||||||
@ -30,9 +41,14 @@ namespace RuntimeData.Commodore {
|
|||||||
|
|
||||||
// Visualization identifiers; DO NOT change or projects that use them will break.
|
// Visualization identifiers; DO NOT change or projects that use them will break.
|
||||||
private const string VIS_GEN_HI_RES_SPRITE = "c64-hi-res-sprite";
|
private const string VIS_GEN_HI_RES_SPRITE = "c64-hi-res-sprite";
|
||||||
|
private const string VIS_GEN_HI_RES_SPRITE_GRID = "c64-hi-res-sprite-grid";
|
||||||
private const string VIS_GEN_MULTI_COLOR_SPRITE = "c64-multi-color-sprite";
|
private const string VIS_GEN_MULTI_COLOR_SPRITE = "c64-multi-color-sprite";
|
||||||
|
private const string VIS_GEN_MULTI_COLOR_SPRITE_GRID = "c64-multi-color-sprite-grid";
|
||||||
|
private const string VIS_GEN_HI_RES_FONT = "c64-hi-res-font";
|
||||||
|
private const string VIS_GEN_MULTI_COLOR_FONT = "c64-multi-color-font";
|
||||||
|
|
||||||
private const string P_OFFSET = "offset";
|
private const string P_OFFSET = "offset";
|
||||||
|
private const string P_COUNT = "count";
|
||||||
private const string P_DOUBLE_WIDE = "doubleWide";
|
private const string P_DOUBLE_WIDE = "doubleWide";
|
||||||
private const string P_DOUBLE_HIGH = "doubleHigh";
|
private const string P_DOUBLE_HIGH = "doubleHigh";
|
||||||
private const string P_COLOR = "color"; // sprite color (hi-res or multi-color)
|
private const string P_COLOR = "color"; // sprite color (hi-res or multi-color)
|
||||||
@ -40,9 +56,10 @@ namespace RuntimeData.Commodore {
|
|||||||
private const string P_COLOR_11 = "color11"; // multi-color 2
|
private const string P_COLOR_11 = "color11"; // multi-color 2
|
||||||
|
|
||||||
private const int MAX_COLOR = 15;
|
private const int MAX_COLOR = 15;
|
||||||
private const int BYTE_WIDTH = 3;
|
private const int SPRITE_BYTE_WIDTH = 3;
|
||||||
private const int HEIGHT = 21;
|
private const int SPRITE_HEIGHT = 21;
|
||||||
private const int SPRITE_SIZE = BYTE_WIDTH * HEIGHT; // 63
|
private const int SPRITE_SIZE = SPRITE_BYTE_WIDTH * SPRITE_HEIGHT; // 63
|
||||||
|
private const int SPRITE_STRIDE = 64; // hardware sprites are 64-byte aligned
|
||||||
|
|
||||||
// Visualization descriptors.
|
// Visualization descriptors.
|
||||||
private VisDescr[] mDescriptors = new VisDescr[] {
|
private VisDescr[] mDescriptors = new VisDescr[] {
|
||||||
@ -72,6 +89,50 @@ namespace RuntimeData.Commodore {
|
|||||||
new VisParamDescr("Double high",
|
new VisParamDescr("Double high",
|
||||||
P_DOUBLE_HIGH, typeof(bool), 0, 0, 0, false),
|
P_DOUBLE_HIGH, typeof(bool), 0, 0, 0, false),
|
||||||
}),
|
}),
|
||||||
|
new VisDescr(VIS_GEN_HI_RES_SPRITE_GRID, "C64 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("Number of items",
|
||||||
|
P_COUNT, typeof(int), 1, 1024, 0, 16),
|
||||||
|
new VisParamDescr("Sprite color",
|
||||||
|
P_COLOR, typeof(int), 0, 15, 0, 0),
|
||||||
|
new VisParamDescr("Double wide",
|
||||||
|
P_DOUBLE_WIDE, typeof(bool), 0, 0, 0, false),
|
||||||
|
new VisParamDescr("Double high",
|
||||||
|
P_DOUBLE_HIGH, typeof(bool), 0, 0, 0, false),
|
||||||
|
}),
|
||||||
|
new VisDescr(VIS_GEN_MULTI_COLOR_SPRITE_GRID, "C64 Multi-Color Sprite Sheet", VisDescr.VisType.Bitmap,
|
||||||
|
new VisParamDescr[] {
|
||||||
|
new VisParamDescr("File offset (hex)",
|
||||||
|
P_OFFSET, typeof(int), 0, 0x00ffffff, VisParamDescr.SpecialMode.Offset, 0),
|
||||||
|
new VisParamDescr("Number of items",
|
||||||
|
P_COUNT, typeof(int), 1, 1024, 0, 16),
|
||||||
|
new VisParamDescr("Sprite color",
|
||||||
|
P_COLOR, typeof(int), 0, 15, 0, 1),
|
||||||
|
new VisParamDescr("Multi-color 1",
|
||||||
|
P_COLOR_01, typeof(int), 0, 15, 0, 0),
|
||||||
|
new VisParamDescr("Multi-color 2",
|
||||||
|
P_COLOR_11, typeof(int), 0, 15, 0, 2),
|
||||||
|
new VisParamDescr("Double wide",
|
||||||
|
P_DOUBLE_WIDE, typeof(bool), 0, 0, 0, false),
|
||||||
|
new VisParamDescr("Double high",
|
||||||
|
P_DOUBLE_HIGH, typeof(bool), 0, 0, 0, false),
|
||||||
|
}),
|
||||||
|
new VisDescr(VIS_GEN_HI_RES_FONT, "C64 Hi-Res Font", VisDescr.VisType.Bitmap,
|
||||||
|
new VisParamDescr[] {
|
||||||
|
new VisParamDescr("File offset (hex)",
|
||||||
|
P_OFFSET, typeof(int), 0, 0x00ffffff, VisParamDescr.SpecialMode.Offset, 0),
|
||||||
|
new VisParamDescr("Number of items",
|
||||||
|
P_COUNT, typeof(int), 1, 256, 0, 96),
|
||||||
|
}),
|
||||||
|
new VisDescr(VIS_GEN_MULTI_COLOR_FONT, "C64 Multi-Color Font", VisDescr.VisType.Bitmap,
|
||||||
|
new VisParamDescr[] {
|
||||||
|
new VisParamDescr("File offset (hex)",
|
||||||
|
P_OFFSET, typeof(int), 0, 0x00ffffff, VisParamDescr.SpecialMode.Offset, 0),
|
||||||
|
new VisParamDescr("Number of items",
|
||||||
|
P_COUNT, typeof(int), 1, 256, 0, 96),
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -104,74 +165,36 @@ namespace RuntimeData.Commodore {
|
|||||||
ReadOnlyDictionary<string, object> parms) {
|
ReadOnlyDictionary<string, object> parms) {
|
||||||
switch (descr.Ident) {
|
switch (descr.Ident) {
|
||||||
case VIS_GEN_HI_RES_SPRITE:
|
case VIS_GEN_HI_RES_SPRITE:
|
||||||
return GenerateHiResSprite(parms);
|
return GenerateSprite(parms, false);
|
||||||
case VIS_GEN_MULTI_COLOR_SPRITE:
|
case VIS_GEN_MULTI_COLOR_SPRITE:
|
||||||
return GenerateMultiColorSprite(parms);
|
return GenerateSprite(parms, true);
|
||||||
|
case VIS_GEN_HI_RES_SPRITE_GRID:
|
||||||
|
return GenerateSpriteGrid(parms, false);
|
||||||
|
case VIS_GEN_MULTI_COLOR_SPRITE_GRID:
|
||||||
|
return GenerateSpriteGrid(parms, true);
|
||||||
|
case VIS_GEN_HI_RES_FONT:
|
||||||
|
return GenerateFont(parms, false);
|
||||||
|
case VIS_GEN_MULTI_COLOR_FONT:
|
||||||
|
return GenerateFont(parms, true);
|
||||||
default:
|
default:
|
||||||
mAppRef.ReportError("Unknown ident " + descr.Ident);
|
mAppRef.ReportError("Unknown ident " + descr.Ident);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IVisualization2d GenerateHiResSprite(ReadOnlyDictionary<string, object> parms) {
|
private IVisualization2d GenerateSprite(ReadOnlyDictionary<string, object> parms,
|
||||||
|
bool isMultiColor) {
|
||||||
int offset = Util.GetFromObjDict(parms, P_OFFSET, 0);
|
int offset = Util.GetFromObjDict(parms, P_OFFSET, 0);
|
||||||
byte color = (byte)Util.GetFromObjDict(parms, P_COLOR, 0);
|
byte color = (byte)Util.GetFromObjDict(parms, P_COLOR, 0);
|
||||||
bool isDoubleWide = Util.GetFromObjDict(parms, P_DOUBLE_WIDE, false);
|
bool isDoubleWide = Util.GetFromObjDict(parms, P_DOUBLE_WIDE, false);
|
||||||
bool isDoubleHigh = Util.GetFromObjDict(parms, P_DOUBLE_HIGH, false);
|
bool isDoubleHigh = Util.GetFromObjDict(parms, P_DOUBLE_HIGH, false);
|
||||||
|
byte color01 = 0;
|
||||||
if (offset < 0 || offset >= mFileData.Length || color < 0 || color > MAX_COLOR) {
|
byte color11 = 0;
|
||||||
// the UI should flag these based on range (and ideally wouldn't have called us)
|
if (isMultiColor) {
|
||||||
mAppRef.ReportError("Invalid parameter");
|
color01 = (byte)Util.GetFromObjDict(parms, P_COLOR_01, 0);
|
||||||
return null;
|
color11 = (byte)Util.GetFromObjDict(parms, P_COLOR_11, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int lastOffset = offset + SPRITE_SIZE - 1;
|
|
||||||
if (lastOffset >= mFileData.Length) {
|
|
||||||
mAppRef.ReportError("Sprite runs off end of file (last offset +" +
|
|
||||||
lastOffset.ToString("x6") + ")");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
int xwide = isDoubleWide ? 2 : 1;
|
|
||||||
int xhigh = isDoubleHigh ? 2 : 1;
|
|
||||||
|
|
||||||
VisBitmap8 vb = new VisBitmap8(BYTE_WIDTH * 8 * xwide, HEIGHT * xhigh);
|
|
||||||
SetPalette(vb);
|
|
||||||
|
|
||||||
// Clear all pixels to transparent, then just draw the non-transparent ones.
|
|
||||||
vb.SetAllPixelIndices(TRANSPARENT);
|
|
||||||
|
|
||||||
for (int row = 0; row < HEIGHT; row++) {
|
|
||||||
for (int col = 0; col < BYTE_WIDTH; col++) {
|
|
||||||
byte val = mFileData[offset + row * BYTE_WIDTH + col];
|
|
||||||
for (int bit = 0; bit < 8; bit++) {
|
|
||||||
if ((val & 0x80) != 0) {
|
|
||||||
int xc = (col * 8 + bit) * xwide;
|
|
||||||
int yc = row * xhigh;
|
|
||||||
vb.SetPixelIndex(xc, yc, color);
|
|
||||||
if (isDoubleWide || isDoubleHigh) {
|
|
||||||
// Draw doubled pixels. If we're only doubled in one dimension
|
|
||||||
// this will draw pixels twice.
|
|
||||||
vb.SetPixelIndex(xc + xwide - 1, yc, color);
|
|
||||||
vb.SetPixelIndex(xc, yc + xhigh - 1, color);
|
|
||||||
vb.SetPixelIndex(xc + xwide - 1, yc + xhigh - 1, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vb;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IVisualization2d GenerateMultiColorSprite(ReadOnlyDictionary<string, object> parms) {
|
|
||||||
int offset = Util.GetFromObjDict(parms, P_OFFSET, 0);
|
|
||||||
byte color = (byte)Util.GetFromObjDict(parms, P_COLOR, 0);
|
|
||||||
byte color01 = (byte)Util.GetFromObjDict(parms, P_COLOR_01, 0);
|
|
||||||
byte color11 = (byte)Util.GetFromObjDict(parms, P_COLOR_11, 0);
|
|
||||||
bool isDoubleWide = Util.GetFromObjDict(parms, P_DOUBLE_WIDE, false);
|
|
||||||
bool isDoubleHigh = Util.GetFromObjDict(parms, P_DOUBLE_HIGH, false);
|
|
||||||
|
|
||||||
if (offset < 0 || offset >= mFileData.Length ||
|
if (offset < 0 || offset >= mFileData.Length ||
|
||||||
color < 0 || color > MAX_COLOR ||
|
color < 0 || color > MAX_COLOR ||
|
||||||
color01 < 0 || color01 > MAX_COLOR ||
|
color01 < 0 || color01 > MAX_COLOR ||
|
||||||
@ -180,7 +203,6 @@ namespace RuntimeData.Commodore {
|
|||||||
mAppRef.ReportError("Invalid parameter");
|
mAppRef.ReportError("Invalid parameter");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lastOffset = offset + SPRITE_SIZE - 1;
|
int lastOffset = offset + SPRITE_SIZE - 1;
|
||||||
if (lastOffset >= mFileData.Length) {
|
if (lastOffset >= mFileData.Length) {
|
||||||
mAppRef.ReportError("Sprite runs off end of file (last offset +" +
|
mAppRef.ReportError("Sprite runs off end of file (last offset +" +
|
||||||
@ -191,13 +213,196 @@ namespace RuntimeData.Commodore {
|
|||||||
int xwide = isDoubleWide ? 2 : 1;
|
int xwide = isDoubleWide ? 2 : 1;
|
||||||
int xhigh = isDoubleHigh ? 2 : 1;
|
int xhigh = isDoubleHigh ? 2 : 1;
|
||||||
|
|
||||||
VisBitmap8 vb = new VisBitmap8(BYTE_WIDTH * 8 * xwide, HEIGHT * xhigh);
|
VisBitmap8 vb = new VisBitmap8(SPRITE_BYTE_WIDTH * 8 * xwide, SPRITE_HEIGHT * xhigh);
|
||||||
SetPalette(vb);
|
SetPalette(vb);
|
||||||
vb.SetAllPixelIndices(TRANSPARENT);
|
vb.SetAllPixelIndices(TRANSPARENT);
|
||||||
|
|
||||||
for (int row = 0; row < HEIGHT; row++) {
|
if (isMultiColor) {
|
||||||
for (int col = 0; col < BYTE_WIDTH; col++) {
|
RenderMultiColorBitmap(offset, SPRITE_BYTE_WIDTH, SPRITE_HEIGHT,
|
||||||
byte val = mFileData[offset + row * BYTE_WIDTH + col];
|
isDoubleWide, isDoubleHigh, color, color01, color11, vb, 0, 0);
|
||||||
|
} else {
|
||||||
|
RenderHiResBitmap(offset, SPRITE_BYTE_WIDTH, SPRITE_HEIGHT,
|
||||||
|
isDoubleWide, isDoubleHigh, color, vb, 0, 0);
|
||||||
|
}
|
||||||
|
return vb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IVisualization2d GenerateSpriteGrid(ReadOnlyDictionary<string, object> parms,
|
||||||
|
bool isMultiColor) {
|
||||||
|
int offset = Util.GetFromObjDict(parms, P_OFFSET, 0);
|
||||||
|
int count = Util.GetFromObjDict(parms, P_COUNT, 16);
|
||||||
|
byte color = (byte)Util.GetFromObjDict(parms, P_COLOR, 0);
|
||||||
|
bool isDoubleWide = Util.GetFromObjDict(parms, P_DOUBLE_WIDE, false);
|
||||||
|
bool isDoubleHigh = Util.GetFromObjDict(parms, P_DOUBLE_HIGH, false);
|
||||||
|
byte color01 = 0;
|
||||||
|
byte color11 = 0;
|
||||||
|
if (isMultiColor) {
|
||||||
|
color01 = (byte)Util.GetFromObjDict(parms, P_COLOR_01, 0);
|
||||||
|
color11 = (byte)Util.GetFromObjDict(parms, P_COLOR_11, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset < 0 || offset >= mFileData.Length ||
|
||||||
|
color < 0 || color > MAX_COLOR ||
|
||||||
|
color01 < 0 || color01 > MAX_COLOR ||
|
||||||
|
color11 < 0 || color11 > MAX_COLOR) {
|
||||||
|
// the UI should flag these based on range (and ideally wouldn't have called us)
|
||||||
|
mAppRef.ReportError("Invalid parameter");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int lastOffset = offset + SPRITE_STRIDE * count - 1;
|
||||||
|
if (lastOffset >= mFileData.Length) {
|
||||||
|
mAppRef.ReportError("Sprite set runs off end of file (last offset +" +
|
||||||
|
lastOffset.ToString("x6") + ")");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xwide = isDoubleWide ? 2 : 1;
|
||||||
|
int xhigh = isDoubleHigh ? 2 : 1;
|
||||||
|
|
||||||
|
// Try to make it square, unless there's a large number of them. Limit the width
|
||||||
|
// to 16 sprites (384 pixels + padding).
|
||||||
|
int hcells;
|
||||||
|
if (count * xwide > 64) {
|
||||||
|
hcells = 16 / xwide;
|
||||||
|
} else if (count * xwide >= 32) {
|
||||||
|
hcells = 8 / xwide;
|
||||||
|
} else {
|
||||||
|
hcells = (int)Math.Sqrt(count * xwide + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vcells = (count + hcells - 1) / hcells;
|
||||||
|
|
||||||
|
VisBitmap8 vb = new VisBitmap8(1 + hcells * SPRITE_BYTE_WIDTH * 8 * xwide + hcells,
|
||||||
|
1 + vcells * SPRITE_HEIGHT * xhigh + vcells);
|
||||||
|
SetPalette(vb);
|
||||||
|
vb.SetAllPixelIndices(BORDER_COLOR);
|
||||||
|
|
||||||
|
int cellX = 1;
|
||||||
|
int cellY = 1;
|
||||||
|
for (int idx = 0; idx < count; idx++) {
|
||||||
|
if (isMultiColor) {
|
||||||
|
RenderMultiColorBitmap(offset + idx * SPRITE_STRIDE,
|
||||||
|
SPRITE_BYTE_WIDTH, SPRITE_HEIGHT, isDoubleWide, isDoubleHigh,
|
||||||
|
color, color01, color11, vb, cellX, cellY);
|
||||||
|
} else {
|
||||||
|
RenderHiResBitmap(offset + idx * SPRITE_STRIDE,
|
||||||
|
SPRITE_BYTE_WIDTH, SPRITE_HEIGHT, isDoubleWide, isDoubleHigh,
|
||||||
|
color, vb, cellX, cellY);
|
||||||
|
}
|
||||||
|
|
||||||
|
cellX += SPRITE_BYTE_WIDTH * 8 * xwide + 1;
|
||||||
|
if (cellX == vb.Width) {
|
||||||
|
cellX = 1;
|
||||||
|
cellY += SPRITE_HEIGHT * xhigh + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IVisualization2d GenerateFont(ReadOnlyDictionary<string, object> parms,
|
||||||
|
bool isMultiColor) {
|
||||||
|
int offset = Util.GetFromObjDict(parms, P_OFFSET, 0);
|
||||||
|
int count = Util.GetFromObjDict(parms, P_COUNT, 96);
|
||||||
|
|
||||||
|
if (offset < 0 || offset >= mFileData.Length) {
|
||||||
|
mAppRef.ReportError("Invalid parameter");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int lastOffset = offset + count - 1;
|
||||||
|
if (lastOffset >= mFileData.Length) {
|
||||||
|
mAppRef.ReportError("Font runs off end of file (last offset +" +
|
||||||
|
lastOffset.ToString("x6") + ")");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the number of horizontal cells. For small counts we try to make it square,
|
||||||
|
// for larger counts we use a reasonable power of 2.
|
||||||
|
int hcells;
|
||||||
|
if (count > 128) {
|
||||||
|
hcells = 32;
|
||||||
|
} else if (count > 64) {
|
||||||
|
hcells = 16;
|
||||||
|
} else if (count >= 32) {
|
||||||
|
hcells = 8;
|
||||||
|
} else {
|
||||||
|
hcells = (int)Math.Sqrt(count + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vcells = (count + hcells - 1) / hcells;
|
||||||
|
|
||||||
|
const int FONT_BYTE_WIDTH = 1;
|
||||||
|
const int FONT_HEIGHT = 8;
|
||||||
|
const int CELL_STRIDE = FONT_BYTE_WIDTH * FONT_HEIGHT;
|
||||||
|
|
||||||
|
// Create a bitmap with room for each cell, plus a 1-pixel boundary
|
||||||
|
// between them and around the edges.
|
||||||
|
VisBitmap8 vb = new VisBitmap8(1 + hcells * FONT_BYTE_WIDTH * 8 + hcells,
|
||||||
|
1 + vcells * FONT_HEIGHT + vcells);
|
||||||
|
SetPalette(vb);
|
||||||
|
vb.SetAllPixelIndices(BORDER_COLOR);
|
||||||
|
|
||||||
|
int cellX = 1;
|
||||||
|
int cellY = 1;
|
||||||
|
byte color = 0; /* black */
|
||||||
|
byte color01 = 11; /* dark grey */
|
||||||
|
byte color11 = 15; /* light grey */
|
||||||
|
for (int idx = 0; idx < count; idx++) {
|
||||||
|
if (isMultiColor) {
|
||||||
|
RenderMultiColorBitmap(offset + idx * CELL_STRIDE, FONT_BYTE_WIDTH, FONT_HEIGHT,
|
||||||
|
false, false, color, color01, color11, vb, cellX, cellY);
|
||||||
|
} else {
|
||||||
|
RenderHiResBitmap(offset + idx * CELL_STRIDE, FONT_BYTE_WIDTH, FONT_HEIGHT,
|
||||||
|
false, false, color, vb, cellX, cellY);
|
||||||
|
}
|
||||||
|
|
||||||
|
cellX += FONT_BYTE_WIDTH * 8 + 1;
|
||||||
|
if (cellX == vb.Width) {
|
||||||
|
cellX = 1;
|
||||||
|
cellY += FONT_HEIGHT + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderHiResBitmap(int offset, int byteWidth, int height,
|
||||||
|
bool isDoubleWide, bool isDoubleHigh,
|
||||||
|
byte color, VisBitmap8 vb, int startx, int starty) {
|
||||||
|
int xwide = isDoubleWide ? 2 : 1;
|
||||||
|
int xhigh = isDoubleHigh ? 2 : 1;
|
||||||
|
for (int row = 0; row < height; row++) {
|
||||||
|
for (int col = 0; col < byteWidth; col++) {
|
||||||
|
byte val = mFileData[offset + row * byteWidth + col];
|
||||||
|
for (int bit = 0; bit < 8; bit++) {
|
||||||
|
byte pixColor;
|
||||||
|
if ((val & 0x80) == 0) {
|
||||||
|
pixColor = TRANSPARENT;
|
||||||
|
} else {
|
||||||
|
pixColor = color;
|
||||||
|
}
|
||||||
|
int xc = startx + (col * 8 + bit) * xwide;
|
||||||
|
int yc = starty + row * xhigh;
|
||||||
|
vb.SetPixelIndex(xc, yc, pixColor);
|
||||||
|
if (isDoubleWide || isDoubleHigh) {
|
||||||
|
// Draw doubled pixels. If we're only doubled in one dimension
|
||||||
|
// this will draw some pixels twice.
|
||||||
|
vb.SetPixelIndex(xc + xwide - 1, yc, pixColor);
|
||||||
|
vb.SetPixelIndex(xc, yc + xhigh - 1, pixColor);
|
||||||
|
vb.SetPixelIndex(xc + xwide - 1, yc + xhigh - 1, pixColor);
|
||||||
|
}
|
||||||
|
val <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderMultiColorBitmap(int offset, int byteWidth, int height,
|
||||||
|
bool isDoubleWide, bool isDoubleHigh,
|
||||||
|
byte color, byte color01, byte color11, VisBitmap8 vb, int startx, int starty) {
|
||||||
|
int xwide = isDoubleWide ? 2 : 1;
|
||||||
|
int xhigh = isDoubleHigh ? 2 : 1;
|
||||||
|
for (int row = 0; row < height; row++) {
|
||||||
|
for (int col = 0; col < byteWidth; col++) {
|
||||||
|
byte val = mFileData[offset + row * byteWidth + col];
|
||||||
for (int bit = 0; bit < 8; bit += 2) {
|
for (int bit = 0; bit < 8; bit += 2) {
|
||||||
byte pixColor = 0;
|
byte pixColor = 0;
|
||||||
switch (val & 0xc0) {
|
switch (val & 0xc0) {
|
||||||
@ -206,13 +411,14 @@ namespace RuntimeData.Commodore {
|
|||||||
case 0x40: pixColor = color01; break;
|
case 0x40: pixColor = color01; break;
|
||||||
case 0xc0: pixColor = color11; break;
|
case 0xc0: pixColor = color11; break;
|
||||||
}
|
}
|
||||||
int xc = (col * 8 + bit) * xwide;
|
int xc = startx + (col * 8 + bit) * xwide;
|
||||||
int yc = row * xhigh;
|
int yc = starty + row * xhigh;
|
||||||
|
// Set two adjacent pixels.
|
||||||
vb.SetPixelIndex(xc, yc, pixColor);
|
vb.SetPixelIndex(xc, yc, pixColor);
|
||||||
vb.SetPixelIndex(xc+1, yc, pixColor);
|
vb.SetPixelIndex(xc+1, yc, pixColor);
|
||||||
if (isDoubleWide || isDoubleHigh) {
|
if (isDoubleWide || isDoubleHigh) {
|
||||||
// Draw doubled pixels. If we're only doubled in one dimension
|
// Draw doubled pixels. If we're only doubled in one dimension
|
||||||
// this will draw pixels twice.
|
// this will draw some pixels twice.
|
||||||
vb.SetPixelIndex(xc + xwide*2 - 2, yc, pixColor);
|
vb.SetPixelIndex(xc + xwide*2 - 2, yc, pixColor);
|
||||||
vb.SetPixelIndex(xc + xwide*2 - 1, yc, pixColor);
|
vb.SetPixelIndex(xc + xwide*2 - 1, yc, pixColor);
|
||||||
vb.SetPixelIndex(xc, yc + xhigh - 1, pixColor);
|
vb.SetPixelIndex(xc, yc + xhigh - 1, pixColor);
|
||||||
@ -224,31 +430,36 @@ namespace RuntimeData.Commodore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return vb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private const byte TRANSPARENT = 16;
|
private const byte TRANSPARENT = 16;
|
||||||
|
private const byte BORDER_COLOR = 17;
|
||||||
|
|
||||||
// C64 colors, from http://unusedino.de/ec64/technical/misc/vic656x/colors/
|
// C64 colors, from http://unusedino.de/ec64/technical/misc/vic656x/colors/
|
||||||
// (the ones on https://www.c64-wiki.com/wiki/Color looked wrong)
|
// (the ones on https://www.c64-wiki.com/wiki/Color looked wrong)
|
||||||
private void SetPalette(VisBitmap8 vb) {
|
private void SetPalette(VisBitmap8 vb) {
|
||||||
vb.AddColor(0xff, 0x00, 0x00, 0x00); // 0=black
|
vb.SetColor(0, 0xff, 0x00, 0x00, 0x00); // 0=black
|
||||||
vb.AddColor(0xff, 0xff, 0xff, 0xff); // 1=white
|
vb.SetColor(1, 0xff, 0xff, 0xff, 0xff); // 1=white
|
||||||
vb.AddColor(0xff, 0x68, 0x37, 0x2b); // 2=red
|
vb.SetColor(2, 0xff, 0x68, 0x37, 0x2b); // 2=red
|
||||||
vb.AddColor(0xff, 0x70, 0xa4, 0xb2); // 3=cyan
|
vb.SetColor(3, 0xff, 0x70, 0xa4, 0xb2); // 3=cyan
|
||||||
vb.AddColor(0xff, 0x6f, 0x3d, 0x86); // 4=purple
|
vb.SetColor(4, 0xff, 0x6f, 0x3d, 0x86); // 4=purple
|
||||||
vb.AddColor(0xff, 0x58, 0x8d, 0x43); // 5=green
|
vb.SetColor(5, 0xff, 0x58, 0x8d, 0x43); // 5=green
|
||||||
vb.AddColor(0xff, 0x35, 0x28, 0x79); // 6=blue
|
vb.SetColor(6, 0xff, 0x35, 0x28, 0x79); // 6=blue
|
||||||
vb.AddColor(0xff, 0xb8, 0xc7, 0x6f); // 7=yellow
|
vb.SetColor(7, 0xff, 0xb8, 0xc7, 0x6f); // 7=yellow
|
||||||
vb.AddColor(0xff, 0x6f, 0x4f, 0x25); // 8=orange
|
vb.SetColor(8, 0xff, 0x6f, 0x4f, 0x25); // 8=orange
|
||||||
vb.AddColor(0xff, 0x43, 0x39, 0x00); // 9-brown
|
vb.SetColor(9, 0xff, 0x43, 0x39, 0x00); // 9-brown
|
||||||
vb.AddColor(0xff, 0x9a, 0x67, 0x59); // 10=light red
|
vb.SetColor(10, 0xff, 0x9a, 0x67, 0x59); // 10=light red
|
||||||
vb.AddColor(0xff, 0x44, 0x44, 0x44); // 11=dark grey
|
vb.SetColor(11, 0xff, 0x44, 0x44, 0x44); // 11=dark grey
|
||||||
vb.AddColor(0xff, 0x6c, 0x6c, 0x6c); // 12=grey
|
vb.SetColor(12, 0xff, 0x6c, 0x6c, 0x6c); // 12=grey
|
||||||
vb.AddColor(0xff, 0x9a, 0xd2, 0x84); // 13=light green
|
vb.SetColor(13, 0xff, 0x9a, 0xd2, 0x84); // 13=light green
|
||||||
vb.AddColor(0xff, 0x6c, 0x5e, 0xb5); // 14=light blue
|
vb.SetColor(14, 0xff, 0x6c, 0x5e, 0xb5); // 14=light blue
|
||||||
vb.AddColor(0xff, 0x95, 0x95, 0x95); // 15=light grey
|
vb.SetColor(15, 0xff, 0x95, 0x95, 0x95); // 15=light grey
|
||||||
vb.AddColor(0, 0, 0, 0); // 16=transparent
|
vb.SetColor(16, 0, 0, 0, 0); // 16=transparent
|
||||||
|
#if SHOW_BORDER
|
||||||
|
vb.SetColor(17, 0xff, 0x00, 0xd6, 0xff); // 17=grid border
|
||||||
|
#else
|
||||||
|
vb.SetColor(17, 0, 0, 0, 0); // 17=grid border
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,16 +251,17 @@ straightforward fashion.</p>
|
|||||||
repeated as-is or flipped.</li>
|
repeated as-is or flipped.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h3>Atari Arcade : Atari/VisAVG</h3>
|
<h3>Atari Arcade : Atari/VisAVG and Atari/VisDVG</h3>
|
||||||
|
|
||||||
<p>Different versions of Atari's Analog Vector Graphics were used in
|
<p>Different versions of Atari's Analog Vector Graphics and
|
||||||
several games, notably Battlezone, Tempest, and Star Wars. The commands
|
Digital Vector Graphics were used in several games, notably Asteroids,
|
||||||
|
Battlezone, Tempest, and Star Wars. The commands
|
||||||
drove a vector display monitor. SourceGen visualizes them as 2D
|
drove a vector display monitor. SourceGen visualizes them as 2D
|
||||||
wireframes, which isn't a perfect fit since they can describe points as
|
wireframes, which isn't a perfect fit since they can describe points as
|
||||||
well as lines, but works fine for annotating a disassembly.</p>
|
well as lines, but works fine for annotating a disassembly.</p>
|
||||||
<p>The visualizer takes two arguments: the offset of the start of
|
<p>The visualizer takes two arguments: the offset of the start of
|
||||||
the commands to visualize, and the base address of vector RAM. The latter
|
the commands to visualize, and the base address of vector RAM. The latter
|
||||||
is necessary to convert AVG JMP/JSR commands into offsets.</p>
|
is needed to convert vector JMP/JSR commands into offsets.</p>
|
||||||
|
|
||||||
<h3>Commodore 64 : Commodore/VisC64</h3>
|
<h3>Commodore 64 : Commodore/VisC64</h3>
|
||||||
|
|
||||||
@ -297,6 +298,14 @@ It comes in two basic varieties:</p>
|
|||||||
a sprite that is doubled in both width and height will look exactly like
|
a sprite that is doubled in both width and height will look exactly like
|
||||||
a sprite that is not doubled at all.</p>
|
a sprite that is not doubled at all.</p>
|
||||||
|
|
||||||
|
<p>If multiple sprites are defined consecutively, at 64-byte intervals,
|
||||||
|
they can be combined into a sprite sheet. A single set of parameters
|
||||||
|
for color and scaling is applied to all sprites.</p>
|
||||||
|
|
||||||
|
<p>The visualizer also handles high-resolution and multi-color fonts,
|
||||||
|
which are displayed in a grid.</p>
|
||||||
|
|
||||||
|
|
||||||
<h3>Nintendo Entertainment System : Nintendo/VisNES</h3>
|
<h3>Nintendo Entertainment System : Nintendo/VisNES</h3>
|
||||||
|
|
||||||
<p>NES PPU pattern tables hold 8x8 tiles with 2 bits of color per pixel.
|
<p>NES PPU pattern tables hold 8x8 tiles with 2 bits of color per pixel.
|
||||||
|
Loading…
Reference in New Issue
Block a user