• fullscreen
  • GlaucusAtlanticus.pde
  • float springRate = 0.1;
    float damping = 0.2;
    float angularSpringRate = 0.2;
    float angularDamping = 0.2;
    float angularMomentum = 150;
    float globalDamping = 0.0005;
    node[] nodes;
    element[] elements;
    node grippedNode;
    boolean nodeIsGripped = false;
    float mouseSpringRate = 0.1;
    int iterationRate = 8;
    int scaleUpFactor = 3;
    int scaleDownFactor = 8;
    void setup(){
      PImage Glaucus = loadImage("j40_1279988272.jpeg");
      PImage GlaucusMask = loadImage("GlaucusMask.jpg");
      GlaucusMask.filter(INVERT);
      Glaucus.mask(GlaucusMask);
      size(800,600);
    //  Glaucus.resize(Glaucus.width*scaleUpFactor/scaleDownFactor,0);
      Glaucus.resize(Glaucus.width/scaleDownFactor,0);
      GlaucusMask.resize(GlaucusMask.width/scaleDownFactor,0);
      nodes = new node[0];
      elements = new element[0];
      boolean[][] maskData = new boolean[GlaucusMask.width][GlaucusMask.height];
      node[][] tempNodes = new node[GlaucusMask.width][GlaucusMask.height];
      for(int i=0;i<GlaucusMask.width;i++){
        for(int j=0;j<GlaucusMask.height;j++){
          maskData[i][j] = brightness(GlaucusMask.get(i,j)) > 128;
          if(maskData[i][j]){
    //        PImage img = Glaucus.get(
    //        round(i*scaleDownFactor/scaleUpFactor)+25,
    //        round(j*scaleDownFactor/scaleUpFactor)+25,
    //        round(3*scaleUpFactor),round(3*scaleUpFactor));
            node newNode = new node(i,j,Glaucus.get(i,j));
    //        node newNode = new node(i,j,img);
            tempNodes[i][j] = newNode;
            nodes = (node[]) append(nodes,newNode);
          }
        }
      }
      PVector directionX = new PVector(0.5,0);
      directionX.mult(scaleUpFactor);
      for(int i=1;i<GlaucusMask.width;i++){
        for(int j=0;j<GlaucusMask.height;j++){
          if(maskData[i-1][j]&&maskData[i][j]){
            elements = (element[]) append(elements,
            new element(tempNodes[i-1][j],tempNodes[i][j],directionX));
          }
        }
      }
      PVector directionY = new PVector(0,0.5);
      directionY.mult(scaleUpFactor);
      for(int i=0;i<GlaucusMask.width;i++){
        for(int j=1;j<GlaucusMask.height;j++){
          if(maskData[i][j-1]&&maskData[i][j]){
            elements = (element[]) append(elements,
            new element(tempNodes[i][j-1],tempNodes[i][j],directionY));
          }
        }
      }
      cleanUpStrayNodes();
      println(nodes.length+" nodes");
      println(elements.length+" elements");
      strokeWeight(2*scaleUpFactor);
      smooth();
      imageMode(CENTER);
    }
    void draw(){
      background(255);
      for(int m=0;m<iterationRate;m++){
        for(int i=0;i<nodes.length;i++){
          nodes[i].update();
        }
        for(int i=0;i<elements.length;i++){
          elements[i].update();
        }
        if(nodeIsGripped){
          PVector force = PVector.mult(PVector.sub(new PVector(mouseX,mouseY),
          grippedNode.location),mouseSpringRate);
          grippedNode.forceSum.add(force);
        }
      }
      for(int i=0;i<nodes.length;i++){
        stroke(nodes[i].clr);
        point(nodes[i].location.x,nodes[i].location.y);
    
    //    pushMatrix();
    //    translate(nodes[i].location.x,nodes[i].location.y);
    //    rotate(nodes[i].rotation);
    //    image(nodes[i].img,0,0);
    //    popMatrix();
      }
    }
    void mousePressed(){
      PVector mouse = new PVector(mouseX,mouseY);
      for(int i=0;i<nodes.length;i++){
        if(PVector.sub(nodes[i].location,mouse).mag()<scaleUpFactor*1.5){
          nodeIsGripped = true;
          grippedNode = nodes[i];
        }
      }
    }
    void mouseReleased(){
      nodeIsGripped = false;
    }
    class node{
      color clr;
      PImage img;
      PVector location;
      PVector velocity;
      PVector forceSum;
      float rotation = 0;
      float angularVelocity = 0;
      float torqueSum = 0;
      boolean isTouchedByElement = false;
    //  node(int x,int y,PImage img){
      node(int x,int y,color clr){
        this.clr = clr;
    //    this.clr = color(#000000);
    //    this.img = img;
        location = new PVector(x,y);
        location.mult(scaleUpFactor);
        velocity = new PVector();
        forceSum = new PVector();
      }
      void applyForce(PVector force, PVector at){
        torqueSum += PVector.sub(at,location).cross(force).z;
        forceSum.add(force);
      }
      PVector toWorld(PVector at){
        float angle = atan2(at.y,at.x)+rotation;
        float magnitude = mag(at.y,at.x);
        return PVector.add(
        new PVector(magnitude*cos(angle),magnitude*sin(angle))
        ,location);
      }
      PVector totalVelocity(PVector at){
        return PVector.add(velocity,
        new PVector(0,0,angularVelocity).cross(PVector.sub(at,location)));
      }
      void update(){
        location.add(velocity);
        velocity.add(forceSum);
        velocity.mult(1.0-globalDamping);
        forceSum = new PVector();
        rotation += angularVelocity;
        angularVelocity += torqueSum/angularMomentum;
        angularVelocity = constrain(angularVelocity,-PI/4,PI/4);
        torqueSum = 0;
      }
    }
    class element{
      node nodeA;
      node nodeB;
      PVector direction;
      element(node A,node B,PVector dir){
        nodeA = A;
        nodeB = B;
        nodeA.isTouchedByElement = true;
        nodeB.isTouchedByElement = true;
        direction = dir;
      }
      void update(){
        PVector middleA = nodeA.toWorld(direction);
        PVector middleB = nodeB.toWorld(PVector.mult(direction,-1));
        PVector middleAB = PVector.mult(PVector.add(middleB,middleA),0.5);
        PVector force = PVector.mult(PVector.sub(middleB,middleA),springRate);
        PVector velocityA = nodeA.totalVelocity(middleAB);
        PVector velocityB = nodeB.totalVelocity(middleAB);
        force.add(PVector.mult(PVector.sub(velocityB,velocityA),damping));
        float torque = (nodeB.rotation-nodeA.rotation)*angularSpringRate;
        torque += (nodeB.angularVelocity-nodeA.angularVelocity)*angularDamping;
        nodeA.applyForce(force,middleAB);
        nodeB.applyForce(PVector.mult(force,-1),middleAB);
        nodeA.torqueSum += torque;
        nodeB.torqueSum -= torque;
      }
    }
    void cleanUpStrayNodes(){
      for(int i=nodes.length-1;i>=0;i--){
        if(nodes[i].isTouchedByElement==false){
          nodes = 
          (node[]) concat(
          (node[]) subset(nodes,0,i),
          (node[]) subset(nodes,i+1));
        }
      }
    }
    

    code

    tweaks (0)

    about this sketch

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

    license

    advertisement

    Report Sketch

    Report for inappropriate content

    Please provide details if possible:

    Your have successfully reported the sketch. Thank you very much for helping to keep OpenProcessing clean and tidy :)

    Make a Copyright Infringement claim

    Asher Salomon
    bitcraft
    10 Sep 2012
    Then the LORD God breathed into the pixels the breath of life, and the JPEG became a living creature.
    Felix Woitzel
    11 Sep 2012
    really cool one! skeleton animation next, or what? - made me think of my experiments with framsticks years ago: http://www.framsticks.com/muscles_and_receptors
    Ashley Brown
    11 Sep 2012
    such great code and great results.
    amazing.
    Nickson Yap
    8 Jun 2013
    Wobbly.
    Pierre MARZIN
    22 Jun 2014
    So good! Bravo!
    You need to login/register to comment.