topical media & game development

talk show tell print

graphic-processing-site-examples-Libraries-OpenGL-Yellowtail-Yellowtail.pde / pde



  
Yellowtail by Golan Levin (www.flong.com). Click, drag, and release to create a kinetic gesture. Yellowtail (1998-2000) is an interactive software system for the gestural creation and performance of real-time abstract animation. Yellowtail repeats a user's strokes end-over-end, enabling simultaneous specification of a line's shape and quality of movement. Each line repeats according to its own period, producing an ever-changing and responsive display of lively, worm-like textures.

  
  
  import processing.opengl.*;
  
  Gesture gestureArray[];
  final int nGestures = 36;  // Number of gestures
  final int minMove = 3;     // Minimum travel for a new point
  int currentGestureID;
  
  Polygon tempP;
  int tmpXp[];
  int tmpYp[];
  
  void setup() {
    size(1024, 768, OPENGL);
    background(0, 0, 0);
    noStroke();
  
    currentGestureID = -1;
    gestureArray = new Gesture[nGestures];
    for (int i = 0; i < nGestures; i++) {
      gestureArray[i] = new Gesture(width, height);
    }
    clearGestures();
  }
  
  void draw() {
    background(0);
  
    updateGeometry();
    fill(255, 255, 245);
    for (int i = 0; i < nGestures; i++) {
      renderGesture(gestureArray[i], width, height);
    }
  }
  
  void mousePressed() {
    currentGestureID = (currentGestureID+1) % nGestures;
    Gesture G = gestureArray[currentGestureID];
    G.clear();
    G.clearPolys();
    G.addPoint(mouseX, mouseY);
  }
  
  void mouseDragged() {
    if (currentGestureID >= 0) {
      Gesture G = gestureArray[currentGestureID];
      if (G.distToLast(mouseX, mouseY) > minMove) {
        G.addPoint(mouseX, mouseY);
        G.smooth();
        G.compile();
      }
    }
  }
  
  void keyPressed() {
    if (key == '+' || key == '=') {
      if (currentGestureID >= 0) {
        float th = gestureArray[currentGestureID].thickness;
        gestureArray[currentGestureID].thickness = min(96, th+1);
        gestureArray[currentGestureID].compile();
      }
    } else if (key == '-') {
      if (currentGestureID >= 0) {
        float th = gestureArray[currentGestureID].thickness;
        gestureArray[currentGestureID].thickness = max(2, th-1);
        gestureArray[currentGestureID].compile();
      }
    } else if (key == ' ') {
      clearGestures();
    }
  }
  
  void renderGesture(Gesture gesture, int w, int h) {
    if (gesture.exists) {
      if (gesture.nPolys > 0) {
        Polygon polygons[] = gesture.polygons;
        int crosses[] = gesture.crosses;
  
        int xpts[];
        int ypts[];
        Polygon p;
        int cr;
  
        beginShape(QUADS);
        int gnp = gesture.nPolys;
        for (int i=0; i<gnp; i++) {
  
          p = polygons[i];
          xpts = p.xpoints;
          ypts = p.ypoints;
  
          vertex(xpts[0], ypts[0]);
          vertex(xpts[1], ypts[1]);
          vertex(xpts[2], ypts[2]);
          vertex(xpts[3], ypts[3]);
  
          if ((cr = crosses[i]) > 0) {
            if ((cr & 3)>0) {
              vertex(xpts[0]+w, ypts[0]);
              vertex(xpts[1]+w, ypts[1]);
              vertex(xpts[2]+w, ypts[2]);
              vertex(xpts[3]+w, ypts[3]);
  
              vertex(xpts[0]-w, ypts[0]);
              vertex(xpts[1]-w, ypts[1]);
              vertex(xpts[2]-w, ypts[2]);
              vertex(xpts[3]-w, ypts[3]);
            }
            if ((cr & 12)>0) {
              vertex(xpts[0], ypts[0]+h);
              vertex(xpts[1], ypts[1]+h);
              vertex(xpts[2], ypts[2]+h);
              vertex(xpts[3], ypts[3]+h);
  
              vertex(xpts[0], ypts[0]-h);
              vertex(xpts[1], ypts[1]-h);
              vertex(xpts[2], ypts[2]-h);
              vertex(xpts[3], ypts[3]-h);
            }
  
            // I have knowingly retained the small flaw of not
            // completely dealing with the corner conditions
            // (the case in which both of the above are true).
          }
        }
        endShape();
      }
    }
  }
  
  void updateGeometry() {
    Gesture J;
    for (int g=0; g<nGestures; g++) {
      if ((J=gestureArray[g]).exists) {
        if (g!=currentGestureID) {
          advanceGesture(J);
        } else if (!mousePressed) {
          advanceGesture(J);
        }
      }
    }
  }
  
  void advanceGesture(Gesture gesture) {
    // Move a Gesture one step
    if (gesture.exists) { // check
      int nPts = gesture.nPoints;
      int nPts1 = nPts-1;
      Vec3f path[];
      float jx = gesture.jumpDx;
      float jy = gesture.jumpDy;
  
      if (nPts > 0) {
        path = gesture.path;
        for (int i = nPts1; i > 0; i--) {
          path[i].x = path[i-1].x;
          path[i].y = path[i-1].y;
        }
        path[0].x = path[nPts1].x - jx;
        path[0].y = path[nPts1].y - jy;
        gesture.compile();
      }
    }
  }
  
  void clearGestures() {
    for (int i = 0; i < nGestures; i++) {
      gestureArray[i].clear();
    }
  }
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.