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:
parent
e7fccfda03
commit
9244ceda7c
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
88
PluginCommon/VisBitmap8.cs
Normal file
88
PluginCommon/VisBitmap8.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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>
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user