• fullscreen
  • Signatur.pde
  • SuperChar.pde
  • User_Interface.pde
  • wordcollider_2_0_1.pde
  • class Signatur {
    
      ArrayList<PVector> mainPath; // this is the main path, it is the same for all types. 
      ArrayList<PVector> subPath; // this is the visible and indivdual flight path for each type. It's the mainPath with an individual offset.
    
      int type;
      int direction;
    
      PVector target;
      PVector origin;
      PVector rotation;
    
      color pathColor;
    
      float progress = 0;
      float[] progressOf = {0};
      float[] negativProgressOf = {1};
      float[] mainPathMag = {0};
    
      Signatur(int theType, int dir, int theTargetAreaX, int theTargetAreaYZ, int theNoTargetAreaX, float thePathDeviation) {
        type = theType;
        direction = dir;
        origin = new PVector(0, 0, 0);
    
        //  ---------------- set targets / right side ----------------
        if (dir > 0) {
          if (type == 2) { // constrain the targets to the x-axis if the char is a nasal…
            target = new PVector(random(theNoTargetAreaX, theTargetAreaX), random(-theTargetAreaYZ/15, theTargetAreaYZ/15), random(-theTargetAreaYZ/15, theTargetAreaYZ/15));
          } 
          else if (type == 1) { // plosive
            target = new PVector(random(1, theNoTargetAreaX/2), random(-theTargetAreaYZ, theTargetAreaYZ), random(-theTargetAreaYZ, theTargetAreaYZ));
          } 
          else {
            target = new PVector(random(theNoTargetAreaX, theTargetAreaX), random(-theTargetAreaYZ, theTargetAreaYZ), random(-theTargetAreaYZ, theTargetAreaYZ));
          }
    
          //  ---------------- set targets / left side ----------------
        } 
        else {
          if (type == 2) { // constrain the targets to the x-axis if the char is a nasal…
            target = new PVector(random(-theTargetAreaX, -theNoTargetAreaX), random(-theTargetAreaYZ/15, theTargetAreaYZ/15), random(-theTargetAreaYZ/15, theTargetAreaYZ/15));
          } 
          else if (type == 1) { // plosive
            target = new PVector(random(-theNoTargetAreaX/2, -1), random(-theTargetAreaYZ, theTargetAreaYZ), random(-theTargetAreaYZ, theTargetAreaYZ));
          } 
          else {
            target = new PVector(random(-theTargetAreaX, -theNoTargetAreaX), random(-theTargetAreaYZ, theTargetAreaYZ), random(-theTargetAreaYZ, theTargetAreaYZ));
          }
        }
    
        //  ---------------- create random Vector for the aproximant signature ----------------
        PVector randomVector = new PVector(random(-thePathDeviation, thePathDeviation), random(-thePathDeviation, thePathDeviation), random(-thePathDeviation, thePathDeviation));
        rotation = PVector.add(target, randomVector);
    
        //  ---------------- ArrayLists ----------------
        mainPath = new ArrayList<PVector>();
        mainPath.add(new PVector(origin.x, origin.y, origin.z));
    
        subPath = new ArrayList<PVector>();
        subPath.add(new PVector(origin.x, origin.y, origin.z));
      }
    
      /////////////////////////////////////////////////////
      void update() {
        if (mainPath.size() >= 1 && progress < 0.98) {
    
          float speed = 0; // spreading speed (smaller = faster)
          float factor = 0; // mostly used as multiplyer or size
    
          //  ---------------- define type specific parameters ----------------
          switch (type) {
          case 0: // vowel
            speed = 40;
            break;
          case 1: // plosiv
            speed = 15;
            factor = 20;
            break;
          case 2: // nasal
            speed = 40;
            factor = 40;
            break;
          case 3: // vibrant
            speed = 60;
            factor = 35;
            break;
          case 4: // fricative
            speed = 40;
            factor = 20;
            noiseDetail(3);
            break;
          case 5: // aproximant
            speed = 35;
            factor = 50;
            break;
          case 6: // special-sign
            speed = 15;
            break;
          case 7: // numeric character
            speed = 25;
            break;
          }
    
    
          //  ---------------- calculate mainPath ----------------
    
          int index = mainPath.size()-1;
          PVector step = new PVector (mainPath.get(index).x, mainPath.get(index).y, mainPath.get(index).z);
          PVector newPos = new PVector (mainPath.get(index).x, mainPath.get(index).y, mainPath.get(index).z);
    
    
          // calculate progress
          if (type != 5) {
            progress = map(dist(origin.x, origin.y, origin.z, newPos.x, newPos.y, newPos.z), 0, dist(origin.x, origin.y, origin.z, target.x, target.y, target.z), 0, 1);
            step.sub(target);
          } 
          else {
            progress = map(dist(origin.x, origin.y, origin.z, newPos.x, newPos.y, newPos.z), 0, dist(origin.x, origin.y, origin.z, rotation.x, rotation.y, rotation.z), 0, 1);
            step.sub(rotation);
          }
    
          step.div(speed);
          newPos.sub(step);
          mainPath.add(newPos);
    
          PVector subStep = new PVector(mainPath.get(index).x, mainPath.get(index).y, mainPath.get(index).z);
          PVector subPos = new PVector (mainPath.get(index).x, mainPath.get(index).y, mainPath.get(index).z);
    
    
          //  ---------------- calculate type specific flightpath (subPath) ----------------
    
          if (type == 1) { // plosiv = fast and fragmented flight path
            float noiseX = random(-0.5, 0.5);
            float noiseY = random(-1, 1);
            float noiseZ = random(-1, 1);
            subStep.set((noiseX*factor)*progress, (noiseY*factor)*progress, (noiseZ*factor)*progress);
            subPos.add(subStep);
          }
    
          else if (type == 2) { // nasal = resonating flight path
            float amplitude = factor*progress;
            float noiseY = noise(subPos.y);
            subPos.y += cos(progress*factor)*amplitude;
          } 
    
          else if (type == 3) { // vibrant = oscillating, spiraling flight path
            float rad = factor*progress;
            subPos.x += sin(progress*factor)*rad;
            subPos.y += cos(progress*factor)*rad;
          } 
    
          else if (type == 4) { // fricative = noisy flight path
            float noiseX = noise(subPos.x);
            float noiseY = noise(subPos.y);
            float noiseZ = noise(subPos.z);
            subStep.set((noiseX*factor)*progress, (noiseY*factor)*progress, (noiseZ*factor)*progress);
            subPos.add(subStep);
          } 
    
          else if (type == 5) { // approximant = slightly curved flight path
            PVector targetApproximation = new PVector();
            targetApproximation.set(rotation);
            targetApproximation.sub(target);
            targetApproximation.div(40);
            rotation.sub(targetApproximation);
          }
    
          //  ---------------- add new values ----------------
          subPath.add(subPos);
    
          progressOf = append(progressOf, progress); // store the progress in an Array (from 0 to 1)
          negativProgressOf = append(negativProgressOf, map(progress, 0, 1, 1, 0)); // store the negativ progress in an Array (from 1 to 0)
          mainPathMag = append(mainPathMag, dist(origin.x, origin.y, origin.z, newPos.x, newPos.y, newPos.z)); // store the magnitude in an Array
        }
      }
    
    
      /////////////////////////////////////////////////////
      void display(char c) {
        noStroke();
    
        //  ---------------- different line weights for different types ----------------
    
        float lineWeight = 0.8;
    
        switch (type) {
        case 0: // vowel
          lineWeight = 0.9;
          break;
        case 5: // approximant
          lineWeight = 1;
          break;
        }
    
    
        //  ---------------- draw subPath ----------------
    
        if (subPath.size() > 1) {
          if (signaturVisible) {
            for (int i=1; i< subPath.size(); i++) {
    
              // nasal color
              if (type == 2) {
                pathColor = color(255, 250, 100, 255-(progressOf[i]*255));
              }
    
              // default color
              else {
                pathColor = color(255, 255-(progressOf[i]*255));
              }
    
              // vowel
              if (type == 0) { 
                pathColor = color(120, 200, 255, 255-(progressOf[i]*255));
                line_3d(new PVector(subPath.get(i-1).x, subPath.get(i-1).y, subPath.get(i-1).z), new PVector(subPath.get(i).x, subPath.get(i).y, subPath.get(i).z), lineWeight*negativProgressOf[i], pathColor);
              }
    
              // plosiv
              else if (type == 1) { 
                pathColor = color(255, 70, 10, 255-(progressOf[i]*255));
                if (sin(i) < 0.2) {
                  line_3d(new PVector(subPath.get(i-1).x, subPath.get(i-1).y, subPath.get(i-1).z), new PVector(subPath.get(i).x, subPath.get(i).y, subPath.get(i).z), lineWeight*negativProgressOf[i], pathColor);
                }
              } 
    
              // special-sign
              else if (type == 6) { 
                if (i > 10 && i < 50) {
                  pathColor = color(128, 255-(progressOf[i]*255));
    
                  // ------ draw a cross ------
                  gl.glPushMatrix();
                  gl.glTranslatef(subPath.get(i).x, subPath.get(i).y, subPath.get(i).z);
                  gl.glColor4f(red(pathColor)/255, green(pathColor)/255, blue(pathColor)/255, alpha(pathColor)/255);
                  float crossSize = progressOf[i]*2;
    
                  gl.glBegin(gl.GL_LINES);
                  gl.glVertex3f(-crossSize, 0, 0);
                  gl.glVertex3f(crossSize, 0, 0);
                  gl.glEnd();
                  gl.glBegin(gl.GL_LINES);
                  gl.glVertex3f(0, -crossSize, 0);
                  gl.glVertex3f(0, crossSize, 0);
                  gl.glEnd();
                  gl.glBegin(gl.GL_LINES);
                  gl.glVertex3f(0, 0, -crossSize);
                  gl.glVertex3f(0, 0, crossSize);
                  gl.glEnd();
    
                  gl.glPopMatrix();
                }
              } 
    
              // default
              else {
                line_3d(new PVector(subPath.get(i-1).x, subPath.get(i-1).y, subPath.get(i-1).z), new PVector(subPath.get(i).x, subPath.get(i).y, subPath.get(i).z), lineWeight*negativProgressOf[i], pathColor);
              }
            }
          }
    
    
          //  ---------------- debug/info modes ----------------
    
          if (infoVisible) { // draw info text
            fill(255);
            offscreen.endGL();
            offscreen.textFont(font, 10);
              offscreen.pushMatrix();
              offscreen.translate(subPath.get(subPath.size() -1).x + 2, subPath.get(subPath.size() -1).y - 2, subPath.get(subPath.size() -1).z);
              offscreen.text(c, 0, 0, 0);
              offscreen.popMatrix();
            offscreen.beginGL();
          }
    
          if (mainPathVisible) { // draw mainPath
            gl.glColor4f(1, 0, 0, 0.5);
            gl.glBegin(gl.GL_LINES);
            gl.glVertex3f(origin.x, origin.y, origin.z);
            gl.glVertex3f(target.x, target.y, target.z);
            gl.glEnd();
          }
    
          if (targetVisible) { // draw a cross at the target
            int crossSize = 5;
    
            gl.glPushMatrix();
            gl.glTranslatef(target.x, target.y, target.z);
            gl.glColor4f(1, 0, 0, 1);
    
            gl.glBegin(gl.GL_LINES);
            gl.glVertex3f(-crossSize, 0, 0);
            gl.glVertex3f(crossSize, 0, 0);
            gl.glEnd();
            gl.glBegin(gl.GL_LINES);
            gl.glVertex3f(0, -crossSize, 0);
            gl.glVertex3f(0, crossSize, 0);
            gl.glEnd();
            gl.glBegin(gl.GL_LINES);
            gl.glVertex3f(0, 0, -crossSize);
            gl.glVertex3f(0, 0, crossSize);
            gl.glEnd();
    
            gl.glPopMatrix();
    
    
            gl.glPushMatrix();
            gl.glTranslatef(rotation.x, rotation.y, rotation.z);
            gl.glColor4f(0, 1, 0, 1);
    
            gl.glBegin(gl.GL_LINES);
            gl.glVertex3f(-crossSize, 0, 0);
            gl.glVertex3f(crossSize, 0, 0);
            gl.glEnd();
            gl.glBegin(gl.GL_LINES);
            gl.glVertex3f(0, -crossSize, 0);
            gl.glVertex3f(0, crossSize, 0);
            gl.glEnd();
            gl.glBegin(gl.GL_LINES);
            gl.glVertex3f(0, 0, -crossSize);
            gl.glVertex3f(0, 0, crossSize);
            gl.glEnd();
    
            gl.glPopMatrix();
          }
        }
      }
    
      //inspired from James Carruthers's drawLine function
      //http://processing.org/discourse/yabb2/YaBB.pl?num=1262458611/4#4
      void line_3d(PVector pv1, PVector pv2, float weight, color _color) {
        PVector v1 = new PVector(pv2.x - pv1.x, pv2.y - pv1.y, pv2.z - pv1.z);
    
        float rho = sqrt(pow(v1.x, 2) + pow(v1.y, 2) + pow(v1.z, 2));
        float phi = acos(v1.z / rho);
        float the = atan2(v1.y, v1.x);
    
        v1.mult(0.5);      
    
        float zval = pv1.dist(pv2) * 0.5;  
        float rad = radians(120) * weight * 0.5;
    
        gl.glPushMatrix();
        gl.glTranslatef(pv1.x, pv1.y, pv1.z);
        gl.glTranslatef(v1.x, v1.y, v1.z);
        gl.glRotatef(degrees(the), 0, 0, 1);
        gl.glRotatef(degrees(phi), 0, 1, 0);
        gl.glColor4f(red(_color)/255, green(_color)/255, blue(_color)/255, alpha(_color)/255);
    
        //DRAW THE 3D 'LINE' (with 3 planes)  
        gl.glBegin(GL.GL_QUADS);
        //1
        gl.glVertex3f( rad, -rad, zval);
        gl.glVertex3f( rad, -rad, -zval);
        gl.glVertex3f(-rad, -rad, -zval);
        gl.glVertex3f(-rad, -rad, zval);      
        //2
        gl.glVertex3f(-rad, -rad, zval);
        gl.glVertex3f(-rad, -rad, -zval);
        gl.glVertex3f(   0, rad, -zval);
        gl.glVertex3f(   0, rad, zval);
        //3
        gl.glVertex3f(   0, rad, zval);
        gl.glVertex3f(   0, rad, -zval);
        gl.glVertex3f( rad, -rad, -zval);
        gl.glVertex3f( rad, -rad, zval);
        gl.glEnd();
    
        gl.glPopMatrix();
      }
    }
    
    
    class SuperChar {
      
      char c;
      boolean isCollided = false;
      
      //---------------- parameters ----------------
      color charColor = color(255, 0);
      int fadeIn = 0;
    
      PVector location;
      PVector velocity;
      PVector acceleration;
      float speedLimit = 50;
      int direction;
      
      Signatur signatur;
      
      
      SuperChar(float theX, char theChar, int dir) {
        c = theChar;
        location = new PVector(theX, 0, 0);
        velocity = new PVector(0, 0, 0);
        direction = dir;
        
        //---------------- which type is it? ----------------
        int theType = 0;
    
        if (isVowel()) {
          theType = 0;
        } else if (isPlosive()) {
          theType = 1;
        } else if (isNasal()) {
          theType = 2;
        } else if (isVibrant()) {
          theType = 3;
        } else if (isFricative()) {
          theType = 4;
        } else if (isAproximant()) {
          theType = 5;
        } else if (isSpecialSign()) {
          theType = 6;
        } else if (isNumericCharacter()) {
          theType = 7;
        }
        
        //---------------- signature ----------------
        signatur = new Signatur(theType, direction, targetAreaX, targetAreaYZ, noTargetAreaX, pathDeviation);
      }
    
      //////////////////////////////////////////////////////////////////////////////
      //---------------- is it a vowel? (type 0) ----------------
      boolean isVowel() { 
        if (c == 'a' || c == 'ä' || c == 'e' || c == 'i' || c == 'o' || c == 'ö' || c == 'u' || c == 'ü' || c == 'y') {
          return true;
        } return false;
      }
      
      //---------------- is it a plosiv? (type 1) ----------------
      boolean isPlosive() { 
        if (c == 'p' || c == 'b' || c == 't' || c == 'd' || c == 'c' || c == 'k' || c == 'g' || c == 'q') {
          return true;
        } return false;
      }
      
      //---------------- is it a nasal? (type 2) ----------------
      boolean isNasal() { 
        if (c == 'm' || c == 'n') {
          return true;
        } return false;
      }
      
      //---------------- is it a vibrant? (type 3) ----------------
      boolean isVibrant() { 
        if (c == 'r') {
          return true;
        } return false;
      }
      
      //---------------- is it a fricative? (type 4) ----------------
      boolean isFricative() { 
        if (c == 'ß' || c == 'f' || c == 'v' || c == 's' || c == 'z' || c == 'x' || c == 'h') {
          return true;
        } return false;
      }
      
      //---------------- is it a aproximant? (type 5) ----------------
      boolean isAproximant() { 
        if (c == 'j' || c == 'l' || c == 'w') {
          return true;
        } return false;
      }
      
      //---------------- is it a point, whitespace or a question mark? (type 6) ----------------
      boolean isSpecialSign() { 
        if (c == ' ' || c == '-' || c == '?' || c == '!' || c == '.' || c == ':' || c == ',' || c == '%') {
          return true;
        } return false;
      }
      
      //---------------- is it a number? (type 7) ----------------
      boolean isNumericCharacter() { 
        if (c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7' || c == '8' || c == '9') {
          return true;
        } return false;
      }
    
      //////////////////////////////////////////////////////////////////////////////
      void update(float acc) {
        
        PVector center = new PVector(0, 0, 0);
        float d = location.dist(center);
        
        if (d <  speedLimit && !isCollided) {
          isCollided = true;
        }
        
        if (!isCollided) {
          acceleration = new PVector(acc*direction, 0, 0);
          velocity.add(acceleration);
          velocity.limit(speedLimit);
          location.add(velocity);
          
          if(fadeIn <= 255) {
            fadeIn += 5;
          }
          
          charColor = color(255, fadeIn);
          
          
        } else {
          signatur.update();
        }   
      } 
    
      //////////////////////////////////////////////////////////////////////////////
      void display() {
        
        if (!isCollided) {
          offscreen.endGL();
            offscreen.fill(charColor);
            offscreen.textFont(font, 13);
            offscreen.pushMatrix();
            offscreen.translate(location.x, location.y, location.z);
            offscreen.text(c, 0, 0, 0);
            offscreen.popMatrix();
          offscreen.beginGL();
        } else {
          signatur.display(c);
        }
      }
    }
    
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void keyReleased() {
      // ---------------- start/restart collision ----------------
      if (key == ' ') {
        preprocessing();
      } 
      
      // ---------------- load text from TXT file ----------------
      if (key == 'l') {
        loadText();
      }
      
      // ---------------- save hi-resolution image (with offscreen resolution) ----------------
      if (key == 's') {
        hiResImageOutput = true;
        exportCounter++;
      }
      
      // ---------------- display options ----------------
      if (key == '1') {
        signaturVisible = !signaturVisible;
      } 
      
      if (key == '2') {
        targetVisible = !targetVisible;
      } 
      
      if (key == '3') {
        mainPathVisible = !mainPathVisible;
      } 
      
      if (key == '4') {
        infoVisible = !infoVisible;
      } 
      
    }
    
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void mouseDragged() {
      if (keyPressed) {
        if (keyCode == SHIFT) {
          cam.track((mouseX - pmouseX)*(-1), (mouseY - pmouseY)*(-1));
        } else if (keyCode == ALT) {
          cam.zoom(radians(mouseY - pmouseY) / 2.0);
        }
        
      } else {
          cam.tumble(radians((mouseX - pmouseX)*(-1)), radians((mouseY - pmouseY)/2)*(-1));
          //cam.circle(radians(((mouseX - pmouseX)/2)*-1));
      }
    }
    
    //////////////////////////////////////////////////////////
    public void loadText() {
      String[] textLoaded = loadStrings("../text/text_to_collide.txt");
      //String[] textLoaded = loadStrings("text/text_to_collide.txt");
      
      a = textLoaded[0];
      b = textLoaded[1];
      println(".txt-file loaded");
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    String event() {
      return String.format("%1$ty%1$tm%1$td_%1$tH%1$tM%1$tS", Calendar.getInstance());
    }
    
    /* ------------------------------------------------------------------------
     * wordcollider 2.0.1
     * Code by Moritz Heller
     
     * This Sketch requires: 
       GLGraphics Library (http://glgraphics.sourceforge.net/)
       OCD Library (http://gdsstudios.com/processing/libraries/ocd/)
     
     * rotate view   =   Mouse Click + drag
     * move view     =   Shift + Mouse Click + drag
     * zoom view     =   Alt + Mouse Click + drag
    
     * keyboard shortcuts:
     * Press [Spacebar] to restart the simulation
     * Press [L] to load a text from a *.txt file
     * Press [S] to save a hi-resolution image (with offscreen resolution)
     
     * Press [1] to toggle signature display
     * Press [2] to display the targets (for debugging)
     * Press [3] to display the mainPath (for debugging)
     * Press [4] to display infotext
     
     ------------------------------------------------------------------------ */
     
    import processing.opengl.*;
    import javax.media.opengl.GL;
    import codeanticode.glgraphics.*;
    
    import damkjer.ocd.*;
    
    //---------------- controle variables ----------------
    boolean run = true;
    
    int frame;
    int maxFrameCount = 250;
    float acc = 1.05;
    
    //---------------- signature parameters ----------------
    // default text strings a (left) and b (right)
    String a = "What If CERN Smashed Words Rather Than Protons?";
    String b = "the signatures look how I imagine they would look like based on phonetic descriptions…";
    
    SuperChar[] sc1;
    SuperChar[] sc2;
    
    int wordStartposition = 2000;
    int targetAreaX  = 850;
    int targetAreaYZ = 300;
    int noTargetAreaX = 100;
    float pathDeviation = 600;
    
    // ---------------- signature display ----------------
    boolean signaturVisible = true;
    boolean infoVisible = false;
    boolean mainPathVisible = false;
    boolean targetVisible = false;
    
    PFont font;
    
    // ---------------- OpenGL / Camera ----------------
    GLGraphics pgl;
    GLGraphicsOffScreen offscreen;
    GL gl;
    GLTexture tex;
    
    Camera cam;
    
    // ---------------- image output ----------------
    boolean hiResImageOutput = false;
    String currentEvent;
    int exportCounter;
    
    //offscreen rendering resolution:
    int offscreenWidth = 1920*2;
    int offscreenHeight = 1080*2;
    
    
    //////////////////////////////////////////////////////////
    void setup() {
      size(1280, 720, GLConstants.GLGRAPHICS); //720p
      //size(1920, 1080, GLConstants.GLGRAPHICS); //1080p
      //size(screen.width, screen.height, GLConstants.GLGRAPHICS); //Fullscreen
      //frameRate(30);
      
      // ---------------- OpenGL ----------------
      offscreen = new GLGraphicsOffScreen(this, offscreenWidth, offscreenHeight, true, 4);  
      pgl = (GLGraphics) g;  
      gl = offscreen.gl;
      
      // ---------------- camera settings -----------------
      cam = new Camera(this, 0, 0, 500);
      cam.zoom(0.4);
      
      font = loadFont("HelveticaNeue-Light-18.vlw");
      
      preprocessing();
    }
    
    //////////////////////////////////////////////////////////
    void draw() {
      background(0);
      
      // ---------------- save the texture in the video memory as *.tif ----------------
      if(hiResImageOutput) {
        tex.updateTexture();
        tex.save("../output/hiRes_event_"+ currentEvent + "_" + exportCounter + ".tif");
        //tex.save("output/hiRes_event_"+ currentEvent + "_" + exportCounter + ".tif");
        hiResImageOutput = false;
        println("high-resolution image: \"hiRes_event_" + currentEvent + "_" + exportCounter + ".tif\" successful saved!");
      }
      
      // ---------------- offscreen rendering ----------------
      offscreen.beginDraw();
        offscreen.background(0);
        
        // Disabling depth masking to properly render a semitransparent
        offscreen.setDepthMask(false);
        
        cam.feed();
        
        offscreen.beginGL();
        
        // ---------------- blend modes ----------------
        gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE); // add
      
        for (int i=0; i < sc1.length; i++) {
          if(run) {
            sc1[i].update(acc);
          }
          sc1[i].display();
        }
        
        for (int i=0; i < sc2.length; i++) {
          if(run) {
            sc2[i].update(acc);
          }
          sc2[i].display();
        }
      
        offscreen.endGL();
      offscreen.endDraw();
      
      //display offscreen rendering
      tex = offscreen.getTexture();
      image(tex, 0, 0, width, height);
    }
    
    
    //////////////////////////////////////////////////////////
    void preprocessing() {
      currentEvent = event();
      exportCounter = 0;
      frame = 0;
      
      a = a.toLowerCase();
      b = b.toLowerCase();
      
      sc1 = new SuperChar[a.length()];
      sc2 = new SuperChar[b.length()];
      
      textFont(font, 13);
      
      // calculate the length of the left word
      float wordLength = 0;
      for (int i=0; i < a.length(); i++) { 
        wordLength += textWidth(a.charAt(i)); 
      }
      
      // offset the start position of the left word so that both word hit the center at once
      float x = (wordStartposition*-1)-wordLength; 
      
      // left word
      for (int i=0; i < a.length(); i++) { 
        float charWidth = textWidth(a.charAt(i));
        sc1[i] = new SuperChar(x, a.charAt(i), 1);
        x += charWidth;
      }
    
      x = wordStartposition;
      
      // right word
      for (int i=0; i < b.length(); i++) { 
        float charWidth = textWidth(b.charAt(i));
        sc2[i] = new SuperChar(x, b.charAt(i), -1);
        x += charWidth;
      }
      
    }
    
    

    code

    tweaks (0)

    about this sketch

    This sketch is running as Java applet, exported from Processing.

    license

    advertisement


    Moritz Heller

    wordcollider_2_0_1

    Add to Faves Me Likey@!
    You must login/register to add this sketch to your favorites.

    The source code of Wordcollider 2.0.1

    Inspired by visualizations of particle collisions at LHC CERN, wordcollider accelerate two phrases against each other on a collision course. The collision split the words up in their letters, their elementary particles, so to speak. After collision, wordcollider visualize a signature for each letter, based on their phonetic characteristics.

    more about the project:
    http://vimeo.com/moritzheller/wordcollider
    http://www.fastcodesign.com/1670249/infographic-what-if-cern-smashed-words-rather-than-protons#1

    You need to login/register to comment.