From 1cdb31de3252640eddabd7fc667ae77d97e9d683 Mon Sep 17 00:00:00 2001
From: Andy McFadden
Date: Fri, 6 Dec 2019 14:49:35 -0800
Subject: [PATCH] Visualizer improvements
Various changes:
- Generally treat visualization sets like long comments and notes
when it comes to defining data region boundaries. (We were doing
this for selections; now we're also doing it for format-as-word
and in the data analyzer when scanning for strings/fill.)
- Clear the visualization cache when the address map is altered.
This is necessary for visualizers that dereference addresses.
- Read the Apple II screen image from a series of addresses rather
than a series of offsets. This allows it to work when the image
is contiguous in memory but split into chunks in the file.
- Put 1 pixel of padding around the images in the main code list,
so they don't blend into the background.
- Remember the last visualizer used, so we can re-use it the next
time the user selects "new".
- Move min-size hack from Loaded to ContentRendered, as it apparently
spoils CenterOwner placement.
---
SourceGen/DataAnalysis.cs | 2 +-
SourceGen/DisasmProject.cs | 32 ++++++++++++-------
SourceGen/MainController.cs | 9 ++----
SourceGen/RuntimeData/Apple/VisHiRes.cs | 32 ++++++++++++-------
SourceGen/RuntimeData/Help/index.html | 14 ++++----
SourceGen/RuntimeData/Help/visualization.html | 18 ++++++++---
.../apple2-bitmap-test#061000.dis65 | 2 +-
SourceGen/WpfGui/CodeListItemStyle.xaml | 2 +-
SourceGen/WpfGui/EditVisualization.xaml | 2 +-
SourceGen/WpfGui/EditVisualization.xaml.cs | 20 ++++++++++--
10 files changed, 87 insertions(+), 46 deletions(-)
diff --git a/SourceGen/DataAnalysis.cs b/SourceGen/DataAnalysis.cs
index 5174822..3c72cc3 100644
--- a/SourceGen/DataAnalysis.cs
+++ b/SourceGen/DataAnalysis.cs
@@ -552,7 +552,7 @@ namespace SourceGen {
Debug.Assert(attr.Length > 0);
offset += attr.Length;
}
- } else if (attr.Symbol != null || mProject.HasCommentOrNote(offset)) {
+ } else if (attr.Symbol != null || mProject.HasCommentNoteOrVis(offset)) {
// In an uncategorized area, but we want to break at this byte
// so the user or auto label doesn't get buried in the middle of
// a large chunk.
diff --git a/SourceGen/DisasmProject.cs b/SourceGen/DisasmProject.cs
index 91ff6dd..cf33d83 100644
--- a/SourceGen/DisasmProject.cs
+++ b/SourceGen/DisasmProject.cs
@@ -1798,14 +1798,16 @@ namespace SourceGen {
}
///
- /// Returns true if the offset has a long comment or note. Used for determining how to
- /// split up a data area. Currently not returning true for an end-of-line comment.
+ /// Returns true if the offset has a long comment, note, or visualization. Used for
+ /// determining how to split up a data area.
+ /// Currently not returning true for an end-of-line comment.
///
/// Offset of interest.
- /// True if a comment or note was found.
- public bool HasCommentOrNote(int offset) {
+ /// True if a comment, note, or visualization was found.
+ public bool HasCommentNoteOrVis(int offset) {
return (LongComments.ContainsKey(offset) ||
- Notes.ContainsKey(offset));
+ Notes.ContainsKey(offset) ||
+ VisualizationSets.ContainsKey(offset));
}
///
@@ -1986,6 +1988,10 @@ namespace SourceGen {
Debug.WriteLine("Map offset +" + offset.ToString("x6") + " to $" +
((int)newValue).ToString("x6"));
+ // Visualization generators in extension scripts could be chasing
+ // addresses. Give them a chance to update.
+ ClearVisualizationCache();
+
// ignore affectedOffsets
Debug.Assert(uc.ReanalysisRequired ==
UndoableChange.ReanalysisScope.CodeAndData);
@@ -2238,12 +2244,7 @@ namespace SourceGen {
// run through here.)
}
if (needExtScriptReload) {
- // Clear all the Visualization thumbnails. We don't do GUI
- // stuff in here, so this just sets a flag.
- foreach (KeyValuePair kvp
- in VisualizationSets) {
- kvp.Value.RefreshNeeded();
- }
+ ClearVisualizationCache();
}
}
// ignore affectedOffsets
@@ -2292,6 +2293,15 @@ namespace SourceGen {
return needReanalysis;
}
+ ///
+ /// Clears all visualization cached images.
+ ///
+ private void ClearVisualizationCache() {
+ foreach (KeyValuePair kvp in VisualizationSets) {
+ kvp.Value.RefreshNeeded();
+ }
+ }
+
///
/// Updates all symbolic references to the old label. Call this after replacing
/// mAnattribs[labelOffset].Symbol.
diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs
index f67eed3..dc2b0fa 100644
--- a/SourceGen/MainController.cs
+++ b/SourceGen/MainController.cs
@@ -2344,7 +2344,7 @@ namespace SourceGen {
Anattrib nextAttr = mProject.GetAnattrib(nextOffset);
// This must match what GroupedOffsetSetFromSelected() does.
if (!mProject.UserLabels.ContainsKey(nextOffset) &&
- !mProject.HasCommentOrNote(nextOffset) &&
+ !mProject.HasCommentNoteOrVis(nextOffset) &&
thisAttr.Address == nextAttr.Address - 1) {
// Good to go.
Debug.WriteLine("Grabbing second byte from +" + nextOffset.ToString("x6"));
@@ -3329,11 +3329,8 @@ namespace SourceGen {
// for the uncategorized data analyzer, but very annoying if you want to
// slap a 16-bit numeric format on all entries in a table.
groupNum++;
- } else if (mProject.HasCommentOrNote(offset)) {
- // Don't carry across a long comment or note.
- groupNum++;
- } else if (mProject.VisualizationSets.ContainsKey(offset)) {
- // Don't carry across a visualization.
+ } else if (mProject.HasCommentNoteOrVis(offset)) {
+ // Don't carry across a long comment, note, or visualization.
groupNum++;
}
diff --git a/SourceGen/RuntimeData/Apple/VisHiRes.cs b/SourceGen/RuntimeData/Apple/VisHiRes.cs
index 51b5b05..8a7f6a7 100644
--- a/SourceGen/RuntimeData/Apple/VisHiRes.cs
+++ b/SourceGen/RuntimeData/Apple/VisHiRes.cs
@@ -247,7 +247,7 @@ namespace RuntimeData.Apple {
}
private IVisualization2d GenerateScreen(ReadOnlyDictionary parms) {
- const int RAW_IMAGE_SIZE = 0x1ff8;
+ //const int RAW_IMAGE_SIZE = 0x1ff8;
const int HR_WIDTH = 280;
const int HR_BYTE_WIDTH = HR_WIDTH / 7;
const int HR_HEIGHT = 192;
@@ -261,24 +261,34 @@ namespace RuntimeData.Apple {
return null;
}
- int lastOffset = offset + RAW_IMAGE_SIZE - 1;
- if (lastOffset >= mFileData.Length) {
- mAppRef.ReportError("Bitmap runs off end of file (last offset +" +
- lastOffset.ToString("x6") + ")");
- return null;
- }
+ //int lastOffset = offset + RAW_IMAGE_SIZE - 1;
+ //if (lastOffset >= mFileData.Length) {
+ // mAppRef.ReportError("Bitmap runs off end of file (last offset +" +
+ // lastOffset.ToString("x6") + ")");
+ // return null;
+ //}
- // Linearize the data.
+ // Linearize the data. To handle programs that move themselves around before
+ // executing we use the address translator (e.g. the title screen in Space Eggs
+ // is contiguous in memory but split in half in the file). This is slower, but
+ // mAddrTrans is a local (not proxy) object, so it's not too bad.
byte[] buf = new byte[HR_BYTE_WIDTH * HR_HEIGHT];
int outIdx = 0;
+ int baseAddr = mAddrTrans.OffsetToAddress(offset);
for (int row = 0; row < HR_HEIGHT; row++) {
- // If row is ABCDEFGH, we want pppFGHCD EABAB000 (where p is zero for us).
+ // If row is ABCDEFGH, we want pppFGHCD EABAB000 (where p would be $20/$40).
int low = ((row & 0xc0) >> 1) | ((row & 0xc0) >> 3) | ((row & 0x08) << 4);
int high = ((row & 0x07) << 2) | ((row & 0x30) >> 4);
- int addr = (high << 8) | low;
+ int rowAddr = baseAddr + ((high << 8) | low);
for (int col = 0; col < HR_BYTE_WIDTH; col++) {
- buf[outIdx++] = mFileData[offset + addr + col];
+ int srcOffset = mAddrTrans.AddressToOffset(offset, rowAddr + col);
+ if (srcOffset < 0) {
+ mAppRef.ReportError("Address $" + (rowAddr + col).ToString("x4") +
+ " is outside of file");
+ return null;
+ }
+ buf[outIdx++] = mFileData[srcOffset];
}
}
diff --git a/SourceGen/RuntimeData/Help/index.html b/SourceGen/RuntimeData/Help/index.html
index d226572..16980bd 100644
--- a/SourceGen/RuntimeData/Help/index.html
+++ b/SourceGen/RuntimeData/Help/index.html
@@ -69,13 +69,6 @@ and 65816 code. The official web site is
- Visualizations
-
-
Editors
+ Visualizations
+
+
Code Generation & Assembly
- Supported Assemblers
diff --git a/SourceGen/RuntimeData/Help/visualization.html b/SourceGen/RuntimeData/Help/visualization.html
index 0eadb5e..541e62b 100644
--- a/SourceGen/RuntimeData/Help/visualization.html
+++ b/SourceGen/RuntimeData/Help/visualization.html
@@ -30,10 +30,14 @@ include them in your project.
The project file doesn't store the converted graphics. Instead, the
project file holds a string that identifies the converter, and a list of
parameters that are passed to the converter. Images are generated when
-the project is first opened, and updated if the set of loaded extension
-scripts changes.
+the project is first opened, and updated when certain things change in
+the project.
Visualizations are not included in generated assembly output. They
may be included in HTML exports.
+Because visualizations are associated with a specific file offset,
+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.
@@ -43,7 +47,9 @@ assembled output, and do not change how code is analyzed. They are
contained in sets that are placed at arbitrary offsets. Each set can
contain multiple items. For example, if a file has data for
10 bitmaps, you can place a visualization near each, or create a single
-visualization set with all 10 items and put it at the start of the file.
+visualization set with all 10 items and put it at the start of the file.
+You can display a visualization near the instructions that perform the
+drawing.
To create a visualization set, select a code or data line, and use
Actions > Create/Edit Visualization Set. To edit a visualization set,
@@ -115,7 +121,11 @@ arrangements are common. The script defines three generators:
converted as monochrome, and have a 1-pixel transparent gap
between elements.
Hi-Res Screen Image - used for 8KiB screen images. The
- data is linearized and converted to a 280x192 bitmap.
+ data is linearized and converted to a 280x192 bitmap. Because
+ images are relatively large, the generator does not require them
+ to be contiguous in the file, i.e. two halves of the image can be
+ in different parts of the file so long as they end up contiguous
+ in memory.
Widths are specified in bytes, not pixels. Each byte represents 7
diff --git a/SourceGen/SGTestData/Visualization/apple2-bitmap-test#061000.dis65 b/SourceGen/SGTestData/Visualization/apple2-bitmap-test#061000.dis65
index 00fd089..a064771 100644
--- a/SourceGen/SGTestData/Visualization/apple2-bitmap-test#061000.dis65
+++ b/SourceGen/SGTestData/Visualization/apple2-bitmap-test#061000.dis65
@@ -21,7 +21,7 @@
"LongComments":{
},
"Notes":{
-"213":{
+"222":{
"Text":"Bitmaps here","BoxMode":false,"MaxWidth":80,"BackgroundColor":-256}},
"UserLabels":{
},
diff --git a/SourceGen/WpfGui/CodeListItemStyle.xaml b/SourceGen/WpfGui/CodeListItemStyle.xaml
index 4185a6c..c62d4ea 100644
--- a/SourceGen/WpfGui/CodeListItemStyle.xaml
+++ b/SourceGen/WpfGui/CodeListItemStyle.xaml
@@ -106,7 +106,7 @@ See also https://github.com/fadden/DisasmUiTest
-
diff --git a/SourceGen/WpfGui/EditVisualization.xaml b/SourceGen/WpfGui/EditVisualization.xaml
index 00e201a..c2f2616 100644
--- a/SourceGen/WpfGui/EditVisualization.xaml
+++ b/SourceGen/WpfGui/EditVisualization.xaml
@@ -25,7 +25,7 @@ limitations under the License.
Title="Edit Visualization"
SizeToContent="WidthAndHeight" ResizeMode="CanResizeWithGrip"
ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
- Loaded="Window_Loaded"
+ ContentRendered="Window_ContentRendered"
Closed="Window_Closed">
diff --git a/SourceGen/WpfGui/EditVisualization.xaml.cs b/SourceGen/WpfGui/EditVisualization.xaml.cs
index 3a1841b..0172cc1 100644
--- a/SourceGen/WpfGui/EditVisualization.xaml.cs
+++ b/SourceGen/WpfGui/EditVisualization.xaml.cs
@@ -42,6 +42,11 @@ namespace SourceGen.WpfGui {
private Visualization mOrigVis;
private string mOrigTag;
+ ///
+ /// Identifier for last visualizer we used, for the benefit of "new".
+ ///
+ private static string sLastVisIdent = string.Empty;
+
private Brush mDefaultLabelColor = SystemColors.WindowTextBrush;
private Brush mErrorLabelColor = Brushes.Red;
@@ -168,7 +173,7 @@ namespace SourceGen.WpfGui {
mFormatter = formatter;
mSetOffset = setOffset;
mOrigVis = vis;
- mOrigTag = vis.Tag;
+ mOrigTag = (vis == null) ? string.Empty : vis.Tag;
mScriptSupport = new ScriptSupport(this);
mProject.PrepareScripts(mScriptSupport);
@@ -180,7 +185,7 @@ namespace SourceGen.WpfGui {
TagString = "vis" + mSetOffset.ToString("x6");
}
- int visSelection = 0;
+ int visSelection = -1;
VisualizationList = new List();
List plugins = proj.GetActivePlugins();
foreach (IPlugin chkPlug in plugins) {
@@ -190,6 +195,10 @@ namespace SourceGen.WpfGui {
IPlugin_Visualizer vplug = (IPlugin_Visualizer)chkPlug;
foreach (VisDescr descr in vplug.GetVisGenDescrs()) {
if (vis != null && vis.VisGenIdent == descr.Ident) {
+ // found matching descriptor, set selection to this
+ visSelection = VisualizationList.Count;
+ } else if (visSelection < 0 && descr.Ident == sLastVisIdent) {
+ // we used this one last time, use it if nothing better comes along
visSelection = VisualizationList.Count;
}
VisualizationList.Add(new VisualizationItem(vplug, descr));
@@ -197,6 +206,9 @@ namespace SourceGen.WpfGui {
}
// Set the selection. This should cause the sel change event to fire.
+ if (visSelection < 0) {
+ visSelection = 0;
+ }
visComboBox.SelectedIndex = visSelection;
}
@@ -253,7 +265,7 @@ namespace SourceGen.WpfGui {
}
}
- private void Window_Loaded(object sender, RoutedEventArgs e) {
+ private void Window_ContentRendered(object sender, EventArgs e) {
// https://stackoverflow.com/a/31407415/294248
// After the window's size has been established to minimally wrap the elements,
// we set the minimum width to the current width, and un-freeze the preview image
@@ -284,6 +296,8 @@ namespace SourceGen.WpfGui {
NewVis = new Visualization(trimTag, item.VisDescriptor.Ident, valueDict);
NewVis.CachedImage = (BitmapSource)previewImage.Source;
+ sLastVisIdent = NewVis.VisGenIdent;
+
DialogResult = true;
}