Skip to content

Instantly share code, notes, and snippets.

@cansik
Last active January 7, 2016 07:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cansik/9d5ffe5cbbe4d194cbe6 to your computer and use it in GitHub Desktop.
Save cansik/9d5ffe5cbbe4d194cbe6 to your computer and use it in GitHub Desktop.
MadMapper Remote Example
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