• fullscreen
  • curves.pde
  • revolutionSurfaces.pde
  • revolutionary.pde
  • //
    //  Curve manipulation library
    //
    PVector[] curveResizeTo( PVector[] pts, int newSize)
    {
      assert( newSize > pts.length);
      PVector[] r = new PVector[newSize];
      float numPtsAdd = (float)(newSize-3)/(float)(pts.length-3);
      float ptIdx= 0.;
      int cnt=0;
      r[cnt++]= pts[0];
      for (int i = 1; i < pts.length-2; i++) 
      {
        ptIdx += numPtsAdd;
        int numAddSeg = (int)floor(ptIdx);
        for (int j=0; j < numAddSeg; j++)
        {
          float t = (float)j/(float)(numAddSeg);
          r[cnt++] = curveCatmulRom( t,  pts[i-1],pts[i], pts[i+1], pts[i+2] );
        }
        ptIdx -= floor(ptIdx);
      }
      if ( ptIdx > 0.9f)
      {
        r[cnt++] =  pts[pts.length-2];
        ptIdx -= 1.0f;
      }
       r[cnt++]= pts[pts.length-2];
       r[cnt++]= pts[pts.length-1];
      assert( cnt == newSize);
      assert( ptIdx < 0.001f);
      return r;
    }
    PVector[] curveBlend( PVector[] pts1, PVector[] pts2, float t )
    {
       if ( pts1.length > pts2.length)
       {
         pts2 = curveResizeTo( pts2, pts1.length);
       }
       if ( pts2.length > pts1.length)
       {
         pts1 = curveResizeTo( pts1, pts2.length);
       } 
       assert( pts1.length == pts2.length);
       PVector[] r = new PVector[pts1.length];
       for (int i =0; i < pts1.length;i++)
       {
         r[i] = new PVector(lerp(pts1[i].x,pts2[i].x,t),
                             lerp(pts1[i].y,pts2[i].y,t),
                             lerp(pts1[i].z,pts2[i].z,t));
       }
       return r;
    }
      
    PVector[] curveSortOnY( PVector[] pts)
    {
      float maxY = -1000.0f;
       PVector[] res = new PVector[pts.length];
        for (int i = 0; i < pts.length; i++)
        {
          PVector minPt = null;
          float minY = 10000.0f;
       
          for (PVector p: pts) {
              if ( p.y<minY && p.y > maxY ){
                 minPt = p;
                 minY = p.y;
             }
          }      
          maxY =minY;
          res[i] = minPt;
        }
        return res;
    }
    
    PVector[] curveCalcNormals( PVector[] pts)
    {
        assert( pts.length>=2);
        PVector[] normals = new PVector[pts.length];
        if ( pts.length<2)
          return normals;
         
         for (int i =1;i<pts.length-1;i++) // compute 2D normal
         {
            normals[i] = new PVector( (pts[i-1].y - pts[i+1].y),(pts[i-1].x - pts[i+1].x),0.0f);
            normals[i].normalize();
         }
         normals[0]= new PVector( (pts[0].y - pts[1].y),(pts[0].x - pts[1].x),0.0f);
         normals[0].normalize();
       
         int e = pts.length-1;
         
         normals[e]= new PVector((pts[e-1].y - pts[e].y),(pts[e-1].x - pts[e].x),0.0f);
         normals[e].normalize();
         return normals;
    }
    PVector lerp( PVector c1, PVector c2, float t )
    {
      return new PVector( lerp(c1.x,c2.x,t), lerp(c1.y,c2.y,t),lerp(c1.z,c2.z,t));
    }
    PVector  curveCatmulRom( float t, PVector x1,PVector x2, PVector x3, PVector x4 )
    {
       PVector p = new PVector();
       p.x = curveCatmulRom( t, x1.x, x2.x, x3.x, x4.x );
       p.y = curveCatmulRom( t, x1.y, x2.y, x3.y, x4.y );
       p.z = curveCatmulRom( t, x1.z, x2.z, x3.z, x4.z );
       return p;
    }
    float  curveCatmulRom( float t, float x1,float x2, float x3, float x4 )
    {
        float t2 =t*t;
        float t3 = t*t2;
        return 1./2.*( (-t + 2.*t2 - t3)*x1  +
                  (2 -5*t2 + 3 * t3)*x2 +
                 (t+4*t2 -3*t3) *x3 +
                 (-t2+t3)*x4 );
    }
    PVector[] curveSubdividePoints( PVector[] pts, int numSubdivs) {
       assert( pts.length>=4);
       assert( numSubdivs >=1);
       
       int numpoints = ((pts.length-3)*numSubdivs) +1;
       assert( numpoints >=2);
       PVector[] np = new PVector[ numpoints];
       int idx = 0;
      
       for (int i =1;i<pts.length-2;i++)
       {
         for (int j=0;j<numSubdivs;j++)
         {
           float t = (float)j/(float)numSubdivs;
           np[idx++]= curveCatmulRom(  t, pts[i-1],pts[i], pts[i+1], pts[i+2] );
         }
       }
       np[idx]= new PVector();
       np[idx++].set(pts[ pts.length-2]);
       assert( idx == numpoints);
       return np;
    }
    
    PVector[] curveUnpack( float[] pts)
    {
      assert( pts.length >= 8);
      assert( pts.length%2 == 0);
      PVector[] r = new PVector[pts.length/2];
      for(int i=0; i < r.length; i++)
        r[i] = new PVector( pts[i*2], pts[i*2+1], 1.0f);
       
      return r;
    }
    
    //
    // revolutionSurfaces
    //
    //  Code to draw and manipule revolution surfaces
    //
    class Revolute
    {
      private PVector[] subPoints;
      private PVector[] normals;
      private PVector[] subPointsLow;
      private PVector[] normalsLow;
      private PVector c1;
      private PVector c2;
      private int  hiQuality;
      private int  lowQuality;
    
      private PVector drawPos;
      private boolean m_visible;
      
      public Revolute( PVector[] pts, PVector pos, PVector cpos, float aoStrength, PVector _c1, PVector _c2 )
      {
        PVector realPos = new PVector();
        realPos.set(pos);
        drawPos = new PVector();
        drawPos.set(pos);
        
        realPos.mult(100.0f);
        int quality = CalculateQuality( realPos, radians(45.0f), cpos, 3.5, 2.);
        m_visible = quality >= 0;
        quality = min(max(quality,2),24);
        
        assert( pts.length>=4);
        hiQuality = quality*2;
        lowQuality = max(quality/2,4);
        subPoints = calculateAO( pts, true, aoStrength );
        assert( subPoints.length>=4);
        
        // allow for number of pts
        quality =(int)(quality/sqrt((float)(pts.length-3)));
        quality = max( quality, 1);
        
        subPointsLow = curveSubdividePoints( pts, max(quality/4,1));   
        subPoints = curveSubdividePoints( subPoints, quality);
         
        normals = curveCalcNormals(subPoints);
        normalsLow = curveCalcNormals(subPointsLow);
    
        c1 = _c1;
        c2 = _c2;
      } 
      public void AddNoise( float noiseScale, float amp, float time)
      {
        if ( m_visible  )
        {
          subPoints = AddDisplacement( subPoints, normals, noiseScale, amp,time );
          normals =  curveCalcNormals(subPoints);
        }
      }
      public void DrawReflection( float angleEnd )
      {
        if ( !m_visible  )
          return;
          
          pushMatrix();
          translate( drawPos.x, -drawPos.y,drawPos.z);
          rotateX(PI);
          RevolutionObject( subPointsLow, normalsLow, lowQuality, c1,c2,angleEnd);
          rotateX(PI);
          popMatrix();
      }
      public void Draw( PVector lightDir, float angleEnd, boolean dropShaow )
      {  
          if ( !m_visible  )
            return;
                
          if ( hiQuality >4 && dropShaow)
          {
            pushMatrix();
            translate( drawPos.x, 0.0,drawPos.z);
            scale(findBaseSize( subPointsLow, 0.05f ));
    
            drawDropShadow(); 
            popMatrix();
          }
            pushMatrix();
          translate( drawPos.x, drawPos.y,drawPos.z);
          
          // draw shadow
          fill( color(0,0,0,32));
          RevolutionObjectShadows( subPointsLow, normalsLow, lightDir, lowQuality, angleEnd );
          RevolutionObject( subPoints, normals, hiQuality, c1,c2, angleEnd  );
          
          popMatrix();
      }
    }
    
    void drawDropShadow()
    {
      beginShape(TRIANGLE_FAN);
      
      //normal(-0.707,-0.7,0.1.0); // this is weird
      normal(0.0f,0.0f,1.); // this is weird
      fill(0,0,0,255);
      vertex(0.0f,0.0f,0.0f);    
      fill(0,0,0,0);    
      for (float ang = 0.; ang <= (2.0f * PI+0.001); ang += 2.0f * PI/16.)
        vertex(sin(ang)*1.5f, 0.01f,cos(ang)*1.5f);
    
      endShape();
    }
    
    
    void RevolutionObjectShadows( PVector[] pts, PVector[] normals, PVector lightDir, int numSegs, float angleEnd )  
    { 
        float delta = 1.0f/((float)numSegs-1) * 2.0*PI; 
        float ang = 0;
        int numSteps =(int)ceil( angleEnd/delta);
        float x = sin(ang);
        float z = cos(ang);
       float ygrad = 1.0f/ lightDir.y; 
        float zgrad =lightDir.z*ygrad ;
        float xgrad = lightDir.x*ygrad ;
        
        beginShape(QUADS);   
        for (int i = 0; i < numSteps; i++)
        {
           ang += delta;
           float x2 = sin(ang);
           float z2 = cos(ang);
    
          // skip if not facing light      
           for(int j =0; j < pts.length-1; j++)
           {     
             PVector n = normals[j];
             n = new PVector(x*n.x, n.y, z*n.x);
              if ( lightDir.dot( n ) >0.0f )  // bace face culling
             {
               continue;
             }
             PVector p = pts[j];
              // project to ground plane
             float x1=  p.y * xgrad;
             float z1 = p.y * zgrad;
              
             vertex( x*p.x + x1 , 0.0f, z*p.x + z1);
             vertex( x2*p.x + x1, 0.0f, z2*p.x + z1);
             
             p = pts[j+1];
              // project to ground plane
             x1=  p.y * xgrad;
             z1 = p.y * zgrad;
              
             vertex( x2*p.x + x1, 0.0f, z2*p.x + z1);
             vertex( x*p.x + x1 , 0.0f, z*p.x + z1);         
           }
           x = x2;
           z = z2;
        }
        endShape();
     }
    void RevolutionObject( PVector[] pts,PVector[] normals, int numSegs, PVector col1, PVector col2, 
                          float angleEnd )  { 
       assert(pts.length == normals.length);
       PVector c1 = new PVector();
       PVector c2 = new PVector();
       PVector c = new PVector();
       
        float delta = 1.0f/((float)numSegs-1) * 2.0*PI; 
        float ang = 0;
       
       int numSteps =(int)ceil( angleEnd/delta);
          
        float x = sin(ang);
        float z = cos(ang); 
        for (int i = 0; i < numSteps; i++)
        {
           ang += delta;
           float x2 =sin(ang);
           float z2 =cos(ang);
       
           c1.set(col1);  // set up the colors
           c2.set(col2);
           c2.sub(c1);
           c1.mult(255.0f);
           c2.mult(255.0f/(float)pts.length);
                   
           beginShape(QUAD_STRIP); 
           for (int j =0; j < pts.length;j++)
           {                         
             PVector p = pts[j];
             PVector n = normals[j];
          
             c.set(c1);
             c.mult(p.z);
             fill( c.x, c.y,c.z);        
             c1.add(c2); 
             normal(x*n.x, n.y, z*n.x);
             vertex( x*p.x, p.y, z*p.x);
             normal(x2*n.x, n.y, z2*n.x);
             vertex( x2*p.x, p.y, z2*p.x);        
           }
           endShape();
           x = x2;
           z = z2;
        }
    
     }
     float CalcAO( PVector[] pts, PVector pt, int index, boolean onGround)
    {
       float lg = -1000.0f,rg = -1000.0f;
        PVector d = new PVector();
       if ( onGround)
       {
         d.set(1.0f, -0.5f,0.0f);
         d.sub(pt);
         d.z=0.0f;
         d.normalize();
         lg = d.x;
       }
      
       for(int i =0; i < index;i++)
       {
         d.set(pts[i]);
         d.sub(pt);
         d.z=0.0f;
         d.normalize();
         lg = max( lg, d.x);
       }
       for(int i =index+1; i < pts.length-1;i++)
       {
         d.set(pts[i]);
         d.sub(pt);
         d.z=0.0f;
         d.normalize();
         rg = max( rg, d.x);
       }
       float ao = min(max(((1.-rg) + (1.-lg))*0.75,0.0f),1.0f);
       return ao*ao+0.1;
    }
    PVector[] calculateAO( PVector[] pts, boolean onGround, float aoStrength )
    {
       PVector[] np = new PVector[ pts.length];  
       for(int i =0; i < pts.length;i++)
       {
         np[i] = new PVector();
         np[i].set(pts[i]);
         np[i].z = min( CalcAO( pts, np[i], i, onGround) + aoStrength, 1.);
       }
       return np;
    }
    
    PVector wobbleMove( PVector pos, float t , PVector dir, float speed )
    {
       float f =  sin(t*2.0*PI)>0.01f ? speed: 0.0f;
       float u =  max(sin(t*2.0*PI),0.)*5. * speed;
       return new PVector( pos.x + dir.x*f, u, pos.z + dir.z*f );
    }
    PVector[] wobble( PVector[] pts, float t, float amp, float gplane )
    {
      t = t*2.0*PI;
       PVector[] r = new PVector[pts.length];
       for ( int i = 0; i < pts.length;i++)
       {
         r[i] = new PVector();
         r[i].set(pts[i]);
         r[i].y = r[i].y + sin(t)*amp*pts[i].x;
         r[i].y = max(r[i].y, gplane);
       }
       return r;
    }
    float findBaseSize( PVector[] pts, float threshold )
    {
      float bsize= 0.0f;
      for ( PVector p:pts )
          bsize = max( bsize, p.x * 1.0f - p.y);
      return bsize;
    }
    PVector[] AddDisplacement( PVector[] pts, PVector[] normals, float scaleV, float amplitude, float time )
    {
        PVector[] rpts = new PVector[pts.length];
         for (int i =0;i<pts.length;i++)
         {
           float t = (float)i/(float)(pts.length-1) * scaleV;
           float n = sin(t*2.*PI*scaleV+time);//noise( t, time)*2.0f - 1.;
           rpts[i] = new PVector();
           rpts[i].set(normals[i]);
           rpts[i].mult(amplitude*n);
           rpts[i].add(pts[i]);
           rpts[i].x = max( rpts[i].x,0.0f);
         }
        return rpts;
    }
    int CalculateQuality( PVector pos, float fov, PVector cpos, float initialsize, float lodFactor)
    {
      PVector dvect = new PVector();
      dvect.set(cpos);
      dvect.sub(pos);
      float dist = dvect.mag();
    
      // find width of single pixel
      PVector cvect = new PVector();
      cvect.set(cpos);
      dvect.normalize();
      cvect.normalize();
      if ( cvect.dot(dvect) < cos(radians(45)))  // cull if offscreen
        return -1;
      if ( cvect.dot(dvect) < cos(radians(35)))
         initialsize*=0.5f;
        
      float pixelwidth = (tan( fov *0.5)*dist / 480.0f )*lodFactor;
      // cull quality on behinid or to the side of the camera
      return (int)(( initialsize / pixelwidth) );
    }
    
    // Revolutionary
    //
    // -- Example of using surfaces of revolution
    //
    float[] cone = {
      0.25666666, -0.106666684,   0.21666667, 0.0, -0.0016666667, 0.50666666,  
      -0.065, 0.65    };
    
    float[] splash = {
      0.2, -0.1533333, 0.165, 0.0033333302,  0.23333333, 0.100000024,  
      0.0, 0.01999998,  -0.108333334, 0.26666668  };
      
    float[] lobe = {
      0.2, -0.1533333,     0.165, 0.0033333302,  0.02, 0.060000002,   0.035, 0.29,
      0.0016666667, 0.38, -0.075, 0.4333333 };
    
    float[] teardrop = {
      -0.12166667, 0.093333304,  -0.0016666667, 0.0033333302,   0.065, 0.120000005,        
      0.0033333334, 0.43666667,  0.0, 0.68333334 };
    
    float [] puddle = {
      0.26166666, -0.0033333302,   0.21, 0.0033333302, 
      -0.0016666667, 0.01999998,  -0.20333333, 0.04666668 };
    
    float[] pawn = {
    0.21, -0.08333331,         0.123333335, 0.0033333302,  0.07333333, 0.04333335,  
     0.115, 0.13,              0.036666665, 0.37666667,  0.08, 0.48666668,
     0.02, 0.49333334,         0.05, 0.56, -0.0033333334, 0.5966667, 
     -0.10333333, 0.60333335 };
    
    float[] house = {
    0.008333334, 0.0,          0.11666667, 0.0033333302,  0.108333334, 0.19666666, 
    0.12833333, 0.23000002,    0.195, 0.25666666,        0.028333334, 0.47666666,
     0.02, 0.52,                0.0033333334, 0.62333333 };
     
    float[] torus = {
    	0.035, 0.13999999,	0.15333334, 0.16000003,	0.14666666, 0.27,	0.09833334, 0.27333334,
    	0.09166667, 0.16000003,	0.15166667, 0.16333336,	0.16666667, 0.44666666,};
    
    float [] lamp = {
      0.23166667, -0.04333335,    0.07666667, 0.0,   0.14, 0.33,               
      0.05666667, 0.45333335,    0.09166667, 0.5733333,    0.16, 0.5966667 };
      
    float[] beerbottle ={
      0.08833333, 0.0,         0.016666668, 0.0033333302,  0.08833333, 0.026666641, 
      0.08166666, 0.24000001,   0.031666666, 0.40666667, 0.021666666, 0.46333334, 
      -0.14833333, 0.64666665 };
      
    float[] tree = {
      0.08833333, -0.12666667,  0.025, 0.0,   0.026666667, 0.04666668,  
      0.17666666, 0.056666672,   0.108333334, 0.17333335,  -0.0016666667, 0.40666667,
       0.10333333, 0.62 };  
    
    float [] fountain ={
    	0.16, -0.13999999,	0.15833333, 0.00999999,	0.15666667, 0.13666666,	0.13, 0.14333332,
    	0.13166666, 0.023333311,	0.07666667, 0.026666641,	0.065, 0.14999998,	0.035, 0.18,
    	0.026666667, 0.29666665,	0.048333332, 0.33,	0.026666667, 0.36333334,	0.11666667, 0.40333334,
    	0.12666667, 0.46666667,	0.14833333, 0.50666666,	0.108333334, 0.50666666,	0.093333334, 0.45,
    	0.038333334, 0.42,	0.035, 0.48666668,	0.011666667, 0.52666664,	0.008333334, 0.63,
    	0.035, 0.65999997,	0.0016666667, 0.65999997,	-0.07666667, 0.6533333};
    
    float [] nothing={
      0.0f,0.0f,  0.0f,0.0f,   0.0f,0.0f,  0.0f,0.0f,
    };
    
    class Scene
    {
      public   int colorIdx;
      public   boolean  ySort;
      public   float[]  pts;
      public   PVector  c1;
      public   PVector  c2;
      Scene( int c, float[] p, boolean sort, PVector _c1, PVector _c2 ) { 
        colorIdx = c; 
        pts =p; 
        ySort = sort; 
        c1 =_c1; 
        c2=_c2;
      }
    };
    
    Scene[] g_Scenes = new Scene[] {
      new Scene( 2, teardrop, false, new PVector(0.7f,0.9f,1.0f),new PVector(0.8f,1.0f,1.0f) ),
      new Scene( 2, puddle, false, new PVector(0.7f,0.9f,1.0f),new PVector(0.8f,1.0f,1.0f)),
      new Scene( 2, splash, false, new PVector(0.7f,0.9f,1.0f),new PVector(0.8f,1.0f,1.0f)),
      new Scene( 2, puddle, false, new PVector(0.7f,0.9f,1.0f),new PVector(0.8f,1.0f,1.0f)),
      new Scene( 2, lobe, false, new PVector(0.7f,0.9f,1.0f),new PVector(0.8f,1.0f,1.0f)),  
      new Scene( 2, puddle, false, new PVector(0.7f,0.9f,1.0f),new PVector(0.8f,1.0f,1.0f)),
      new Scene( 3, pawn,  true,  new PVector(0.9f,0.8f,0.7f),new PVector(1.0f,1.0f,1.0f)), //new PVector(0.4f,0.35f,0.1f),new PVector(0.8f,0.85f,0.2f)),
      new Scene( 0, house, true, new PVector(1.0f,0.0f,0.0f),new PVector(1.0f,1.0f,0.0f)),
      new Scene( 2, puddle, false, new PVector(0.7f,0.9f,1.0f),new PVector(0.8f,1.0f,1.0f)),  
      new Scene( 2, nothing, false, new PVector(0.0f,0.0f,0.0f),new PVector(0.0f,0.0f,0.0f)),  
    
      new Scene( 3, pawn,  true,   new PVector(0.9f,0.8f,0.7f),new PVector(1.0f,1.0f,1.0f)), //new PVector(0.4f,0.35f,0.1f),new PVector(0.8f,0.85f,0.2f)),
      new Scene( 0, house, true, new PVector(1.0f,0.0f,0.0f),new PVector(1.0f,1.0f,0.0f)),
      new Scene( 3, cone,  true, new PVector(1.0f,0.0f,1.0f),new PVector(0.0f,1.0f,1.0f)),
      new Scene( 0, torus, true, new PVector(1.0f,1.0f,0.0f),new PVector(1.0f,1.0f,0.0f)),
      new Scene( 3, lamp,  true, new PVector(0.0f,0.0f,1.0f),new PVector(0.0f,1.0f,1.0f)),
      new Scene( 0, beerbottle, true, new PVector(0.1f,0.1f,1.f),new PVector(1.0f,1.0f,1.0f)), 
      new Scene( 3, tree,  true,   new PVector(0.4f,0.4f,0.1f),new PVector(0.6f,0.95f,0.4f)),
      new Scene( 0, fountain,  false,  new PVector(0.9f,0.8f,0.7f),new PVector(1.0f,1.0f,1.0f)),
      
    };
    
    PFont g_font;
    void setup() {
      size(640,480,P3D);
      noSmooth();
      noStroke();
      mouseX=width/2-80;
      mouseY=40;
      g_font = loadFont("Arial-ItalicMT-32.vlw");
    }
    float smoothstep (float edge0, float edge1, float x)
    {
      x =  min(max((x - edge0) / (edge1 - edge0),0.0f),1.0f); 
      return x*x*(3-2*x);
    }
    void drawGround()
    {
      fill( color(180,180,180,220));
      float fbase=400.0f;
      beginShape(QUADS);
      vertex(-fbase, 0.0f,-fbase);
      vertex(fbase, 0.0f,-fbase);
      vertex(fbase, 0.0f,fbase);
      vertex(-fbase, 0.0f,fbase);
      endShape();
    }
    
    final int SHOW_TITLE =0;
    final int SHOW_WOBBLE=2;
    final int SHOW_DROP=3;
    final int SHOW_CROSS_FADE=4;
    final int SHOW_DROP_FAST = 7;
    final int SHOW_CROSS_AO=8;
    final int SHOW_PROCEDURAL_DETAIL=9;
    final int SHOW_PROCEDURAL_DETAIL2=10;
    final int SHOW_LODS=11;
    final int SHOW_MOVING=12;
    
    float  stateTime = 0.0f;
    int    DemoState = SHOW_TITLE;
    
    PVector[] g_positions= new PVector[] {  new PVector(0.0f,0.0f,0.0f)  };
    int[]  g_StartScene= new int[] {  0};     
    
    void fadeText( String v, int x, int y, float s, float e, float anim)
    {
      float textAlpha = smoothstep(s,s+1,anim)*smoothstep(e,e-1,anim)*128;
      fill(0,0,0,textAlpha);
      text(v, x, y);
    }
    void DrawText( float anim, int state )
    {
      textFont(g_font, 32); 
      textMode(SCREEN);
    
      switch( state )
      {
      case SHOW_TITLE:            
        float textAlpha = smoothstep(0.,2.,anim)*smoothstep(6.,4.,anim)*255;
        fill(0xFF,0xFF,0xFF,textAlpha);
        text("Surfaces of Revolution", width/4, height/4);
    
        fadeText( "rotate a curve", 10, 110, 4., 9., anim);
        fadeText( "to create a surface",width/2+40, 140, 8., 12., anim);
        break;
      case SHOW_WOBBLE:
        fadeText("move the curve",  width/2, 110, 0., 5., anim);
        fadeText( "move the surface", width/2+40, 140, 4., 11., anim);
        break;
      case SHOW_DROP:
        fadeText("blend between curves", width/2, 110, 0., 5., anim);
        fadeText( "to animate", width/2+40, 140, 4., 11., anim);
        break;      
      case SHOW_CROSS_AO:
        fadeText("Real Time Ambient Occlusion", 20, height-50, 0., 5., anim);
        break;
      case SHOW_PROCEDURAL_DETAIL:
        fadeText("Procedural Detail", width/2, 110, 0., 5., anim);
        break;
      case SHOW_LODS:
        fadeText("Automatic LODs",  20, height-50, 0., 5., anim);
        break;
      }
    //  fill(0);
    //   text("fps: "+(int)frameRate ,20,40 );
    }
    
    void TransitionState( float anim, float t, int newState)
    {
      if ( anim>t)
      {
        stateTime+=t;
        DemoState = newState;
      }
    }
    void draw()
    {
      beginCamera();
      PVector cpos = new PVector( mouseX-width*0.5,10+mouseY*0.6,34.0);
      camera(cpos.x,cpos.y,cpos.z,
      0.0,20.0,0.0,
      0.0,-1.0,0.0);
    
      perspective(45.0f, float(width)/float(height), 0.1f, 100.0f);       
      endCamera();
    
      float anim =(float)millis()/1000.0f;
      float fade =smoothstep(1.,3.,anim)*255;
      background(color(fade,fade,fade));
    
      PVector lightDir = new PVector(0.0f,-0.5f, -1.0f);
      lightDir.normalize();
      ambientLight(102, 102, 102);
      lightSpecular(204, 204, 204);
      directionalLight(102, 102, 102, lightDir.x, lightDir.y, lightDir.z);
      specular(255, 255, 255);
      noStroke();
      shininess(40.0f);
    
      scale(100.0f);
      anim -=stateTime;
    
      final int MaxAmt = 60;
      float angleEnd = 2.0*PI;
      float[] wobbleAmt = new float[MaxAmt];
      wobbleAmt[0] = 0.0f;
      int amt =1;
      int[] startScene = new int[MaxAmt];
      int[] nextScene = new int[MaxAmt];
      float[] scBlend = new float[MaxAmt];
      float[] noiseAmp = new float[MaxAmt];
    
      startScene[0]=0; 
      nextScene[0]=1;
      noiseAmp[0]=0.0f;
      scBlend[0] =0.0f;
    
      float a0Blend = 0.0f;
      float colorFade = 1.;
    
      switch( DemoState)
      {
      case SHOW_TITLE:
        angleEnd = smoothstep(6.,11.,anim)*2.0*PI;
        TransitionState( anim, 13.,  SHOW_WOBBLE);
        break;       
      case SHOW_WOBBLE:
        wobbleAmt[0] = smoothstep(1.,3.,anim)*smoothstep(12.,11.,anim)*1.0f;
        TransitionState( anim, 13., SHOW_DROP);
        break;
      case SHOW_DROP:     
        scBlend[0] = smoothstep(3.,12.,anim)*5.;
        float t = floor(scBlend[0]);
        scBlend[0] -= t;
        startScene[0] = (int)(t);
        nextScene[0]= startScene[0]+1;
    
        noiseAmp[0] = smoothstep(12.,13.,anim)*smoothstep(16.,15.,anim)*0.1f;
        TransitionState( anim, 15., SHOW_DROP_FAST);
        break;
      case SHOW_DROP_FAST: 
        {
          scBlend[0] = min(max((anim-1.0f)/2.0f,0.0f),1.0f)*5.;
          float t2 = floor(scBlend[0]);
          scBlend[0] -= t2;
          startScene[0] = (int)(t2);
          nextScene[0]= startScene[0]+1;
    
          TransitionState( anim, 3., SHOW_CROSS_FADE); 
          break;
        }
      case SHOW_CROSS_FADE: 
        {
          scBlend[0] = smoothstep(1.,5.,anim);
          startScene[0] = 5;  
          nextScene[0] =6;   
          TransitionState( anim, 5., SHOW_CROSS_AO);  
          break;
        }
      case SHOW_CROSS_AO:
        {
          startScene[0] = 6; 
          nextScene[0]=7;    
    
          a0Blend = smoothstep(0.,2.,anim)* smoothstep(5.,2.,anim) +
            smoothstep(9.,11.,anim)* smoothstep(12.,11.,anim); 
          scBlend[0] = smoothstep(8.,9.,anim);
          wobbleAmt[0] = smoothstep(12.,13.,anim)*smoothstep(16.,15.,anim)*1.2f;
          colorFade = 1.0 - smoothstep(18.,13.,anim)* smoothstep(0.,2.,anim);
          TransitionState( anim, 18., SHOW_PROCEDURAL_DETAIL);
          break;
        }
      case SHOW_PROCEDURAL_DETAIL:
        {      
          scBlend[0] = smoothstep(2.,5.,anim);
          startScene[0] = 7;   
          nextScene[0]=8;         
          noiseAmp[0] = smoothstep(0.,1.,anim)* smoothstep(7.9,4.,anim);
    
          TransitionState( anim, 8., SHOW_PROCEDURAL_DETAIL2);
          break;
        }
      case SHOW_PROCEDURAL_DETAIL2:
        {
          noiseAmp[0] =0.; 
          wobbleAmt[0] = 0.;
          scBlend[0] = smoothstep(0.,3.,anim);
          startScene[0] = 8; 
          nextScene[0]=9;    
          TransitionState( anim, 4., SHOW_LODS);
          break;
        } 
      case SHOW_LODS:
        {  
          float numLods = smoothstep(0.,10.,anim);
          numLods=pow(numLods,3);
          amt = (int)(numLods*(float)(MaxAmt-1))+1;
          g_positions= new PVector[amt];
          g_StartScene = new int[amt];
          for (int i =0; i < amt; i++)
          {
            g_positions[i] = new PVector(i*.5,0.,0.);
            g_StartScene[i] = 6;
            startScene[i] = 6;  
            nextScene[i]=11 + i %7;    
            scBlend[i] = smoothstep(16.,17.,anim) * smoothstep(29.,28.,anim);
            wobbleAmt[i] = smoothstep(12.,13.,anim)*smoothstep(22.,20.,anim)*0.5f;
            noiseAmp[i] = smoothstep(20.,21.,anim) * smoothstep(27.,26.,anim)*3.;
          }
          TransitionState( anim, 30., SHOW_MOVING);
          break;
        }
      case SHOW_MOVING:
        { 
          anim*=1.5;
          amt = 40;
          if ( g_positions.length <amt)
          { 
            g_positions= new PVector[amt];
            g_StartScene = new int[amt];
            for (int i =0; i < amt; i++)
            {
              g_positions[i] = new PVector(i*.5,0.,0.);   
              g_StartScene[i] =7;
            }
          }
          randomSeed(100);
          for (int i =0; i < amt; i++)
          {
            float animf = anim + random(-5.0f,10.0f);
    
            startScene[i] =g_StartScene[i];  
            nextScene[i]= 8;
            scBlend[i] = smoothstep(10.,12.,animf) * smoothstep(14.5,12.5,animf);
            PVector dir = new PVector(random(-1.,1.), 0.0f, random(-1.,1.));
            dir.normalize();
            float ws =max(1.-scBlend[i]*2.,0);
            g_positions[i] = wobbleMove( g_positions[i], anim + (float)i*0.2f, dir, 0.02*ws);
            if (scBlend[i]>0.95)
            {
              g_positions[i] =dir;
              g_positions[i].mult(2.5f * (float)(i%8)/8.+.5);   
              g_StartScene[i]=  10 + (g_StartScene[i] + 13) % 8;
            }
            noiseAmp[i]=scBlend[i];
            wobbleAmt[i] =.6 * ws;
          }     
          TransitionState( anim, 25., SHOW_MOVING); 
          break;
        }
      }
    
      noiseDetail(3,0.5);
      Revolute [] revObjs = new Revolute[amt];
      boolean[] culled =  new boolean[amt];
      PVector[] camDir = new PVector[amt];
      for (int i =0; i < amt; i++)
      {
        assert( startScene[i]< g_Scenes.length);
        assert( nextScene[i]< g_Scenes.length);
            
        PVector [] pts = curveBlend( curveUnpack( g_Scenes[startScene[i] ].pts ), curveUnpack( g_Scenes[nextScene[i]].pts ), scBlend[i]);
        PVector c1 = lerp( g_Scenes[startScene[i]].c1, g_Scenes[nextScene[i]].c1, scBlend[i]);
        PVector c2 = lerp( g_Scenes[startScene[i]].c2, g_Scenes[nextScene[i]].c2, scBlend[i]);
        c1 = lerp( c1, new PVector(0.75,0.75,0.85), 1.-colorFade);
        c2 = lerp( c2, new PVector(0.75,0.75,0.95), 1.-colorFade);
    
        revObjs[i] = new Revolute(  wobble( pts, anim + (float)i*0.2f, wobbleAmt[i],0.0f), g_positions[i], cpos, a0Blend, c1, c2 );
        
        if ( noiseAmp[i] > 0.0f )
        {
          revObjs[i].AddNoise( 3.f, noiseAmp[i]*0.005, anim*10.);
        }
      }
    
      for ( Revolute r : revObjs)
        r.DrawReflection( angleEnd);
      
      drawGround();
      
      for ( Revolute r : revObjs)
        r.Draw( lightDir,angleEnd, DemoState != SHOW_MOVING);
        
      DrawText( anim, DemoState );
    }  
    

    code

    tweaks (0)

    about this sketch

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

    license

    advertisement

    edward Porten

    Revolutionary

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

    This is results of looking into surfaces of revolution. They combine a lot of the benefits of subdivision surfaces but are a lot simpler to work with.

    Word's do not describe how tight!!! this is.
    bejoscha
    1 Aug 2010
    Great. Thanks for showing.
    You need to login/register to comment.