mirror of
https://github.com/fadden/6502bench.git
synced 2024-08-14 18:28:57 +00:00
Added comments, renamed files, removed cruft. Stop showing the visualization tag name in the code list. It's often redundant with the code label, and it's distracting. (We may want to make this an option so you can Ctrl+F to find a tag.)
255 lines
12 KiB
C#
255 lines
12 KiB
C#
/*
|
|
* Copyright 2019 faddenSoft
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
using System;
|
|
using System.Collections.ObjectModel;
|
|
|
|
using PluginCommon;
|
|
|
|
namespace RuntimeData.Commodore {
|
|
public class VisC64 : MarshalByRefObject, IPlugin, IPlugin_Visualizer {
|
|
// IPlugin
|
|
public string Identifier {
|
|
get { return "C64 Graphic Visualizer"; }
|
|
}
|
|
private IApplication mAppRef;
|
|
private byte[] mFileData;
|
|
private AddressTranslate mAddrTrans;
|
|
|
|
// 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_MULTI_COLOR_SPRITE = "c64-multi-color-sprite";
|
|
|
|
private const string P_OFFSET = "offset";
|
|
private const string P_DOUBLE_WIDE = "doubleWide";
|
|
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_01 = "color01"; // multi-color 1
|
|
private const string P_COLOR_11 = "color11"; // multi-color 2
|
|
|
|
private const int MAX_COLOR = 15;
|
|
private const int BYTE_WIDTH = 3;
|
|
private const int HEIGHT = 21;
|
|
private const int SPRITE_SIZE = BYTE_WIDTH * HEIGHT; // 63
|
|
|
|
// Visualization descriptors.
|
|
private VisDescr[] mDescriptors = new VisDescr[] {
|
|
new VisDescr(VIS_GEN_HI_RES_SPRITE, "C64 Hi-Res Sprite", VisDescr.VisType.Bitmap,
|
|
new VisParamDescr[] {
|
|
new VisParamDescr("File offset (hex)",
|
|
P_OFFSET, typeof(int), 0, 0x00ffffff, VisParamDescr.SpecialMode.Offset, 0),
|
|
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, "C64 Multi-Color Sprite", VisDescr.VisType.Bitmap,
|
|
new VisParamDescr[] {
|
|
new VisParamDescr("File offset (hex)",
|
|
P_OFFSET, typeof(int), 0, 0x00ffffff, VisParamDescr.SpecialMode.Offset, 0),
|
|
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),
|
|
}),
|
|
};
|
|
|
|
|
|
// IPlugin
|
|
public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) {
|
|
mAppRef = appRef;
|
|
mFileData = fileData;
|
|
mAddrTrans = addrTrans;
|
|
}
|
|
|
|
// IPlugin
|
|
public void Unprepare() {
|
|
mAppRef = null;
|
|
mFileData = null;
|
|
mAddrTrans = null;
|
|
}
|
|
|
|
// IPlugin_Visualizer
|
|
public VisDescr[] GetVisGenDescrs() {
|
|
// We're using a static set, but it could be generated based on file contents.
|
|
// Confirm that we're prepared.
|
|
if (mFileData == null) {
|
|
return null;
|
|
}
|
|
return mDescriptors;
|
|
}
|
|
|
|
// IPlugin_Visualizer
|
|
public IVisualization2d Generate2d(VisDescr descr,
|
|
ReadOnlyDictionary<string, object> parms) {
|
|
switch (descr.Ident) {
|
|
case VIS_GEN_HI_RES_SPRITE:
|
|
return GenerateHiResSprite(parms);
|
|
case VIS_GEN_MULTI_COLOR_SPRITE:
|
|
return GenerateMultiColorSprite(parms);
|
|
default:
|
|
mAppRef.ReportError("Unknown ident " + descr.Ident);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private IVisualization2d GenerateHiResSprite(ReadOnlyDictionary<string, object> parms) {
|
|
int offset = Util.GetFromObjDict(parms, P_OFFSET, 0);
|
|
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);
|
|
|
|
if (offset < 0 || offset >= mFileData.Length || color < 0 || color > 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_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 ||
|
|
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_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);
|
|
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 += 2) {
|
|
byte pixColor = 0;
|
|
switch (val & 0xc0) {
|
|
case 0x00: pixColor = TRANSPARENT; break;
|
|
case 0x80: pixColor = color; break;
|
|
case 0x40: pixColor = color01; break;
|
|
case 0xc0: pixColor = color11; break;
|
|
}
|
|
int xc = (col * 8 + bit) * xwide;
|
|
int yc = row * xhigh;
|
|
vb.SetPixelIndex(xc, yc, pixColor);
|
|
vb.SetPixelIndex(xc+1, yc, pixColor);
|
|
if (isDoubleWide || isDoubleHigh) {
|
|
// Draw doubled pixels. If we're only doubled in one dimension
|
|
// this will draw pixels twice.
|
|
vb.SetPixelIndex(xc + xwide*2 - 2, yc, pixColor);
|
|
vb.SetPixelIndex(xc + xwide*2 - 1, yc, pixColor);
|
|
vb.SetPixelIndex(xc, yc + xhigh - 1, pixColor);
|
|
vb.SetPixelIndex(xc + 1, yc + xhigh - 1, pixColor);
|
|
vb.SetPixelIndex(xc + xwide*2 - 2, yc + xhigh - 1, pixColor);
|
|
vb.SetPixelIndex(xc + xwide*2 - 1, yc + xhigh - 1, pixColor);
|
|
}
|
|
val <<= 2;
|
|
}
|
|
}
|
|
}
|
|
return vb;
|
|
}
|
|
|
|
private const byte TRANSPARENT = 16;
|
|
|
|
// C64 colors, from http://unusedino.de/ec64/technical/misc/vic656x/colors/
|
|
// (the ones on https://www.c64-wiki.com/wiki/Color looked wrong)
|
|
private void SetPalette(VisBitmap8 vb) {
|
|
vb.AddColor(0xff, 0x00, 0x00, 0x00); // 0=black
|
|
vb.AddColor(0xff, 0xff, 0xff, 0xff); // 1=white
|
|
vb.AddColor(0xff, 0x68, 0x37, 0x2b); // 2=red
|
|
vb.AddColor(0xff, 0x70, 0xa4, 0xb2); // 3=cyan
|
|
vb.AddColor(0xff, 0x6f, 0x3d, 0x86); // 4=purple
|
|
vb.AddColor(0xff, 0x58, 0x8d, 0x43); // 5=green
|
|
vb.AddColor(0xff, 0x35, 0x28, 0x79); // 6=blue
|
|
vb.AddColor(0xff, 0xb8, 0xc7, 0x6f); // 7=yellow
|
|
vb.AddColor(0xff, 0x6f, 0x4f, 0x25); // 8=orange
|
|
vb.AddColor(0xff, 0x43, 0x39, 0x00); // 9-brown
|
|
vb.AddColor(0xff, 0x9a, 0x67, 0x59); // 10=light red
|
|
vb.AddColor(0xff, 0x44, 0x44, 0x44); // 11=dark grey
|
|
vb.AddColor(0xff, 0x6c, 0x6c, 0x6c); // 12=grey
|
|
vb.AddColor(0xff, 0x9a, 0xd2, 0x84); // 13=light green
|
|
vb.AddColor(0xff, 0x6c, 0x5e, 0xb5); // 14=light blue
|
|
vb.AddColor(0xff, 0x95, 0x95, 0x95); // 15=light grey
|
|
vb.AddColor(0, 0, 0, 0); // 16=transparent
|
|
}
|
|
}
|
|
}
|