// How much will each vertex "wiggle" (note: relative to distance from origin (first vertex in curvy)) final float WIGGLE_MODIFIER = 0.01; // As a curvy grows, the next vertex can be within this many pixels of the last one final int POINT_SPACING_MAX_DISTANCE = 50; // Set to true if you have some red/cyan 3D glasses handy. final boolean MODE_3D = false; // When in 3D mode, how much stereo separation? (note: relative to distance from origin) final float OFFSET_3D = 0.05; // maximum number of points (vertices) for one curvy final int MAX_POINTS = 300; // maximum number of curvys (faster systems can possibly increase this) final int MAX_CURVYS = 25; // a 'z' portion of a vertex can be between 0 and this number final int MAX_Z_DISTANCE = 450; // initial angle of rotation float myAngle = 0.0; // initail scale float myScale = 0.0; // the amount the angle will change each draw cycle final float ANGLE_CHANGE = 0.001; // the maximum scale until zooming in stops final float MAX_SCALE = 0.75; ArrayList curvys = new ArrayList(); // when creating a new curvy, use this function. Will return the correct type of // curvy depending on 3D mode. Curvy GetNewCurvy() { if ( MODE_3D ) return new Curvy3D(); else return new Curvy(); } // The maximum number of curvys needs to be cut in half when in 3D mode as there are // twice as many splines being drawn. int GetMaxCurvys() { if ( MODE_3D ) return int(MAX_CURVYS/2.0); else return MAX_CURVYS; } void setup() { size(800, 600, P3D); smooth(); curvys.add(GetNewCurvy()); // get things started //pushMatrix(); } void draw() { // clear the screen background(0); // you can zoom in and then rotate if you uncomment the next line //if ( !zoomIn() ) rotateScreen(); // or you can do both at the same time with the next 2 lines zoomIn(); rotateScreen(); // tell each curvy to draw itself for ( int i=0; i < curvys.size(); i++ ) { Curvy thisCurvy = curvys.get(i); thisCurvy.draw(); } // possibly add another curvy if ( !curvys.isEmpty() ) { Curvy lastCurvy = curvys.get(curvys.size()-1); if ( lastCurvy.HasGrown() ) { if ( curvys.size() >= GetMaxCurvys() ) { // too many curvys, pick one at random and kill it curvys.remove((int)random(0,curvys.size()-1)); } // add a new curvy curvys.add(GetNewCurvy()); } } } void rotateScreen() { myAngle += ANGLE_CHANGE; if(myAngle >= TWO_PI || myAngle < 0) myAngle = 0.0; translate(width/2, height/2); rotateX(myAngle); rotateY(myAngle); translate(width/-2, height/-2); } boolean zoomIn() { if ( myScale < MAX_SCALE ) { myScale += 0.005 * (MAX_SCALE - myScale); } translate(width/2,height/2); scale(myScale); translate(-width/2,-height/2); return myScale < MAX_SCALE; } class Curvy { // true if adding points, false if removing them protected boolean growing=true; // holds all of the vertices for this spline protected ArrayList allPoints = new ArrayList(); // will set to true when MAX_POINTS has been reached protected boolean hasGrown = false; protected Colour myColour = new Colour(); protected class Colour { public int r,g,b; public Colour() { r=(int)random(0,255); g=(int)random(0,255); b=(int)random(0,255); } } protected class Point { public int x; public int y; public int z; public Point() { // assume center of the screen // until told otherwise x=(int)width/2; y=(int)height/2; z=0; } public void Move(float modifier) { x += random(-modifier,modifier+1);// for some unknown reason this y += random(-modifier,modifier+1);// tends toward negative, z += random(-modifier,modifier+1);// add 1 to positive to balance it out // stay on the screen if ( x > width ) x = width; if ( x < 0 ) x = 0; if ( y > height ) y = height; if ( y < 0 ) y = 0; if ( z > MAX_Z_DISTANCE ) z = MAX_Z_DISTANCE; if ( z < 0 ) z = 0; } } public void draw() { if ( growing ) { if (allPoints.size() < MAX_POINTS ) addPoint(); else { growing=false; hasGrown=true; } } if ( !growing ) { if ( allPoints.size() > 0 ) removePoint(); else growing=true; } movePoints(); try { drawCurves(); } catch (Exception ex) { } } public boolean HasGrown() { return hasGrown; } protected void addPoint() { Point lastPoint = null; if ( !allPoints.isEmpty() ) lastPoint = allPoints.get(allPoints.size()-1); Point thisPoint = new Point(); if ( null == lastPoint ) { thisPoint.x = (int)random(0,width); thisPoint.y = (int)random(0,height); thisPoint.z = (int)random(0, MAX_Z_DISTANCE); } else { thisPoint.x = lastPoint.x + (int)random(-POINT_SPACING_MAX_DISTANCE, POINT_SPACING_MAX_DISTANCE); thisPoint.y = lastPoint.y + (int)random(-POINT_SPACING_MAX_DISTANCE, POINT_SPACING_MAX_DISTANCE); thisPoint.z = lastPoint.z + (int)random(-POINT_SPACING_MAX_DISTANCE, POINT_SPACING_MAX_DISTANCE); if ( thisPoint.x > width ) thisPoint.x = width; if ( thisPoint.x < 0 ) thisPoint.x = 0; if ( thisPoint.y > height ) thisPoint.y = height; if ( thisPoint.y < 0 ) thisPoint.y = 0; if ( thisPoint.z > MAX_Z_DISTANCE ) thisPoint.z = MAX_Z_DISTANCE; if ( thisPoint.z < 0 ) thisPoint.z = 0; } allPoints.add(thisPoint); } protected void removePoint() { allPoints.remove(allPoints.size()-1); } protected void movePoints() { for ( int i=1; i < allPoints.size(); i++ ) { Point thisPoint = allPoints.get(i); thisPoint.Move(i * WIGGLE_MODIFIER); } } protected void drawCurves() { if ( allPoints.isEmpty() ) return; noFill(); stroke (myColour.r, myColour.g, myColour.b); beginShape(); Point startPoint = allPoints.get(0); Point endPoint = allPoints.get(allPoints.size()-1); curveVertex(startPoint.x, startPoint.y, startPoint.z); for ( int i=0; i < allPoints.size(); i++ ) { Point thisPoint = allPoints.get(i); curveVertex(thisPoint.x, thisPoint.y, thisPoint.z); } curveVertex(endPoint.x, endPoint.y, endPoint.z); endShape(); } } class Curvy3D extends Curvy { protected void drawCurves() { if ( allPoints.isEmpty() ) return; drawCurves("red"); drawCurves("cyan"); } private void drawCurves(String colour) { noFill(); if ( "red" == colour ) { stroke(255, 0, 0); } else { stroke(0, 255, 255); } beginShape(); Point startPoint = allPoints.get(0); Point endPoint = allPoints.get(allPoints.size()-1); curveVertex(startPoint.x, startPoint.y, startPoint.z); for ( int i=0; i < allPoints.size(); i++ ) { Point thisPoint = allPoints.get(i); if ( "cyan" == colour ) { int offset = (int)(i * OFFSET_3D); curveVertex(thisPoint.x+offset, thisPoint.y+offset, thisPoint.z+offset); } else { curveVertex(thisPoint.x, thisPoint.y, thisPoint.z); } } curveVertex(endPoint.x, endPoint.y, endPoint.z); endShape(); } }