- // Copyright (c) Microsoft Corporation. All rights reserved.
- // Licensed under the MIT License. See LICENSE in the project root for license information.
-
- using System;
- using System.Collections.Generic;
- using System.IO;
- #if UNITY_EDITOR || UNITY_STANDALONE_WIN
- using System.Net;
- using System.Net.Sockets;
- #endif
- using UnityEngine;
-
- namespace HoloToolkit.Unity.SpatialMapping
- {
- /// <summary>
- /// RemoteMeshTarget will listen for meshes being sent from a remote system (HoloLens).
- /// It is intended to run in the Unity Editor with exactly one
- /// HoloLens device sending data.
- /// </summary>
- public class RemoteMeshTarget : SpatialMappingSource
- {
- [Tooltip("The IPv4 Address of the machine running the Unity editor.")]
- public string ServerIP;
-
- [Tooltip("The connection port on the machine to use.")]
- public int ConnectionPort = 11000;
-
- #if UNITY_EDITOR || UNITY_STANDALONE_WIN
- /// <summary>
- /// Listens for network connections over TCP.
- /// </summary>
- private TcpListener networkListener;
-
- /// <summary>
- /// Keeps client information when a connection happens.
- /// </summary>
- private TcpClient networkClient;
-
- /// <summary>
- /// Tracks if a client is connected.
- /// </summary>
- private bool clientConnected;
-
- // Use this for initialization.
- private void Start()
- {
- // Setup the network listener.
- IPAddress localAddr = IPAddress.Parse(ServerIP.Trim());
- networkListener = new TcpListener(localAddr, ConnectionPort);
- networkListener.Start();
-
- // Request the network listener to wait for connections asynchronously.
- AsyncCallback callback = OnClientConnect;
- networkListener.BeginAcceptTcpClient(callback, this);
- }
-
- // Update is called once per frame.
- private void Update()
- {
- // If we have a connected client, presumably the client wants to send some meshes.
- if (clientConnected)
- {
- // Get the clients stream.
- NetworkStream stream = networkClient.GetStream();
-
- // Make sure there is data in the stream.
- if (stream.DataAvailable)
- {
- // The first 4 bytes will be the size of the data containing the mesh(es).
- int datasize = ReadInt(stream);
-
- // Allocate a buffer to hold the data.
- byte[] dataBuffer = new byte[datasize];
-
- // Read the data.
- // The data can come in chunks.
- int readsize = 0;
-
- while (readsize != datasize)
- {
- readsize += stream.Read(dataBuffer, readsize, datasize - readsize);
- }
-
- if (readsize != datasize)
- {
- Debug.Log("reading mesh failed: " + readsize + " != " + datasize);
- }
-
- // Pass the data to the mesh serializer.
- List<Mesh> meshes = new List<Mesh>(SimpleMeshSerializer.Deserialize(dataBuffer));
-
- if (meshes.Count > 0)
- {
- // Use the network-based mapping source to receive meshes in the Unity editor.
- SpatialMappingManager.Instance.SetSpatialMappingSource(this);
- }
-
- // For each mesh, create a GameObject to render it.
- for (int index = 0; index < meshes.Count; index++)
- {
- int meshID = SurfaceObjects.Count;
-
- SurfaceObject surface = CreateSurfaceObject(
- mesh: meshes[index],
- objectName: "Beamed-" + meshID,
- parentObject: transform,
- meshID: meshID
- );
-
- surface.Object.transform.parent = SpatialMappingManager.Instance.transform;
-
- AddSurfaceObject(surface);
- }
-
- // Finally disconnect.
- clientConnected = false;
- networkClient.Close();
-
- // And wait for the next connection.
- AsyncCallback callback = OnClientConnect;
- networkListener.BeginAcceptTcpClient(callback, this);
- }
- }
- }
-
- /// <summary>
- /// Reads an int from the next 4 bytes of the supplied stream.
- /// </summary>
- /// <param name="stream">The stream to read the bytes from.</param>
- /// <returns>An integer representing the bytes.</returns>
- private int ReadInt(Stream stream)
- {
- // The bytes arrive in the wrong order, so swap them.
- byte[] bytes = new byte[4];
- stream.Read(bytes, 0, 4);
- byte t = bytes[0];
- bytes[0] = bytes[3];
- bytes[3] = t;
-
- t = bytes[1];
- bytes[1] = bytes[2];
- bytes[2] = t;
-
- // Then bitconverter can read the int32.
- return BitConverter.ToInt32(bytes, 0);
- }
-
- /// <summary>
- /// Called when a client connects.
- /// </summary>
- /// <param name="result">The result of the connection.</param>
- private void OnClientConnect(IAsyncResult result)
- {
- if (result.IsCompleted)
- {
- networkClient = networkListener.EndAcceptTcpClient(result);
- if (networkClient != null)
- {
- Debug.Log("Connected");
- clientConnected = true;
- }
- }
- }
- #endif
- }
- }