/* * @author Valentin Simonov / http://va.lent.in/ */ #if TOUCHSCRIPT_TUIO #if UNITY_EDITOR || UNITY_STANDALONE || UNITY_IOS || UNITY_ANDROID using System; using System.Collections.Generic; using TouchScript.Pointers; using TouchScript.Utils; using TUIOsharp; using TUIOsharp.DataProcessors; using TUIOsharp.Entities; using UnityEngine; namespace TouchScript.InputSources { /// /// Processes TUIO 1.1 input. /// [AddComponentMenu("TouchScript/Input Sources/TUIO Input")] [HelpURL("http://touchscript.github.io/docs/html/T_TouchScript_InputSources_TuioInput.htm")] public sealed class TuioInput : InputSource { #region Constants /// /// Type of TUIO input object. /// [Flags] public enum InputType { /// /// Pointer. /// Cursors = 1 << 0, /// /// Shape. /// Blobs = 1 << 1, /// /// Tagged object. /// Objects = 1 << 2 } #endregion #region Public properties /// /// Port to listen to. /// public int TuioPort { get { return tuioPort; } set { if (tuioPort == value) return; tuioPort = value; connect(); } } /// /// What input types should the input source listen to. /// public InputType SupportedInputs { get { return supportedInputs; } set { if (supportedInputs == value) return; supportedInputs = value; updateInputs(); } } #endregion #region Private variables [SerializeField] private int tuioPort = 3333; [SerializeField] private InputType supportedInputs = InputType.Cursors | InputType.Blobs | InputType.Objects; private TuioServer server; private CursorProcessor cursorProcessor; private ObjectProcessor objectProcessor; private BlobProcessor blobProcessor; private Dictionary cursorToInternalId = new Dictionary(10); private Dictionary blobToInternalId = new Dictionary(); private Dictionary objectToInternalId = new Dictionary(); private int screenWidth; private int screenHeight; private ObjectPool touchPool; private ObjectPool objectPool; #endregion #region Constructor public TuioInput() { touchPool = new ObjectPool(20, () => new TouchPointer(this), null, resetPointer); objectPool = new ObjectPool(10, () => new ObjectPointer(this), null, resetPointer); } #endregion #region Public methods /// public override bool UpdateInput() { if (base.UpdateInput()) return true; screenWidth = Screen.width; screenHeight = Screen.height; return true; } /// public override bool CancelPointer(Pointer pointer, bool shouldReturn) { base.CancelPointer(pointer, shouldReturn); lock (this) { if (pointer.Type == Pointer.PointerType.Touch) { TuioCursor cursor = null; foreach (var touchPoint in cursorToInternalId) { if (touchPoint.Value.Id == pointer.Id) { cursor = touchPoint.Key; break; } } if (cursor != null) { cancelPointer(pointer); if (shouldReturn) { cursorToInternalId[cursor] = internalReturnTouch(pointer as TouchPointer); } else { cursorToInternalId.Remove(cursor); } return true; } return false; } TuioObject obj = null; foreach (var touchPoint in objectToInternalId) { if (touchPoint.Value.Id == pointer.Id) { obj = touchPoint.Key; break; } } if (obj != null) { cancelPointer(pointer); if (shouldReturn) { objectToInternalId[obj] = internalReturnObject(pointer as ObjectPointer, pointer.Position); } else { objectToInternalId.Remove(obj); } return true; } TuioBlob blob = null; foreach (var touchPoint in blobToInternalId) { if (touchPoint.Value.Id == pointer.Id) { blob = touchPoint.Key; break; } } if (blob != null) { cancelPointer(pointer); if (shouldReturn) { blobToInternalId[blob] = internalReturnObject(pointer as ObjectPointer, pointer.Position); } else { blobToInternalId.Remove(blob); } return true; } return false; } } #endregion #region Internal methods /// public override void INTERNAL_DiscardPointer(Pointer pointer) { if (pointer.Type == Pointer.PointerType.Touch) { touchPool.Release(pointer as TouchPointer); } else if (pointer.Type == Pointer.PointerType.Object) { objectPool.Release(pointer as ObjectPointer); } } #endregion #region Unity /// protected override void OnEnable() { base.OnEnable(); screenWidth = Screen.width; screenHeight = Screen.height; cursorProcessor = new CursorProcessor(); cursorProcessor.CursorAdded += OnCursorAdded; cursorProcessor.CursorUpdated += OnCursorUpdated; cursorProcessor.CursorRemoved += OnCursorRemoved; blobProcessor = new BlobProcessor(); blobProcessor.BlobAdded += OnBlobAdded; blobProcessor.BlobUpdated += OnBlobUpdated; blobProcessor.BlobRemoved += OnBlobRemoved; objectProcessor = new ObjectProcessor(); objectProcessor.ObjectAdded += OnObjectAdded; objectProcessor.ObjectUpdated += OnObjectUpdated; objectProcessor.ObjectRemoved += OnObjectRemoved; connect(); } /// protected override void OnDisable() { disconnect(); base.OnDisable(); } #endregion #region Private functions private TouchPointer internalAddTouch(Vector2 position) { var pointer = touchPool.Get(); pointer.Position = remapCoordinates(position); pointer.Buttons |= Pointer.PointerButtonState.FirstButtonDown | Pointer.PointerButtonState.FirstButtonPressed; addPointer(pointer); pressPointer(pointer); return pointer; } private TouchPointer internalReturnTouch(TouchPointer pointer) { var newPointer = touchPool.Get(); newPointer.CopyFrom(pointer); pointer.Buttons |= Pointer.PointerButtonState.FirstButtonDown | Pointer.PointerButtonState.FirstButtonPressed; newPointer.Flags |= Pointer.FLAG_RETURNED; addPointer(newPointer); pressPointer(newPointer); return newPointer; } private ObjectPointer internalAddObject(Vector2 position) { var pointer = objectPool.Get(); pointer.Position = remapCoordinates(position); pointer.Buttons |= Pointer.PointerButtonState.FirstButtonDown | Pointer.PointerButtonState.FirstButtonPressed; addPointer(pointer); pressPointer(pointer); return pointer; } private ObjectPointer internalReturnObject(ObjectPointer pointer, Vector2 position) { var newPointer = objectPool.Get(); newPointer.CopyFrom(pointer); pointer.Buttons |= Pointer.PointerButtonState.FirstButtonDown | Pointer.PointerButtonState.FirstButtonPressed; newPointer.Flags |= Pointer.FLAG_RETURNED; addPointer(newPointer); pressPointer(newPointer); return newPointer; } private void connect() { if (!Application.isPlaying) return; if (server != null) disconnect(); server = new TuioServer(TuioPort); server.Connect(); updateInputs(); } private void disconnect() { if (server != null) { server.RemoveAllDataProcessors(); server.Disconnect(); server = null; } foreach (var i in cursorToInternalId) cancelPointer(i.Value); foreach (var i in blobToInternalId) cancelPointer(i.Value); foreach (var i in objectToInternalId) cancelPointer(i.Value); cursorToInternalId.Clear(); blobToInternalId.Clear(); objectToInternalId.Clear(); } private void updateInputs() { if (server == null) return; if ((supportedInputs & InputType.Cursors) != 0) server.AddDataProcessor(cursorProcessor); else server.RemoveDataProcessor(cursorProcessor); if ((supportedInputs & InputType.Blobs) != 0) server.AddDataProcessor(blobProcessor); else server.RemoveDataProcessor(blobProcessor); if ((supportedInputs & InputType.Objects) != 0) server.AddDataProcessor(objectProcessor); else server.RemoveDataProcessor(objectProcessor); } private void updateBlobProperties(ObjectPointer obj, TuioBlob target) { obj.Width = target.Width; obj.Height = target.Height; obj.Angle = target.Angle; } private void updateObjectProperties(ObjectPointer obj, TuioObject target) { obj.ObjectId = target.ClassId; obj.Angle = target.Angle; } private void resetPointer(Pointer p) { p.INTERNAL_Reset(); } #endregion #region Event handlers private void OnCursorAdded(object sender, TuioCursorEventArgs e) { var entity = e.Cursor; lock (this) { var x = entity.X * screenWidth; var y = (1 - entity.Y) * screenHeight; cursorToInternalId.Add(entity, internalAddTouch(new Vector2(x, y))); } } private void OnCursorUpdated(object sender, TuioCursorEventArgs e) { var entity = e.Cursor; lock (this) { TouchPointer touch; if (!cursorToInternalId.TryGetValue(entity, out touch)) return; var x = entity.X * screenWidth; var y = (1 - entity.Y) * screenHeight; touch.Position = remapCoordinates(new Vector2(x, y)); updatePointer(touch); } } private void OnCursorRemoved(object sender, TuioCursorEventArgs e) { var entity = e.Cursor; lock (this) { TouchPointer touch; if (!cursorToInternalId.TryGetValue(entity, out touch)) return; cursorToInternalId.Remove(entity); releasePointer(touch); removePointer(touch); } } private void OnBlobAdded(object sender, TuioBlobEventArgs e) { var entity = e.Blob; lock (this) { var x = entity.X * screenWidth; var y = (1 - entity.Y) * screenHeight; var touch = internalAddObject(new Vector2(x, y)); updateBlobProperties(touch, entity); blobToInternalId.Add(entity, touch); } } private void OnBlobUpdated(object sender, TuioBlobEventArgs e) { var entity = e.Blob; lock (this) { ObjectPointer touch; if (!blobToInternalId.TryGetValue(entity, out touch)) return; var x = entity.X * screenWidth; var y = (1 - entity.Y) * screenHeight; touch.Position = remapCoordinates(new Vector2(x, y)); updateBlobProperties(touch, entity); updatePointer(touch); } } private void OnBlobRemoved(object sender, TuioBlobEventArgs e) { var entity = e.Blob; lock (this) { ObjectPointer touch; if (!blobToInternalId.TryGetValue(entity, out touch)) return; blobToInternalId.Remove(entity); releasePointer(touch); removePointer(touch); } } private void OnObjectAdded(object sender, TuioObjectEventArgs e) { var entity = e.Object; lock (this) { var x = entity.X * screenWidth; var y = (1 - entity.Y) * screenHeight; var touch = internalAddObject(new Vector2(x, y)); updateObjectProperties(touch, entity); objectToInternalId.Add(entity, touch); } } private void OnObjectUpdated(object sender, TuioObjectEventArgs e) { var entity = e.Object; lock (this) { ObjectPointer touch; if (!objectToInternalId.TryGetValue(entity, out touch)) return; var x = entity.X * screenWidth; var y = (1 - entity.Y) * screenHeight; touch.Position = remapCoordinates(new Vector2(x, y)); updateObjectProperties(touch, entity); updatePointer(touch); } } private void OnObjectRemoved(object sender, TuioObjectEventArgs e) { var entity = e.Object; lock (this) { ObjectPointer touch; if (!objectToInternalId.TryGetValue(entity, out touch)) return; objectToInternalId.Remove(entity); releasePointer(touch); removePointer(touch); } } #endregion } } #endif #endif