// Lock the node dictionary, and rebuild the static // geometry for objects of this kind protected void Rebuild(SceneManager mgr, Dictionary <long, WorldEntity> nodeDictionary) { log.DebugFormat("Entering StaticGeometryHelper.Rebuild for geometry '{0}'", name); long tickStart = TimeTool.CurrentTime; try { nodesAddedSinceLastRebuild = 0; nodesRemovedSinceLastRebuild = 0; force = false; Monitor.Enter(mgr); if (objectGeometry != null) { objectGeometry.Reset(); } else { objectGeometry = new StaticGeometry(mgr, name); } // Dictionary mapping Material into a list of // ObjectNodes in which some submesh uses the material Dictionary <Material, MaterialAndNodeCounts> materialsUsedMap = new Dictionary <Material, MaterialAndNodeCounts>(); lock (nodeDictionary) { foreach (WorldEntity entity in nodeDictionary.Values) { if (entity is ObjectNode) { ObjectNode node = (ObjectNode)entity; // For now, we only consider "props" that have an associated SceneNode // and are direct descendants of the root scene node, and are of the right // kind, i.e., don't have a perception radius if this static geometry is for // little nodes, and vice versa. // log.DebugFormat("StaticGeometry.Rebuild: Examining node {0}, oid {1}, type {2}, sceneNode {3}, InStaticGeometry {4}, top-level {5}", // node.Name, node.Oid, node.ObjectType, node.SceneNode, node.InStaticGeometry, node.SceneNode.Parent == mgr.RootSceneNode); if (node.ObjectType == ObjectNodeType.Prop && (node.InStaticGeometry || (node.SceneNode != null && node.SceneNode.Parent == mgr.RootSceneNode)) && RightKind(node)) { foreach (Material m in node.Entity.SubEntityMaterials) { MaterialAndNodeCounts nodesUsingMaterial; if (!materialsUsedMap.TryGetValue(m, out nodesUsingMaterial)) { nodesUsingMaterial = new MaterialAndNodeCounts(); materialsUsedMap[m] = nodesUsingMaterial; } nodesUsingMaterial.materialUseCount++; int subMeshUseCount; Dictionary <ObjectNode, int> submeshUseCounts = nodesUsingMaterial.submeshUseCounts; if (!submeshUseCounts.TryGetValue(node, out subMeshUseCount)) { submeshUseCounts[node] = 1; } else { submeshUseCounts[node] = subMeshUseCount + 1; } } } } } } // Now we have a count of uses of each material, and // for each node, the number of subentities that use the // material. Now we need to calculate the number of // instance of sharings for each object node Dictionary <ObjectNode, bool> candidateNodes = new Dictionary <ObjectNode, bool>(); foreach (MaterialAndNodeCounts counts in materialsUsedMap.Values) { if (counts.materialUseCount > 1) { foreach (KeyValuePair <ObjectNode, int> pair in counts.submeshUseCounts) { candidateNodes[pair.Key] = true; } } } Dictionary <ObjectNode, int> staticNodes = new Dictionary <ObjectNode, int>(); foreach (KeyValuePair <ObjectNode, bool> pair in candidateNodes) { ObjectNode candidate = pair.Key; bool useIt = pair.Value; if (useIt) { staticNodes[candidate] = 0; } } if (staticNodes.Count == 0) { log.InfoFormat("StaticGeometryHelper.Rebuild: Didn't build static geometry {0} because object count was zero", name); } else { log.InfoFormat("StaticGeometryHelper.Rebuild: {0} ObjectNodes", staticNodes.Count); foreach (ObjectNode staticNode in staticNodes.Keys) { SceneNode sc = staticNode.SceneNode; if (!staticNode.InStaticGeometry) { sc.RemoveFromParent(); staticNode.InStaticGeometry = true; } log.DebugFormat("StaticGeometryHelper.Rebuild: Add node {0} with name {1} to static geometry", staticNode.Oid, staticNode.Name); objectGeometry.AddSceneNode(sc); } } if (lastStaticNodes != null) { foreach (ObjectNode node in lastStaticNodes.Keys) { if (!staticNodes.ContainsKey(node)) { // Only 1 instance of the mesh, so make sure that if in a former build it was in // static geometry, that we add it back to the scene graph. if (node.InStaticGeometry) { SceneNode sn = node.SceneNode; if (sn != null) { mgr.RootSceneNode.AddChild(sn); } node.InStaticGeometry = false; } } } } if (staticNodes.Count > 0) { objectGeometry.Build(); } lastStaticNodes = staticNodes; timeOfLastRebuild = TimeTool.CurrentTime; } finally { Monitor.Exit(mgr); } log.InfoFormat("StaticGeometryHelper.Rebuild: Rebuild of geometry '{0}' took {1} ms", name, TimeTool.CurrentTime - tickStart); }
// Lock the node dictionary, and rebuild the static // geometry for objects of this kind protected void Rebuild(SceneManager mgr, Dictionary<long, WorldEntity> nodeDictionary) { log.DebugFormat("Entering StaticGeometryHelper.Rebuild for geometry '{0}'", name); long tickStart = TimeTool.CurrentTime; try { nodesAddedSinceLastRebuild = 0; nodesRemovedSinceLastRebuild = 0; force = false; Monitor.Enter(mgr); if (objectGeometry != null) objectGeometry.Reset(); else objectGeometry = new StaticGeometry(mgr, name); // Dictionary mapping Material into a list of // ObjectNodes in which some submesh uses the material Dictionary<Material, MaterialAndNodeCounts> materialsUsedMap = new Dictionary<Material, MaterialAndNodeCounts>(); lock(nodeDictionary) { foreach (WorldEntity entity in nodeDictionary.Values) { if (entity is ObjectNode) { ObjectNode node = (ObjectNode)entity; // For now, we only consider "props" that have an associated SceneNode // and are direct descendants of the root scene node, and are of the right // kind, i.e., don't have a perception radius if this static geometry is for // little nodes, and vice versa. // log.DebugFormat("StaticGeometry.Rebuild: Examining node {0}, oid {1}, type {2}, sceneNode {3}, InStaticGeometry {4}, top-level {5}", // node.Name, node.Oid, node.ObjectType, node.SceneNode, node.InStaticGeometry, node.SceneNode.Parent == mgr.RootSceneNode); if (node.ObjectType == ObjectNodeType.Prop && (node.InStaticGeometry || (node.SceneNode != null && node.SceneNode.Parent == mgr.RootSceneNode)) && RightKind(node)) { foreach (Material m in node.Entity.SubEntityMaterials) { MaterialAndNodeCounts nodesUsingMaterial; if (!materialsUsedMap.TryGetValue(m, out nodesUsingMaterial)) { nodesUsingMaterial = new MaterialAndNodeCounts(); materialsUsedMap[m] = nodesUsingMaterial; } nodesUsingMaterial.materialUseCount++; int subMeshUseCount; Dictionary<ObjectNode, int> submeshUseCounts = nodesUsingMaterial.submeshUseCounts; if (!submeshUseCounts.TryGetValue(node, out subMeshUseCount)) submeshUseCounts[node] = 1; else submeshUseCounts[node] = subMeshUseCount + 1; } } } } } // Now we have a count of uses of each material, and // for each node, the number of subentities that use the // material. Now we need to calculate the number of // instance of sharings for each object node Dictionary<ObjectNode, bool> candidateNodes = new Dictionary<ObjectNode, bool>(); foreach (MaterialAndNodeCounts counts in materialsUsedMap.Values) { if (counts.materialUseCount > 1) { foreach (KeyValuePair<ObjectNode, int> pair in counts.submeshUseCounts) candidateNodes[pair.Key] = true; } } Dictionary<ObjectNode, int> staticNodes = new Dictionary<ObjectNode, int>(); foreach (KeyValuePair<ObjectNode, bool> pair in candidateNodes) { ObjectNode candidate = pair.Key; bool useIt = pair.Value; if (useIt) staticNodes[candidate] = 0; } if (staticNodes.Count == 0) log.InfoFormat("StaticGeometryHelper.Rebuild: Didn't build static geometry {0} because object count was zero", name); else { log.InfoFormat("StaticGeometryHelper.Rebuild: {0} ObjectNodes", staticNodes.Count); foreach(ObjectNode staticNode in staticNodes.Keys) { SceneNode sc = staticNode.SceneNode; if (!staticNode.InStaticGeometry) { sc.RemoveFromParent(); staticNode.InStaticGeometry = true; } log.DebugFormat("StaticGeometryHelper.Rebuild: Add node {0} with name {1} to static geometry", staticNode.Oid, staticNode.Name); objectGeometry.AddSceneNode(sc); } } if (lastStaticNodes != null) { foreach(ObjectNode node in lastStaticNodes.Keys) { if (!staticNodes.ContainsKey(node)) { // Only 1 instance of the mesh, so make sure that if in a former build it was in // static geometry, that we add it back to the scene graph. if (node.InStaticGeometry) { SceneNode sn = node.SceneNode; if (sn != null) mgr.RootSceneNode.AddChild(sn); node.InStaticGeometry = false; } } } } if (staticNodes.Count > 0) objectGeometry.Build(); lastStaticNodes = staticNodes; timeOfLastRebuild = TimeTool.CurrentTime; } finally { Monitor.Exit(mgr); } log.InfoFormat("StaticGeometryHelper.Rebuild: Rebuild of geometry '{0}' took {1} ms", name, TimeTool.CurrentTime - tickStart); }