private void ProcessPendingUpdates() { // We must be called in edit lock var timer = System.Diagnostics.Stopwatch.StartNew(); // Measure time precise in update #region Dynamic Loading/Add/Remove native handles --------------------------------------------------------------- Performance.Enter("PendNative"); foreach (NodeLoadInfo nodeLoadInfo in pendingLoaders) { if (nodeLoadInfo.state == DynamicLoadingState.LOADED) // We got a callback from dyn loader that we were loaded or unloaded { unTransform transform = NodeUtils.FindFirstGameObjectTransform(nodeLoadInfo.loader.GetNativeReference()); if (transform == null) // We have been unloaded or not registered { continue; } if (transform.childCount != 0) // We have already a child and our sub graph was loaded { continue; } GameObject go = Traverse(nodeLoadInfo.node, null); // Build sub graph if (go != null) { go.transform.SetParent(transform, false); // Connect to our parent } } else if (nodeLoadInfo.state == DynamicLoadingState.UNLOADED) { List <GameObject> list; if (NodeUtils.FindGameObjects(nodeLoadInfo.loader.GetNativeReference(), out list)) { foreach (GameObject go in list) { foreach (unTransform child in go.transform) //We need to unload all limked go in hierarchy { RemoveGameObjectHandles(child.gameObject); GameObject.Destroy(child.gameObject); } } } } } pendingLoaders.Clear(); Performance.Leave(); #endregion #region Activate/Deactivate GameObjects based on scenegraph ----------------------------------------------------- Performance.Enter("PendActGO"); foreach (ActivationInfo activationInfo in pendingActivations) { List <GameObject> list; // We need to activate the correct nodes if (NodeUtils.FindGameObjects(activationInfo.node.GetNativeReference(), out list)) { foreach (GameObject obj in list) { if (activationInfo.state == NodeActionEvent.IS_TRAVERSABLE) { obj.SetActive(true); } else { obj.SetActive(false); } } } } pendingActivations.Clear(); Performance.Leave(); #endregion #region Update slow loading assets ------------------------------------------------------------------------------ Performance.Enter("PendSlow"); while (pendingBuilds.Count > 0 && timer.Elapsed.TotalSeconds < Settings.MaxBuildTime) { NodeHandle handle = pendingBuilds.Dequeue(); handle.BuildGameObject(); } Performance.Leave(); #endregion // Right now we use this as a dirty fix to handle unused shared materials _unusedCounter = (_unusedCounter + 1) % Settings.FrameCleanupInterval; if (_unusedCounter == 0) { Performance.Enter("PendCleanup"); Resources.UnloadUnusedAssets(); Performance.Leave(); } }
// TODO: Make functions... public bool Build(NodeHandle nodeHandle, GameObject gameObject, NodeHandle activeStateNode) { var node = nodeHandle.node; var cb = node as Crossboard; if (cb == null) { return(false); } float[] position_data; if (!cb.GetObjectPositions(out position_data)) { return(false); } float[] object_data; if (!cb.GetObjectData(out object_data)) { return(false); } var objects = position_data.Length / 3; // Number of objects // NOTE: CrossboardDatasets are copied to compute buffers when assigning the dataset, // thus we can reuse same dataset objects to reduce GC pressure if needed. CrossboardDataset dataset = new CrossboardDataset(); dataset.POSITION = new Vector3[objects]; dataset.UV0ListComp = new List <Vector4>(objects); dataset.UV1ListComp = new List <Vector4>(objects); dataset.COLOR = new Color[objects]; var float3_index = 0; var float4_index = 0; for (var i = 0; i < objects; i++) { dataset.POSITION[i] = new Vector3(position_data[float3_index], position_data[float3_index + 1], position_data[float3_index + 2]); // size, heading, pitch, roll dataset.UV0ListComp.Add(new Vector4(object_data[float4_index] * 2f, object_data[float4_index + 1], object_data[float4_index + 2], object_data[float4_index + 3])); // postion offset (x - its up normal), planes offset ( xyz - in there normal direction) dataset.UV1ListComp.Add(new Vector4(-0.02f, 0, 0, 0)); float3_index += 3; float4_index += 4; } // Shouldnt this be our settings? if (cb.UseColors) { float[] color_data; if (!cb.GetColorData(out color_data)) { return(false); } float4_index = 0; var colors = new Color[objects]; for (int i = 0; i < objects; i++) { colors[i] = new Color(color_data[float4_index], color_data[float4_index + 1], color_data[float4_index + 2], color_data[float4_index + 3]); float4_index += 4; } dataset.COLOR = colors; } var renderer = gameObject.GetComponent <CrossboardRenderer_ComputeShader>(); if (renderer == null) { renderer = gameObject.AddComponent <CrossboardRenderer_ComputeShader>(); renderer.OpaqueCrossboardCompute = true; renderer._computeShader = GameObject.Instantiate(_computeShader); } var material = GameObject.Instantiate(_crossboardMaterial); // check if the texture is loaded for this state, otherwise load it if (activeStateNode != null) { if ((activeStateNode.stateLoadInfo & StateLoadInfo.Texture) == StateLoadInfo.None) { var state = activeStateNode.node.State; if (!StateHelper.Build(state, out StateBuildOutput buildOutput, _textureCache)) { return(false); } activeStateNode.stateLoadInfo |= StateLoadInfo.Texture; activeStateNode.texture = buildOutput.Texture; } material.mainTexture = activeStateNode.texture; } renderer.SetCrossboardDataset(dataset, material); return(true); }
//Add GameObjects to dictionary // Traverse function iterates the scene graph to build local branches on Unity GameObject Traverse(Node n, Material currentMaterial) { // We must be called in edit lock if (n == null || !n.IsValid()) { return(null); } // --------------------------- Add game object --------------------------------------- string name = n.GetName(); if (String.IsNullOrEmpty(name)) { name = n.GetNativeTypeName(); } GameObject gameObject = new GameObject(name); var nodeHandle = gameObject.AddComponent <NodeHandle>(); //nodeHandle.Renderer = Renderer; nodeHandle.node = n; nodeHandle.currentMaterial = currentMaterial; nodeHandle.ComputeShader = Settings.ComputeShader; // ---------------------------- Check material state ---------------------------------- if (n.HasState()) { State state = n.State; if (state.HasTexture(0) && state.GetMode(StateMode.TEXTURE) == StateModeActivation.ON) { gzTexture texture = state.GetTexture(0); if (!textureMaterialStorage.TryGetValue(texture.GetNativeReference(), out currentMaterial)) { if (texture.HasImage()) { ImageFormat image_format; ComponentType comp_type; uint components; uint depth; uint width; uint height; uint size; bool uncompress = false; Image image = texture.GetImage(); image_format = image.GetFormat(); image.Dispose(); switch (image_format) // Not yet { case ImageFormat.COMPRESSED_RGBA8_ETC2: if (!SystemInfo.SupportsTextureFormat(TextureFormat.ETC2_RGBA8)) { uncompress = true; } break; case ImageFormat.COMPRESSED_RGB8_ETC2: if (!SystemInfo.SupportsTextureFormat(TextureFormat.ETC2_RGB)) { uncompress = true; } break; case ImageFormat.COMPRESSED_RGBA_S3TC_DXT1: case ImageFormat.COMPRESSED_RGB_S3TC_DXT1: if (!SystemInfo.SupportsTextureFormat(TextureFormat.DXT1)) { uncompress = true; } break; case ImageFormat.COMPRESSED_RGBA_S3TC_DXT5: if (!SystemInfo.SupportsTextureFormat(TextureFormat.DXT5)) { uncompress = true; } break; } if (texture.GetMipMapImageArray(ref _image_texture_data, out size, out image_format, out comp_type, out components, out width, out height, out depth, true, uncompress)) { if (depth == 1) { if (n is Crossboard) { currentMaterial = new Material(Settings.CrossboardShader); } else { currentMaterial = new Material(Settings.DefaultShader); } TextureFormat format = TextureFormat.ARGB32; switch (comp_type) { case ComponentType.UNSIGNED_BYTE: { switch (image_format) { case ImageFormat.RGBA: format = TextureFormat.RGBA32; break; case ImageFormat.RGB: format = TextureFormat.RGB24; break; case ImageFormat.COMPRESSED_RGBA_S3TC_DXT1: case ImageFormat.COMPRESSED_RGB_S3TC_DXT1: format = TextureFormat.DXT1; break; case ImageFormat.COMPRESSED_RGBA_S3TC_DXT5: format = TextureFormat.DXT5; break; case ImageFormat.COMPRESSED_RGB8_ETC2: format = TextureFormat.ETC2_RGB; break; case ImageFormat.COMPRESSED_RGBA8_ETC2: format = TextureFormat.ETC2_RGBA8; break; default: // Issue your own error here because we can not use this texture yet return(null); } } break; default: // Issue your own error here because we can not use this texture yet return(null); } Texture2D tex = new Texture2D((int)width, (int)height, format, true); tex.LoadRawTextureData(_image_texture_data); switch (texture.MinFilter) { default: tex.filterMode = FilterMode.Point; break; case gzTexture.TextureMinFilter.LINEAR: case gzTexture.TextureMinFilter.LINEAR_MIPMAP_NEAREST: tex.filterMode = FilterMode.Bilinear; break; case gzTexture.TextureMinFilter.LINEAR_MIPMAP_LINEAR: tex.filterMode = FilterMode.Trilinear; break; } tex.Apply(texture.UseMipMaps, true); currentMaterial.mainTexture = tex; } } } // Add some kind of check for textures shared by many // Right now only for crossboards if (n is Crossboard) { textureMaterialStorage.Add(texture.GetNativeReference(), currentMaterial); } } nodeHandle.currentMaterial = currentMaterial; texture.Dispose(); } state.Dispose(); } // ---------------------------- Transform check ------------------------------------- gzTransform tr = n as gzTransform; if (tr != null) { Vec3 translation; if (tr.GetTranslation(out translation)) { Vector3 trans = new Vector3(translation.x, translation.y, translation.z); gameObject.transform.localPosition = trans; } // Notify subscribers of new Transform OnNewTransform?.Invoke(gameObject); } // ---------------------------- DynamicLoader check ------------------------------------- DynamicLoader dl = n as DynamicLoader; // Add dynamic loader as game object in dictionary // so other dynamic loaded data can parent them as child to loader if (dl != null) { List <GameObject> list; if (!NodeUtils.FindGameObjects(dl.GetNativeReference(), out list)) // We are not registered { NodeUtils.AddGameObjectReference(dl.GetNativeReference(), gameObject); nodeHandle.inNodeUtilsRegistry = true; // Added to registry // We shall continue to iterate as a group to see if we already have loaded children } else // We are already in list { return(list[0]); // Lets return first object wich is our main registered node } // Notify subscribers of new Loader OnNewLoader?.Invoke(gameObject); } // ---------------------------- Lod check ------------------------------------- Lod ld = n as Lod; if (ld != null) { foreach (Node child in ld) { GameObject go_child = Traverse(child, currentMaterial); if (go_child == null) { return(null); } NodeHandle h = go_child.GetComponent <NodeHandle>(); if (h != null) { if (!NodeUtils.HasGameObjects(h.node.GetNativeReference())) { NodeUtils.AddGameObjectReference(h.node.GetNativeReference(), go_child); h.inNodeUtilsRegistry = true; h.node.AddActionInterface(_actionReceiver, NodeActionEvent.IS_TRAVERSABLE); h.node.AddActionInterface(_actionReceiver, NodeActionEvent.IS_NOT_TRAVERSABLE); } } go_child.transform.SetParent(gameObject.transform, false); } // Notify subscribers of new Lod OnNewLod?.Invoke(gameObject); // Dont process group as group is already processed return(gameObject); } // ---------------------------- Roi check ------------------------------------- Roi roi = n as Roi; if (roi != null) { nodeHandle.updateTransform = true; nodeHandle.inNodeUpdateList = true; updateNodeObjects.AddLast(gameObject); foreach (Node child in roi) { GameObject go_child = Traverse(child, currentMaterial); if (go_child == null) { return(null); } NodeHandle h = go_child.GetComponent <NodeHandle>(); if (h != null) { if (!NodeUtils.HasGameObjects(h.node.GetNativeReference())) { NodeUtils.AddGameObjectReference(h.node.GetNativeReference(), go_child); h.inNodeUtilsRegistry = true; h.node.AddActionInterface(_actionReceiver, NodeActionEvent.IS_TRAVERSABLE); h.node.AddActionInterface(_actionReceiver, NodeActionEvent.IS_NOT_TRAVERSABLE); } } go_child.transform.SetParent(gameObject.transform, false); } // Dont process group return(gameObject); } // ---------------------------- RoiNode check ------------------------------------- RoiNode roinode = n as RoiNode; if (roinode != null) { nodeHandle.updateTransform = true; nodeHandle.inNodeUpdateList = true; updateNodeObjects.AddLast(gameObject); } // ---------------------------- Group check ------------------------------------- Group g = n as Group; if (g != null) { foreach (Node child in g) { GameObject go_child = Traverse(child, currentMaterial); if (go_child == null) { return(null); } go_child.transform.SetParent(gameObject.transform, false); } return(gameObject); } // ---------------------------ExtRef check ----------------------------------------- ExtRef ext = n as ExtRef; if (ext != null) { AssetLoadInfo info = new AssetLoadInfo(gameObject, ext.ResourceURL, ext.ObjectID); pendingAssetLoads.Push(info); } // ---------------------------- Crossboard check ----------------------------------- Crossboard cb = n as Crossboard; if (cb != null && GfxCaps.HasCapability(Capability.UseTreeCrossboards)) { // Scheduled for later build pendingBuilds.Enqueue(nodeHandle); } // ---------------------------- Geometry check ------------------------------------- Geometry geom = n as Geometry; if (geom != null) { nodeHandle.BuildGameObject(); // Notify subscribers of new Geometry OnNewGeometry?.Invoke(gameObject); // Later on we will identify types of geoemtry that will be scheduled later if they are extensive and not ground that covers other geometry // and build them in a later pass distributed over time // pendingBuilds.Enqueue(nodeHandle); } return(gameObject); }
private GameObject TraverseInternal(Node node, NodeHandle activeStateNode) { // We must be called in edit lock System.Diagnostics.Debug.Assert(node != null && node.IsValid()); // --------------------------- Add game object --------------------------------------- NodeHandle nodeHandle; var builder = GetBuilderForNode(node); if (builder == null) { nodeHandle = CreateNodeHandle(node, PoolObjectFeature.None); // check for new active state if (node.HasState()) { activeStateNode = nodeHandle; } } else { nodeHandle = CreateNodeHandle(node, builder.Feature); // check for new active state if (node.HasState()) { activeStateNode = nodeHandle; } // build gameobjects for this node BuildNode(builder, nodeHandle, activeStateNode); } var gameObject = nodeHandle.gameObject; // ---------------------------- Transform check ------------------------------------- if (node is gzTransform tr) { try { Performance.Enter("SM.Traverse.Transform"); ProcessTransformNode(tr, gameObject.transform); Performance.Enter("SM.Traverse.OnNewTransform"); // Notify subscribers of new Transform OnNewTransform?.Invoke(gameObject); Performance.Leave(); } finally { Performance.Leave(); } } // ---------------------------- DynamicLoader check ------------------------------------- // Add dynamic loader as game object in dictionary // so other dynamic loaded data can parent them as child to loader if (node is DynamicLoader dl) { try { Performance.Enter("SM.Traverse.Loader"); var res = ProcessDynamicLoaderNode(dl, nodeHandle); if (res != null) { return(res); } // We shall continue to iterate as a group to see if we already have loaded children Performance.Enter("SM.Traverse.OnNewLoader"); // Notify subscribers of new Loader OnNewLoader?.Invoke(gameObject); Performance.Leave(); } finally { Performance.Leave(); } } // ---------------------------- Lod check ------------------------------------- if (node is Lod ld) { ProcessLodNode(ld, nodeHandle, activeStateNode); Performance.Enter("SM.Traverse.OnNewLod"); // Notify subscribers of new Lod OnNewLod?.Invoke(gameObject); Performance.Leave(); // Dont process group as group is already processed return(gameObject); } // ---------------------------- Roi check ------------------------------------- if (node is Roi roi) { ProcessRoiNode(roi, nodeHandle, activeStateNode); // Dont process group as group is already processed return(gameObject); } // ---------------------------- RoiNode check ------------------------------------- if (node is RoiNode) { RegisterNodeForUpdate(nodeHandle); } // ---------------------------- Group check ------------------------------------- if (node is Group g) { ProcessGroup(g, nodeHandle, activeStateNode); return(gameObject); } // ---------------------------ExtRef check ----------------------------------------- if (node is ExtRef extRef) { var info = new AssetLoadInfo(gameObject, extRef.ResourceURL, extRef.ObjectID); pendingAssetLoads.Push(info); } // ---------------------------- Geometry check ------------------------------------- if (node is Geometry geom) { OnNewGeometry?.Invoke(gameObject); } return(gameObject); }
private void RegisterNodeForUpdate(NodeHandle nodeHandle) { nodeHandle.updateTransform = true; nodeHandle.inNodeUpdateList = true; updateNodeObjects.AddLast(nodeHandle.gameObject); }
private void ProcessRoiNode(Roi node, NodeHandle nodeHandle, NodeHandle activeStateNode) { RegisterNodeForUpdate(nodeHandle); ProcessGroup(node, nodeHandle, activeStateNode, true); }
private void ProcessLodNode(Lod node, NodeHandle nodeHandle, NodeHandle activeStateNode) { ProcessGroup(node, nodeHandle, activeStateNode, true); }