1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-05-31 22:41:37 +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:
Andy McFadden 2019-12-06 21:25:31 -08:00
parent 3c541089a7
commit ed66e129cd
7 changed files with 357 additions and 0 deletions

View File

@ -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;

View 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
}
}
}

View File

@ -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">&nbsp;black&nbsp;</span></li>
<li><span style="color:#000000;background-color:#ffffff">&nbsp;white&nbsp;</span></li>
<li><span style="color:#ffffff;background-color:#67372b">&nbsp;red&nbsp;</span></li>
<li><span style="color:#ffffff;background-color:#70a4b2">&nbsp;cyan&nbsp;</span></li>
<li><span style="color:#ffffff;background-color:#6f3d86">&nbsp;purple&nbsp;</span></li>
<li><span style="color:#ffffff;background-color:#588d43">&nbsp;green&nbsp;</span></li>
<li><span style="color:#ffffff;background-color:#352879">&nbsp;blue&nbsp;</span></li>
<li><span style="color:#000000;background-color:#b8c76f">&nbsp;yellow&nbsp;</span></li>
<li><span style="color:#ffffff;background-color:#6f4f25">&nbsp;orange&nbsp;</span></li>
<li><span style="color:#ffffff;background-color:#433900">&nbsp;brown&nbsp;</span></li>
<li><span style="color:#ffffff;background-color:#9a6759">&nbsp;light red&nbsp;</span></li>
<li><span style="color:#ffffff;background-color:#444444">&nbsp;dark grey&nbsp;</span></li>
<li><span style="color:#ffffff;background-color:#6c6c6c">&nbsp;grey&nbsp;</span></li>
<li><span style="color:#000000;background-color:#9ad284">&nbsp;light green&nbsp;</span></li>
<li><span style="color:#ffffff;background-color:#6c5eb5">&nbsp;light blue&nbsp;</span></li>
<li><span style="color:#ffffff;background-color:#959595">&nbsp;light grey&nbsp;</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">

View File

@ -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"

View 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}}]}}}

Binary file not shown.

Binary file not shown.