diff --git a/SourceGen/Exporter.cs b/SourceGen/Exporter.cs index 657fe9a..a3eeaf3 100644 --- a/SourceGen/Exporter.cs +++ b/SourceGen/Exporter.cs @@ -808,7 +808,6 @@ namespace SourceGen { Debug.Assert(false); // not expected } } - #if false // try feeding the animated GIF into our GIF unpacker using (MemoryStream ms = new MemoryStream()) { @@ -828,8 +827,25 @@ namespace SourceGen { } } catch (Exception ex) { // TODO: add an error report - Debug.WriteLine("Error creating animated GIF file '" + pathName + "': " + - ex.Message); + Debug.WriteLine("Error creating animated GIF file '" + pathName + + "': " + ex.Message); + dispWidth = dispHeight = 1; + } + } else if (vis is VisWireframeAnimation) { + AnimatedGifEncoder encoder = new AnimatedGifEncoder(); + ((VisWireframeAnimation)vis).EncodeGif(encoder, IMAGE_SIZE); + + // Create new or replace existing image file. + fileName += "_ani.gif"; + string pathName = Path.Combine(mImageDirPath, fileName); + try { + using (FileStream stream = new FileStream(pathName, FileMode.Create)) { + encoder.Save(stream, out dispWidth, out dispHeight); + } + } catch (Exception ex) { + // TODO: add an error report + Debug.WriteLine("Error creating animated WF GIF file '" + pathName + + "': " + ex.Message); dispWidth = dispHeight = 1; } } else { diff --git a/SourceGen/SGTestData/Visualization/wireframe-test.dis65 b/SourceGen/SGTestData/Visualization/wireframe-test.dis65 index b861f34..c78de9b 100644 --- a/SourceGen/SGTestData/Visualization/wireframe-test.dis65 +++ b/SourceGen/SGTestData/Visualization/wireframe-test.dis65 @@ -267,13 +267,13 @@ "_isPerspective":true, "_isBfcEnabled":true, "_eulerRotX":0, -"_eulerRotY":21, -"_eulerRotZ":65, +"_eulerRotY":0, +"_eulerRotZ":0, "_isAnimatedWireframe":true, -"_deltaRotX":-6, -"_deltaRotY":30, +"_deltaRotX":3, +"_deltaRotY":6, "_deltaRotZ":0, -"_frameCount":60, +"_frameCount":120, "_frameDelayMsec":100}}, { @@ -291,14 +291,14 @@ "VisualizationAnimations":[{ "Tags":["wf_data", "bmp_data"], -"Tag":"anim00002c", +"Tag":"ugly flash", "VisGenIdent":"(animation)", "VisGenParams":{ -"_frameDelayMsec":100}}], +"_frameDelayMsec":1000}}], "VisualizationSets":{ "10":{ "Tags":["wf_data", "bmp_data"]}, "44":{ -"Tags":["anim00002c"]}}} +"Tags":["ugly flash"]}}} diff --git a/SourceGen/SourceGen.csproj b/SourceGen/SourceGen.csproj index 886bd80..76891de 100644 --- a/SourceGen/SourceGen.csproj +++ b/SourceGen/SourceGen.csproj @@ -207,6 +207,9 @@ + + ShowWireframeAnimation.xaml + @@ -418,6 +421,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + diff --git a/SourceGen/VisWireframeAnimation.cs b/SourceGen/VisWireframeAnimation.cs index 5e6a3ad..52242cf 100644 --- a/SourceGen/VisWireframeAnimation.cs +++ b/SourceGen/VisWireframeAnimation.cs @@ -17,7 +17,9 @@ 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 { @@ -51,18 +53,61 @@ namespace SourceGen { private IVisualizationWireframe mVisWire; + + /// + /// Constructor. Mostly pass-through, but we want to set the overlay image. + /// public VisWireframeAnimation(string tag, string visGenIdent, ReadOnlyDictionary visGenParams, Visualization oldObj, IVisualizationWireframe visWire) : base(tag, visGenIdent, visGenParams, oldObj) { // visWire may be null when loading from project file mVisWire = visWire; + OverlayImage = ANIM_OVERLAY_IMAGE; } + /// + /// Updates the thumbnail. + /// + /// + /// We override it because this is our first opportunity to capture the + /// IVisualizationWireframe reference when the object was created during project + /// file loading. + /// + /// Reference to wireframe data generated by plugin. + /// Render parameters. public override void SetThumbnail(IVisualizationWireframe visWire, ReadOnlyDictionary parms) { base.SetThumbnail(visWire, parms); mVisWire = visWire; } + + /// + /// Generates an animated GIF from a series of frames. + /// + /// GIF encoder. + /// Output dimensions. + 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); + + for (int frame = 0; frame < frameCount; frame++) { + BitmapSource bs = GenerateWireframeImage(mVisWire, dim, + curX, curY, curZ, doPersp, doBfc); + encoder.AddFrame(BitmapFrame.Create(bs), frameDelayMsec); + + curX = (curX + 360 + deltaX) % 360; + curY = (curY + 360 + deltaY) % 360; + curZ = (curZ + 360 + deltaZ) % 360; + } + } } } diff --git a/SourceGen/Visualization.cs b/SourceGen/Visualization.cs index e58fd7e..9d51c5e 100644 --- a/SourceGen/Visualization.cs +++ b/SourceGen/Visualization.cs @@ -196,7 +196,7 @@ namespace SourceGen { ReadOnlyDictionary parms) { Debug.Assert(visWire != null); Debug.Assert(parms != null); - CachedImage = GenerateWireframeImage(visWire, parms, THUMBNAIL_DIM); + CachedImage = GenerateWireframeImage(visWire, THUMBNAIL_DIM, parms); } /// @@ -254,13 +254,28 @@ namespace SourceGen { /// and GIF exports. /// /// Visualization data. - /// Parameter set, for rotations and render options. /// Output bitmap dimension (width and height). + /// Parameter set, for rotations and render options. /// Rendered bitmap. public static BitmapSource GenerateWireframeImage(IVisualizationWireframe visWire, - ReadOnlyDictionary parms, double dim) { + double dim, ReadOnlyDictionary parms) { + int eulerX = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_X, 0); + int eulerY = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_Y, 0); + int eulerZ = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_Z, 0); + bool doPersp = Util.GetFromObjDict(parms, VisWireframe.P_IS_PERSPECTIVE, false); + bool doBfc = Util.GetFromObjDict(parms, VisWireframe.P_IS_BFC_ENABLED, false); + return GenerateWireframeImage(visWire, dim, eulerX, eulerY, eulerZ, doPersp, doBfc); + } + + /// + /// Generates a BitmapSource from IVisualizationWireframe data. Useful for thumbnails + /// and GIF exports. + /// + public static BitmapSource GenerateWireframeImage(IVisualizationWireframe visWire, + double dim, int eulerX, int eulerY, int eulerZ, bool doPersp, bool doBfc) { // Generate the path geometry. - GeometryGroup geo = GenerateWireframePath(visWire, parms, dim); + GeometryGroup geo = GenerateWireframePath(visWire, dim, eulerX, eulerY, eulerZ, + doPersp, doBfc); // Render Path to bitmap -- https://stackoverflow.com/a/23582564/294248 Rect bounds = geo.GetRenderBounds(null); @@ -302,14 +317,25 @@ namespace SourceGen { /// coordinates so they fit within the box. /// /// Visualization data. - /// Visualization parameters. /// Width/height to use for path area. + /// Visualization parameters. public static GeometryGroup GenerateWireframePath(IVisualizationWireframe visWire, - ReadOnlyDictionary parms, double dim) { + double dim, ReadOnlyDictionary parms) { int eulerX = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_X, 0); int eulerY = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_Y, 0); int eulerZ = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_Z, 0); + bool doPersp = Util.GetFromObjDict(parms, VisWireframe.P_IS_PERSPECTIVE, false); + bool doBfc = Util.GetFromObjDict(parms, VisWireframe.P_IS_BFC_ENABLED, false); + return GenerateWireframePath(visWire, dim, eulerX, eulerY, eulerZ, doPersp, doBfc); + } + /// + /// Generates WPF Path geometry from IVisualizationWireframe data. Line widths get + /// scaled if the output area is larger or smaller than the path bounds, so this scales + /// coordinates so they fit within the box. + /// + public static GeometryGroup GenerateWireframePath(IVisualizationWireframe visWire, + double dim, int eulerX, int eulerY, int eulerZ, bool doPersp, bool doBfc) { // WPF path drawing is based on a system where a pixel is drawn at the center // of the coordinate, and integer coordinates start at the top left edge. If // you draw a pixel at (0,0), most of the pixel will be outside the window @@ -352,7 +378,8 @@ namespace SourceGen { // Generate a list of clip-space line segments. Coordinate values are in the // range [-1,1], with +X to the right and +Y upward. WireframeObject wireObj = WireframeObject.Create(visWire); - List segs = wireObj.Generate(parms, eulerX, eulerY, eulerZ); + List segs = wireObj.Generate(eulerX, eulerY, eulerZ, + doPersp, doBfc); // Convert clip-space coords to screen. We need to translate to [0,2] with +Y // toward the bottom of the screen, scale up, round to the nearest whole pixel, diff --git a/SourceGen/WireframeObject.cs b/SourceGen/WireframeObject.cs index 2c6598f..e80c339 100644 --- a/SourceGen/WireframeObject.cs +++ b/SourceGen/WireframeObject.cs @@ -206,14 +206,16 @@ namespace SourceGen { /// Generates a list of line segments for the wireframe data and the specified /// parameters. /// - /// Visualization parameters. - /// List of line segments, which could be empty if backface removal + /// Rotation about X axis. + /// Rotation about Y axis. + /// Rotation about Z axis. + /// Perspective or othographic projection? + /// Perform backface culling? + /// List a of line segments, which could be empty if backface culling /// was especially successful. - public List Generate(ReadOnlyDictionary parms, - int eulerX, int eulerY, int eulerZ) { + public List Generate(int eulerX, int eulerY, int eulerZ, + bool doPersp, bool doBfc) { List segs = new List(mEdges.Count); - bool doPersp = Util.GetFromObjDict(parms, VisWireframe.P_IS_PERSPECTIVE, false); - bool doBfc = Util.GetFromObjDict(parms, VisWireframe.P_IS_BFC_ENABLED, false); // Camera Z coordinate adjustment, used to control how perspective projections // appear. The larger the value, the farther the object appears to be. Very diff --git a/SourceGen/WpfGui/EditVisualization.xaml b/SourceGen/WpfGui/EditVisualization.xaml index 2da6f81..35ac87a 100644 --- a/SourceGen/WpfGui/EditVisualization.xaml +++ b/SourceGen/WpfGui/EditVisualization.xaml @@ -255,8 +255,8 @@ limitations under the License. - -