Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions XWOpt/OptFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,10 @@ public IEnumerator<BaseNode> GetEnumerator()
{
foreach (var node in RootNodes)
{
yield return node;

if (node is NodeCollection branch)
// Recursely walk the hierarchy - the first item is always node, then any children
foreach (var nodeItem in node)
{
foreach (var subNode in branch)
{
yield return subNode;
}
yield return nodeItem;
}
}
}
Expand Down
66 changes: 62 additions & 4 deletions XWOpt/OptNode/BaseNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,81 @@
* OR OTHER DEALINGS IN THE SOFTWARE.
*/

using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using SchmooTech.XWOpt.OptNode.Types;

namespace SchmooTech.XWOpt.OptNode
{
/// <summary>
/// Common type for all types of nodes in an OPT file.
/// </summary>
public class BaseNode
public class BaseNode : IEnumerable<BaseNode>
{
/// <summary>
/// Offset at which this node was read from the file. Use for read debugging.
/// </summary>
public long OffsetInFile { get; private set; }
public long OffsetInFile { get; }
public string Name { get; }
public NodeType NodeType { get; }

internal BaseNode() { }
internal BaseNode(OptReader opt)
public Collection<BaseNode> Children { get; } = new Collection<BaseNode>();
public BaseNode Parent { get; private set; }
internal BaseNode(string name, NodeType nodeType)
{
Name = name;
NodeType = nodeType;
}

internal BaseNode(OptReader opt, NodeHeader header)
{
OffsetInFile = opt.BaseStream.Position;
Name = header.Name;
NodeType = header.NodeType;
Parent = header.Parent;

for (var i = 0; i < header.ChildCount; i++)
{
opt.Seek(header.ChildAddressTable + i * 4);
var childAddress = opt.ReadInt32();

if (childAddress != 0)
{
var node = opt.ReadNodeAt(childAddress, this, this);
Children.Add(node);
}
}
}

public IEnumerator<BaseNode> GetEnumerator()
{
yield return this;

foreach (var node in Children)
{
// Recursive walk down the hierarchy
foreach (var subNode in node)
{
yield return subNode;
}
}
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

public void AddChild(BaseNode node)
{
Children.Add(node);
node.Parent = this;
}

public bool RemoveChild(BaseNode node)
{
return Children.Remove(node);
}
}
}
8 changes: 3 additions & 5 deletions XWOpt/OptNode/EngineGlow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,10 @@ class EngineGlow<TVector3> : BaseNode
public TVector3 Y { get; set; }
public TVector3 Z { get; set; }

internal EngineGlow(OptReader reader) : base(reader)
internal EngineGlow(OptReader reader, NodeHeader nodeHeader) : base(reader, nodeHeader)
{
reader.ReadUnknownUseValue(0, this);
reader.ReadUnknownUseValue(0, this);
reader.ReadUnknownUseValue(1, this);
reader.FollowPointerToNextByte(this);
reader.Seek(nodeHeader.DataAddress);

reader.ReadUnknownUseValue(0, this);

InnerColor = reader.ReadInt32();
Expand Down
29 changes: 14 additions & 15 deletions XWOpt/OptNode/FaceList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,12 @@ public class FaceList<TVector3> : BaseNode
private Collection<TVector3> faceNormals;
private Collection<TextureBasisVectors<TVector3>> basisVectors;

private int edgeCount;

[SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Member")]
private Collection<CoordinateReferenceTuple> vertexRef;
[SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Member")]
private Collection<CoordinateReferenceTuple> edgeRef;
[SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Member")]
private Collection<CoordinateReferenceTuple> uVRef;
private int count;

[SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Member")]
public Collection<CoordinateReferenceTuple> VertexRef { get => vertexRef; }
Expand All @@ -52,36 +49,38 @@ public class FaceList<TVector3> : BaseNode
public Collection<CoordinateReferenceTuple> VertexNormalRef { get => vertexNormalRef; }
public Collection<TVector3> FaceNormals { get => faceNormals; }
public Collection<TextureBasisVectors<TVector3>> BasisVectors { get => basisVectors; }
public int Count { get => count; set => count = value; }
public int EdgeCount { get => edgeCount; set => edgeCount = value; }
public int Count { get; }
public int EdgeCount { get; }
public int FaceListSize { get; }

internal FaceList(OptReader reader) : base(reader)
internal FaceList(OptReader reader, NodeHeader nodeHeader) : base(reader, nodeHeader)
{
// unknown zeros
reader.ReadUnknownUseValue(0, this);
reader.ReadUnknownUseValue(0, this);
reader.Seek(nodeHeader.DataAddress);
Count = nodeHeader.DataCount;

count = reader.ReadInt32();
reader.FollowPointerToNextByte(this);
edgeCount = reader.ReadInt32();
// read the IFS Size
FaceListSize = reader.ReadInt32();

// Next up is the DataCount * Faces, size 64
vertexRef = new Collection<CoordinateReferenceTuple>();
edgeRef = new Collection<CoordinateReferenceTuple>();
uVRef = new Collection<CoordinateReferenceTuple>();
vertexNormalRef = new Collection<CoordinateReferenceTuple>();

for (int i = 0; i < count; i++)
for (int i = 0; i < nodeHeader.DataCount; i++)
{
vertexRef.Add(new CoordinateReferenceTuple(reader));
edgeRef.Add(new CoordinateReferenceTuple(reader));
UVRef.Add(new CoordinateReferenceTuple(reader));
vertexNormalRef.Add(new CoordinateReferenceTuple(reader));
}

faceNormals = reader.ReadVectorCollection<TVector3>(count);
// Next up is the DataCount * Face Normals, size 12
faceNormals = reader.ReadVectorCollection<TVector3>(nodeHeader.DataCount);

// Next up is the DataCount * Texture Basis Vectors, size 24
basisVectors = new Collection<TextureBasisVectors<TVector3>>();
for (int i = 0; i < count; i++)
for (int i = 0; i < nodeHeader.DataCount; i++)
{
// Edge case: TIE98 CORVTA.OPT is missing a float at EOF.
try
Expand Down
23 changes: 11 additions & 12 deletions XWOpt/OptNode/Hardpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,22 @@ public enum WeaponType

public class Hardpoint<TVector3> : BaseNode
{
private WeaponType weaponType;
private TVector3 location;
public WeaponType WeaponType { get; }
public TVector3 Location { get; }

public WeaponType WeaponType { get => weaponType; set => weaponType = value; }
public TVector3 Location { get => location; set => location = value; }

internal Hardpoint(OptReader reader) : base(reader)
internal Hardpoint(OptReader reader, NodeHeader nodeHeader) : base(reader, nodeHeader)
{
reader.ReadUnknownUseValue(0, this);
reader.ReadUnknownUseValue(0, this);
reader.ReadUnknownUseValue(1, this);
reader.Seek(nodeHeader.DataAddress);

reader.FollowPointerToNextByte(this);
WeaponType = (WeaponType)reader.ReadUInt32();

weaponType = (WeaponType)reader.ReadUInt32();
Location = reader.ReadVector<TVector3>();
}

location = reader.ReadVector<TVector3>();
public Hardpoint(string name, WeaponType type, TVector3 position) : base(name, Types.NodeType.Hardpoint)
{
WeaponType = type;
Location = position;
}
}
}
23 changes: 6 additions & 17 deletions XWOpt/OptNode/LodCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,38 +25,27 @@

namespace SchmooTech.XWOpt.OptNode
{
public class LodCollection : NodeCollection
public class LodCollection : BaseNode
{
/// <summary>
/// Render cutoff distances associated with each LOD, in same order as Children. (This may be in no logical order.)
/// </summary>
public Collection<float> MaxRenderDistance { get; } = new Collection<float>();

internal LodCollection(OptReader reader) : base()
internal LodCollection(OptReader reader, NodeHeader nodeHeader) : base(reader, nodeHeader)
{
int lodChildCount = reader.ReadInt32();
int lodChildOffset = reader.ReadInt32();
int lodThresholdCount = reader.ReadInt32();
int lodThresholdOffset = reader.ReadInt32();

// No idea why this would happen, but my understanding of this block is wrong if it does.
if (lodChildCount != lodThresholdCount)
if (nodeHeader.ChildCount != nodeHeader.DataCount)
{
reader.logger?.Invoke(String.Format(CultureInfo.CurrentCulture, "Not the same number of LOD meshes ({0}) as LOD offsets ({1}) at {2:X}", lodChildCount, lodThresholdCount, reader.BaseStream.Position));
reader.logger?.Invoke(String.Format(CultureInfo.CurrentCulture, "Not the same number of LOD meshes ({0}) as LOD offsets ({1}) at {2:X}", nodeHeader.ChildCount, nodeHeader.DataCount, reader.BaseStream.Position));
}

reader.Seek(lodChildOffset);
ReadChildren(reader, lodChildCount, lodChildOffset);

reader.Seek(lodThresholdOffset);
reader.Seek(nodeHeader.DataAddress);
MaxRenderDistance.Clear();
for (int i = 0; i < lodChildCount; i++)
for (int i = 0; i < nodeHeader.DataCount; i++)
{
float distance = reader.ReadSingle();
MaxRenderDistance.Add(distance);
// A distance of 0 represents infinate draw distance
// Converting to PositiveInfinity sorts it correctly.
distance = distance == 0 ? float.PositiveInfinity : distance;
}
}
}
Expand Down
14 changes: 4 additions & 10 deletions XWOpt/OptNode/MeshVerticies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,13 @@ namespace SchmooTech.XWOpt.OptNode
{
public class MeshVertices<TVector3> : BaseNode
{
public Collection<TVector3> Vertices { get; private set; }
public Collection<TVector3> Vertices { get; }

internal MeshVertices(OptReader reader) : base(reader)
internal MeshVertices(OptReader reader, NodeHeader nodeHeader) : base(reader, nodeHeader)
{
// unknown zeros
reader.ReadUnknownUseValue(0, this);
reader.ReadUnknownUseValue(0, this);
reader.Seek(nodeHeader.DataAddress);

var count = reader.ReadInt32();

reader.FollowPointerToNextByte(this);

Vertices = reader.ReadVectorCollection<TVector3>(count);
Vertices = reader.ReadVectorCollection<TVector3>(nodeHeader.DataCount);
}
}
}
33 changes: 0 additions & 33 deletions XWOpt/OptNode/NamedGroup.cs

This file was deleted.

Loading