/// <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> /// Updates the cached thumbnail image. /// </summary> /// <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) { 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> /// Attempts to refresh broken thumbnails across all visualization sets in the project. /// </summary> /// <param name="project">Project reference.</param> public static void RefreshAllThumbnails(DisasmProject project) { ScriptSupport iapp = null; Dictionary <string, IPlugin> plugins = null; SortedList <int, VisualizationSet> visSets = project.VisualizationSets; foreach (KeyValuePair <int, VisualizationSet> kvp in visSets) { VisualizationSet visSet = kvp.Value; foreach (Visualization vis in visSet) { if (vis.HasImage) { continue; } //Debug.WriteLine("Vis needs refresh: " + vis.Tag); if (vis is VisBitmapAnimation) { continue; } if (iapp == null) { // Prep the plugins on first need. iapp = new ScriptSupport(); project.PrepareScripts(iapp); } iapp.MsgTag = vis.Tag; if (plugins == null) { plugins = project.GetActivePlugins(); } IPlugin_Visualizer vplug = FindPluginByVisGenIdent(plugins, vis.VisGenIdent, out VisDescr visDescr); if (vplug == null) { Debug.WriteLine("Unable to refresh " + vis.Tag + ": plugin not found"); continue; } IVisualization2d vis2d = null; IVisualizationWireframe visWire = null; ReadOnlyDictionary <string, object> parms = new ReadOnlyDictionary <string, object>(vis.VisGenParams); try { if (visDescr.VisualizationType == VisDescr.VisType.Bitmap) { vis2d = vplug.Generate2d(visDescr, parms); if (vis2d == null) { Debug.WriteLine("Vis2d generator returned null"); } } else if (visDescr.VisualizationType == VisDescr.VisType.Wireframe) { IPlugin_Visualizer_v2 plugin2 = (IPlugin_Visualizer_v2)vplug; visWire = plugin2.GenerateWireframe(visDescr, parms); if (visWire == null) { Debug.WriteLine("VisWire generator returned null"); } } else { Debug.Assert(false); } } catch (Exception ex) { Debug.WriteLine("Vis generation failed: " + ex); } if (vis2d != null) { //Debug.WriteLine(" Rendered thumbnail: " + vis.Tag); vis.SetThumbnail(vis2d); } else if (visWire != null) { vis.SetThumbnail(visWire, parms); } } } if (iapp != null) { project.UnprepareScripts(); } // Now that we've generated images for the Visualizations, update any // VisBitmapAnimation thumbnails that may have been affected. foreach (KeyValuePair <int, VisualizationSet> kvp in visSets) { VisualizationSet visSet = kvp.Value; foreach (Visualization vis in visSet) { if (!(vis is VisBitmapAnimation)) { continue; } VisBitmapAnimation visAnim = (VisBitmapAnimation)vis; visAnim.GenerateImage(visSets); } } }
/// <summary> /// Creates a new object from a wireframe visualization. /// </summary> /// <param name="visWire">Visualization object.</param> /// <returns>New object, or null if visualization data fails validation.</returns> public static WireframeObject Create(IVisualizationWireframe visWire) { if (!visWire.Validate(out string msg)) { // Should not be here -- visualizer should have checked validation and // reported an error. Debug.WriteLine("Wireframe validation failed: " + msg); return(null); } WireframeObject wireObj = new WireframeObject(); wireObj.mIs2d = visWire.Is2d; // // Start by extracting data from the visualization object. Everything stored // there is loaded into this object. The VisWireframe validator will have // ensured that all the indices are in range. // // IMPORTANT: do not retain "visWire", as it may be a proxy for an object with a // limited lifespan. // float[] normalsX = visWire.GetNormalsX(); if (normalsX.Length > 0) { float[] normalsY = visWire.GetNormalsY(); float[] normalsZ = visWire.GetNormalsZ(); for (int i = 0; i < normalsX.Length; i++) { wireObj.mFaces.Add(new Face(normalsX[i], normalsY[i], normalsZ[i])); } } float[] verticesX = visWire.GetVerticesX(); float[] verticesY = visWire.GetVerticesY(); float[] verticesZ = visWire.GetVerticesZ(); int[] excludedVertices = visWire.GetExcludedVertices(); // Compute min/max for X/Y for 2d re-centering. The trick is that we only want // to use vertices that are visible. If the shape starts with a huge move off to // the left, we don't want to include (0,0). double xmin, xmax, ymin, ymax; xmin = ymin = 10e9; xmax = ymax = -10e9; for (int i = 0; i < verticesX.Length; i++) { wireObj.mVertices.Add(new Vertex(verticesX[i], verticesY[i], verticesZ[i], HasIndex(excludedVertices, i))); } int[] points = visWire.GetPoints(); for (int i = 0; i < points.Length; i++) { Vertex vert = wireObj.mVertices[points[i]]; wireObj.mPoints.Add(vert); UpdateMinMax(vert, ref xmin, ref xmax, ref ymin, ref ymax); } IntPair[] edges = visWire.GetEdges(); int[] excludedEdges = visWire.GetExcludedEdges(); for (int i = 0; i < edges.Length; i++) { int v0index = edges[i].Val0; int v1index = edges[i].Val1; //if (v0index < 0 || v0index >= wireObj.mVertices.Count || // v1index < 0 || v1index >= wireObj.mVertices.Count) { // Debug.Assert(false); // return null; //} Vertex vert0 = wireObj.mVertices[v0index]; Vertex vert1 = wireObj.mVertices[v1index]; wireObj.mEdges.Add(new Edge(vert0, vert1, HasIndex(excludedEdges, i))); UpdateMinMax(vert0, ref xmin, ref xmax, ref ymin, ref ymax); UpdateMinMax(vert1, ref xmin, ref xmax, ref ymin, ref ymax); } IntPair[] vfaces = visWire.GetVertexFaces(); for (int i = 0; i < vfaces.Length; i++) { int vindex = vfaces[i].Val0; int findex = vfaces[i].Val1; //if (vindex < 0 || vindex >= wireObj.mVertices.Count || // findex < 0 || findex >= wireObj.mFaces.Count) { // Debug.Assert(false); // return null; //} Face face = wireObj.mFaces[findex]; wireObj.mVertices[vindex].Faces.Add(face); if (face.Vert == null) { face.Vert = wireObj.mVertices[vindex]; } } IntPair[] efaces = visWire.GetEdgeFaces(); for (int i = 0; i < efaces.Length; i++) { int eindex = efaces[i].Val0; int findex = efaces[i].Val1; //if (eindex < 0 || eindex >= wireObj.mEdges.Count || // findex < 0 || findex >= wireObj.mFaces.Count) { // Debug.Assert(false); // return null; //} Face face = wireObj.mFaces[findex]; wireObj.mEdges[eindex].Faces.Add(face); if (face.Vert == null) { face.Vert = wireObj.mEdges[eindex].Vertex0; } } // // All data has been loaded into friendly classes. // // Compute center of visible vertices. wireObj.mCenterAdjX = -(xmin + xmax) / 2; wireObj.mCenterAdjY = -(ymin + ymax / 2); // Compute the magnitude of the largest vertex, for scaling. double bigMag = -1.0; double bigMagRc = -1.0; for (int i = 0; i < wireObj.mVertices.Count; i++) { Vector3 vec = wireObj.mVertices[i].Vec; double mag = vec.Magnitude(); if (bigMag < mag) { bigMag = mag; } // Repeat the operation with recentering. This isn't quite right as we're // including all vertices, not just the visible ones. mag = new Vector3(vec.X + wireObj.mCenterAdjX, vec.Y + wireObj.mCenterAdjY, vec.Z).Magnitude(); if (bigMagRc < mag) { bigMagRc = mag; } } // Avoid divide-by-zero. if (bigMag == 0) { Debug.WriteLine("NOTE: wireframe magnitude was zero"); bigMag = 1; } if (bigMagRc == 0) { bigMagRc = 1; } wireObj.mBigMag = bigMag; wireObj.mBigMagRc = bigMagRc; return(wireObj); }
/// <summary> /// Creates a new object from a wireframe visualization. /// </summary> /// <param name="visWire">Visualization object.</param> /// <returns>New object.</returns> public static WireframeObject Create(IVisualizationWireframe visWire) { WireframeObject wireObj = new WireframeObject(); // // Start by extracting data from the visualization object. Everything stored // there is loaded into this object. // float[] normalsX = visWire.GetNormalsX(); if (normalsX.Length > 0) { float[] normalsY = visWire.GetNormalsY(); float[] normalsZ = visWire.GetNormalsZ(); if (normalsX.Length != normalsY.Length || normalsX.Length != normalsZ.Length) { Debug.Assert(false); return(null); } for (int i = 0; i < normalsX.Length; i++) { wireObj.mFaces.Add(new Face(normalsX[i], normalsY[i], normalsZ[i])); } } float[] verticesX = visWire.GetVerticesX(); float[] verticesY = visWire.GetVerticesY(); float[] verticesZ = visWire.GetVerticesZ(); int[] excludedVertices = visWire.GetExcludedVertices(); if (verticesX.Length == 0) { Debug.Assert(false); return(null); } if (verticesX.Length != verticesY.Length || verticesX.Length != verticesZ.Length) { Debug.Assert(false); return(null); } for (int i = 0; i < verticesX.Length; i++) { wireObj.mVertices.Add(new Vertex(verticesX[i], verticesY[i], verticesZ[i], HasIndex(excludedVertices, i))); } IntPair[] edges = visWire.GetEdges(); int[] excludedEdges = visWire.GetExcludedEdges(); for (int i = 0; i < edges.Length; i++) { int v0index = edges[i].Val0; int v1index = edges[i].Val1; if (v0index < 0 || v0index >= wireObj.mVertices.Count || v1index < 0 || v1index >= wireObj.mVertices.Count) { Debug.Assert(false); return(null); } wireObj.mEdges.Add(new Edge(wireObj.mVertices[v0index], wireObj.mVertices[v1index], HasIndex(excludedEdges, i))); } IntPair[] vfaces = visWire.GetVertexFaces(); for (int i = 0; i < vfaces.Length; i++) { int vindex = vfaces[i].Val0; int findex = vfaces[i].Val1; if (vindex < 0 || vindex >= wireObj.mVertices.Count || findex < 0 || findex >= wireObj.mFaces.Count) { Debug.Assert(false); return(null); } Face face = wireObj.mFaces[findex]; wireObj.mVertices[vindex].Faces.Add(face); if (face.Vert == null) { face.Vert = wireObj.mVertices[vindex]; } } IntPair[] efaces = visWire.GetEdgeFaces(); for (int i = 0; i < efaces.Length; i++) { int eindex = efaces[i].Val0; int findex = efaces[i].Val1; if (eindex < 0 || eindex >= wireObj.mEdges.Count || findex < 0 || findex >= wireObj.mFaces.Count) { Debug.Assert(false); return(null); } Face face = wireObj.mFaces[findex]; wireObj.mEdges[eindex].Faces.Add(face); if (face.Vert == null) { face.Vert = wireObj.mEdges[eindex].Vertex0; } } // // All data has been loaded into friendly classes. // // Compute the magnitude of the largest vertex, for scaling. double bigMag = -1.0; for (int i = 0; i < wireObj.mVertices.Count; i++) { double mag = wireObj.mVertices[i].Vec.Magnitude(); if (bigMag < mag) { bigMag = mag; } } wireObj.mBigMag = bigMag; return(wireObj); }
private void UpdateControls() { IsValid = true; foreach (ParameterValue pv in ParameterList) { pv.ForegroundBrush = mDefaultLabelColor; if (pv.Descr.CsType == typeof(bool)) { // always fine continue; } else if (pv.Descr.CsType == typeof(int)) { // integer, possibly Offset special bool ok = ParseIntObj(pv.Value, pv.Descr.Special, out int intVal); if (ok && (intVal < (int)pv.Descr.Min || intVal > (int)pv.Descr.Max)) { // TODO(someday): make the range text red instead of the label ok = false; } if (!ok) { pv.ForegroundBrush = mErrorLabelColor; IsValid = false; } } else if (pv.Descr.CsType == typeof(float)) { // float bool ok = ParseFloatObj(pv.Value, out float floatVal); if (ok && (floatVal < (float)pv.Descr.Min || floatVal > (float)pv.Descr.Max)) { ok = false; } if (!ok) { pv.ForegroundBrush = mErrorLabelColor; IsValid = false; } } else { // unexpected Debug.Assert(false); } } VisualizationItem item = (VisualizationItem)visComboBox.SelectedItem; BitmapDimensions = "?"; previewGrid.Background = null; wireframePath.Data = new GeometryGroup(); if (!IsValid || item == null) { previewImage.Source = sBadParamsImage; } else { // Invoke the plugin. PluginErrMessage = string.Empty; IVisualization2d vis2d = null; IVisualizationWireframe visWire = null; ReadOnlyDictionary <string, object> parms = null; try { IPlugin_Visualizer plugin = (IPlugin_Visualizer)mProject.GetPlugin(item.ScriptIdent); if (item.VisDescriptor.VisualizationType == VisDescr.VisType.Bitmap) { parms = CreateVisGenParams(false); vis2d = plugin.Generate2d(item.VisDescriptor, parms); if (vis2d == null) { Debug.WriteLine("Vis2d generator returned null"); } } else if (item.VisDescriptor.VisualizationType == VisDescr.VisType.Wireframe) { parms = CreateVisGenParams(true); 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); if (string.IsNullOrEmpty(LastPluginMessage)) { LastPluginMessage = ex.Message; } } bool failed = false; if (vis2d == null && visWire == null) { failed = true; } else if (vis2d != null) { previewGrid.Background = null; previewImage.Source = Visualization.ConvertToBitmapSource(vis2d); wireframePath.Data = new GeometryGroup(); BitmapDimensions = string.Format("{0}x{1}", previewImage.Source.Width, previewImage.Source.Height); mThumbnail = (BitmapSource)previewImage.Source; } else { WireframeObject wireObj = WireframeObject.Create(visWire); if (wireObj != null) { previewGrid.Background = Brushes.Black; previewImage.Source = Visualization.BLANK_IMAGE; double dim = Math.Floor( Math.Min(previewGrid.ActualWidth, previewGrid.ActualHeight)); wireframePath.Data = Visualization.GenerateWireframePath(wireObj, dim, parms); BitmapDimensions = "n/a"; mWireObj = wireObj; } else { failed = true; } } if (failed) { previewImage.Source = sBadParamsImage; if (!string.IsNullOrEmpty(LastPluginMessage)) { // Report the last message we got as an error. PluginErrMessage = LastPluginMessage; } else { // Generic failure message. PluginErrMessage = (string)FindResource("str_VisGenFailed"); } IsValid = false; } } string trimTag = Visualization.TrimAndValidateTag(TagString, out bool tagOk); Visualization match = EditVisualizationSet.FindVisualizationByTag(mEditedList, trimTag); if (match != null && (mOrigVis == null || trimTag != mOrigVis.Tag)) { // Another vis already has this tag. We're checking the edited list, so we'll // be current with edits to this or other Visualizations in the same set. tagOk = false; } if (!tagOk) { TagLabelBrush = mErrorLabelColor; IsValid = false; } else { TagLabelBrush = mDefaultLabelColor; } }