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; } } }