mirror of
https://github.com/fadden/6502bench.git
synced 2024-11-29 10:50:28 +00:00
Add C64 sprite visualization generator
Handles high-resolution and multi-color sprites. The visualization can be doubled in height and/or width. I created some test sprites with SpritePad.
This commit is contained in:
parent
3c541089a7
commit
ed66e129cd
@ -72,6 +72,16 @@ namespace PluginCommon {
|
||||
mData[x + y * Width] = colorIndex;
|
||||
}
|
||||
|
||||
public void SetAllPixelIndices(byte colorIndex) {
|
||||
if (colorIndex < 0 || colorIndex >= mNextColor) {
|
||||
throw new ArgumentException("Bad color: " + colorIndex + " (nextCol=" +
|
||||
mNextColor + ")");
|
||||
}
|
||||
for (int i = 0; i < mData.Length; i++) {
|
||||
mData[i] = colorIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// IVisualization2d
|
||||
public byte[] GetPixels() {
|
||||
return mData;
|
||||
|
256
SourceGen/RuntimeData/Commodore/VisC64.cs
Normal file
256
SourceGen/RuntimeData/Commodore/VisC64.cs
Normal file
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text;
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
@ -38,6 +38,10 @@ may be included in HTML exports.</p>
|
||||
they will become "hidden" if the offset isn't at the start of a line,
|
||||
e.g. it's in the middle of a multi-byte instruction or data item. The
|
||||
editors will try to prevent you from doing this.</p>
|
||||
<p>Bitmaps will always be scaled up as much as possible to make them
|
||||
easy to see. This means that small shapes and large shapes may appears
|
||||
to be the same size. Bear in mind that this is a disassembler, not a
|
||||
graphics conversion tool.</p>
|
||||
|
||||
|
||||
<h2><a name="vis-and-sets">Visualizations and Visualization Sets</a></h2>
|
||||
@ -156,6 +160,35 @@ generator works for data stored in a straightforward fashion.</p>
|
||||
to repeat each row N times to adjust the proportions.</li>
|
||||
</ul>
|
||||
|
||||
<h3>Commodore 64 - Commodore/VisC64</h3>
|
||||
|
||||
<p>The Commodore 64 has a 64-bit sprite format defined by the hardware.
|
||||
It supports a single-color "high resolution" 24x21 format, and a 12x21
|
||||
"multi-color" format. Sprites can be doubled in width or height.</p>
|
||||
<p>Colors come from a hardware-defined palette of 16:</p>
|
||||
<ol start="0">
|
||||
<li><span style="color:#ffffff;background-color:#000000"> black </span></li>
|
||||
<li><span style="color:#000000;background-color:#ffffff"> white </span></li>
|
||||
<li><span style="color:#ffffff;background-color:#67372b"> red </span></li>
|
||||
<li><span style="color:#ffffff;background-color:#70a4b2"> cyan </span></li>
|
||||
<li><span style="color:#ffffff;background-color:#6f3d86"> purple </span></li>
|
||||
<li><span style="color:#ffffff;background-color:#588d43"> green </span></li>
|
||||
<li><span style="color:#ffffff;background-color:#352879"> blue </span></li>
|
||||
<li><span style="color:#000000;background-color:#b8c76f"> yellow </span></li>
|
||||
<li><span style="color:#ffffff;background-color:#6f4f25"> orange </span></li>
|
||||
<li><span style="color:#ffffff;background-color:#433900"> brown </span></li>
|
||||
<li><span style="color:#ffffff;background-color:#9a6759"> light red </span></li>
|
||||
<li><span style="color:#ffffff;background-color:#444444"> dark grey </span></li>
|
||||
<li><span style="color:#ffffff;background-color:#6c6c6c"> grey </span></li>
|
||||
<li><span style="color:#000000;background-color:#9ad284"> light green </span></li>
|
||||
<li><span style="color:#ffffff;background-color:#6c5eb5"> light blue </span></li>
|
||||
<li><span style="color:#ffffff;background-color:#959595"> light grey </span></li>
|
||||
</ol>
|
||||
|
||||
<p>Bear in mind that the editor scales images to their maximum size, so
|
||||
a sprite that is doubled in both width and height will look exactly like
|
||||
a sprite that is not doubled at all.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="footer">
|
||||
|
@ -193,6 +193,7 @@
|
||||
"RT:Commodore/C64-Kernal.sym65"
|
||||
],
|
||||
"ExtensionScripts" : [
|
||||
"RT:Commodore/VisC64.cs"
|
||||
],
|
||||
"Parameters" : {
|
||||
"first-word-is-load-addr":"true",
|
||||
@ -209,6 +210,7 @@
|
||||
"RT:Commodore/C64-Kernal.sym65"
|
||||
],
|
||||
"ExtensionScripts" : [
|
||||
"RT:Commodore/VisC64.cs"
|
||||
],
|
||||
"Parameters" : {
|
||||
"default-text-encoding":"c64-petscii"
|
||||
@ -225,6 +227,7 @@
|
||||
"RT:Commodore/C128-Kernal.sym65"
|
||||
],
|
||||
"ExtensionScripts" : [
|
||||
"RT:Commodore/VisC64.cs"
|
||||
],
|
||||
"Parameters" : {
|
||||
"default-text-encoding":"c64-petscii"
|
||||
|
55
SourceGen/SGTestData/Visualization/c64-sprites.dis65
Normal file
55
SourceGen/SGTestData/Visualization/c64-sprites.dis65
Normal file
@ -0,0 +1,55 @@
|
||||
### 6502bench SourceGen dis65 v1.0 ###
|
||||
{
|
||||
"_ContentVersion":3,"FileDataLength":2048,"FileDataCrc32":-811860884,"ProjectProps":{
|
||||
"CpuName":"6502","IncludeUndocumentedInstr":false,"TwoByteBrk":false,"EntryFlags":32702671,"AutoLabelStyle":"Simple","AnalysisParams":{
|
||||
"AnalyzeUncategorizedData":true,"DefaultTextScanMode":"C64Petscii","MinCharsForString":4,"SeekNearbyTargets":true,"SmartPlpHandling":true},
|
||||
"PlatformSymbolFileIdentifiers":["RT:Commodore/C64-Kernal.sym65"],"ExtensionScriptFileIdentifiers":["RT:Commodore/VisC64.cs"],"ProjectSyms":{
|
||||
}},
|
||||
"AddressMap":[{
|
||||
"Offset":0,"Addr":4096}],"TypeHints":[],"StatusFlagOverrides":{
|
||||
},
|
||||
"Comments":{
|
||||
},
|
||||
"LongComments":{
|
||||
"-2147483647":{
|
||||
"Text":"Sprites created with SpritePad v1.8.1\r\n","BoxMode":false,"MaxWidth":80,"BackgroundColor":0},
|
||||
"0":{
|
||||
"Text":"Multi-color","BoxMode":false,"MaxWidth":80,"BackgroundColor":0},
|
||||
"64":{
|
||||
"Text":"High-resolution","BoxMode":false,"MaxWidth":80,"BackgroundColor":0},
|
||||
"128":{
|
||||
"Text":"Multi-color, use 2x width\r\n","BoxMode":false,"MaxWidth":80,"BackgroundColor":0},
|
||||
"192":{
|
||||
"Text":"High-resolution, use 2x width \u0026 height","BoxMode":false,"MaxWidth":80,"BackgroundColor":0}},
|
||||
"Notes":{
|
||||
},
|
||||
"UserLabels":{
|
||||
},
|
||||
"OperandFormats":{
|
||||
"0":{
|
||||
"Length":64,"Format":"Dense","SubFormat":"None","SymbolRef":null},
|
||||
"64":{
|
||||
"Length":64,"Format":"Dense","SubFormat":"None","SymbolRef":null},
|
||||
"128":{
|
||||
"Length":64,"Format":"Dense","SubFormat":"None","SymbolRef":null},
|
||||
"192":{
|
||||
"Length":64,"Format":"Dense","SubFormat":"None","SymbolRef":null}},
|
||||
"LvTables":{
|
||||
},
|
||||
"VisualizationSets":{
|
||||
"0":{
|
||||
"Items":[{
|
||||
"Tag":"vis000000","VisGenIdent":"c64-multi-color-sprite","VisGenParams":{
|
||||
"offset":0,"color":3,"color01":6,"color11":10,"doubleWide":false,"doubleHigh":false}}]},
|
||||
"64":{
|
||||
"Items":[{
|
||||
"Tag":"vis000040","VisGenIdent":"c64-hi-res-sprite","VisGenParams":{
|
||||
"offset":64,"color":14,"doubleWide":false,"doubleHigh":false}}]},
|
||||
"128":{
|
||||
"Items":[{
|
||||
"Tag":"vis000080","VisGenIdent":"c64-multi-color-sprite","VisGenParams":{
|
||||
"offset":128,"color":4,"color01":6,"color11":10,"doubleWide":true,"doubleHigh":false}}]},
|
||||
"192":{
|
||||
"Items":[{
|
||||
"Tag":"vis0000c0","VisGenIdent":"c64-hi-res-sprite","VisGenParams":{
|
||||
"offset":192,"color":5,"doubleWide":true,"doubleHigh":true}}]}}}
|
BIN
SourceGen/SGTestData/Visualization/c64-sprites.raw
Normal file
BIN
SourceGen/SGTestData/Visualization/c64-sprites.raw
Normal file
Binary file not shown.
BIN
SourceGen/SGTestData/Visualization/c64-sprites.spd
Normal file
BIN
SourceGen/SGTestData/Visualization/c64-sprites.spd
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user