diff --git a/PluginCommon/VisWireframe.cs b/PluginCommon/VisWireframe.cs index cebc7b9..d0fde4c 100644 --- a/PluginCommon/VisWireframe.cs +++ b/PluginCommon/VisWireframe.cs @@ -20,9 +20,27 @@ using System.Diagnostics; namespace PluginCommon { /// /// Wireframe mesh with optional backface normals, for use with visualization generators. + /// Call the various functions to add data, then call Validate() to check for broken + /// references. /// [Serializable] public class VisWireframe : IVisualizationWireframe { + public static VisParamDescr Param_IsPerspective(string uiLabel, bool defaultVal) { + return new VisParamDescr(uiLabel, "_isPerspective", typeof(bool), 0, 0, 0, defaultVal); + } + public static VisParamDescr Param_IsBackfaceRemoved(string uiLabel, bool defaultVal) { + return new VisParamDescr(uiLabel, "_isBackfaceRemoved", typeof(bool), 0, 0, 0, defaultVal); + } + public static VisParamDescr Param_EulerX(string uiLabel, int defaultVal) { + return new VisParamDescr(uiLabel, "_eulerRotX", typeof(int), 0, 359, 0, defaultVal); + } + public static VisParamDescr Param_EulerY(string uiLabel, int defaultVal) { + return new VisParamDescr(uiLabel, "_eulerRotY", typeof(int), 0, 359, 0, defaultVal); + } + public static VisParamDescr Param_EulerZ(string uiLabel, int defaultVal) { + return new VisParamDescr(uiLabel, "_eulerRotZ", typeof(int), 0, 359, 0, defaultVal); + } + private List mVerticesX = new List(); private List mVerticesY = new List(); private List mVerticesZ = new List(); @@ -56,14 +74,15 @@ namespace PluginCommon { } /// - /// Adds the edge to the list. + /// Adds an edge to the list. The referenced vertices do not need to be defined + /// before calling. /// /// Index of first vertex. /// Index of second vertex. /// Edge index. Indices start at zero and count up. public int AddEdge(int index0, int index1) { - Debug.Assert(index0 >= 0 && index0 < mVerticesX.Count); - Debug.Assert(index1 >= 0 && index1 < mVerticesX.Count); + Debug.Assert(index0 >= 0); + Debug.Assert(index1 >= 0); mEdges.Add(new IntPair(index0, index1)); return mEdges.Count - 1; } @@ -84,24 +103,26 @@ namespace PluginCommon { } /// - /// Marks a vertex's visibility as being tied to the specified face. The face does - /// not need to be in the list yet. + /// Marks a vertex's visibility as being tied to the specified face. The vertices and + /// faces being referenced do not need to exist yet. /// /// Index of vertex. /// Index of face. public void AddVertexFace(int vertexIndex, int faceIndex) { - Debug.Assert(vertexIndex >= 0 && vertexIndex < mVerticesX.Count); + Debug.Assert(vertexIndex >= 0); + Debug.Assert(faceIndex >= 0); mVertexFaces.Add(new IntPair(vertexIndex, faceIndex)); } /// - /// Marks an edge's visibility as being tied to the specified face. The face does - /// not need to be in the list yet. + /// Marks an edge's visibility as being tied to the specified face. The edges and + /// faces being referenced do not need to exist yet. /// /// Index of edge. /// Index of face. public void AddEdgeFace(int edgeIndex, int faceIndex) { - Debug.Assert(edgeIndex >= 0 && edgeIndex < mEdges.Count); + Debug.Assert(edgeIndex >= 0); + Debug.Assert(faceIndex >= 0); mEdgeFaces.Add(new IntPair(edgeIndex, faceIndex)); } diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs index 04c853a..3897a76 100644 --- a/SourceGen/MainController.cs +++ b/SourceGen/MainController.cs @@ -697,7 +697,7 @@ namespace SourceGen { float dataPerc = (mProject.ByteCounts.DataByteCount * 100.0f) / total; float junkPerc = (mProject.ByteCounts.JunkByteCount * 100.0f) / total; mMainWin.ByteCountText = string.Format(Res.Strings.STATUS_BYTE_COUNT_FMT, - codePerc, dataPerc, junkPerc); + total / 1024.0f, codePerc, dataPerc, junkPerc); } #endregion Init and settings diff --git a/SourceGen/Res/Strings.xaml b/SourceGen/Res/Strings.xaml index a4c2d5d..c0d3718 100644 --- a/SourceGen/Res/Strings.xaml +++ b/SourceGen/Res/Strings.xaml @@ -161,7 +161,7 @@ limitations under the License. C64 Screen Code {1} CPU @ {2} MHz Show - {0:F1}% code, {1:F1}% data, {2:F1}% junk + {0:F1}KB: {1:F1}% code, {2:F1}% data, {3:F1}% junk Ready DCI string has mixed data DCI string not terminated diff --git a/SourceGen/SGTestData/Visualization/VisWireframeTest.cs b/SourceGen/SGTestData/Visualization/VisWireframeTest.cs index 12cb916..6baba6d 100644 --- a/SourceGen/SGTestData/Visualization/VisWireframeTest.cs +++ b/SourceGen/SGTestData/Visualization/VisWireframeTest.cs @@ -41,6 +41,12 @@ namespace WireframeTest { new VisParamDescr[] { new VisParamDescr("File offset (hex)", P_OFFSET, typeof(int), 0, 0x00ffffff, VisParamDescr.SpecialMode.Offset, 0), + + // These are interpreted by the main app. + VisWireframe.Param_EulerX("Euler rotation X", 0), + VisWireframe.Param_EulerY("Euler rotation Y", 0), + VisWireframe.Param_EulerZ("Euler rotation Z", 0), + VisWireframe.Param_IsPerspective("Perspective projection", true), }), }; diff --git a/SourceGen/SGTestData/Visualization/wireframe-test.dis65 b/SourceGen/SGTestData/Visualization/wireframe-test.dis65 index 56c868a..bf0eebf 100644 --- a/SourceGen/SGTestData/Visualization/wireframe-test.dis65 +++ b/SourceGen/SGTestData/Visualization/wireframe-test.dis65 @@ -17,7 +17,8 @@ "SmartPlpHandling":true}, "PlatformSymbolFileIdentifiers":[], -"ExtensionScriptFileIdentifiers":["PROJ:VisWireframeTest.cs"], +"ExtensionScriptFileIdentifiers":["PROJ:VisWireframeTest.cs", +"RT:Apple/VisHiRes.cs"], "ProjectSyms":{ }}, @@ -239,7 +240,30 @@ "LvTables":{ }, -"Visualizations":[], +"Visualizations":[{ +"Tag":"wf_data", +"VisGenIdent":"wireframe-test", +"VisGenParams":{ +"offset":10, +"_eulerRotX":0, +"_eulerRotY":0, +"_eulerRotZ":0, +"_isPerspective":true}}, + +{ +"Tag":"bmp_data", +"VisGenIdent":"apple2-hi-res-bitmap", +"VisGenParams":{ +"offset":10, +"byteWidth":3, +"height":11, +"colStride":0, +"rowStride":0, +"isColor":true, +"isFirstOdd":false, +"isHighBitFlipped":false}}], "VisualizationAnimations":[], "VisualizationSets":{ -}} +"10":{ +"Tags":["wf_data", +"bmp_data"]}}} diff --git a/SourceGen/Visualization.cs b/SourceGen/Visualization.cs index c9515d9..32e76be 100644 --- a/SourceGen/Visualization.cs +++ b/SourceGen/Visualization.cs @@ -18,6 +18,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Text; +using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; @@ -99,6 +100,7 @@ namespace SourceGen { VisualizationAnimation.GenerateAnimOverlayImage(); internal static readonly BitmapSource BLANK_IMAGE = GenerateBlankImage(); + internal static readonly BitmapSource BLACK_IMAGE = GenerateBlackImage(); /// /// Serial number, for reference from other Visualization objects. Not serialized. @@ -106,9 +108,10 @@ namespace SourceGen { /// /// This value is only valid in the current session. It exists because animations /// need to refer to other Visualization objects, and doing so by Tag gets sticky - /// if a tag gets renamed. We need a way to uniquely identify a reference to a + /// if a Tag gets renamed. We need a way to uniquely identify a reference to a /// Visualization that persists across Tag renames and other edits. When the objects - /// are serialized to the project file we just output the tags. + /// are serialized to the project file we don't include the serial, and just reference + /// by Tag. /// public int SerialNumber { get; private set; } @@ -191,7 +194,8 @@ namespace SourceGen { } /// - /// Converts an IVisualization2d to a BitmapSource for display. + /// Converts an IVisualization2d to a BitmapSource for display. The bitmap will be + /// the same size as the original content. /// public static BitmapSource ConvertToBitmapSource(IVisualization2d vis2d) { // Create indexed color palette. @@ -218,12 +222,69 @@ namespace SourceGen { return image; } + /// + /// Generates a BitmapSource from IVisualizationWireframe data. Useful for thumbnails + /// and GIF exports. + /// + /// Visualization data. + /// Parameter set, for rotations and render options. + /// Output bitmap width. + /// Output bitmap height. + /// + public static BitmapSource GenerateWireframeImage(IVisualizationWireframe visWire, + ReadOnlyDictionary parms, double width, double height) { + // TODO(xyzzy): need to get path into a bitmap for thumbnails / GIFs...; call + // GenerateWireframePath and then render the path + // https://stackoverflow.com/a/23582564/294248 + Debug.WriteLine("Render " + visWire + " at " + width + "x" + height); + return null; + } + + /// + /// Generates a WPF path from IVisualizationWireframe data. + /// + public static GeometryGroup GenerateWireframePath(IVisualizationWireframe visWire, + ReadOnlyDictionary parms, double scale) { + GeometryGroup geo = new GeometryGroup(); + // This establishes the geometry bounds. It's a zero-length line segment, so + // nothing is actually drawn. + Debug.WriteLine("using scale=" + scale); + Point corner = new Point(scale + 1, scale + 1); + geo.Children.Add(new LineGeometry(corner, corner)); + + // TODO(xyzzy): render + geo.Children.Add(new LineGeometry(new Point(6, 6), new Point(197, 197))); + geo.Children.Add(new LineGeometry(new Point(6, 197), new Point(197, 6))); + return geo; + } + + /// + /// Returns a bitmap with a single transparent pixel. + /// private static BitmapSource GenerateBlankImage() { RenderTargetBitmap bmp = new RenderTargetBitmap(1, 1, 96.0, 96.0, PixelFormats.Pbgra32); return bmp; } + /// + /// Returns a bitmap with a single black pixel. + /// + private static BitmapSource GenerateBlackImage() { + BitmapPalette palette = new BitmapPalette(new List { Colors.Black }); + BitmapSource image = BitmapSource.Create( + 1, + 1, + 96.0, + 96.0, + PixelFormats.Indexed8, + palette, + new byte[] { 0 }, + 1); + + return image; + } + public override string ToString() { return "[Vis: " + Tag + " (" + VisGenIdent + ") count=" + VisGenParams.Count + "]"; diff --git a/SourceGen/WpfGui/EditVisualization.xaml b/SourceGen/WpfGui/EditVisualization.xaml index d7ecef6..3de5ab2 100644 --- a/SourceGen/WpfGui/EditVisualization.xaml +++ b/SourceGen/WpfGui/EditVisualization.xaml @@ -134,8 +134,13 @@ limitations under the License. - + + + + + + diff --git a/SourceGen/WpfGui/EditVisualization.xaml.cs b/SourceGen/WpfGui/EditVisualization.xaml.cs index 4b4ee60..370ae27 100644 --- a/SourceGen/WpfGui/EditVisualization.xaml.cs +++ b/SourceGen/WpfGui/EditVisualization.xaml.cs @@ -302,8 +302,8 @@ namespace SourceGen.WpfGui { ClearValue(SizeToContentProperty); SetValue(MinWidthProperty, this.Width); SetValue(MinHeightProperty, this.Height); - previewImage.ClearValue(WidthProperty); - previewImage.ClearValue(HeightProperty); + previewGrid.ClearValue(WidthProperty); + previewGrid.ClearValue(HeightProperty); tagTextBox.SelectAll(); tagTextBox.Focus(); @@ -450,13 +450,25 @@ namespace SourceGen.WpfGui { // Invoke the plugin. PluginErrMessage = string.Empty; - IVisualization2d vis2d; + IVisualization2d vis2d = null; + IVisualizationWireframe visWire = null; + ReadOnlyDictionary parms = CreateVisGenParams(); try { IPlugin_Visualizer plugin = (IPlugin_Visualizer)mProject.GetPlugin(item.ScriptIdent); - vis2d = plugin.Generate2d(item.VisDescriptor, CreateVisGenParams()); - if (vis2d == null) { - Debug.WriteLine("Vis generator returned null"); + if (item.VisDescriptor.VisualizationType == VisDescr.VisType.Bitmap) { + vis2d = plugin.Generate2d(item.VisDescriptor, parms); + if (vis2d == null) { + Debug.WriteLine("Vis2d generator returned null"); + } + } else if (item.VisDescriptor.VisualizationType == VisDescr.VisType.Wireframe) { + IPlugin_Visualizer_v2 plugin2 = (IPlugin_Visualizer_v2)plugin; + visWire = plugin2.GenerateWireframe(item.VisDescriptor, parms); + if (visWire == null) { + Debug.WriteLine("VisWire generator returned null"); + } + } else { + Debug.Assert(false); } } catch (Exception ex) { Debug.WriteLine("Vis generation failed: " + ex); @@ -465,7 +477,7 @@ namespace SourceGen.WpfGui { LastPluginMessage = ex.Message; } } - if (vis2d == null) { + if (vis2d == null && visWire == null) { previewImage.Source = sBadParamsImage; if (!string.IsNullOrEmpty(LastPluginMessage)) { // Report the last message we got as an error. @@ -474,10 +486,16 @@ namespace SourceGen.WpfGui { PluginErrMessage = (string)FindResource("str_VisGenFailed"); } IsValid = false; - } else { + } else if (vis2d != null) { previewImage.Source = Visualization.ConvertToBitmapSource(vis2d); + wireframePath.Data = new GeometryGroup(); BitmapDimensions = string.Format("{0}x{1}", previewImage.Source.Width, previewImage.Source.Height); + } else { + previewImage.Source = Visualization.BLACK_IMAGE; + wireframePath.Data = Visualization.GenerateWireframePath(visWire, parms, + previewImage.ActualWidth / 2); + BitmapDimensions = "n/a"; } } diff --git a/SourceGen/WpfGui/EditVisualizationSet.xaml b/SourceGen/WpfGui/EditVisualizationSet.xaml index 64f1bc8..bc2322e 100644 --- a/SourceGen/WpfGui/EditVisualizationSet.xaml +++ b/SourceGen/WpfGui/EditVisualizationSet.xaml @@ -85,15 +85,22 @@ limitations under the License. - + - + +