Skip to content

Instantly share code, notes, and snippets.

@zalo
Last active June 27, 2019 04:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zalo/a88b6c188cbe504784374de656afe3c4 to your computer and use it in GitHub Desktop.
Save zalo/a88b6c188cbe504784374de656afe3c4 to your computer and use it in GitHub Desktop.
A simple Unity Wacom Multitouch Data Provider that uses the WacomMTDN.dll from the Wacom Feel Multitouch Samples (linked in the comments)
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using UnityEngine;
using WacomMTDN;
// Simple Wacom Multitouch Unity Integration built from the Wacom's DotNet Example:
// https://developer-docs.wacom.com/display/DevDocs/Feel+Multi-touch+Sample+Code+Downloads
// WacomMTDN.dll can be found at: https://drive.google.com/file/d/1fvoRfIev28fKMvTrfF9IBZkAaWow5UJ4/view?usp=sharing
public class WacomMultiTouchProvider : MonoBehaviour {
///<summary> How long since the last touch event to nullify fingers </summary>
private const float NO_TOUCH_TIMEOUT = 0.032f;
///<summary> How many historical samples per finger to keep </summary>
private const int HISTORY_LENGTH = 20;
///<summary> The container for the latest frame of multitouch data </summary>
[NonSerialized]
public WacomMTFingerCollection CurrentFrame;
///<summary> The container for the histories of multitouch data </summary>
[NonSerialized]
public Dictionary<int, List<WacomMTFinger>> fingerHistories =
new Dictionary<int, List<WacomMTFinger>>();
[Tooltip("The status Returned from the Wacom Multitouch Driver")]
[SerializeField]
private string currentStatus;
[Header("Optional Gizmo Drawing")]
[Tooltip("A transform for a surface to draw touch gizmos")]
public Transform touchSurface;
///<summary> Gets data about connected Wacom Tablets </summary>
protected CWacomMTConfig mWacomMTConfig = new CWacomMTConfig();
///<summary> Manages receiving data from a subscribed Wacom Tablet </summary>
protected CWacomMTWindowClient mWacomMTWindowClient;
private IntPtr mUserDataIntPtr = IntPtr.Zero;
private ConcurrentQueue<WacomMTFingerCollection> fingerUpdates =
new ConcurrentQueue<WacomMTFingerCollection>();
private float noTouchTimer = 0f;
private List<int> IDsToKeep = new List<int>(10),
IDsToRemove = new List<int>(10);
private void Update() {
if (mWacomMTWindowClient != null &&
mWacomMTWindowClient.IsRegisteredAsHitRectClient()) {
noTouchTimer += Time.unscaledDeltaTime;
WacomMTFingerCollection latestFrame;
while (fingerUpdates.TryDequeue(out latestFrame)) {
CurrentFrame = latestFrame;
//Manage Historical Data
IDsToKeep.Clear(); IDsToRemove.Clear();
for (int i = 0; i < CurrentFrame.FingerCount; i++) {
var finger = CurrentFrame.GetFingerByIndex((uint)i);
if (!(finger.X == 0f && finger.Y == 0)){
List<WacomMTFinger> fingerHistory;
if (!fingerHistories.TryGetValue(finger.FingerID, out fingerHistory)) {
fingerHistory = new List<WacomMTFinger>(HISTORY_LENGTH);
fingerHistories.Add(finger.FingerID, fingerHistory);
}
fingerHistory.Insert(0, finger);
while (fingerHistory.Count > HISTORY_LENGTH) {
fingerHistory.RemoveAt(fingerHistory.Count - 1);
}
IDsToKeep.Add(finger.FingerID);
}
}
foreach (KeyValuePair<int, List<WacomMTFinger>> finger in fingerHistories) {
if (!IDsToKeep.Contains(finger.Key)) { IDsToRemove.Add(finger.Key); }
}
foreach (int ID in IDsToRemove) { fingerHistories.Remove(ID); }
noTouchTimer = 0f;
}
// Nullify fingers if have not received any touch events for longer than
// NO_TOUCH_TIMEOUT
if (noTouchTimer > NO_TOUCH_TIMEOUT) {
CurrentFrame.FingerCount = 0;
fingerHistories.Clear();
}
}
}
void OnDrawGizmos() {
for (int i = 0; i < CurrentFrame.FingerCount; i++) {
WacomMTFinger finger = CurrentFrame.GetFingerByIndex((uint)i);
Gizmos.color = Color.HSVToRGB((finger.FingerID * 0.309f) % 1f, 1f, 1f);
Gizmos.DrawSphere(FingerToGizmoPosition(finger), 0.02f);
List<WacomMTFinger> fingerHistory;
if(fingerHistories.TryGetValue(finger.FingerID, out fingerHistory) &&
fingerHistory.Count > 1) {
for (int j = 1; j < fingerHistory.Count; j++) {
Gizmos.DrawLine(FingerToGizmoPosition(fingerHistory[j - 1]) + Vector3.up * 0.01f,
FingerToGizmoPosition(fingerHistory[j]) + Vector3.up * 0.01f);
}
}
}
}
Vector3 FingerToGizmoPosition(WacomMTFinger finger) {
Vector3 fingerPos = new Vector3(finger.X-0.5f, 0f, 0.5f - finger.Y);
return touchSurface.TransformPoint(fingerPos);
}
#region Boring Connection Management Stuff
void OnEnable() {
mWacomMTConfig.Init();
try {
// Prepares some test userdata to send when client is registered.
currentStatus = "User data returned to client...";
mUserDataIntPtr = CMemUtils.AllocateUnmanagedString(currentStatus);
if (mWacomMTConfig.DeviceIDList.data.Length > 0) {
//Subscribe to Finger Touch Events
mWacomMTWindowClient = new CWacomMTFingerClient(
WacomMTProcessingMode.WMTProcessingModeConsumer);
//Use this to capture messages within region of the tablet space
var callback = new WacomMTCallback(DoFingerDataUpdateCallback);
WacomMTHitRect fullScreenHitRect = new WacomMTHitRect(
0f, 0f, 1f, 1f);//Display.main.systemWidth, Display.main.systemHeight);
//Use the display resolution if it is a display tablet...
mWacomMTWindowClient.RegisterHitRectClient(
mWacomMTConfig.DeviceIDList.data[0],
fullScreenHitRect,
ref callback,
mUserDataIntPtr);
}
Debug.Log("Wacom Connection Opened Successfully; Device ID: " +
mWacomMTWindowClient.DeviceID);
} catch (Exception ex) {
Debug.LogError(ex.ToString());
}
}
void OnDisable() {
try {
// Remove our client (if one created).
if (mWacomMTWindowClient != null &&
mWacomMTWindowClient.IsRegisteredAsHitRectClient()) {
mWacomMTWindowClient.UnregisterHitRectClient();
}
if (mWacomMTConfig != null) {
// Close the WacomMT connection.
mWacomMTConfig.Quit();
mWacomMTConfig = null;
}
if (mUserDataIntPtr != IntPtr.Zero) {
CMemUtils.FreeUnmanagedString(mUserDataIntPtr);
mUserDataIntPtr = IntPtr.Zero;
}
Debug.Log("Wacom Multitouch Connection Shut Down Successfully!");
} catch (Exception ex) {
Debug.LogError(ex.ToString());
}
}
public UInt32 DoFingerDataUpdateCallback(IntPtr packet_I, IntPtr userData_I) {
try {
// Recover the finger collection sent back.
WacomMTFingerCollection fingerCollection =
CMemUtils.PtrToStructure<WacomMTFingerCollection>(packet_I);
fingerUpdates.Enqueue(fingerCollection);
// Recover the user data sent back.
currentStatus = CMemUtils.PtrToManagedString(userData_I);
} catch (Exception ex) {
Debug.LogError(ex.ToString());
}
return 0;
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment