1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-06-12 08:29:29 +00:00
6502bench/SourceGen/VisWireframeAnimation.cs
Andy McFadden 356492d6da Add Atari AVG visualizer
This converts AVG commands to wireframes.  We don't try to track
color or intensity.  (This is a disassembler, not a graphics
converter; perfection is not required.)  The various rotation and
animation options are still enabled, though they're not terribly
useful for this.

Commands that are meant to be used in series, such as font glyphs,
tend to use (0,0) as their left edge and baseline.  This puts the
shape in the upper-right corner of the thumbnail, which makes
everything smaller.  The change adds a "re-center" option to the
wireframe renderer that computes the visible bounds and adjusts
the coordinates so that the center of the object is at (0,0) for
display.
2020-04-11 17:24:21 -07:00

134 lines
5.7 KiB
C#

/*
* Copyright 2020 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.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using CommonWPF;
using PluginCommon;
namespace SourceGen {
/// <summary>
/// A wireframe visualization with animation.
/// </summary>
/// <remarks>
/// All of the animation parameters get added to the Visualization parameter set, so this
/// is just a place to hold the IVisualizationWireframe reference and some constants.
/// </remarks>
public class VisWireframeAnimation : Visualization {
/// <summary>
/// Frame delay parameter.
/// </summary>
public const string P_FRAME_DELAY_MSEC = "_frameDelayMsec";
/// <summary>
/// Frame count parameter.
/// </summary>
public const string P_FRAME_COUNT = "_frameCount";
public const string P_IS_ANIMATED = "_isAnimatedWireframe";
public const string P_EULER_ROT_X = "_eulerRotX";
public const string P_EULER_ROT_Y = "_eulerRotY";
public const string P_EULER_ROT_Z = "_eulerRotZ";
public const string P_DELTA_ROT_X = "_deltaRotX";
public const string P_DELTA_ROT_Y = "_deltaRotY";
public const string P_DELTA_ROT_Z = "_deltaRotZ";
private WireframeObject mWireObj;
/// <summary>
/// Constructor. Mostly pass-through, but we want to set the overlay image.
/// </summary>
public VisWireframeAnimation(string tag, string visGenIdent,
ReadOnlyDictionary<string, object> visGenParams, Visualization oldObj,
WireframeObject wireObj)
: base(tag, visGenIdent, visGenParams, oldObj) {
// wireObj may be null when loading from project file
mWireObj = wireObj;
OverlayImage = ANIM_OVERLAY_IMAGE;
}
/// <summary>
/// Updates the thumbnail.
/// </summary>
/// <remarks>
/// We override it because this is our first opportunity to capture the
/// wireframe object reference if the object was created during project
/// file loading.
/// </remarks>
/// <param name="visWire">Reference to wireframe data generated by plugin.</param>
/// <param name="parms">Render parameters.</param>
public override void SetThumbnail(IVisualizationWireframe visWire,
ReadOnlyDictionary<string, object> parms) {
base.SetThumbnail(visWire, parms);
if (visWire == null) {
// Thumbnail cache is being cleared. Throw out the wireframe object too.
mWireObj = null;
} else {
mWireObj = WireframeObject.Create(visWire);
}
}
/// <summary>
/// Generates an animated GIF from a series of frames.
/// </summary>
/// <param name="encoder">GIF encoder.</param>
/// <param name="dim">Output dimensions.</param>
public void EncodeGif(AnimatedGifEncoder encoder, double dim) {
int curX = Util.GetFromObjDict(VisGenParams, P_EULER_ROT_X, 0);
int curY = Util.GetFromObjDict(VisGenParams, P_EULER_ROT_Y, 0);
int curZ = Util.GetFromObjDict(VisGenParams, P_EULER_ROT_Z, 0);
int deltaX = Util.GetFromObjDict(VisGenParams, P_DELTA_ROT_X, 0);
int deltaY = Util.GetFromObjDict(VisGenParams, P_DELTA_ROT_Y, 0);
int deltaZ = Util.GetFromObjDict(VisGenParams, P_DELTA_ROT_Z, 0);
int frameCount = Util.GetFromObjDict(VisGenParams, P_FRAME_COUNT, 1);
int frameDelayMsec = Util.GetFromObjDict(VisGenParams, P_FRAME_DELAY_MSEC, 100);
bool doPersp = Util.GetFromObjDict(VisGenParams, VisWireframe.P_IS_PERSPECTIVE, true);
bool doBfc = Util.GetFromObjDict(VisGenParams, VisWireframe.P_IS_BFC_ENABLED, false);
bool doRecenter = Util.GetFromObjDict(VisGenParams, VisWireframe.P_IS_RECENTERED, false);
// Try to avoid System.Runtime.InteropServices.COMException (0x88980003):
// MILERR_WIN32ERROR (Exception from HRESULT: 0x88980003)
// The problem seems to be that the bitmaps are GDI handles, there's a hard limit of
// 10,000, and they don't get released until finalizers run. If we wait for
// pending finalizers the pool stays at a manageable level. If we poke the GC
// every time the memory graph looks better but I suspect there's a performance hit.
//GC.Collect();
GC.WaitForPendingFinalizers();
if (mWireObj == null) {
Debug.WriteLine("EncodeGif: wire obj is null");
frameCount = 1;
}
for (int frame = 0; frame < frameCount; frame++) {
BitmapSource bs = GenerateWireframeImage(mWireObj, dim,
curX, curY, curZ, doPersp, doBfc, doRecenter);
encoder.AddFrame(BitmapFrame.Create(bs), frameDelayMsec);
curX = (curX + 360 + deltaX) % 360;
curY = (curY + 360 + deltaY) % 360;
curZ = (curZ + 360 + deltaZ) % 360;
}
}
}
}