/// <summary> /// Build X3D Scene Graph using XPathNavigator /// </summary> private void build_scene_iterativily(XPathNavigator nav) { XPathNavigator startPosition; SceneGraphNode parent; SceneGraphNode child; SceneGraphNode def; int current_depth; nav.MoveToFirstChild(); startPosition = nav.Clone(); current_depth = 0; parent = null; nav.MoveToFirstChild(); while (nav.NodeType != XPathNodeType.Root && !nav.IsSamePosition(startPosition)) { child = XMLParser.ParseXMLElement(nav); if (child != null) { IXmlLineInfo lineInfo; lineInfo = (IXmlLineInfo)nav; child.XMLDocumentLocation = new OpenTK.Vector2(lineInfo.LinePosition, lineInfo.LineNumber); child._id = make_id(); child.Depth = current_depth; #if DEBUG_SCENE_GRAPH Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("".PadLeft(current_depth, '»') + nav.Name + " " + child.DEF + " " + current_depth.ToString() + "/" + child._id.ToString()); #endif if (parent != null) { child.Parent = parent; child.Parents.Add(parent); //TODO: implement containerField parent.Children.Add(child); // Apply Container Field if (!string.IsNullOrEmpty(child.containerField) && child.containerField != "children") { if (parent.HasAttribute(child.containerField)) { parent.setAttribute(child.containerField, child); } else { Console.WriteLine("[warning] could not apply containerField reference \"{0}\" to parent \"{1}\"", child.containerField, parent); } } } else { _root = child; } if (nav.HasChildren) { child.IsLeaf = false; } else { child.IsLeaf = true; } //child.ContinueDeserialization(); // ... DEF_use #region DEF/USE if (!string.IsNullOrEmpty(child.DEF)) { child.USE = string.Empty; if (defUseScope.ContainsKey(child.DEF)) { defUseScope[child.DEF] = child; // override existing } else { defUseScope.Add(child.DEF, child); } } else if (!string.IsNullOrEmpty(child.USE)) { child.DEF = string.Empty; var asc = child.Ascendants(); if (asc.Any(ascendant => ascendant.DEF == child.USE)) { Console.WriteLine("Cyclic reference ignored DEF_USE ", child.USE); continue; } // if DEF is not an ancestor (self referential) then there are no cyclic references, so we are good to go. // insert the DEF node a 2nd time as a child of the USE node parent // resulting in the DEF node having multiple parents. See DEF/USE semantics. def = QueryDFS(_root, (SceneGraphNode n) => n.DEF == child.USE).FirstOrDefault(); if (def != null && child.Parent != null) { def.Parents.Add(child.Parent); child.Parent.Children.Add(def); } } #endregion #region Event Model if (child.GetType() == typeof(ROUTE)) { // Quick way to get all ROUTE nodes Routes.Add((ROUTE)child); } #endregion #region Prototyping if (!string.IsNullOrEmpty(child.name)) { this.nameScope.Add(new KeyValuePair <string, SceneGraphNode>(child.name, child)); if (child.GetType() == typeof(ProtoInstance)) { ProtoInstance protoInstance = (ProtoInstance)child; KeyValuePair <string, SceneGraphNode> _value = this.nameScope.FirstOrDefault(n => n.Key == child.name); // slow if (_value.Value != null) { protoInstance.Prototype = (ProtoDeclare)_value.Value; } else { Console.WriteLine("[Warning] Could not immediatly find ProtoDeclare \"{0}\". Placing ProtoDeclare above ProtoInstance usually fixes this warning.", child.name); } } } if (child.GetType() == typeof(ProtoDeclare)) { child.Hidden = true; // Not renderable. child.PassthroughAllowed = false; // not considered part of the Runtime SceneGraph or EventGraph, // ProtoDeclare is only a SceneGraphStructureStatement. // Only ProtoInstance can access its ProtoDeclare // Events are not passed in to where the prototype is declared, // instead, ProtoInstance creates a new shadow-instance of the ProtoDeclare. // All the nodes under the proto declare are shadow-copied under the ProtoInstance // becoming part of the Scene Graph again as a new instance but managed explicitly by ProtoInstance. } #endregion child.PostDeserialization(); } if (nav.HasChildren) { parent = child; current_depth++; nav.MoveToFirstChild(); } else { if (nav.MoveToNext(XPathNodeType.Element) == false) { do { if (nav.MoveToParent() == false) { break; } if (parent != null) { parent.PostDescendantDeserialization(); if (parent.IsLeaf == false && parent.Children.Count > 0) { foreach (SceneGraphNode ch in parent.Children) { foreach (SceneGraphNode sibling in parent.Children) { if (ch != sibling && ch.Siblings.Contains(sibling) == false) { ch.Siblings.Add(sibling); sibling.Siblings.Add(ch); } } } } /* Go back to the previous depth to follow the nav: */ parent = parent.Parent; current_depth--; } }while (nav.MoveToNext(XPathNodeType.Element) == false); } } } }
/// <summary> /// Build X3D Scene Graph using XDocument /// </summary> private void build_scene_iterativily_xdoc(XDocument doc) { SceneGraphNode parent; SceneGraphNode child; SceneGraphNode def; Queue <_graph_node> work_items; _graph_node xmlElem; bool hasChildren; int current_depth; int i; IEnumerable <XElement> children; IXmlLineInfo lineInfo; current_depth = 0; parent = null; work_items = new Queue <_graph_node>(); work_items.Enqueue(new _graph_node() { node = doc.Root }); while (work_items.Count > 0) { xmlElem = work_items.Dequeue(); child = XMLParser.ParseXMLElement(xmlElem.node); parent = xmlElem.parent; hasChildren = xmlElem.node.Elements().Count() > 0; #region Process Node if (child != null) { lineInfo = (IXmlLineInfo)xmlElem.node; child.XMLDocumentLocation = new Vector2(lineInfo.LinePosition, lineInfo.LineNumber); child._id = make_id(); current_depth = (parent == null) ? 0 : parent.Depth + 1; child.Depth = current_depth; #if DEBUG_SCENE_GRAPH Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("".PadLeft(current_depth, '»') + xmlElem.node.Name.LocalName + " " + child.DEF + " " + current_depth.ToString() + "/" + child._id.ToString()); #endif if (parent != null) { child.Parent = parent; child.Parents.Add(parent); //TODO: implement containerField parent.Children.Add(child); // Apply Container Field if (!string.IsNullOrEmpty(child.containerField) && child.containerField != "children") { if (parent.HasAttribute(child.containerField)) { parent.setAttribute(child.containerField, child); } else { Console.WriteLine("[warning] could not apply containerField reference \"{0}\" to parent \"{1}\"", child.containerField, parent); } } } else { _root = child; } if (hasChildren) { child.IsLeaf = false; } else { child.IsLeaf = true; } //child.ContinueDeserialization(); // ... DEF_use #region DEF/USE if (!string.IsNullOrEmpty(child.DEF)) { child.USE = string.Empty; if (defUseScope.ContainsKey(child.DEF)) { defUseScope[child.DEF] = child; // override existing } else { defUseScope.Add(child.DEF, child); } } else if (!string.IsNullOrEmpty(child.USE)) { child.DEF = string.Empty; var asc = child.Ascendants(); if (asc.Any(ascendant => ascendant.DEF == child.USE)) { Console.WriteLine("Cyclic reference ignored DEF_USE ", child.USE); continue; } // if DEF is not an ancestor (self referential) then there are no cyclic references, so we are good to go. // insert the DEF node a 2nd time as a child of the USE node parent // resulting in the DEF node having multiple parents. See DEF/USE semantics. def = QueryDFS(_root, (SceneGraphNode n) => n.DEF == child.USE).FirstOrDefault(); if (def != null && child.Parent != null) { def.Parents.Add(child.Parent); child.Parent.Children.Add(def); } } #endregion #region Class if (!string.IsNullOrEmpty(child.@class)) { List <SceneGraphNode> lstClasses; if (classScope.ContainsKey(child.@class)) { lstClasses = classScope[child.@class]; } else { lstClasses = new List <SceneGraphNode>(); } lstClasses.Add(child); classScope[child.@class] = lstClasses; } #endregion #region Event Model if (child.GetType() == typeof(ROUTE)) { // Quick way to get all ROUTE nodes Routes.Add((ROUTE)child); } #endregion #region Prototyping if (!string.IsNullOrEmpty(child.name)) { this.nameScope.Add(new KeyValuePair <string, SceneGraphNode>(child.name, child)); if (child.GetType() == typeof(ProtoInstance)) { ProtoInstance protoInstance = (ProtoInstance)child; KeyValuePair <string, SceneGraphNode> _value = this.nameScope.FirstOrDefault(n => n.Key == child.name); // slow if (_value.Value != null) { protoInstance.Prototype = (ProtoDeclare)_value.Value; } else { Console.WriteLine("[Warning] Could not immediatly find ProtoDeclare \"{0}\". Placing ProtoDeclare above ProtoInstance usually fixes this warning.", child.name); } } } if (child.GetType() == typeof(ProtoDeclare)) { child.Hidden = true; // Not renderable. child.PassthroughAllowed = false; // not considered part of the Runtime SceneGraph or EventGraph, // ProtoDeclare is only a SceneGraphStructureStatement. // Only ProtoInstance can access its ProtoDeclare // Events are not passed in to where the prototype is declared, // instead, ProtoInstance creates a new shadow-instance of the ProtoDeclare. // All the nodes under the proto declare are shadow-copied under the ProtoInstance // becoming part of the Scene Graph again as a new instance but managed explicitly by ProtoInstance. } #endregion child.PostDeserialization(); if (child.IsLeaf) { // BACKTRACK if (parent != null && parent.Children.Count - 1 == parent.Children.IndexOf(child)) { parent.PostDescendantDeserialization(); } } } #endregion #region Process Children if (hasChildren) { parent = child; children = xmlElem.node.Elements(); if (parent.IsLeaf == false && parent.Children.Count > 0) { foreach (SceneGraphNode ch in parent.Children) { foreach (SceneGraphNode sibling in parent.Children) { if (ch != sibling && ch.Siblings.Contains(sibling) == false) { ch.Siblings.Add(sibling); sibling.Siblings.Add(ch); } } } } for (i = 0; i < children.Count(); i++) { work_items.Enqueue(new _graph_node() { node = children.ElementAt(i), parent = parent }); } } #endregion } }