/// <summary>
        /// Handles the SurfaceObserver's OnSurfaceChanged event.
        /// </summary>
        /// <param name="id">The identifier assigned to the surface which has changed.</param>
        /// <param name="changeType">The type of change that occurred on the surface.</param>
        /// <param name="bounds">The bounds of the surface.</param>
        /// <param name="updateTime">The date and time at which the change occurred.</param>
        private void SurfaceObserver_OnSurfaceChanged(SurfaceId id, SurfaceChange changeType, Bounds bounds, DateTime updateTime)
        {
            // Verify that the client of the Surface Observer is expecting updates.
            if (ObserverState != ObserverStates.Running)
            {
                return;
            }

            switch (changeType)
            {
            case SurfaceChange.Added:
            case SurfaceChange.Updated:
                surfaceWorkQueue.Enqueue(id);
                break;

            case SurfaceChange.Removed:
                SurfaceObject?removedSurface = RemoveSurfaceIfFound(id.handle, destroyGameObject: false);
                if (removedSurface != null)
                {
                    ReclaimSurface(removedSurface.Value);
                }
                break;

            default:
                Debug.LogErrorFormat("Unexpected {0} value: {1}.", changeType.GetType(), changeType);
                break;
            }
        }
        /// <summary>
        /// Cleans up all memory and objects associated with the observer.
        /// </summary>
        public void CleanupObserver()
        {
#if UNITY_WSA
            StopObserving();

            if (observer != null)
            {
                observer.Dispose();
                observer = null;
            }

            if (outstandingMeshRequest != null)
            {
                CleanUpSurface(outstandingMeshRequest.Value);
                outstandingMeshRequest = null;
            }

            if (spareSurfaceObject != null)
            {
                CleanUpSurface(spareSurfaceObject.Value);
                spareSurfaceObject = null;
            }

            Cleanup();
#endif
        }
        /// <summary>
        /// Remove the first surface with the specified ID if one exists in <see cref="SurfaceObjects"/>.
        /// </summary>
        /// <param name="surfaceID">The ID of the surface to remove.</param>
        /// <param name="destroyGameObject">True to destroy the <see cref="SurfaceObject.Object"/> associated with the surface, false otherwise.</param>
        /// <param name="destroyMeshes">True to destroy the meshes associated with the surface, false otherwise.</param>
        /// <returns>The surface object if one was found and removed or null if one was not found.</returns>
        protected SurfaceObject?RemoveSurfaceIfFound(int surfaceID, bool destroyGameObject = true, bool destroyMeshes = true)
        {
            SurfaceObject?removed = null;

            for (int iSurface = 0; iSurface < surfaceObjectsWriteable.Count; iSurface++)
            {
                SurfaceObject surface = surfaceObjectsWriteable[iSurface];

                if (surface.ID == surfaceID)
                {
                    surfaceObjectsWriteable.RemoveAt(iSurface);

                    var handlers = SurfaceRemoved;
                    if (handlers != null)
                    {
                        handlers(this, DataEventArgs.Create(surface));
                    }

                    CleanUpSurface(surface, destroyGameObject, destroyMeshes);

                    removed = surface;
                    break;
                }
            }

            return(removed);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Handles the SurfaceObserver's OnSurfaceChanged event.
        /// </summary>
        /// <param name="id">The identifier assigned to the surface which has changed.</param>
        /// <param name="changeType">The type of change that occurred on the surface.</param>
        /// <param name="bounds">The bounds of the surface.</param>
        /// <param name="updateTime">The date and time at which the change occurred.</param>
        private void SurfaceObserver_OnSurfaceChanged(SurfaceId id, SurfaceChange changeType, Bounds bounds, DateTime updateTime)
        {
            var soundManager = GameObject.Find("Audio Source");

            HoloToolkit.Unity.TextToSpeech t2s = soundManager.GetComponent <HoloToolkit.Unity.TextToSpeech>();
            t2s.Voice = HoloToolkit.Unity.TextToSpeechVoice.Zira;
            t2s.StartSpeaking("Observer 1");
            // Verify that the client of the Surface Observer is expecting updates.
            if (ObserverState != ObserverStates.Running)
            {
                return;
            }

            switch (changeType)
            {
            case SurfaceChange.Added:
            case SurfaceChange.Updated:
                surfaceWorkQueue.Enqueue(id);
                break;

            case SurfaceChange.Removed:
                SurfaceObject?removedSurface = RemoveSurfaceIfFound(id.handle, destroyGameObject: false);
                if (removedSurface != null)
                {
                    ReclaimSurface(removedSurface.Value);
                }
                break;

            default:
                Debug.LogErrorFormat("Unexpected {0} value: {1}.", changeType.GetType(), changeType);
                break;
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Handles the SurfaceObserver's OnDataReady event.
        /// </summary>
        /// <param name="cookedData">Struct containing output data.</param>
        /// <param name="outputWritten">Set to true if output has been written.</param>
        /// <param name="elapsedCookTimeSeconds">Seconds between mesh cook request and propagation of this event.</param>
        private void SurfaceObserver_OnDataReady(SurfaceData cookedData, bool outputWritten, float elapsedCookTimeSeconds)
        {
            if (outstandingMeshRequest == null)
            {
                Debug.LogErrorFormat("Got OnDataReady for surface {0} while no request was outstanding.",
                                     cookedData.id.handle
                                     );

                return;
            }

            if (!IsMatchingSurface(outstandingMeshRequest.Value, cookedData))
            {
                Debug.LogErrorFormat("Got mismatched OnDataReady for surface {0} while request for surface {1} was outstanding.",
                                     cookedData.id.handle,
                                     outstandingMeshRequest.Value.ID
                                     );

                ReclaimSurface(outstandingMeshRequest.Value);
                outstandingMeshRequest = null;

                return;
            }

            if (ObserverState != ObserverStates.Running)
            {
                Debug.LogFormat("Got OnDataReady for surface {0}, but observer was no longer running.",
                                cookedData.id.handle
                                );

                ReclaimSurface(outstandingMeshRequest.Value);
                outstandingMeshRequest = null;

                return;
            }

            if (!outputWritten)
            {
                ReclaimSurface(outstandingMeshRequest.Value);
                outstandingMeshRequest = null;

                return;
            }

            Debug.Assert(outstandingMeshRequest.Value.Object.activeSelf);
            outstandingMeshRequest.Value.Renderer.enabled = SpatialMappingManager.Instance.DrawVisualMeshes;

            SurfaceObject?replacedSurface = UpdateOrAddSurfaceObject(outstandingMeshRequest.Value, destroyGameObjectIfReplaced: false);

            outstandingMeshRequest = null;

            if (replacedSurface != null)
            {
                ReclaimSurface(replacedSurface.Value);
            }
        }
Exemplo n.º 6
0
        /// <summary>
        /// Update the first surface with a matching ID if one exists in <see cref="SurfaceObjects"/>, otherwise add the surface as new.
        /// </summary>
        /// <param name="toUpdateOrAdd">The surface to be updated or added.</param>
        /// <param name="destroyGameObjectIfReplaced">If a surface is updated, and a game object is being replaced, pass true to destroy the outgoing game object or false otherwise.</param>
        /// <param name="destroyMeshesIfReplaced">If a surface is updated, and new meshes are replacing old meshes, pass true to destroy the outgoing meshes or false otherwise.</param>
        /// <returns>The surface object that was updated or null if one was not found meaning a new surface was added.</returns>
        protected SurfaceObject?UpdateOrAddSurfaceObject(SurfaceObject toUpdateOrAdd, SurfacePoints extras,
                                                         bool destroyGameObjectIfReplaced = true, bool destroyMeshesIfReplaced = true)
        {
            /*
             * // debug
             * Debug.Log(string.Format("Attempting to Add/Update surface to SMS. Wvertices Length: {0}, TriCount: {1}. " +
             *  "Currently, SurfaceObject Count: {2}, ExtraData Count: {3}",
             *  extras.Wvertices.Count, extras.TriangleCount, SurfaceObjects.Count, ExtraData.Count));
             */

            SurfaceObject?replaced = null;

            // verify correct material
            toUpdateOrAdd.Renderer.sharedMaterial = RenderMaterial;

            for (int iSurface = 0; iSurface < surfaceObjectsWriteable.Count; iSurface++)
            {
                SurfaceObject existing = surfaceObjectsWriteable[iSurface];

                if (existing.ID == toUpdateOrAdd.ID)
                {
                    surfaceObjectsWriteable[iSurface] = toUpdateOrAdd;
                    ExtraData[iSurface] = extras;

                    var handlers = SurfaceUpdated;
                    if (handlers != null)
                    {
                        handlers(this, DataEventArgs.Create(new SurfaceUpdate {
                            Old = existing, New = toUpdateOrAdd
                        }));
                    }

                    CleanUpSurface(
                        existing,
                        destroyGameObjectIfReplaced,
                        destroyMeshesIfReplaced,
                        objectToPreserve: toUpdateOrAdd.Object,
                        meshToPreserveA: toUpdateOrAdd.Filter.sharedMesh,
                        meshToPreserveB: toUpdateOrAdd.Collider.sharedMesh
                        );

                    replaced = existing;
                    break;
                }
            }

            if (replaced == null)
            {
                AddSurfaceObject(toUpdateOrAdd, extras);
            }

            return(replaced);
        }
        private void ReclaimSurface(SurfaceObject availableSurface)
        {
            if (spareSurfaceObject == null)
            {
                CleanUpSurface(availableSurface, destroyGameObject: false);

                availableSurface.Object.name = "Unused Surface";
                availableSurface.Object.SetActive(false);

                spareSurfaceObject = availableSurface;
            }
            else
            {
                CleanUpSurface(availableSurface);
            }
        }
        /// <summary>
        /// Update the first surface with a matching ID if one exists in <see cref="SurfaceObjects"/>, otherwise add the surface as new.
        /// </summary>
        /// <param name="toUpdateOrAdd">The surface to be updated or added.</param>
        /// <param name="destroyGameObjectIfReplaced">If a surface is updated, and a game object is being replaced, pass true to destroy the outgoing game object or false otherwise.</param>
        /// <param name="destroyMeshesIfReplaced">If a surface is updated, and new meshes are replacing old meshes, pass true to destroy the outgoing meshes or false otherwise.</param>
        /// <returns>The surface object that was updated or null if one was not found meaning a new surface was added.</returns>
        protected SurfaceObject?UpdateOrAddSurfaceObject(SurfaceObject toUpdateOrAdd, bool destroyGameObjectIfReplaced = true, bool destroyMeshesIfReplaced = true)
        {
            SurfaceObject?replaced = null;

            for (int iSurface = 0; iSurface < surfaceObjectsWriteable.Count; iSurface++)
            {
                SurfaceObject existing = surfaceObjectsWriteable[iSurface];

                if (existing.ID == toUpdateOrAdd.ID)
                {
                    surfaceObjectsWriteable[iSurface] = toUpdateOrAdd;

                    var handlers = SurfaceUpdated;
                    if (handlers != null)
                    {
                        handlers(this, DataEventArgs.Create(new SurfaceUpdate {
                            Old = existing, New = toUpdateOrAdd
                        }));
                    }

                    CleanUpSurface(
                        existing,
                        destroyGameObjectIfReplaced,
                        destroyMeshesIfReplaced,
                        objectToPreserve: toUpdateOrAdd.Object,
                        meshToPreserveA: toUpdateOrAdd.Filter.sharedMesh,
                        meshToPreserveB: toUpdateOrAdd.Collider.sharedMesh
                        );

                    replaced = existing;
                    break;
                }
            }

            if (replaced == null)
            {
                AddSurfaceObject(toUpdateOrAdd);
            }

            return(replaced);
        }
Exemplo n.º 9
0
        /// <summary>
        /// Handles the SurfaceObserver's OnSurfaceChanged event.
        /// </summary>
        /// <param name="id">The identifier assigned to the surface which has changed.</param>
        /// <param name="changeType">The type of change that occurred on the surface.</param>
        /// <param name="bounds">The bounds of the surface.</param>
        /// <param name="updateTime">The date and time at which the change occurred.</param>
        private void SurfaceObserver_OnSurfaceChanged(SurfaceId id, SurfaceChange changeType, Bounds bounds, DateTime updateTime)
        {
            // Verify that the client of the Surface Observer is expecting updates.
            if (ObserverState != ObserverStates.Running)
            {
                return;
            }

            switch (changeType)
            {
            /// Interestingly, surface is pushed to queue only when it's updated but not added.

            case SurfaceChange.Added:
                //Debug.Log(System.String.Format("SurfaceObserver_OnSurfaceChanged:    ADDED id: {0}", id));
                surfaceAddCount += 1;
                break;

            case SurfaceChange.Updated:
                if (!isSurfaceObsolete(id) || SpatialMappingManager.Instance.isSurfaceNearCamera(bounds))
                {
                    surfaceWorkQueue.Enqueue(id);
                    //Debug.Log(System.String.Format("SurfaceObserver_OnSurfaceChanged:    UPDATED id: {0}", id));
                    surfaceUpdateCount += 1;
                }
                break;

            case SurfaceChange.Removed:
                Debug.Log(System.String.Format("SurfaceObserver_OnSurfaceChanged:    REMOVED id: {0}", id));
                surfaceRemoveCount += 1;
                SurfaceObject?removedSurface = RemoveSurfaceIfFound(id.handle, destroyGameObject: false);
                if (removedSurface != null)
                {
                    ReclaimSurface(removedSurface.Value);
                }
                break;

            default:
                Debug.LogErrorFormat("Unexpected {0} value: {1}.", changeType.GetType(), changeType);
                break;
            }
        }
Exemplo n.º 10
0
        /// <summary>
        /// Handles the SurfaceObserver's OnDataReady event.
        /// </summary>
        /// <param name="cookedData">Struct containing output data.</param>
        /// <param name="outputWritten">Set to true if output has been written.</param>
        /// <param name="elapsedCookTimeSeconds">Seconds between mesh cook request and propagation of this event.</param>
        private void SurfaceObserver_OnDataReady(SurfaceData cookedData, bool outputWritten, float elapsedCookTimeSeconds)
        {
            if (outstandingMeshRequest == null)
            {
                Debug.LogErrorFormat("Got OnDataReady for surface {0} while no request was outstanding.",
                                     cookedData.id.handle
                                     );

                return;
            }

            if (!IsMatchingSurface(outstandingMeshRequest.Value, cookedData))
            {
                Debug.LogErrorFormat("Got mismatched OnDataReady for surface {0} while request for surface {1} was outstanding.",
                                     cookedData.id.handle,
                                     outstandingMeshRequest.Value.ID
                                     );

                ReclaimSurface(outstandingMeshRequest.Value);
                outstandingMeshRequest = null;

                return;
            }

            if (ObserverState != ObserverStates.Running)
            {
                Debug.LogFormat("Got OnDataReady for surface {0}, but observer was no longer running.",
                                cookedData.id.handle
                                );

                ReclaimSurface(outstandingMeshRequest.Value);
                outstandingMeshRequest = null;

                return;
            }

            if (!outputWritten)
            {
                ReclaimSurface(outstandingMeshRequest.Value);
                outstandingMeshRequest = null;

                return;
            }

            Debug.Assert(outstandingMeshRequest.Value.Object.activeSelf);

            // alters properites of mesh as desired: first sets renderer enabled field
            outstandingMeshRequest.Value.Renderer.enabled = SpatialMappingManager.Instance.DrawVisualMeshes;

            // create extra data
            SurfaceObject tmpSO        = outstandingMeshRequest.Value;
            Transform     tmpTransform = tmpSO.Renderer.transform;
            // Wvertices
            List <Vector3> tmpWvertices = tmpSO.Filter.sharedMesh.vertices.ToList();

            for (int i = 0; i < tmpWvertices.Count; i++)
            {
                tmpWvertices[i] = tmpTransform.TransformPoint(tmpWvertices[i]);
            }
            // TriCount
            int tmpTriCount = tmpSO.Filter.sharedMesh.triangles.ToList().Count;
            // SurfacePoints obj
            SurfacePoints extras = new SurfacePoints(
                MeshManager.IntersectionPoints(outstandingMeshRequest.Value.Renderer.bounds), tmpWvertices,
                tmpTriCount, tmpSO.Renderer.bounds, cookedData.trianglesPerCubicMeter);

            // updates/adds mesh in source stored list of SurfaceObjects.
            SurfaceObject?replacedSurface = UpdateOrAddSurfaceObject(outstandingMeshRequest.Value, extras, destroyGameObjectIfReplaced: false);

            outstandingMeshRequest = null;

            if (replacedSurface != null)
            {
                ReclaimSurface(replacedSurface.Value);
            }
        }
Exemplo n.º 11
0
        /// <summary>
        /// Called once per frame.
        /// </summary>
        private void Update()
        {
            if ((ObserverState == ObserverStates.Running) && (outstandingMeshRequest == null))
            {
                if (needRebake)
                {
                    CallForRebake(density);
                }

                if (surfaceWorkQueue.Count > 0)
                {
                    // We're using a simple first-in-first-out rule for requesting meshes, but a more sophisticated algorithm could prioritize
                    // the queue based on distance to the user or some other metric.
                    SurfaceId surfaceID = surfaceWorkQueue.Dequeue();

                    string surfaceName = ("Surface-" + surfaceID.handle);

                    SurfaceObject newSurface;
                    WorldAnchor   worldAnchor;

                    if (spareSurfaceObject == null)
                    {
                        newSurface = CreateSurfaceObject(
                            mesh: null,
                            objectName: surfaceName,
                            parentObject: transform,
                            meshID: surfaceID.handle,
                            drawVisualMeshesOverride: false
                            );

                        worldAnchor = newSurface.Object.AddComponent <WorldAnchor>();
                    }
                    else
                    {
                        newSurface         = spareSurfaceObject.Value;
                        spareSurfaceObject = null;

                        Debug.Assert(!newSurface.Object.activeSelf);
                        newSurface.Object.SetActive(true);

                        Debug.Assert(newSurface.Filter.sharedMesh == null);
                        Debug.Assert(newSurface.Collider.sharedMesh == null);
                        newSurface.Object.name = surfaceName;
                        Debug.Assert(newSurface.Object.transform.parent == transform);
                        newSurface.ID = surfaceID.handle;
                        newSurface.Renderer.enabled = false;

                        worldAnchor = newSurface.Object.GetComponent <WorldAnchor>();
                        Debug.Assert(worldAnchor != null);
                    }

                    /*
                     * // Debug
                     * Debug.Log(string.Format("Requesting baking of Mesh {0} at Density {1}", surfaceID, Density));
                     */

                    var surfaceData = new SurfaceData(
                        surfaceID,
                        newSurface.Filter,
                        worldAnchor,
                        newSurface.Collider,
                        Density,
                        _bakeCollider: true
                        );

                    if (observer.RequestMeshAsync(surfaceData, SurfaceObserver_OnDataReady))
                    {
                        outstandingMeshRequest = newSurface;
                    }
                    else
                    {
                        Debug.LogErrorFormat("Mesh request for failed. Is {0} a valid Surface ID?", surfaceID.handle);

                        Debug.Assert(outstandingMeshRequest == null);
                        ReclaimSurface(newSurface);
                    }
                }
                else if ((Time.unscaledTime - updateTime) >= timeBetweenUpdates)
                {
                    observer.Update(SurfaceObserver_OnSurfaceChanged);
                    updateTime = Time.unscaledTime;
                }
            }
        }