Last active
January 7, 2016 07:38
-
-
Save cansik/9d5ffe5cbbe4d194cbe6 to your computer and use it in GitHub Desktop.
MadMapper Remote Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import oscP5.*; | |
import netP5.*; | |
import java.util.concurrent.*; | |
import java.util.Map; | |
import java.util.ArrayList; | |
// global variables | |
OscP5 osc; | |
NetAddress madMapper; | |
CopyOnWriteArrayList<Surface> surfaces = new CopyOnWriteArrayList<Surface>(); | |
String helpText = "Simple Quad Editor\n" | |
+ "\t`R` = reload the MadMapper surfaces\n" | |
+ "\t`U` = reload the surface positions\n" | |
+ "\t`H` = hide help text"; | |
boolean drawHelpText = true; | |
// drag & drop variables | |
boolean mouseDown = false; | |
PVector startMouseClick = new PVector(); | |
PVector currentHandle = null; | |
Surface currentSurface = null; | |
// design variables for drawing | |
String surfaceBackgroundImageURL = "http://civilconcept.com/wp-content/uploads/2015/09/1024x640xBoard-Wood-Tree-Macro-1024x640.jpg.pagespeed.ic_.Hei_kH8jJf.jpg"; | |
PImage surfaceBackgroundImage; | |
float handlerSize = 20; | |
float strokeWeight = 1; | |
color strokeColor = color(255); | |
color handleFillColor = color(255, 0, 0, 50); | |
float textSize = 12; | |
color textColor = color(255); | |
// objects | |
class Surface | |
{ | |
String name; | |
PVector[] handles; | |
public Surface(String name, int handleCount) | |
{ | |
this.name = name; | |
this.handles = new PVector[handleCount]; | |
for (int i = 0; i < handles.length; i++) | |
{ | |
handles[i] = new PVector(); | |
} | |
} | |
PVector getHandle(PVector clickPosition) | |
{ | |
int c = 0; | |
// search in handles if a handler of this surface match | |
for (PVector h : handles) | |
{ | |
PVector m = clickPosition.copy().add(h.copy().mult(-1)); | |
if (Math.abs(m.x) < handlerSize && Math.abs(m.y) < handlerSize) | |
{ | |
System.out.println("Handler of " + name + " selected: " + handles[c]); | |
return handles[c]; | |
} | |
c++; | |
} | |
return null; | |
} | |
public void render() | |
{ | |
PVector center = getBaryCenter(); | |
// draw handles | |
strokeWeight(strokeWeight); | |
stroke(strokeColor); | |
fill(handleFillColor); | |
for (int i = 0; i < handles.length; i++) | |
{ | |
PVector h = handles[i]; | |
ellipse(h.x, h.y, handlerSize, handlerSize); | |
} | |
//draw image as texture | |
tint(255, 255); | |
beginShape(); | |
textureMode(NORMAL); | |
textureWrap(REPEAT); | |
texture(surfaceBackgroundImage); | |
int u = 0, v = 1; | |
for (int i = 0; i <= handles.length; i++) | |
{ | |
// use modulo to create a loop (first vertex is used twice) | |
PVector h = handles[i % handles.length]; | |
vertex(h.x, h.y, u++%2, v++%2); | |
} | |
endShape(); | |
//draw name of surface | |
textSize(textSize); | |
fill(textColor); | |
text(name, center.x - (textWidth(name) / 2), center.y); | |
} | |
PVector getBaryCenter() | |
{ | |
PVector center = new PVector(); | |
for (int i = 0; i < handles.length; i++) | |
{ | |
center.add(handles[i]); | |
} | |
center.div(handles.length); | |
return center; | |
} | |
} | |
void setup() | |
{ | |
// init | |
size(800, 500, P3D); | |
//init osc | |
osc = new OscP5(this, 9000); | |
madMapper = new NetAddress("127.0.0.1", 8000); | |
//init design | |
surfaceBackgroundImage = loadImage(surfaceBackgroundImageURL, "png"); | |
//demo surfaces | |
/* | |
Surface quad = new Surface("Quad1", 4); | |
quad.handles[0] = new PVector(100, 100); | |
quad.handles[1] = new PVector(100, 200); | |
quad.handles[2] = new PVector(200, 200); | |
quad.handles[3] = new PVector(200, 100); | |
surfaces.add(quad); | |
Surface tr = new Surface("Triangle1", 3); | |
tr.handles[0] = new PVector(300, 300); | |
tr.handles[1] = new PVector(300, 400); | |
tr.handles[2] = new PVector(400, 400); | |
surfaces.add(tr); | |
*/ | |
} | |
void draw() | |
{ | |
background(50); | |
// update shapes | |
if (frameCount % 2 == 0 && !mouseDown) | |
{ | |
updateSurfaces(); | |
} | |
// draw shapes | |
for (Surface s : surfaces) | |
{ | |
s.render(); | |
} | |
// draw help text | |
if (drawHelpText) | |
{ | |
textSize(textSize); | |
fill(textColor); | |
text(helpText, 5, 10); | |
} | |
} | |
//drag and drop methods | |
void mousePressed() { | |
if (!mouseDown) | |
{ | |
startMouseClick = new PVector(mouseX, mouseY); | |
//get handle of surface | |
for (Surface s : surfaces) | |
{ | |
PVector h = s.getHandle(startMouseClick); | |
if (h != null) | |
{ | |
currentHandle = h; | |
currentSurface = s; | |
} | |
} | |
mouseDown = true; | |
} | |
} | |
void mouseDragged() | |
{ | |
if (currentHandle != null) | |
{ | |
syncWithMadMapper(currentSurface); | |
currentHandle.x = mouseX; | |
currentHandle.y = mouseY; | |
} | |
} | |
void mouseReleased() { | |
mouseDown = false; | |
currentHandle = null; | |
currentSurface = null; | |
} | |
// keyboard options | |
void keyPressed() { | |
switch (key) { | |
case 'r': | |
//send refresh surfaces | |
receiveSurfaces(); | |
break; | |
case 'u': | |
//update the surface positions | |
updateSurfaces(); | |
break; | |
case 'h': | |
drawHelpText = !drawHelpText; | |
default: | |
break; | |
} | |
} | |
String getSurfaceName(OscMessage m) | |
{ | |
//parse surface name | |
String[] bits = m.getAddress().split("/"); | |
return bits[2]; | |
} | |
// osc releated methods | |
boolean receiveSurfacesRunning = false; | |
boolean updateSurfacesRunning = false; | |
void receiveSurfaces() { | |
println("send receive surfaces!"); | |
receiveSurfacesRunning = true; | |
osc.send(new OscMessage("/getControls?root=/surfaces&recursive=0"), madMapper); | |
} | |
void receiveSurfacesCompleted(OscBundle bundle) { | |
surfaces.clear(); | |
for (OscMessage m : bundle.get()) { | |
//parse surface name | |
String[] bits = m.getAddress().split("/"); | |
String surfaceName = bits[bits.length-1]; | |
println(surfaceName); | |
if (surfaceName.equals("selected")) | |
{ | |
continue; | |
} | |
//add new surface | |
Surface s = new Surface(surfaceName, 4); | |
surfaces.add(s); | |
} | |
} | |
void updateSurfaces() { | |
//println("send update surfaces!"); | |
updateSurfacesRunning = true; | |
osc.send(new OscMessage("/getControlValues?url=/surfaces/.*/handles/.*&normalized=0"), madMapper); | |
} | |
void updateSurfacesCompleted(OscBundle bundle) { | |
if(mouseDown) | |
{ | |
return; | |
} | |
//no stream support | |
//Map<String, List<OscMessage>> groupedBySurface = bundle.get().stream().collect(Collectors.groupingBy(m -> getSurfaceName(m))); | |
//map handlers to surfaces | |
HashMap<String, ArrayList<OscMessage>> groupedBySurface = new HashMap<String, ArrayList<OscMessage>>(); | |
for (OscMessage m : bundle.get()) { | |
//parse surface name | |
String surfaceName = getSurfaceName(m); | |
if (surfaceName.equals("selected")) | |
{ | |
continue; | |
} | |
//add new surface to map | |
if (!groupedBySurface.containsKey(surfaceName)) | |
{ | |
groupedBySurface.put(surfaceName, new ArrayList<OscMessage>()); | |
} | |
//add handler-message to surface | |
groupedBySurface.get(surfaceName).add(m); | |
} | |
//now create or update surfaces! | |
for (String surfaceName : groupedBySurface.keySet()) | |
{ | |
ArrayList<OscMessage> messages = groupedBySurface.get(surfaceName); | |
int handlerCount = messages.size() / 2; | |
//print(surfaceName + ": " + handlerCount + "\t"); | |
// add surface if it does not exist yet | |
Surface s = findFirstSurface(surfaceName); | |
if(s == null) | |
{ | |
s = new Surface(surfaceName, handlerCount); | |
surfaces.add(s); | |
} | |
//update values of handlers | |
for (int i = 0; i < messages.size(); i += 2) | |
{ | |
OscMessage msgX = messages.get(i); | |
OscMessage msgY = messages.get(i+1); | |
float x = msgX.get(0).floatValue(); | |
float y = msgY.get(0).floatValue(); | |
PVector h = s.handles[i/2]; | |
h.x = x * width; | |
h.y = (1-y) * height; | |
//print("[" + h.x + " ," + h.y + "]\t"); | |
} | |
//println(); | |
} | |
//clear out deleted surfaces | |
for(int i = surfaces.size() - 1; i >= 0; i--) | |
{ | |
Surface s = surfaces.get(i); | |
if(!groupedBySurface.keySet().contains(s.name)) | |
{ | |
surfaces.remove(s); | |
} | |
} | |
} | |
Surface findFirstSurface(String name) | |
{ | |
for(Surface s : surfaces) | |
{ | |
if(s.name.equals(name)) | |
{ | |
return s; | |
} | |
} | |
return null; | |
} | |
void syncWithMadMapper(Surface s) | |
{ | |
for (int i = 0; i < s.handles.length; i++) | |
{ | |
PVector h = s.handles[i]; | |
OscMessage msgX = new OscMessage("/surfaces/"+ s.name +"/handles/"+i+"/x"); | |
OscMessage msgY = new OscMessage("/surfaces/"+ s.name +"/handles/"+i+"/y"); | |
msgX.add((h.x / width)); | |
msgY.add(1 - (h.y / height)); | |
osc.send(msgX, madMapper); | |
osc.send(msgY, madMapper); | |
} | |
} | |
void oscEvent(OscBundle bundle) { | |
//println("bundle by received!"); | |
if (receiveSurfacesRunning) | |
{ | |
receiveSurfacesRunning = false; | |
receiveSurfacesCompleted(bundle); | |
} | |
if (updateSurfacesRunning) | |
{ | |
updateSurfacesRunning = false; | |
updateSurfacesCompleted(bundle); | |
} | |
} | |
void oscBundleEvent(OscBundle bundle) { | |
} | |
void oscEvent(OscMessage msg) { | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment