1
0
mirror of https://github.com/fadden/6502bench.git synced 2025-07-24 22:25:06 +00:00

Add a progress bar to HTML export

Generation of HTML is extremely fast, but compressing thousands
of frames for wireframe animated GIFs can take a little while.

Sharing bitmaps between threads required two changes: (1) bitmaps
need to be "frozen" after being drawn; (2) you can't use Path because
BackgroundWorker isn't a STAThread.  You can, however, use a
DrawingVisual / DrawingContext to do the rendering.  Which is really
what I should have been doing all along; I just didn't know the
approach existed until I was forced to go looking for it.

Also, we now do a "run finalizers" call before generating an animated
GIF.  Without it things explode after more than 10K GDI objects have
been allocated.
This commit is contained in:
Andy McFadden
2020-03-15 11:49:11 -07:00
parent b3dacc2613
commit 1da98d8628
9 changed files with 146 additions and 28 deletions

View File

@@ -106,8 +106,11 @@ namespace SourceGen {
/// <summary>
/// Image to show when things are broken.
/// </summary>
public static readonly BitmapImage BROKEN_IMAGE =
new BitmapImage(new Uri("pack://application:,,,/Res/RedX.png"));
public static readonly BitmapImage BROKEN_IMAGE;
static Visualization() {
BROKEN_IMAGE = new BitmapImage(new Uri("pack://application:,,,/Res/RedX.png"));
BROKEN_IMAGE.Freeze();
}
/// <summary>
/// Image to overlay on animation visualizations.
@@ -185,19 +188,24 @@ namespace SourceGen {
} else {
CachedImage = ConvertToBitmapSource(vis2d);
}
Debug.Assert(CachedImage.IsFrozen);
}
/// <summary>
/// Updates the cached thumbnail image.
/// </summary>
/// <param name="visWire">Visualization object.</param>
/// <param name="visWire">Visualization object, or null to clear the thumbnail.</param>
/// <param name="parms">Visualization parameters.</param>
public virtual void SetThumbnail(IVisualizationWireframe visWire,
ReadOnlyDictionary<string, object> parms) {
Debug.Assert(visWire != null);
Debug.Assert(parms != null);
WireframeObject wireObj = WireframeObject.Create(visWire);
CachedImage = GenerateWireframeImage(wireObj, THUMBNAIL_DIM, parms);
if (visWire == null) {
CachedImage = BROKEN_IMAGE;
} else {
Debug.Assert(parms != null);
WireframeObject wireObj = WireframeObject.Create(visWire);
CachedImage = GenerateWireframeImage(wireObj, THUMBNAIL_DIM, parms);
}
Debug.Assert(CachedImage.IsFrozen);
}
/// <summary>
@@ -246,6 +254,7 @@ namespace SourceGen {
palette,
vis2d.GetPixels(),
vis2d.Width);
image.Freeze();
return image;
}
@@ -274,11 +283,17 @@ namespace SourceGen {
/// </summary>
public static BitmapSource GenerateWireframeImage(WireframeObject wireObj,
double dim, int eulerX, int eulerY, int eulerZ, bool doPersp, bool doBfc) {
if (wireObj == null) {
// Can happen if the visualization generator is failing on stuff loaded from
// the project file.
return BROKEN_IMAGE;
}
// Generate the path geometry.
GeometryGroup geo = GenerateWireframePath(wireObj, dim, eulerX, eulerY, eulerZ,
doPersp, doBfc);
// Render Path to bitmap -- https://stackoverflow.com/a/23582564/294248
// Render geometry to bitmap -- https://stackoverflow.com/a/869767/294248
Rect bounds = geo.GetRenderBounds(null);
//Debug.WriteLine("RenderWF dim=" + dim + " bounds=" + bounds + ": " + wireObj);
@@ -290,7 +305,18 @@ namespace SourceGen {
96,
96,
PixelFormats.Pbgra32);
//RenderOptions.SetEdgeMode(bitmap, EdgeMode.Aliased); <-- doesn't work?
//RenderOptions.SetEdgeMode(bitmap, EdgeMode.Aliased); <-- no apparent effect
DrawingVisual dv = new DrawingVisual();
using (DrawingContext dc = dv.RenderOpen()) {
dc.DrawRectangle(Brushes.Black, null, new Rect(0, 0, bounds.Width, bounds.Height));
Pen pen = new Pen(Brushes.White, 1.0);
dc.DrawGeometry(Brushes.White, pen, geo);
}
bitmap.Render(dv);
#if false
// Old way: render Path to bitmap -- https://stackoverflow.com/a/23582564/294248
// Clear the bitmap to black. (Is there an easier way?)
GeometryGroup bkgnd = new GeometryGroup();
@@ -308,7 +334,9 @@ namespace SourceGen {
path.Measure(bounds.Size);
path.Arrange(bounds);
bitmap.Render(path);
#endif
bitmap.Freeze();
return bitmap;
}
@@ -405,6 +433,7 @@ namespace SourceGen {
private static BitmapSource GenerateBlankImage() {
RenderTargetBitmap bmp = new RenderTargetBitmap(1, 1, 96.0, 96.0,
PixelFormats.Pbgra32);
bmp.Freeze();
return bmp;
}
@@ -438,6 +467,7 @@ namespace SourceGen {
RenderTargetBitmap bmp = new RenderTargetBitmap(IMAGE_SIZE, IMAGE_SIZE, 96.0, 96.0,
PixelFormats.Pbgra32);
bmp.Render(visual);
bmp.Freeze();
return bmp;
}