1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-12-23 16:32:44 +00:00

More progress on visualization

Added some rudimentary bitmap creation code.  Got a test pattern
generated by the plugin to display in the app.  (Most of the time
required for this was spent figuring out how bitmaps are handled
in WPF.)
This commit is contained in:
Andy McFadden 2019-11-27 17:12:26 -08:00
parent e7fccfda03
commit 9244ceda7c
7 changed files with 195 additions and 27 deletions

View File

@ -216,10 +216,15 @@ namespace PluginCommon {
/// without scaling or filtering.
/// </summary>
public interface IVisualization2d {
int GetWidth();
int GetHeight();
int Width { get; }
int Height { get; }
void SetPixelIndex(int x, int y, byte colorIndex);
int GetPixel(int x, int y); // returns ARGB value
byte[] GetPixels(); // densely-packed index or ARGB values
int[] GetPalette(); // 32-bit ARGB values; null for direct-color image
// TODO(maybe): pixel aspect ratio
}

View File

@ -84,5 +84,18 @@ namespace PluginCommon {
appRef.SetInlineDataFormat(brkOffset + 1, 1, DataType.NumericLE, subType, label);
}
}
/// <summary>
/// Converts four 8-bit color values to a single 32-bit ARGB value. Values should
/// not be pre-multiplied.
/// </summary>
/// <param name="a">Alpha channel.</param>
/// <param name="r">Red.</param>
/// <param name="g">Green.</param>
/// <param name="b">Blue.</param>
/// <returns>Combined value.</returns>
public static int MakeARGB(int a, int r, int g, int b) {
return (a << 24) | (r << 16) | (g << 8) | b;
}
}
}

View File

@ -0,0 +1,88 @@
/*
* 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.Diagnostics;
using System.Text;
namespace PluginCommon {
/// <summary>
/// Bitmap with 8-bit palette indices, for use with plugin visualizers.
/// </summary>
[Serializable]
public class VisBitmap8 : IVisualization2d {
public const int MAX_DIMENSION = 4096;
public int Width { get; private set; }
public int Height { get; private set; }
private byte[] mData;
private int[] mPalette;
private int mNextColor;
public VisBitmap8(int width, int height) {
Debug.Assert(width > 0 && width <= MAX_DIMENSION);
Debug.Assert(height > 0 && height <= MAX_DIMENSION);
Width = width;
Height = height;
mData = new byte[width * height];
mPalette = new int[256];
mNextColor = 0;
}
// IVisualization2d
public int GetPixel(int x, int y) {
byte pix = mData[x + y * Width];
return mPalette[pix];
}
public void SetPixelIndex(int x, int y, byte colorIndex) {
if (x < 0 || x >= Width || y < 0 || y >= Width) {
throw new ArgumentException("Bad x/y: " + x + "," + y + " (width=" + Width +
" height=" + Height + ")");
}
if (colorIndex < 0 || colorIndex >= mNextColor) {
throw new ArgumentException("Bad color: " + colorIndex + " (nextCol=" +
mNextColor + ")");
}
mData[x + y * Width] = colorIndex;
}
// IVisualization2d
public byte[] GetPixels() {
return mData;
}
// IVisualization2d
public int[] GetPalette() {
int[] pal = new int[mNextColor];
for (int i = 0; i < mNextColor; i++) {
pal[i] = mPalette[i];
}
return pal;
}
public void AddColor(int color) {
if (mNextColor == 256) {
Debug.WriteLine("Palette is full");
return;
}
mPalette[mNextColor++] = color;
}
}
}

View File

@ -62,7 +62,7 @@ namespace RuntimeData.Apple {
new VisParamDescr("Item width (in bytes)",
"itemByteWidth", typeof(int), 1, 40, 0, 1),
new VisParamDescr("Item height",
"itemHeight", typeof(int), 8, 192, 0, 1),
"itemHeight", typeof(int), 1, 192, 0, 8),
new VisParamDescr("Number of items",
"count", typeof(int), 1, 256, 0, 1),
}),
@ -83,7 +83,17 @@ namespace RuntimeData.Apple {
// IPlugin_Visualizer
public IVisualization2d Generate2d(VisDescr descr,
Dictionary<string, object> parms) {
throw new NotImplementedException();
// TODO: replace with actual
VisBitmap8 vb = new VisBitmap8(16, 16);
vb.AddColor(Util.MakeARGB(0xff, 0x40, 0x40, 0x40));
vb.AddColor(Util.MakeARGB(0xff, 0xff, 0x00, 0x00));
vb.AddColor(Util.MakeARGB(0xff, 0x00, 0xff, 0x80));
for (int i = 0; i < 16; i++) {
vb.SetPixelIndex(i, i, 1);
vb.SetPixelIndex(15 - i, i, 2);
}
return vb;
}
}
}

View File

@ -16,7 +16,8 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using CommonUtil;
using PluginCommon;
@ -53,6 +54,30 @@ namespace SourceGen {
VisGenParams = visGenParams;
}
public static BitmapSource CreateBitmapSource(IVisualization2d vis2d) {
// Create indexed color palette.
int[] intPal = vis2d.GetPalette();
List<Color> colors = new List<Color>(intPal.Length);
foreach (int argb in intPal) {
Color col = Color.FromArgb((byte)(argb >> 24), (byte)(argb >> 16),
(byte)(argb >> 8), (byte)argb);
colors.Add(col);
}
BitmapPalette palette = new BitmapPalette(colors);
// indexed-color; see https://stackoverflow.com/a/15272528/294248 for direct color
BitmapSource image = BitmapSource.Create(
vis2d.Width,
vis2d.Height,
96.0,
96.0,
PixelFormats.Indexed8,
palette,
vis2d.GetPixels(),
vis2d.Width);
return image;
}
/// <summary>
/// Finds a plugin that provides the named visualization generator.

View File

@ -110,7 +110,7 @@ limitations under the License.
<TextBlock Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right" Margin="0,0,4,0"
Text="Visualizer:"/>
<ComboBox Name="visComboBox" Grid.Column="1" Grid.Row="0" Margin="0,0,0,4"
ItemsSource="{Binding VisualizationList}" DisplayMemberPath="UiName"
ItemsSource="{Binding VisualizationList}" DisplayMemberPath="VisDescriptor.UiName"
SelectionChanged="VisComboBox_SelectionChanged"/>
<TextBlock Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right" Margin="0,0,4,0"
@ -124,7 +124,11 @@ limitations under the License.
<TextBlock Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2" Margin="0,20,0,4" Text="Preview:"/>
</Grid>
<Image Grid.Row="1" Width="50" Height="50"/>
<Border Grid.Row="1" BorderThickness="1"
BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}">
<Image Name="previewImage" Width="400" Height="400" Source="/Res/AboutImage.png"
RenderOptions.BitmapScalingMode="NearestNeighbor"/>
</Border>
<Grid Grid.Row="2">
<Grid.RowDefinitions>

View File

@ -25,7 +25,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Asm65;
using PluginCommon;
@ -74,17 +74,26 @@ namespace SourceGen.WpfGui {
}
private Brush mTagLabelBrush;
public class VisualizationItem {
public IPlugin_Visualizer Plugin { get; private set; }
public VisDescr VisDescriptor { get; private set; }
public VisualizationItem(IPlugin_Visualizer plugin, VisDescr descr) {
Plugin = plugin;
VisDescriptor = descr;
}
}
/// <summary>
/// List of visualizers, for combo box.
/// </summary>
public List<VisualizationItem> VisualizationList { get; private set; }
/// <summary>
/// ItemsSource for the ItemsControl with the generated parameter controls.
/// </summary>
public ObservableCollection<ParameterValue> ParameterList { get; private set; } =
new ObservableCollection<ParameterValue>();
/// <summary>
/// List of visualizers, for combo box.
/// </summary>
public List<VisDescr> VisualizationList { get; private set; }
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
@ -114,7 +123,7 @@ namespace SourceGen.WpfGui {
}
int visSelection = 0;
VisualizationList = new List<VisDescr>();
VisualizationList = new List<VisualizationItem>();
List<IPlugin> plugins = proj.GetActivePlugins();
foreach (IPlugin chkPlug in plugins) {
if (!(chkPlug is IPlugin_Visualizer)) {
@ -125,7 +134,7 @@ namespace SourceGen.WpfGui {
if (vis != null && vis.VisGenIdent == descr.Ident) {
visSelection = VisualizationList.Count;
}
VisualizationList.Add(descr);
VisualizationList.Add(new VisualizationItem(vplug, descr));
}
}
@ -180,6 +189,15 @@ namespace SourceGen.WpfGui {
}
private void OkButton_Click(object sender, RoutedEventArgs e) {
VisualizationItem item = (VisualizationItem)visComboBox.SelectedItem;
Debug.Assert(item != null);
Dictionary<string, object> valueDict = CreateVisGenParams();
NewVis = new Visualization(TagString, item.VisDescriptor.Ident, valueDict);
DialogResult = true;
}
private Dictionary<string, object> CreateVisGenParams() {
// Generate value dictionary.
Dictionary<string, object> valueDict =
new Dictionary<string, object>(ParameterList.Count);
@ -211,11 +229,7 @@ namespace SourceGen.WpfGui {
}
}
VisDescr item = (VisDescr)visComboBox.SelectedItem;
Debug.Assert(item != null);
NewVis = new Visualization(TagString, item.Ident, valueDict);
DialogResult = true;
return valueDict;
}
private bool ParseInt(string str, VisParamDescr.SpecialMode special, out int intVal) {
@ -247,7 +261,7 @@ namespace SourceGen.WpfGui {
}
}
private void CheckValid() {
private void UpdateControls() {
IsValid = true;
string trimTag = TagString.Trim();
@ -289,31 +303,40 @@ namespace SourceGen.WpfGui {
Debug.Assert(false);
}
}
if (!IsValid) {
previewImage.Source = new BitmapImage(new Uri("pack://application:,,,/Res/Logo.png"));
} else {
VisualizationItem item = (VisualizationItem)visComboBox.SelectedItem;
IVisualization2d vis2d = item.Plugin.Generate2d(item.VisDescriptor,
CreateVisGenParams());
previewImage.Source = Visualization.CreateBitmapSource(vis2d);
}
}
private void VisComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {
VisDescr item = (VisDescr)visComboBox.SelectedItem;
VisualizationItem item = (VisualizationItem)visComboBox.SelectedItem;
if (item == null) {
Debug.Assert(false); // not expected
return;
}
Debug.WriteLine("VisComboBox sel change: " + item.Ident);
GenerateParamControls(item);
CheckValid();
Debug.WriteLine("VisComboBox sel change: " + item.VisDescriptor.Ident);
GenerateParamControls(item.VisDescriptor);
UpdateControls();
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e) {
TextBox src = (TextBox)sender;
ParameterValue pv = (ParameterValue)src.DataContext;
//Debug.WriteLine("TEXT CHANGE " + pv + ": " + src.Text);
CheckValid();
UpdateControls();
}
private void CheckBox_Changed(object sender, RoutedEventArgs e) {
CheckBox src = (CheckBox)sender;
ParameterValue pv = (ParameterValue)src.DataContext;
//Debug.WriteLine("CHECK CHANGE" + pv);
CheckValid();
UpdateControls();
}
}