import processing.opengl.*; /** The total number of images to display. This should be odd, such that the center image will have an equal nummber of images on either side. **/ int numImages = 7; AngledImage[] images = new AngledImage[numImages]; AngledImage[] temp = new AngledImage[numImages]; /** Defaults: SPACING is the distance from the center for either the right or left initial item. SPACING_OFFSET is the distance between each item on the right or left rows. ANGLE is the angle in which the rows project away from the viewer (in degrees). DISTANCE is the value (in pixels) that the rows will project away from the center viewpane. GREY_TINT is the relative tint value for the first item in each row. **/ int DEFAULT_SPACING = 140; int DEFAULT_SPACING_OFFSET = 80; int DEFAULT_ANGLE = 40; int DEFAULT_DISTANCE = -60; int NO_DISTANCE = 0; int NO_TINT = 255; int TINT_OFFSET = 60; int NO_ANGLE = 0; int NO_SPACING = 0; int GREY_TINT = 150; int LEFTMOST = 0; int RIGHTMOST = 6; int CENTERMOST = 3; int CENTER_LEFT = 2; int CENTER_RIGHT = 4; // Constants to describe the position of a given item in the set. Only one will be // in the CENTER position at one time int LEFT = 0; int RIGHT = 1; int CENTER = 2; int start = DEFAULT_ANGLE; int end; // Are we currently animating? boolean drawing = false; // Values for an item that will be moving from the center pane to // a right/left row during an animation int startAngle = 0; int startSpacing = 0; int startDistance = NO_DISTANCE; // Current value in the animation loop int currentAngle = startAngle; int currentSpacing = startSpacing; int currentDistance = startDistance; // Target value for when we will stop animating int targetSpacing = DEFAULT_SPACING; int targetAngle = DEFAULT_ANGLE; int targetDistance = DEFAULT_DISTANCE; int acceleration = 15; boolean runInit = true; boolean moveImages = false; class AngledImage { int direction = CENTER; int tintColor = NO_TINT; int angle = NO_ANGLE; int spacing = NO_SPACING; int distance = NO_DISTANCE; int startSpacing = NO_SPACING; int startDistance = NO_DISTANCE; int startTintColor = NO_TINT; PImage image; String imagename; AngledImage() { } AngledImage(PImage image, String imagename) { this.image = image; this.imagename = imagename; } AngledImage(PImage image) { this.image = image; } AngledImage copy() { AngledImage i = new AngledImage(this.image); i.direction = this.direction; i.spacing = this.spacing; i.startSpacing = this.startSpacing; i.angle = this.angle; i.distance = this.distance; i.tintColor = this.tintColor; i.startTintColor = this.startTintColor; return i; } int getComputedAngle() { if (this.direction == RIGHT) { return -this.angle; } if (this.direction == LEFT) { return this.angle; } return 0; // default for center } int getComputedSpacing() { if (this.direction == RIGHT) { return this.spacing; // positive value; } if (this.direction == LEFT) return -this.spacing; return 0; } } /** Initialize the applet with a 3D rendered and enough space to view all the images. @todo Calculate the pane based on the image sizes **/ void setup() { size(800,600,OPENGL); //size(800,600,P3D); for (int i = 0;i< numImages;i++) { images[i] = new AngledImage(loadImage((i + 1) + "_big.jpg"), (i + 1) + "_big.jpg"); temp[i] = new AngledImage(); } } /** Compute the values for an angled image drawing based on its direction (dir) value. This handles the necessary offsets for drawing a right vs. left facing image. It also sets up the values for drawing a reflected image. **/ void drawAngled(AngledImage img, boolean showReflection) { int tintColor; angledImage(img, height / 2, img.tintColor, false); if (showReflection) { tintColor = img.tintColor - 100; if (tintColor < 0) tintColor = 20; angledImage(img, height/2 + img.image.height - 80, tintColor, true); } } /** Performs the actual work of drawing an angled image. This has no knowledge of the position of the item, only the values necessary to draw it (except for the case of the invert parameter, in which case we rotate it upside-down. **/ void angledImage(AngledImage img, int heightOffset, int tintColor, boolean invert) { pushMatrix(); ///println(img.distance); translate(width/2 + img.getComputedSpacing(), heightOffset, img.distance); rotateY(radians(img.getComputedAngle())); if (invert) { rotateZ(radians(180)); rotateY(radians(180)); } beginShape(); noStroke(); texture(img.image); int w = img.image.width/2; int h = img.image.height - w; tint(tintColor); vertex(-w,-w,0,0); vertex(w,-w,img.image.width,0); vertex(w,h,img.image.width,img.image.height); vertex(-w,h,0,img.image.height); endShape(CLOSE); popMatrix(); tint(255,255); } /** Draws a row of angled images from start to end of the image array, with the given direction. */ void drawAngledImages(int start, int end, int dir, int angle, int spacing, int distance) { int tintColor = GREY_TINT; if (dir == LEFT) { for (int i=end;i>start;i--) { if (i < end) { spacing = spacing + DEFAULT_SPACING_OFFSET; angle = angle - 10; distance = distance + DEFAULT_DISTANCE; tintColor = tintColor - TINT_OFFSET; } AngledImage img = images[i - 1]; img.spacing = spacing; img.angle = angle; img.direction = dir; img.distance = distance; img.tintColor = tintColor; img.startSpacing = spacing; img.startDistance = distance; img.startTintColor = tintColor; drawAngled(img, true); } } if (dir == RIGHT) { for (int i=start;i start) { spacing = spacing + DEFAULT_SPACING_OFFSET; angle = angle - 10; distance = distance + DEFAULT_DISTANCE; tintColor = tintColor - TINT_OFFSET; } AngledImage img = images[i]; img.spacing = spacing; img.angle = angle; img.direction = dir; img.distance = distance; img.tintColor = tintColor; img.startSpacing = spacing; img.startDistance = distance; img.startTintColor = tintColor; drawAngled(img, true); } } } void drawImages() { for (int i=0;i NO_ANGLE) { images[i].angle -=5; } if (images[i].spacing != 0) images[i].spacing = images[i].spacing - acceleration - 4; if (images[i].tintColor < images[i+1].startTintColor) images[i].tintColor += 5; } else if (i == CENTERMOST) { images[CENTERMOST].direction = RIGHT; if (images[CENTERMOST].angle < DEFAULT_ANGLE) { if (images[CENTERMOST].angle + 20 > DEFAULT_ANGLE) { images[CENTERMOST].angle += 5; } else { images[CENTERMOST].angle += 20; } } println(images[CENTERMOST].distance + " distance from " + DEFAULT_DISTANCE); if (images[CENTERMOST].distance > DEFAULT_DISTANCE) { // images[CENTERMOST].distance -= 1; } if (images[CENTERMOST].spacing + acceleration + 3 < DEFAULT_SPACING) { images[CENTERMOST].spacing = images[CENTERMOST].spacing + acceleration + 3; } else if (images[CENTERMOST].spacing < DEFAULT_SPACING + 3) { images[CENTERMOST].spacing = images[CENTERMOST].spacing + 3; } if (images[i].tintColor > images[i+1].startTintColor) images[i].tintColor -= 5; } else { images[i].spacing = spacing; } // Getting closer if (images[i].direction == LEFT && images[i].distance < images[i+1].startDistance) { images[i].distance += 20; println("BRIGHTENING " + i + " LEFT: " + images[i].tintColor + " / " + images[i+1].startTintColor); if (images[i].tintColor < images[i+1].startTintColor) { images[i].tintColor += 20; println("image " + i + " tintcolor: " + images[i].tintColor); } } // Get further away else if (i != CENTERMOST && images[i].direction == RIGHT && images[i].distance > images[i+1].startDistance ) { images[i].distance -=10; println("FADING " + i + " RIGHT: " + images[i].tintColor + " / " + images[i+1].startTintColor); if (images[i].tintColor > images[i+1].startTintColor) { images[i].tintColor -= 20; } } //println("changing distance for " + i + " to " + images[i].distance + " with " + images[i+1].startDistance); drawAngled(images[i], true); //println("changing spacing for " + i + " / " + images[i].direction + " " + images[i].spacing + " / " + images[i+1].startSpacing); drawAngled(leftmost, true); } if (moveImages == false) { for (int i=1;i 1) acceleration--; } else { // reset acceleration = 3; runInit=false; } } void mousePressed() { moveImages = true; }