diff --git a/PluginCommon/Interfaces.cs b/PluginCommon/Interfaces.cs
index 22528dc..612dcc7 100644
--- a/PluginCommon/Interfaces.cs
+++ b/PluginCommon/Interfaces.cs
@@ -191,6 +191,9 @@ namespace PluginCommon {
///
public string UiName { get; private set; }
+ ///
+ /// Visualization type, used to distinguish between bitmaps and wireframes.
+ ///
public enum VisType {
Unknown = 0,
Bitmap, // 2D bitmap
@@ -349,6 +352,8 @@ namespace PluginCommon {
public interface IVisualizationWireframe {
// Each function returns the specified data. Do not modify the returned arrays.
+ bool Is2d { get; }
+
float[] GetVerticesX();
float[] GetVerticesY();
float[] GetVerticesZ();
diff --git a/PluginCommon/VisWireframe.cs b/PluginCommon/VisWireframe.cs
index 83b1928..814d465 100644
--- a/PluginCommon/VisWireframe.cs
+++ b/PluginCommon/VisWireframe.cs
@@ -25,8 +25,13 @@ namespace PluginCommon {
///
[Serializable]
public class VisWireframe : IVisualizationWireframe {
+ //
+ // Names and definitions of parameters that are interpreted by the wireframe
+ // renderer, rather than the visualization generator.
+ //
public const string P_IS_PERSPECTIVE = "_isPerspective";
public const string P_IS_BFC_ENABLED = "_isBfcEnabled";
+ public const string P_IS_RECENTERED = "_isRecentered";
public static VisParamDescr Param_IsPerspective(string uiLabel, bool defaultVal) {
return new VisParamDescr(uiLabel, P_IS_PERSPECTIVE, typeof(bool), 0, 0, 0, defaultVal);
@@ -34,6 +39,9 @@ namespace PluginCommon {
public static VisParamDescr Param_IsBfcEnabled(string uiLabel, bool defaultVal) {
return new VisParamDescr(uiLabel, P_IS_BFC_ENABLED, typeof(bool), 0, 0, 0, defaultVal);
}
+ public static VisParamDescr Param_IsRecentered(string uiLabel, bool defaultVal) {
+ return new VisParamDescr(uiLabel, P_IS_RECENTERED, typeof(bool), 0, 0, 0, defaultVal);
+ }
private List mVerticesX = new List();
private List mVerticesY = new List();
@@ -255,6 +263,8 @@ namespace PluginCommon {
// IVisualizationWireframe implementation.
//
+ public bool Is2d { get; set; }
+
public float[] GetVerticesX() {
return mVerticesX.ToArray();
}
diff --git a/SourceGen/RuntimeData/Atari/VisAVG.cs b/SourceGen/RuntimeData/Atari/VisAVG.cs
new file mode 100644
index 0000000..9318726
--- /dev/null
+++ b/SourceGen/RuntimeData/Atari/VisAVG.cs
@@ -0,0 +1,276 @@
+/*
+ * 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.ObjectModel;
+
+using PluginCommon;
+
+namespace RuntimeData.Atari {
+ ///
+ /// Visualizer for Atari Analog Vector Generator commands.
+ ///
+ public class VisAVG : MarshalByRefObject, IPlugin, IPlugin_Visualizer_v2 {
+ // IPlugin
+ public string Identifier {
+ get { return "Atari AVG Visualizer"; }
+ }
+ private IApplication mAppRef;
+ private byte[] mFileData;
+ private AddressTranslate mAddrTrans;
+
+ // Visualization identifiers; DO NOT change or projects that use them will break.
+ private const string VIS_GEN_AVG = "atari-avg";
+
+ private const string P_OFFSET = "offset";
+ private const string P_BASE_ADDR = "baseAddr";
+
+ // Visualization descriptors.
+ private VisDescr[] mDescriptors = new VisDescr[] {
+ new VisDescr(VIS_GEN_AVG, "Atari AVG Commands", VisDescr.VisType.Wireframe,
+ new VisParamDescr[] {
+ new VisParamDescr("File offset (hex)",
+ P_OFFSET, typeof(int), 0, 0x00ffffff, VisParamDescr.SpecialMode.Offset, 0),
+ new VisParamDescr("Base address",
+ P_BASE_ADDR, typeof(int), 0x0000, 0xffff, 0, 0x2000),
+
+ VisWireframe.Param_IsRecentered("Re-center", true),
+ }),
+ };
+
+
+ // IPlugin
+ public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) {
+ mAppRef = appRef;
+ mFileData = fileData;
+ mAddrTrans = addrTrans;
+ }
+
+ // IPlugin
+ public void Unprepare() {
+ mAppRef = null;
+ mFileData = null;
+ mAddrTrans = null;
+ }
+
+ // IPlugin_Visualizer
+ public VisDescr[] GetVisGenDescrs() {
+ if (mFileData == null) {
+ return null;
+ }
+ return mDescriptors;
+ }
+
+ // IPlugin_Visualizer
+ public IVisualization2d Generate2d(VisDescr descr,
+ ReadOnlyDictionary parms) {
+ mAppRef.ReportError("2d not supported");
+ return null;
+ }
+
+ // IPlugin_Visualizer_v2
+ public IVisualizationWireframe GenerateWireframe(VisDescr descr,
+ ReadOnlyDictionary parms) {
+ switch (descr.Ident) {
+ case VIS_GEN_AVG:
+ return GenerateWireframe(parms);
+ default:
+ mAppRef.ReportError("Unknown ident " + descr.Ident);
+ return null;
+ }
+ }
+
+ private enum Opcode {
+ Unknown = 0, VCTR, HALT, SVEC, STAT, SCAL, CNTR, JSR, RTS, JMP
+ }
+
+ private IVisualizationWireframe GenerateWireframe(ReadOnlyDictionary parms) {
+ int offset = Util.GetFromObjDict(parms, P_OFFSET, 0);
+ int baseAddr = Util.GetFromObjDict(parms, P_BASE_ADDR, 0);
+
+ if (offset < 0 || offset >= mFileData.Length) {
+ // should be caught by editor
+ mAppRef.ReportError("Invalid parameter");
+ return null;
+ }
+
+ VisWireframe vw = new VisWireframe();
+ vw.Is2d = true;
+
+ try {
+ int[] stack = new int[4];
+ int stackPtr = 0;
+
+ int beamX = 0;
+ int beamY = 0;
+ double scale = 1.0;
+ bool done = false;
+ int centerVertex = vw.AddVertex(0, 0, 0);
+ int curVertex = centerVertex;
+
+ while (!done && offset < mFileData.Length) {
+ ushort code0 = (ushort)Util.GetWord(mFileData, offset, 2, false);
+ offset += 2;
+ Opcode opc = GetOpcode(code0);
+
+ int dx, dy, ii, vaddr;
+ switch (opc) {
+ case Opcode.VCTR: // 000YYYYY YYYYYYYY IIIXXXXX XXXXXXXX
+ ushort code1 = (ushort)Util.GetWord(mFileData, offset, 2, false);
+ offset += 2;
+ dy = sign13(code0 & 0x1fff);
+ dx = sign13(code1 & 0x1fff);
+ ii = code1 >> 13;
+
+ beamX += (int)Math.Round(dx * scale);
+ beamY += (int)Math.Round(dy * scale);
+ if (ii == 0) {
+ // move only
+ curVertex = vw.AddVertex(beamX, beamY, 0);
+ } else if (dx == 0 && dy == 0) {
+ // plot point
+ vw.AddPoint(curVertex);
+ //mAppRef.DebugLog("PLOT v" + curVertex + ": "
+ // + beamX + "," + beamY);
+ } else {
+ // draw line from previous vertex
+ int newVertex = vw.AddVertex(beamX, beamY, 0);
+ vw.AddEdge(curVertex, newVertex);
+ curVertex = newVertex;
+ }
+ break;
+ case Opcode.HALT: // 00100000 00100000
+ if (stackPtr != 0) {
+ mAppRef.DebugLog("NOTE: encountered HALT with nonzero stack");
+ }
+ done = true;
+ break;
+ case Opcode.SVEC: // 010YYYYY IIIXXXXX
+ dy = sign5((code0 >> 8) & 0x1f) * 2;
+ dx = sign5(code0 & 0x1f) * 2;
+ ii = (code0 >> 5) & 0x07;
+ if (ii != 1) {
+ ii *= 2;
+ }
+
+ // note dx/dy==0 is not supported for SVEC
+ beamX += (int)Math.Round(dx * scale);
+ beamY += (int)Math.Round(dy * scale);
+ if (ii == 0) {
+ // move only
+ curVertex = vw.AddVertex(beamX, beamY, 0);
+ } else {
+ // draw line from previous vertex
+ int newVertex = vw.AddVertex(beamX, beamY, 0);
+ vw.AddEdge(curVertex, newVertex);
+ //mAppRef.DebugLog("SVEC edge " + curVertex + " - " + newVertex);
+ curVertex = newVertex;
+ }
+ break;
+ case Opcode.STAT: // 0110-EHO IIIICCCC
+ ii = (code0 >> 4) & 0x0f;
+ break;
+ case Opcode.SCAL: // 0111-BBB LLLLLLLL
+ int bs = (code0 >> 8) & 0x07;
+ int ls = code0 & 0xff;
+ scale = (16384 - (ls << 6)) >> bs;
+ break;
+ case Opcode.CNTR: // 10000000 01------
+ beamX = beamY = 0;
+ curVertex = centerVertex;
+ break;
+ case Opcode.JSR: // 101-AAAA AAAAAAAA
+ vaddr = code0 & 0x0fff;
+ if (stackPtr == stack.Length) {
+ mAppRef.ReportError("Stack overflow at +" + offset.ToString("x6"));
+ return null;
+ }
+ stack[stackPtr++] = offset;
+ if (!Branch(vaddr, baseAddr, ref offset)) {
+ return null;
+ }
+ break;
+ case Opcode.RTS: // 110----- --------
+ if (stackPtr == 0) {
+ done = true;
+ } else {
+ offset = stack[--stackPtr];
+ }
+ break;
+ case Opcode.JMP: // 111-AAAA AAAAAAAA
+ vaddr = code0 & 0x0fff;
+ if (!Branch(vaddr, baseAddr, ref offset)) {
+ return null;
+ }
+ break;
+ default:
+ mAppRef.ReportError("Unhandled code $" + code0.ToString("x4"));
+ return null;
+ }
+ }
+
+ } catch (IndexOutOfRangeException) {
+ // assume it was our file data access that caused the failure
+ mAppRef.ReportError("Ran off end of file");
+ return null;
+ }
+
+ string msg;
+ if (!vw.Validate(out msg)) {
+ mAppRef.ReportError("Data error: " + msg);
+ return null;
+ }
+
+ return vw;
+ }
+
+ private Opcode GetOpcode(ushort code) {
+ switch (code & 0xe000) {
+ case 0x0000: return Opcode.VCTR;
+ case 0x2000: return Opcode.HALT;
+ case 0x4000: return Opcode.SVEC;
+ case 0x6000: return ((code & 0xf000) == 0x6000) ? Opcode.STAT : Opcode.SCAL;
+ case 0x8000: return Opcode.CNTR;
+ case 0xa000: return Opcode.JSR;
+ case 0xc000: return Opcode.RTS;
+ case 0xe000: return Opcode.JMP;
+ default: return Opcode.Unknown; // shouldn't be possible
+ }
+ }
+
+ // Sign-extend a signed 5-bit value.
+ int sign5(int val) {
+ byte val5 = (byte)(val << 3);
+ return (sbyte)val5 >> 3;
+ }
+
+ // Sign-extend a signed 13-bit value.
+ int sign13(int val) {
+ ushort val13 = (ushort)(val << 3);
+ return (short)val13 >> 3;
+ }
+
+ private bool Branch(int vaddr, int baseAddr, ref int offset) {
+ int fileAddr = baseAddr + vaddr * 2;
+ int fileOffset = mAddrTrans.AddressToOffset(offset, fileAddr);
+ if (fileOffset < 0) {
+ mAppRef.ReportError("JMP/JSR to " + vaddr.ToString("x4") + " invalid");
+ return false;
+ }
+ offset = fileOffset;
+ return true;
+ }
+ }
+}
diff --git a/SourceGen/VisWireframeAnimation.cs b/SourceGen/VisWireframeAnimation.cs
index 8b58bdf..9c05334 100644
--- a/SourceGen/VisWireframeAnimation.cs
+++ b/SourceGen/VisWireframeAnimation.cs
@@ -103,6 +103,7 @@ namespace SourceGen {
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)
@@ -120,7 +121,7 @@ namespace SourceGen {
for (int frame = 0; frame < frameCount; frame++) {
BitmapSource bs = GenerateWireframeImage(mWireObj, dim,
- curX, curY, curZ, doPersp, doBfc);
+ curX, curY, curZ, doPersp, doBfc, doRecenter);
encoder.AddFrame(BitmapFrame.Create(bs), frameDelayMsec);
curX = (curX + 360 + deltaX) % 360;
diff --git a/SourceGen/Visualization.cs b/SourceGen/Visualization.cs
index 14acb16..1624005 100644
--- a/SourceGen/Visualization.cs
+++ b/SourceGen/Visualization.cs
@@ -274,7 +274,9 @@ namespace SourceGen {
int eulerZ = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_Z, 0);
bool doPersp = Util.GetFromObjDict(parms, VisWireframe.P_IS_PERSPECTIVE, true);
bool doBfc = Util.GetFromObjDict(parms, VisWireframe.P_IS_BFC_ENABLED, false);
- return GenerateWireframeImage(wireObj, dim, eulerX, eulerY, eulerZ, doPersp, doBfc);
+ bool doRecenter = Util.GetFromObjDict(parms, VisWireframe.P_IS_RECENTERED, true);
+ return GenerateWireframeImage(wireObj, dim, eulerX, eulerY, eulerZ, doPersp, doBfc,
+ doRecenter);
}
///
@@ -282,7 +284,8 @@ namespace SourceGen {
/// and GIF exports.
///
public static BitmapSource GenerateWireframeImage(WireframeObject wireObj,
- double dim, int eulerX, int eulerY, int eulerZ, bool doPersp, bool doBfc) {
+ double dim, int eulerX, int eulerY, int eulerZ, bool doPersp, bool doBfc,
+ bool doRecenter) {
if (wireObj == null) {
// Can happen if the visualization generator is failing on stuff loaded from
// the project file.
@@ -291,7 +294,7 @@ namespace SourceGen {
// Generate the path geometry.
GeometryGroup geo = GenerateWireframePath(wireObj, dim, eulerX, eulerY, eulerZ,
- doPersp, doBfc);
+ doPersp, doBfc, doRecenter);
// Render geometry to bitmap -- https://stackoverflow.com/a/869767/294248
Rect bounds = geo.GetRenderBounds(null);
@@ -355,7 +358,9 @@ namespace SourceGen {
int eulerZ = Util.GetFromObjDict(parms, VisWireframeAnimation.P_EULER_ROT_Z, 0);
bool doPersp = Util.GetFromObjDict(parms, VisWireframe.P_IS_PERSPECTIVE, true);
bool doBfc = Util.GetFromObjDict(parms, VisWireframe.P_IS_BFC_ENABLED, false);
- return GenerateWireframePath(wireObj, dim, eulerX, eulerY, eulerZ, doPersp, doBfc);
+ bool doRecenter = Util.GetFromObjDict(parms, VisWireframe.P_IS_RECENTERED, true);
+ return GenerateWireframePath(wireObj, dim, eulerX, eulerY, eulerZ, doPersp, doBfc,
+ doRecenter);
}
///
@@ -364,7 +369,8 @@ namespace SourceGen {
/// coordinates so they fit within the box.
///
public static GeometryGroup GenerateWireframePath(WireframeObject wireObj,
- double dim, int eulerX, int eulerY, int eulerZ, bool doPersp, bool doBfc) {
+ double dim, int eulerX, int eulerY, int eulerZ, bool doPersp, bool doBfc,
+ bool doRecenter) {
// WPF path drawing is based on a system where a pixel is drawn at the center
// of its coordinates, and integer coordinates start at the top left edge of
// the drawing area. If you draw a pixel at (0,0), 3/4ths of the pixel will be
@@ -409,7 +415,7 @@ 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.
List segs = wireObj.Generate(eulerX, eulerY, eulerZ,
- doPersp, doBfc);
+ doPersp, doBfc, doRecenter);
// 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 114cc21..8739bcb 100644
--- a/SourceGen/WireframeObject.cs
+++ b/SourceGen/WireframeObject.cs
@@ -86,11 +86,14 @@ namespace SourceGen {
}
}
+ private bool mIs2d = false;
private List mVertices = new List();
private List mPoints = new List();
private List mEdges = new List();
private List mFaces = new List();
private double mBigMag = -1.0;
+ private double mBigMagRc = -1.0;
+ private double mCenterAdjX, mCenterAdjY;
// private constructor; use Create()
@@ -104,11 +107,16 @@ namespace SourceGen {
public static WireframeObject Create(IVisualizationWireframe visWire) {
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) {
@@ -138,6 +146,13 @@ namespace SourceGen {
return null;
}
+ // 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)));
@@ -145,7 +160,9 @@ namespace SourceGen {
int[] points = visWire.GetPoints();
for (int i = 0; i < points.Length; i++) {
- wireObj.mPoints.Add(wireObj.mVertices[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();
@@ -160,8 +177,12 @@ namespace SourceGen {
return null;
}
- wireObj.mEdges.Add(new Edge(wireObj.mVertices[v0index],
- wireObj.mVertices[v1index], HasIndex(excludedEdges, i)));
+ 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();
@@ -204,19 +225,48 @@ namespace SourceGen {
// 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++) {
- double mag = wireObj.mVertices[i].Vec.Magnitude();
+ 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;
+ }
}
wireObj.mBigMag = bigMag;
+ wireObj.mBigMagRc = bigMagRc;
return wireObj;
}
+ private static void UpdateMinMax(Vertex vert, ref double xmin, ref double xmax,
+ ref double ymin, ref double ymax) {
+ if (vert.Vec.X < xmin) {
+ xmin = vert.Vec.X;
+ } else if (vert.Vec.X > xmax) {
+ xmax = vert.Vec.X;
+ }
+ if (vert.Vec.Y < ymin) {
+ ymin = vert.Vec.Y;
+ } else if (vert.Vec.Y > ymax) {
+ ymax = vert.Vec.Y;
+ }
+ }
+
private static bool HasIndex(int[] arr, int val) {
for (int i = 0; i < arr.Length; i++) {
if (arr[i] == val) {
@@ -235,11 +285,19 @@ namespace SourceGen {
/// Rotation about Z axis.
/// Perspective or othographic projection?
/// Perform backface culling?
+ /// Re-center 2D renderings?
/// List a of line segments, which could be empty if backface culling
/// was especially successful. All segment coordinates are in the range
/// [-1,1].
public List Generate(int eulerX, int eulerY, int eulerZ,
- bool doPersp, bool doBfc) {
+ bool doPersp, bool doBfc, bool doRecenter) {
+ // overrule flags that don't make sense
+ if (mIs2d) {
+ doPersp = doBfc = false;
+ } else {
+ doRecenter = false;
+ }
+
List segs = new List(mEdges.Count);
// Camera Z coordinate adjustment, used to control how perspective projections
@@ -248,12 +306,25 @@ namespace SourceGen {
const double zadj = 3.0;
// Scale coordinate values to [-1,1].
- double scale = 1.0 / mBigMag;
+ double scale;
+ if (doRecenter) {
+ scale = 1.0 / mBigMagRc;
+ } else {
+ scale = 1.0 / mBigMag;
+ }
if (doPersp) {
// objects closer to camera are bigger; reduce scale slightly
scale = (scale * zadj) / (zadj + 0.3);
}
+ // Configure X/Y translation for 2D wireframes.
+ double transX = 0;
+ double transY = 0;
+ if (doRecenter) {
+ transX = mCenterAdjX;
+ transY = mCenterAdjY;
+ }
+
// In a left-handed coordinate system, +Z is away from the viewer. The
// visualizer expects a left-handed system with the "nose" aimed toward +Z,
// which leaves us looking at the back end of things. We can add a 180 degree
@@ -303,7 +374,12 @@ namespace SourceGen {
foreach (Vertex point in mPoints) {
// There are no "point faces" at the moment, so no BFC is applied.
- Vector3 trv = rotMat.Multiply(point.Vec);
+ Vector3 vec = point.Vec;
+ if (doRecenter) {
+ vec = new Vector3(vec.X + transX, vec.Y + transY, vec.Z);
+ }
+ Vector3 trv = rotMat.Multiply(vec);
+
double xc, yc;
if (doPersp) {
double zc = trv.Z * scale;
@@ -314,6 +390,8 @@ namespace SourceGen {
yc = trv.Y * scale;
}
+ //Debug.WriteLine("POINT " + xc + "," + yc);
+
// Zero-length line segments don't do anything. Try a '+'.
const double dist = 1 / 64.0;
double x0 = Math.Max(-1.0, xc - dist);
@@ -336,8 +414,14 @@ namespace SourceGen {
}
}
- Vector3 trv0 = rotMat.Multiply(edge.Vertex0.Vec);
- Vector3 trv1 = rotMat.Multiply(edge.Vertex1.Vec);
+ Vector3 vec0 = edge.Vertex0.Vec;
+ Vector3 vec1 = edge.Vertex1.Vec;
+ if (doRecenter) {
+ vec0 = new Vector3(vec0.X + transX, vec0.Y + transY, vec0.Z);
+ vec1 = new Vector3(vec1.X + transX, vec1.Y + transY, vec1.Z);
+ }
+ Vector3 trv0 = rotMat.Multiply(vec0);
+ Vector3 trv1 = rotMat.Multiply(vec1);
double x0, y0, x1, y1;
if (doPersp) {
diff --git a/SourceGen/WpfGui/ShowWireframeAnimation.xaml.cs b/SourceGen/WpfGui/ShowWireframeAnimation.xaml.cs
index eaf707f..cd8e5a4 100644
--- a/SourceGen/WpfGui/ShowWireframeAnimation.xaml.cs
+++ b/SourceGen/WpfGui/ShowWireframeAnimation.xaml.cs
@@ -37,7 +37,7 @@ namespace SourceGen.WpfGui {
private int mFrameCount;
private int mInitialX, mInitialY, mInitialZ;
private int mDeltaX, mDeltaY, mDeltaZ;
- private bool mDoPersp, mDoBfc;
+ private bool mDoPersp, mDoBfc, mDoRecenter;
private int mCurX, mCurY, mCurZ;
@@ -59,6 +59,7 @@ namespace SourceGen.WpfGui {
mFrameCount = Util.GetFromObjDict(parms, VisWireframeAnimation.P_FRAME_COUNT, 1);
mDoPersp = Util.GetFromObjDict(parms, VisWireframe.P_IS_PERSPECTIVE, true);
mDoBfc = Util.GetFromObjDict(parms, VisWireframe.P_IS_BFC_ENABLED, false);
+ mDoRecenter = Util.GetFromObjDict(parms, VisWireframe.P_IS_RECENTERED, false);
int intervalMsec = Util.GetFromObjDict(parms,
VisWireframeAnimation.P_FRAME_DELAY_MSEC, 100);
@@ -99,7 +100,7 @@ namespace SourceGen.WpfGui {
// ViewBox itself, because on the first iteration the ViewBox has a size of zero.
double dim = Math.Floor(Math.Min(testBorder.ActualWidth, testBorder.ActualHeight));
wireframePath.Data = Visualization.GenerateWireframePath(mWireObj, dim,
- mCurX, mCurY, mCurZ, mDoPersp, mDoBfc);
+ mCurX, mCurY, mCurZ, mDoPersp, mDoBfc, mDoRecenter);
}
}
}