1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-06-25 05:29:31 +00:00

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.
This commit is contained in:
Andy McFadden 2019-12-06 14:49:35 -08:00
parent af4ec49c9b
commit 1cdb31de32
10 changed files with 87 additions and 46 deletions

View File

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

View File

@ -1798,14 +1798,16 @@ namespace SourceGen {
}
/// <summary>
/// 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.
/// </summary>
/// <param name="offset">Offset of interest.</param>
/// <returns>True if a comment or note was found.</returns>
public bool HasCommentOrNote(int offset) {
/// <returns>True if a comment, note, or visualization was found.</returns>
public bool HasCommentNoteOrVis(int offset) {
return (LongComments.ContainsKey(offset) ||
Notes.ContainsKey(offset));
Notes.ContainsKey(offset) ||
VisualizationSets.ContainsKey(offset));
}
/// <summary>
@ -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<int, VisualizationSet> kvp
in VisualizationSets) {
kvp.Value.RefreshNeeded();
}
ClearVisualizationCache();
}
}
// ignore affectedOffsets
@ -2292,6 +2293,15 @@ namespace SourceGen {
return needReanalysis;
}
/// <summary>
/// Clears all visualization cached images.
/// </summary>
private void ClearVisualizationCache() {
foreach (KeyValuePair<int, VisualizationSet> kvp in VisualizationSets) {
kvp.Value.RefreshNeeded();
}
}
/// <summary>
/// Updates all symbolic references to the old label. Call this after replacing
/// mAnattribs[labelOffset].Symbol.

View File

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

View File

@ -247,7 +247,7 @@ namespace RuntimeData.Apple {
}
private IVisualization2d GenerateScreen(ReadOnlyDictionary<string, object> 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];
}
}

View File

@ -69,13 +69,6 @@ and 65816 code. The official web site is
</ul></li>
</ul></li>
<li><a href="visualization.html">Visualizations</a>
<ul>
<li><a href="visualization.html#overview">Overview</a></li>
<li><a href="visualization.html#vis-and-sets">Visualizations and Visualization Sets</a></li>
<li><a href="visualization.html#runtime">Scripts Included with SourceGen</a></li>
</ul></li>
<li><a href="editors.html">Editors</a>
<ul>
<li><a href="editors.html#address">Edit Address</a></li>
@ -95,6 +88,13 @@ and 65816 code. The official web site is
<li><a href="editors.html#lvtable">Edit Local Variable Table</a></li>
</ul></li>
<li><a href="visualization.html">Visualizations</a>
<ul>
<li><a href="visualization.html#overview">Overview</a></li>
<li><a href="visualization.html#vis-and-sets">Visualizations and Visualization Sets</a></li>
<li><a href="visualization.html#runtime">Scripts Included with SourceGen</a></li>
</ul></li>
<li><a href="codegen.html">Code Generation &amp; Assembly</a>
<ul>
<li><a href="codegen.html#supported">Supported Assemblers</a>

View File

@ -30,10 +30,14 @@ include them in your project.</p>
<p>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.</p>
the project is first opened, and updated when certain things change in
the project.</p>
<p>Visualizations are not included in generated assembly output. They
may be included in HTML exports.</p>
<p>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.</p>
<h2><a name="vis-and-sets">Visualizations and Visualization Sets</a></h2>
@ -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.</p>
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.</p>
<p>To create a visualization set, select a code or data line, and use
Actions &gt; Create/Edit Visualization Set. To edit a visualization set,
@ -115,7 +121,11 @@ arrangements are common. The script defines three generators:</p>
converted as monochrome, and have a 1-pixel transparent gap
between elements.</li>
<li><b>Hi-Res Screen Image</b> - used for 8KiB screen images. The
data is linearized and converted to a 280x192 bitmap.</li>
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.</li>
</ul>
<p>Widths are specified in bytes, not pixels. Each byte represents 7

View File

@ -21,7 +21,7 @@
"LongComments":{
},
"Notes":{
"213":{
"222":{
"Text":"Bitmaps here","BoxMode":false,"MaxWidth":80,"BackgroundColor":-256}},
"UserLabels":{
},

View File

@ -106,7 +106,7 @@ See also https://github.com/fadden/DisasmUiTest
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" Margin="8,0,0,0"
<Border BorderThickness="1" Margin="8,0,0,0" Padding="1"
Background="{StaticResource BitmapBackground}">
<Image Width="64" Height="64" Source="{Binding CachedImage}"
RenderOptions.BitmapScalingMode="NearestNeighbor"/>

View File

@ -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">
<Window.Resources>

View File

@ -42,6 +42,11 @@ namespace SourceGen.WpfGui {
private Visualization mOrigVis;
private string mOrigTag;
/// <summary>
/// Identifier for last visualizer we used, for the benefit of "new".
/// </summary>
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<VisualizationItem>();
List<IPlugin> 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;
}