using System.Collections.Generic;
using System.Linq;
using NIFLib.Core;
using NIFLib.Nodes;
namespace NIFLib
{
///
/// Helper Class for Browsing Nodes in a Nif File
///
public static class NodeWalker
{
///
/// Retrieves Roots from this File
///
///
///
public static IEnumerable GetRoots(this NiFile nif)
{
return nif.Footer.RootNodes.Where(rf => rf.IsValid()).Select(rf => rf.Object).OfType();
}
///
/// Retrieve Direct Children from this Node
///
///
///
public static IEnumerable GetChildren(this NiNode node)
{
return node.Children.Where(rf => rf.IsValid() && rf.Object != null).Select(rf => rf.Object);
}
///
/// Retrieve LOD Children given Distance
///
///
///
///
public static IEnumerable GetChildrenFromLOD(this NiLODNode node, float dist)
{
var lods = node.GetChildren().OfType().ToArray();
var lodlevels = node.LODLevels;
if (lodlevels == null && node.LODLevelData.IsValid() && node.LODLevelData.Object != null)
{
var lodData = node.LODLevelData.Object as NiRangeLODData;
if (lodData != null)
lodlevels = lodData.LODLevels;
}
if (lodlevels == null)
{
// Default to first LOD Level for other LOD mechanisms
var result = lods.FirstOrDefault();
if (result != null)
yield return result;
yield break;
}
foreach (var match in lodlevels
.Select((l, i) => new { Ind = i, Lod = l })
.Where(o => dist >= o.Lod.NearExtent && dist < o.Lod.FarExtent && o.Ind < lods.Length))
yield return lods.ElementAt(match.Ind);
yield break;
}
///
/// Retrieve Tri Based Nodes with 0f LoD Distance in all tree Depth
///
/// Starting Lookup Node
/// NiTriBasedGeometry Collection
public static IEnumerable GetTriBasedNode(this NiNode node)
{
var stack = new Stack();
stack.Push(node);
do
{
var current = stack.Pop();
var nilod = current as NiLODNode;
if (nilod != null)
{
foreach (var child in nilod.GetChildrenFromLOD(0f))
stack.Push(child);
}
else
{
foreach (var child in current.GetChildren())
{
var childNode = child as NiNode;
if (childNode != null)
stack.Push(childNode);
var childGeom = child as NiTriBasedGeometry;
if (childGeom != null)
yield return childGeom;
}
}
}
while (stack.Count > 0);
yield break;
}
///
/// Is This Node Invisible
///
///
///
public static bool IsInvisible(this NiAVObject obj)
{
// Invisible Flag
return (obj.Flags & 1) == 1;
}
}
}