Skip to content

Instantly share code, notes, and snippets.

@colinbdclark
Last active September 19, 2019 17:54
Show Gist options
  • Save colinbdclark/a1e4558ef9a8f4a5fd85aba84796887d to your computer and use it in GitHub Desktop.
Save colinbdclark/a1e4558ef9a8f4a5fd85aba84796887d to your computer and use it in GitHub Desktop.
TUIO Touch Source
// From https://github.com/colinbdclark/phet-osc-bridge
/*
* PhET-OSC Bridge OSC Port
* http://github.com/fluid-studios/phet-osc-bridge
*
* Copyright 2017, OCAD University
* Licensed under the New BSD license.
*/
"use strict";
var fluid = fluid || require("infusion"),
osc = osc || fluid.require("osc", require, "osc"),
phetosc = phetosc || fluid.registerNamespace("phetosc");
fluid.defaults("phetosc.port", {
gradeNames: "fluid.component",
// portType can be any osc.js Port constructor name
// in string form, e.g. "osc.UDPPort" or "osc.WebSocketPort".
// See https://github.com/colinbdclark/osc.js
// for more information and examples.
portType: "fluid.mustBeOverridden",
metadata: true,
unpackSingleArgs: false,
portEventMap: {
open: "onOpen",
ready: "onReady",
error: "onError",
close: "onClose",
message: "onMessage",
bundle: "onBundle",
osc: "onOSC",
raw: "onRaw"
},
members: {
port: {
expander: {
funcName: "phetosc.port.createPort",
args: ["{port}.options"]
}
}
},
invokers: {
open: {
"this": "{that}.port",
method: "open"
},
send: {
"this": "{that}.port",
method: "send"
},
sendRaw: {
"this": "{that}.port",
method: "sendRaw"
},
close: {
"this": "{that}.port",
method: "close"
}
},
events: {
onOpen: null,
onReady: null,
onError: null,
onClose: null,
onMessage: null,
onBundle: null,
onOSC: null,
onRaw: null
},
listeners: {
"onCreate.bindPortEvents": {
funcName: "phetosc.port.bindPortEvents",
args: ["{that}"]
}
}
});
phetosc.port.bindPortEvents = function (that) {
fluid.each(that.options.portEventMap, function (eventName, emitterName) {
that.port.on(emitterName, that.events[eventName].fire);
});
};
phetosc.port.createPort = function (options) {
var optionsClone = fluid.copy(options),
portType = optionsClone.portType,
PortConstructor = fluid.getGlobalValue(portType);
delete optionsClone[portType];
return new PortConstructor(optionsClone);
};
fluid.defaults("phetosc.webSocketPort", {
gradeNames: "phetosc.port",
portType: "osc.WebSocketPort"
});
fluid.defaults("phetosc.udpPort", {
gradeNames: "phetosc.port",
portType: "osc.UDPPort"
});
fluid.defaults("adam.soundplane", {
gradeNames: ["adam.tuioTouchSource"],
oscPortOptions: {
url: "ws://localhost:8080"
},
components: {
oscPort: {
options: "{soundplane}.options.oscPortOptions"
}
}
});
fluid.defaults("adam.tuioCursor", {
gradeNames: "fluid.modelComponent",
sessionID: undefined,
model: {
/*
x:
y:
xVel:
yVel:
mAccel:
*/
},
modelListeners: {
"x": {
// Do something when X changes.
},
"y": {
// Do something when X changes.
}
},
listeners: {
"onCreate.noteOn": {
// Do something like maybe trigger a note when a cursor is created?
},
"onDestroy.noteOff": {
// Do something like maybe release a note when a cursor is created?
}
}
});
fluid.defaults("adam.tuioTouchSource", {
gradeNames: "fluid.modelComponent",
model: {
/*
<sessionID>: {
x:
y:
xVel:
yVel:
mAccel:
}
*/
},
modelListeners: {
"": {
funcName: "adam.tuioTouchSource.fireTouchEvent",
args: ["{that}", "{change}"],
excludeSource: "init"
}
},
components: {
oscPort: {
type: "phetosc.webSocketPort",
options: {
listeners: {
onMessage: {
funcName: "adam.tuioTouchSource.dispatchMessage"
}
}
}
}
},
dynamicComponents: {
cursor: {
type: "adam.tuioCursor",
createOnEvent: "onTouchDown",
options: {
sessionID: "{arguments}.0",
model: "{arguments}.1"
}
}
},
events: {
onTouchDown: null,
onTouchReleased: null,
onTouchMoved: null
},
listeners: {
"onTouchReleased.deleteCursor": {
funcName: "adam.tuioTouchSource.deleteReleasedCursor",
args: ["{that}", "{arguments}.0"]
}
}
});
adam.tuioTouchSource.dispatchMessage = function (that, oscMsg) {
if (oscMsg.address !== "/tuio/2Dcur") {
return;
}
switch (oscMsg.args[0].value) {
case "set":
return adam.tuioTouchSource.updateCursor(that, oscMsg);
case "alive":
return adam.tuioTouchSource.cullInactiveCursors(that, oscMsg);
}
};
adam.tuioTouchSource.updateCursor = function (that, oscMsg) {
var id = oscMsg.args[1].value,
idString = String(id);
// /tuio/2Dcur set s x y X Y m
var cursorSpec = {
x: oscMsg.args[2].value,
y: oscMsg.args[3].value
};
var eventFirer = that.model[idString] === undefined ?
that.events.onTouchDown : that.events.onTouchMoved;
that.applier.change(id, cursorSpec);
eventFirer.fire(idString, cursorSpec);
};
adam.tuioTouchSource.cullInactiveCursors = function (that, oscMsg) {
var objectIDs = packet.args.subarray(1);
// Delete any inactive objects.
fluid.each(that.model, function (value, id) {
var idInt = parseInt(id);
if (objectIDs.indexOf(idInt) <= -1) {
that.applier.change(id, undefined, "DELETE");
that.events.afterTouchReleased.fire(id);
}
});
};
adam.tuioTouchSource.deleteReleasedCursor = function (that, cursorID) {
// TODO: Look up the cursor instance and call destroy() on it.
// Infusion will do this all for us someday.
};
fluid.defaults("adam.tuioTouchSource", {
gradeNames: "fluid.modelComponent",
model: {
/*
<sessionID>: {
x:
y:
xVel:
yVel:
mAccel:
}
*/
},
modelListeners: {
"": {
funcName: "adam.tuioTouchSource.fireTouchEvent",
args: ["{that}", "{change}"],
excludeSource: "init"
}
},
components: {
oscPort: {
type: "phetosc.webSocketPort",
options: {
listeners: {
onMessage: {
funcName: "adam.tuioTouchSource.dispatchMessage"
}
}
}
}
},
events: {
onTouchDown: null,
onTouchReleased: null,
onTouchMoved: null
}
});
adam.tuioTouchSource.dispatchMessage = function (that, oscMsg) {
if (oscMsg.address !== "/tuio/2Dcur") {
return;
}
switch (oscMsg.args[0].value) {
case "set":
return adam.tuioTouchSource.updateCursor(that, oscMsg);
case "alive":
return adam.tuioTouchSource.cullInactiveCursors(that, oscMsg);
}
};
adam.tuioTouchSource.updateCursor = function (that, oscMsg) {
var id = oscMsg.args[1].value;
// /tuio/2Dcur set s x y X Y m
that.applier.change(id, {
x: oscMsg.args[2].value,
y: oscMsg.args[3].value
});
};
adam.tuioTouchSource.cullInactiveCursors = function (that, oscMsg) {
var objectIDs = packet.args.subarray(1);
// Delete any inactive objects.
fluid.each(that.model, function (value, id) {
var idInt = parseInt(id);
if (objectIDs.indexOf(idInt) <= -1) {
that.applier.change(id, undefined, "DELETE");
}
});
};
adam.tuioTouchSource.fireTouchEvent = function (that, change) {
var cursorID = change.segs[0];
if (change.value !== undefined) {
var eventFirer = change.oldValue === undefined ?
that.events.onTouchDown : that.events.onTouchMoved;
eventFirer.fire(cursorID, change.value);
} else {
// A cursor has been removed.
that.events.onTouchReleased.fire(cursorID);
}
};
fluid.defaults("adam.tuioTouchSource", {
gradeNames: "fluid.modelComponent",
model: {
/*
<sessionID>: {
x:
y:
xVel:
yVel:
mAccel:
}
*/
},
components: {
oscPort: {
type: "phetosc.webSocketPort",
options: {
listeners: {
onMessage: {
funcName: "adam.tuioTouchSource.dispatchMessage"
}
}
}
}
},
events: {
onTouchDown: null,
onTouchReleased: null,
onTouchMoved: null
}
});
adam.tuioTouchSource.dispatchMessage = function (that, oscMsg) {
if (oscMsg.address !== "/tuio/2Dcur") {
return;
}
switch (oscMsg.args[0].value) {
case "set":
return adam.tuioTouchSource.updateCursor(that, oscMsg);
case "alive":
return adam.tuioTouchSource.cullInactiveCursors(that, oscMsg);
}
};
adam.tuioTouchSource.updateCursor = function (that, oscMsg) {
var id = oscMsg.args[1].value,
idString = String(id);
// /tuio/2Dcur set s x y X Y m
var cursorSpec = {
x: oscMsg.args[2].value,
y: oscMsg.args[3].value
};
var eventFirer = that.model[idString] === undefined ?
that.events.onTouchDown : that.events.onTouchMoved;
that.applier.change(idString, cursorSpec);
eventFirer.fire(idString, cursorSpec);
};
adam.tuioTouchSource.cullInactiveCursors = function (that, oscMsg) {
var objectIDs = packet.args.subarray(1);
// Delete any inactive objects.
fluid.each(that.model, function (value, id) {
var idInt = parseInt(id);
if (objectIDs.indexOf(idInt) <= -1) {
that.applier.change(id, undefined, "DELETE");
that.events.onTouchReleased(id);
}
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment