• fullscreen
  • nightingale.pde
  • subtitles.pde
  • PImage a, b;
    int offset = 0;
    int imageSize = 400;
    boolean running = false;
    Subtitles s;
    int playTime;
    float imageY;
    int totalLength = 10000;
    
    void setup()
    {
      size(500,600);
      //size(screenWidth,screenHeight,OPENGL);
      //orientation(PORTRAIT);
      a = loadImage("nightingale.jpg");
      if (imageSize>width) imageSize=width;
      a.resize(imageSize, imageSize);
      background(0);
      imageY = max((height-width)/3,0);
      s = new Subtitles(totalLength);
      b = createImage(imageSize, imageSize, RGB);
      a.loadPixels();
      b.loadPixels();
      arrayCopy(a.pixels, b.pixels);
      smooth();
      playTime = millis();
    }
    
    void draw()
    {
      background(0);
      if (running)
      {
        b.loadPixels();
        float br = 0;
        for (int i=0; i<b.pixels.length; i++)
        {
          if (b.pixels[i]==#FFFFFF) b.pixels[i]=#000000;
          else if (b.pixels[i]==#000000) b.pixels[i]=#FFFFFF;
          int pixelColor = b.pixels[i];
          int b_r = (pixelColor >> 16) & 0xff;
          int b_g = (pixelColor >> 8) & 0xff;
          int b_b = pixelColor & 0xff;
          br += 0.3*b_r+0.59*b_g+0.11*b_b;
        }
        float avg = br/b.pixels.length;
        if (avg<150) b.filter(DILATE);
        else b.filter(ERODE);
        fastBlur(b, 1);
        int p = (int)constrain(30-(frameCount-offset)/30, 6, 255);
        b.filter(POSTERIZE, p);
        image(b, 0, imageY, width, width);
      }
      else image(a, 0, imageY, width, width);
      s.write(playTime,running);
      if (((millis()-playTime)/1000)>totalLength)
      {
        running = false;
      }
    }
    
    // Super Fast Blur v1.1 by Mario Klingemann
    void fastBlur(PImage img, int radius) {
    
      if (radius<1) {
        return;
      }
      int w=img.width;
      int h=img.height;
      int wm=w-1;
      int hm=h-1;
      int wh=w*h;
      int div=radius+radius+1;
      int r[]=new int[wh];
      int g[]=new int[wh];
      int b[]=new int[wh];
      int rsum, gsum, bsum, fx, fy, i, p, p1, p2, yp, yi, yw;
      int vmin[] = new int[max(w, h)];
      int vmax[] = new int[max(w, h)];
      int[] pix=img.pixels;
      int dv[]=new int[256*div];
      for (i=0;i<256*div;i++) {
        dv[i]=(i/div);
      }
    
      yw=yi=0;
    
      for (fy=0;fy<h;fy++) {
        rsum=gsum=bsum=0;
        for (i=-radius;i<=radius;i++) {
          p=pix[yi+min(wm, max(i, 0))];
          rsum+=(p & 0xff0000)>>16;
          gsum+=(p & 0x00ff00)>>8;
          bsum+= p & 0x0000ff;
        }
        for (fx=0;fx<w;fx++) {
    
          r[yi]=dv[rsum];
          g[yi]=dv[gsum];
          b[yi]=dv[bsum];
    
          if (fy==0) {
            vmin[fx]=min(fx+radius+1, wm);
            vmax[fx]=max(fx-radius, 0);
          }
          p1=pix[yw+vmin[fx]];
          p2=pix[yw+vmax[fx]];
    
          rsum+=((p1 & 0xff0000)-(p2 & 0xff0000))>>16;
          gsum+=((p1 & 0x00ff00)-(p2 & 0x00ff00))>>8;
          bsum+= (p1 & 0x0000ff)-(p2 & 0x0000ff);
          yi++;
        }
        yw+=w;
      }
    
      for (fx=0;fx<w;fx++) {
        rsum=gsum=bsum=0;
        yp=-radius*w;
        for (i=-radius;i<=radius;i++) {
          yi=max(0, yp)+fx;
          rsum+=r[yi];
          gsum+=g[yi];
          bsum+=b[yi];
          yp+=w;
        }
        yi=fx;
        for (fy=0;fy<h;fy++) {
          pix[yi]=0xff000000 | (dv[rsum]<<16) | (dv[gsum]<<8) | dv[bsum];
          if (fx==0) {
            vmin[fy]=min(fy+radius+1, hm)*w;
            vmax[fy]=max(fy-radius, 0)*w;
          }
          p1=fx+vmin[fy];
          p2=fx+vmax[fy];
    
          rsum+=r[p1]-r[p2];
          gsum+=g[p1]-g[p2];
          bsum+=b[p1]-b[p2];
    
          yi+=w;
        }
      }
    }
    
    void mousePressed()
    {
      if (mouseY>=s.boxY&&mouseY<=(s.boxY+s.boxHeight))
      {
        running = !running;
        if (running)
        {
          a.loadPixels();
          b.loadPixels();
          arrayCopy(a.pixels, b.pixels);
          b.updatePixels();
          offset=frameCount;
          playTime = millis();
          background(0);
          image(a, 0, imageY, width, width);
        }
      }
      else if(mouseY>=imageY&&mouseY<=imageY+width) b.filter(INVERT);
    }
    
    
    class Subtitles
    {
      float boxX; // left edge of box; depends on screen size
      float boxY;
      float boxWidth;
      float boxHeight;
      PFont font;
      int fontSize;
      String title = "The Nightingale - tap to start";
      String[] theText = {
        "The Nightingale",
        "And let those whose eyesight is dim", 
        "catch a nightingale", 
        "before the break of day", 
        "and take its gallbladder", 
        "and empty it,", 
        "and to it add one drop of dew", 
        "found on clean grass,", 
        "and then often anoint the eyelids", 
        "and lashes that are around the eye,", 
        "on retiring to bed", 
        "--and if it touches the eye inside a little", 
        "it does no harm--", 
        "and the dimness", 
        "will be marvelously removed from the eyes."
      };
      int[] timings = {
        0, 2, 4, 7, 9, 11, 13, 15, 17, 20, 22, 25, 27, 29, 30
      };
      int totalLength;
      int repLength = 33;
    
      Subtitles(int t)
      {
        totalLength = t;
        font=createFont("sans_serif", 72, true);
        for (int i=0; i<36; i++)
        {
          textFont(font);
          textSize(i);
          float testSize = 0;
          for (int j=0; j<theText.length;j++)
          {
            float thisSize = textWidth(theText[j]);
            if (thisSize > testSize) testSize = thisSize;
          }
          if (testSize*1.1 > width)
          {
            textSize(i-1);
            break;
          }
        }
        float testSize = 0;
        for (int j=0; j<theText.length;j++)
        {
          float thisSize = textWidth(theText[j]);
          if (thisSize > testSize) testSize = thisSize;
        }
        boxWidth = testSize*1.1;
        boxHeight = (textAscent()+textDescent())*1.5;
        boxX = (width-boxWidth)/2;
        boxY = min(height*.95,height-(1.5*boxHeight));
      }
    
      void write(int ptime, boolean playing)
      {
        smooth();
        stroke(255);
        fill(0);
        roundedRect(boxX, boxY, boxWidth, boxHeight, 15, 15);
        fill(255);
        textAlign(CENTER);
        int time = (int)(millis()-ptime)/1000;
        int whichLine = 0;
        String thisText;
        if (! (playing && time<=totalLength))
        {
          thisText = title;
        }
        else
        {
          for (int i=0; i<timings.length; i++)
          {
            if (time%repLength >= timings[i]) whichLine = i;
          }
          thisText = theText[whichLine%theText.length];
        }
        text(thisText, width/2, boxY+boxHeight*3/4.0);
      }
    
      void roundedRect(float x, float y, float w, float h, float rx, float ry)
      {
        beginShape();
        vertex(x, y+ry); //top of left side 
        bezierVertex(x, y, x, y, x+rx, y); //top left corner
    
        vertex(x+w-rx, y); //right of top side 
        bezierVertex(x+w, y, x+w, y, x+w, y+ry); //top right corner
    
        vertex(x+w, y+h-ry); //bottom of right side
        bezierVertex(x+w, y+h, x+w, y+h, x+w-rx, y+h); //bottom right corner
    
        vertex(x+rx, y+h); //left of bottom side
        bezierVertex(x, y+h, x, y+h, x, y+h-ry); //bottom left corner
    
        endShape(CLOSE);
      }
    }
    
    

    code

    tweaks (0)

    about this sketch

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

    license

    advertisement

    Joel Matthys

    Nightingale

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

    Part of my series of Hildegard von Bingen texts.

    Uses dotlassie's Superfast Blur (http://www.openprocessing.org/visuals/?visualID=5383)

    You need to login/register to comment.