From df823f4c09bd363e00120925a5115132bc679f1e Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Sat, 11 Apr 2020 11:23:16 -0700 Subject: [PATCH] Add support for points in wireframe meshes This allows rendering of a vertex directly, rather than just as an edge endpoint. They're currently drawn as small '+' signs. A round dot would be better, but the code is passing a list of line segments around, so this is simpler. --- CommonUtil/RawData.cs | 3 ++- PluginCommon/Interfaces.cs | 13 +++++++++---- PluginCommon/Util.cs | 3 ++- PluginCommon/VisWireframe.cs | 23 +++++++++++++++++++++++ SourceGen/WireframeObject.cs | 35 +++++++++++++++++++++++++++++++++-- 5 files changed, 69 insertions(+), 8 deletions(-) diff --git a/CommonUtil/RawData.cs b/CommonUtil/RawData.cs index 1ee8c8b..3be7df7 100644 --- a/CommonUtil/RawData.cs +++ b/CommonUtil/RawData.cs @@ -19,7 +19,8 @@ using System.Diagnostics; namespace CommonUtil { public class RawData { /// - /// Extracts an integer from the data stream. + /// Extracts an integer from the data stream. Integers less than 4 bytes wide + /// are not sign-extended. /// /// Raw data stream. /// Start offset. diff --git a/PluginCommon/Interfaces.cs b/PluginCommon/Interfaces.cs index 8da317f..22528dc 100644 --- a/PluginCommon/Interfaces.cs +++ b/PluginCommon/Interfaces.cs @@ -327,20 +327,24 @@ namespace PluginCommon { /// /// Holds raw vertex/edge/normal data collected from a 2D or 3D wireframe mesh. We use /// a left-handed coordinate system (+Z goes into the screen). If the project being - /// disassembled uses different definitions for the axes, it's probably best to convert. - /// 2D data should use X/Y with Z=0. + /// disassembled uses different definitions for the axes, it's probably best to convert + /// them in the visualizer. 2D data should use X/Y with Z=0. /// - /// All objects will have vertices and edges. Face normals are optional. + /// All objects will have vertices. Most will have edges, some will have points. Face + /// normals are optional. /// /// /// The face-normal stuff is designed specifically for Elite. Besides being one of the /// very few 6502-based games to use backface culling, it extended the concept to allow /// convex shapes to have protrusions. /// + /// Points are included primarily for the benefit of AVG games like Battlezone. + /// /// We favor multiple arrays over compound objects for this interface to avoid making /// such objects part of the plugin interface. /// - /// TODO(maybe): specify colors for edges. Not widely used? + /// TODO(maybe): specify colors for points and edges. Not widely used? Could be handy for + /// color AVG games like Tempest. /// public interface IVisualizationWireframe { // Each function returns the specified data. Do not modify the returned arrays. @@ -349,6 +353,7 @@ namespace PluginCommon { float[] GetVerticesY(); float[] GetVerticesZ(); + int[] GetPoints(); IntPair[] GetEdges(); float[] GetNormalsX(); diff --git a/PluginCommon/Util.cs b/PluginCommon/Util.cs index 6ed5894..837425d 100644 --- a/PluginCommon/Util.cs +++ b/PluginCommon/Util.cs @@ -28,7 +28,8 @@ namespace PluginCommon { /// public static class Util { /// - /// Extracts an integer from the data stream. + /// Extracts an integer from the data stream. Integers shorter than 4 bytes are + /// not sign-extended. /// /// Raw data stream. /// Start offset. diff --git a/PluginCommon/VisWireframe.cs b/PluginCommon/VisWireframe.cs index 865cc35..83b1928 100644 --- a/PluginCommon/VisWireframe.cs +++ b/PluginCommon/VisWireframe.cs @@ -39,6 +39,7 @@ namespace PluginCommon { private List mVerticesY = new List(); private List mVerticesZ = new List(); + private List mPoints = new List(); private List mEdges = new List(); private List mNormalsX = new List(); @@ -72,6 +73,16 @@ namespace PluginCommon { return mVerticesX.Count - 1; } + /// + /// Adds a point to the list. + /// + /// Vertex index. + /// Point index. Indices start at zero and count up. + public int AddPoint(int index) { + mPoints.Add(index); + return mPoints.Count - 1; + } + /// /// Adds an edge to the list. The referenced vertices do not need to be defined /// before calling. @@ -172,6 +183,14 @@ namespace PluginCommon { return false; } + // check points + foreach (int vi in mPoints) { + if (vi < 0 || vi >= vertexCount) { + msg = "invalid point (index=" + vi + "; count=" + vertexCount + ")"; + return false; + } + } + // check edges foreach (IntPair ip in mEdges) { if (ip.Val0 < 0 || ip.Val0 >= vertexCount || @@ -248,6 +267,10 @@ namespace PluginCommon { return mVerticesZ.ToArray(); } + public int[] GetPoints() { + return mPoints.ToArray(); + } + public IntPair[] GetEdges() { return mEdges.ToArray(); } diff --git a/SourceGen/WireframeObject.cs b/SourceGen/WireframeObject.cs index dfa124a..114cc21 100644 --- a/SourceGen/WireframeObject.cs +++ b/SourceGen/WireframeObject.cs @@ -87,6 +87,7 @@ namespace SourceGen { } 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; @@ -105,7 +106,8 @@ namespace SourceGen { // // Start by extracting data from the visualization object. Everything stored - // there is loaded into this object. + // there is loaded into this object. The VisWireframe validator will have + // ensured that all the indices are in range. // float[] normalsX = visWire.GetNormalsX(); @@ -141,6 +143,11 @@ namespace SourceGen { HasIndex(excludedVertices, i))); } + int[] points = visWire.GetPoints(); + for (int i = 0; i < points.Length; i++) { + wireObj.mPoints.Add(wireObj.mVertices[i]); + } + IntPair[] edges = visWire.GetEdges(); int[] excludedEdges = visWire.GetExcludedEdges(); for (int i = 0; i < edges.Length; i++) { @@ -229,7 +236,8 @@ namespace SourceGen { /// Perspective or othographic projection? /// Perform backface culling? /// List a of line segments, which could be empty if backface culling - /// was especially successful. + /// 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) { List segs = new List(mEdges.Count); @@ -293,6 +301,29 @@ 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); + double xc, yc; + if (doPersp) { + double zc = trv.Z * scale; + xc = (trv.X * scale * zadj) / (zadj + zc); + yc = (trv.Y * scale * zadj) / (zadj + zc); + } else { + xc = trv.X * scale; + yc = trv.Y * scale; + } + + // Zero-length line segments don't do anything. Try a '+'. + const double dist = 1 / 64.0; + double x0 = Math.Max(-1.0, xc - dist); + double x1 = Math.Min(xc + dist, 1.0); + segs.Add(new LineSeg(x0, yc, x1, yc)); + double y0 = Math.Max(-1.0, yc - dist); + double y1 = Math.Min(yc + dist, 1.0); + segs.Add(new LineSeg(xc, y0, xc, y1)); + } + foreach (Edge edge in mEdges) { if (doBfc) { // To be visible, vertices and edges must either not specify any