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.
This commit is contained in:
Andy McFadden 2020-04-11 11:23:16 -07:00
parent a42584834b
commit df823f4c09
5 changed files with 69 additions and 8 deletions

View File

@ -19,7 +19,8 @@ using System.Diagnostics;
namespace CommonUtil {
public class RawData {
/// <summary>
/// Extracts an integer from the data stream.
/// Extracts an integer from the data stream. Integers less than 4 bytes wide
/// are not sign-extended.
/// </summary>
/// <param name="data">Raw data stream.</param>
/// <param name="offset">Start offset.</param>

View File

@ -327,20 +327,24 @@ namespace PluginCommon {
/// <summary>
/// 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.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
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();

View File

@ -28,7 +28,8 @@ namespace PluginCommon {
/// </summary>
public static class Util {
/// <summary>
/// Extracts an integer from the data stream.
/// Extracts an integer from the data stream. Integers shorter than 4 bytes are
/// not sign-extended.
/// </summary>
/// <param name="data">Raw data stream.</param>
/// <param name="offset">Start offset.</param>

View File

@ -39,6 +39,7 @@ namespace PluginCommon {
private List<float> mVerticesY = new List<float>();
private List<float> mVerticesZ = new List<float>();
private List<int> mPoints = new List<int>();
private List<IntPair> mEdges = new List<IntPair>();
private List<float> mNormalsX = new List<float>();
@ -72,6 +73,16 @@ namespace PluginCommon {
return mVerticesX.Count - 1;
}
/// <summary>
/// Adds a point to the list.
/// </summary>
/// <param name="index">Vertex index.</param>
/// <returns>Point index. Indices start at zero and count up.</returns>
public int AddPoint(int index) {
mPoints.Add(index);
return mPoints.Count - 1;
}
/// <summary>
/// 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();
}

View File

@ -87,6 +87,7 @@ namespace SourceGen {
}
private List<Vertex> mVertices = new List<Vertex>();
private List<Vertex> mPoints = new List<Vertex>();
private List<Edge> mEdges = new List<Edge>();
private List<Face> mFaces = new List<Face>();
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 {
/// <param name="doPersp">Perspective or othographic projection?</param>
/// <param name="doBfc">Perform backface culling?</param>
/// <returns>List a of line segments, which could be empty if backface culling
/// was especially successful.</returns>
/// was especially successful. All segment coordinates are in the range
/// [-1,1].</returns>
public List<LineSeg> Generate(int eulerX, int eulerY, int eulerZ,
bool doPersp, bool doBfc) {
List<LineSeg> segs = new List<LineSeg>(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