Skip to content

Instantly share code, notes, and snippets.

@catfact
Last active October 21, 2018 06:37
Show Gist options
  • Save catfact/908fe029c49cf8392cb147c266ee5b1f to your computer and use it in GitHub Desktop.
Save catfact/908fe029c49cf8392cb147c266ee5b1f to your computer and use it in GitHub Desktop.
// outlets: input index, output index, connection value
outlets = 3;
sketch.default2d();
// I/O count, should be an argument
var num_ins = 4;
var num_outs = 4;
// mouse state (world coordinates)
var wx = 0;
var wy = 0;
// colors
var Color = Object.freeze({
"in_on" : [0.5, 1.0, 0.5, 1.0],
"in_off" : [0.7, 0.8, 0.7, 1.0],
"in_hover" : [0.8, 1.0, 0.8, 1.0],
"out_on" : [1.0, 0.5, 0.5, 1.0],
"out_off" : [0.8, 0.7, 0.7, 1.0],
"out_hover" : [1.0, 0.8, 0.8, 1.0]
});
var in_bounds = [];
var out_bounds = [];
var patched = [];
var in_connected = [];
var out_connected= [];
var in_hover = [];
var out_hover = [];
for(i=0; i<num_ins; i++) {
patched[i] = [];
for(j=0; j<num_outs; j++) {
patched[i][j] = false;
}
}
// interaction state
var ui_state = {
"is_patching": false,
"in_anchor": -1,
"out_anchor": -1
};
function reset_ui_state() {
ui_state.is_patching = false;
ui_state.in_anchor = -1;
ui_state.out_anchor = -1;
}
//---------------------------------
// event handlers
function onresize(width, height) {
set_node_bounds();
}
function onidle(x, y) {
var pos = sketch.screentoworld(x, y);
wx = pos[0];
wy = pos[1];
for(i=0; i<num_ins; i++) {
in_hover[i] = check_node_bounds(in_bounds[i], pos);
}
for(i=0; i<num_outs; i++) {
out_hover[i] = check_node_bounds(out_bounds[i], pos);
}
redraw();
}
function onclick(x, y) {
var pos = sketch.screentoworld(x, y);
for(i=0; i<num_ins; i++) {
if (check_node_bounds(in_bounds[i], pos)) {
do_input(i);
}
}
for(i=0; i<num_outs; i++) {
if(check_node_bounds(out_bounds[i], pos)) {
do_output(i);
}
}
}
function onidleout() {
reset_ui_state();
}
//---------------------------------
//--- "controller logic" (ha)
function do_input(i) {
if(ui_state.is_patching) {
if(ui_state.in_anchor != -1) {
ui_state.in_anchor = i;
} else {
if(ui_state.out_anchor != -1) {
ui_state.in_anchor = i;
do_patch();
} else {
// shouldn't get here
}
}
} else {
ui_state.is_patching = true;
ui_state.in_anchor = i;
ui_state.out_anchor = -1;
}
}
function do_output(j) {
if(ui_state.is_patching) {
if(ui_state.out_anchor != -1) {
ui_state.out_anchor = j;
} else {
if(ui_state.in_anchor != -1) {
ui_state.out_anchor = j;
do_patch();
} else {
// shouldn't get here
}
}
} else {
ui_state.is_patching = true;
ui_state.in_anchor = -1;
ui_state.out_anchor = j;
}
}
function do_patch() {
var i = ui_state.in_anchor;
var j = ui_state.out_anchor;
var val;
if (patched[i][j]) {
patched[i][j] = false;
val = 0;
}
else {
patched[i][j] = true;
val = 1;
}
reset_ui_state();
outlet(2, val);
outlet(1, j);
outlet(0, i);
}
//-----------------
//--- helpers
// calculate bounding boxes for I/O nodes (world coordinates)
function set_node_bounds() {
var in_w = (2.0 / num_ins); // leaving no space at all, lookin dumb
var in_h = 0.2;
for (i=0; i<num_ins; i++) {
var l = (i * in_w) - 1.0;
in_bounds[i] = {"left":l, "right":l+in_w, "top":1, "bottom":1-in_h};
post(in_bounds[i].left, in_bounds[i].right, in_bounds[i].top, in_bounds[i].bottom);
in_connected[i] = false;
in_hover[i] = false;
}
var out_w = (2.0 / num_ins);
var out_h = 0.2;
for (i=0; i<num_outs; i++) {
var l = (i * out_w) - 1.0;
out_bounds[i] = {"left":l, "right":l+out_w, "top":out_h - 1, "bottom":-1.0};
out_connected[i] = false;
out_hover[i] = false;
}
}
function check_node_bounds(b, pos) {
var x = pos[0];
var y = pos[1];
return ((x >= b.left) && (x <= b.right) && (y <= b.top) && (y >= b.bottom));
}
function get_in_coords(i) {
var b = in_bounds[i];
return [b.left + (b.right - b.left) / 2, b.bottom];
}
function get_out_coords(j) {
var b = out_bounds[j];
return [b.left + (b.right - b.left) / 2, b.top];
}
//------------------------
//--- drawing
function redraw() {
with(sketch) {
glclearcolor([1.0, 1.0, 1.0, 1.0]);
glclear();
// draw input nodes
for(i=0; i<num_ins; i++) {
var b = in_bounds[i];
// choose appropriate color based on input state
if(in_hover[i]) {
glcolor(Color.in_hover);
} else {
if(in_connected[i]) {
glcolor(Color.in_on);
} else {
glcolor(Color.in_off);
}
}
// draw filled quad
quad(b.left, b.top, 0, b.right, b.top, 0, b.right, b.bottom, 0, b.left, b.bottom, 0);
// draw black bounding box
glcolor(0.0, 0.0, 0.0, 1.0);
framequad(b.left, b.top, 0, b.right, b.top, 0, b.right, b.bottom, 0, b.left, b.bottom, 0);
}
// draw output nodes
for(i=0; i<num_ins; i++) {
var b = out_bounds[i];
// choose appropriate color based on input state
if(out_hover[i]) {
glcolor(Color.out_hover);
} else {
if(out_connected[i]) {
glcolor(Color.out_on);
} else {
glcolor(Color.out_off);
}
}
// draw filled quad
quad(b.left, b.top, 0, b.right, b.top, 0, b.right, b.bottom, 0, b.left, b.bottom, 0);
// draw black bounding box
glcolor(0.0, 0.0, 0.0, 1.0);
framequad(b.left, b.top, 0, b.right, b.top, 0, b.right, b.bottom, 0, b.left, b.bottom, 0);
}
// draw existing patch cables
for(i=0; i<num_ins; i++) {
for(j=0; j<num_outs; j++) {
if(patched[i][j]) {
var a = get_in_coords(i);
var b = get_out_coords(j);
moveto(a[0], a[1]);
lineto(b[0], b[1]);
}
}
}
// draw current patch cable
if(ui_state.is_patching) {
var a, b;
if(ui_state.in_anchor != -1) {
a = get_in_coords(ui_state.in_anchor);
b = [wx, wy];
} else {
a = [wx, wy];
b = get_out_coords(ui_state.out_anchor);
}
moveto(a[0], a[1]);
lineto(b[0], b[1]);
}
}
refresh();
}
set_node_bounds();
redraw();
{
"patcher" : {
"fileversion" : 1,
"appversion" : {
"major" : 8,
"minor" : 0,
"revision" : 0,
"architecture" : "x64",
"modernui" : 1
}
,
"classnamespace" : "box",
"rect" : [ -1782.0, -38.0, 396.0, 701.0 ],
"bglocked" : 0,
"openinpresentation" : 0,
"default_fontsize" : 12.0,
"default_fontface" : 0,
"default_fontname" : "Arial",
"gridonopen" : 1,
"gridsize" : [ 15.0, 15.0 ],
"gridsnaponopen" : 1,
"objectsnaponopen" : 1,
"statusbarvisible" : 2,
"toolbarvisible" : 1,
"lefttoolbarpinned" : 0,
"toptoolbarpinned" : 0,
"righttoolbarpinned" : 0,
"bottomtoolbarpinned" : 0,
"toolbars_unpinned_last_save" : 0,
"tallnewobj" : 0,
"boxanimatetime" : 200,
"enablehscroll" : 1,
"enablevscroll" : 1,
"devicewidth" : 0.0,
"description" : "",
"digest" : "",
"tags" : "",
"style" : "",
"subpatcher_template" : "",
"boxes" : [ {
"box" : {
"id" : "obj-15",
"maxclass" : "number",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "bang" ],
"parameter_enable" : 0,
"patching_rect" : [ 147.0, 269.0, 50.0, 22.0 ]
}
}
, {
"box" : {
"id" : "obj-14",
"maxclass" : "number",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "bang" ],
"parameter_enable" : 0,
"patching_rect" : [ 88.0, 269.0, 50.0, 22.0 ]
}
}
, {
"box" : {
"id" : "obj-12",
"maxclass" : "newobj",
"numinlets" : 3,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 29.0, 331.0, 64.0, 22.0 ],
"text" : "pack 0 0 0"
}
}
, {
"box" : {
"columns" : 4,
"id" : "obj-8",
"maxclass" : "matrixctrl",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "list", "list" ],
"parameter_enable" : 0,
"patching_rect" : [ 29.0, 373.0, 102.0, 101.0 ]
}
}
, {
"box" : {
"id" : "obj-1",
"maxclass" : "number",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "bang" ],
"parameter_enable" : 0,
"patching_rect" : [ 29.0, 269.0, 50.0, 22.0 ]
}
}
, {
"box" : {
"id" : "obj-6",
"maxclass" : "message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 29.0, 15.0, 35.0, 22.0 ],
"text" : "open"
}
}
, {
"box" : {
"filename" : "mouseover_ui.js",
"id" : "obj-2",
"maxclass" : "jsui",
"numinlets" : 1,
"numoutlets" : 3,
"outlettype" : [ "", "", "" ],
"parameter_enable" : 0,
"patching_rect" : [ 29.0, 58.0, 211.0, 196.0 ]
}
}
],
"lines" : [ {
"patchline" : {
"destination" : [ "obj-12", 0 ],
"source" : [ "obj-1", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-8", 0 ],
"source" : [ "obj-12", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-12", 1 ],
"source" : [ "obj-14", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-12", 2 ],
"source" : [ "obj-15", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-1", 0 ],
"source" : [ "obj-2", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-14", 0 ],
"source" : [ "obj-2", 1 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-15", 0 ],
"source" : [ "obj-2", 2 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-2", 0 ],
"source" : [ "obj-6", 0 ]
}
}
],
"dependency_cache" : [ {
"name" : "mouseover_ui.js",
"bootpath" : "~/max",
"patcherrelativepath" : ".",
"type" : "TEXT",
"implicit" : 1
}
],
"autosave" : 0
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment