src/nu/xero/gui/coverflow.as
package nu.xero.gui {
import caurina.transitions.*;
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.media.*;
import flash.net.*;
import org.papervision3d.cameras.*;
import org.papervision3d.core.render.data.*;
import org.papervision3d.events.*;
import org.papervision3d.materials.*;
import org.papervision3d.objects.*;
import org.papervision3d.objects.primitives.*;
import org.papervision3d.view.*;
public class coverflow extends BasicView {
public var stats :RenderStatistics
private var thisCover :DisplayObject3D
private var theCovers :Array = new Array();
private var coverCount :Number;
private var currentIndex :Number = 0;
private var planeAngle :Number = 65;
private var planeSeparation :Number = 100;
private var planeOffset :Number = 200;
private var needsRendered :Boolean = false;
private var audio :Sound;
private var isPlaying :Boolean = false;
public function coverflow(playlist:XMLList, art:Array, stageRef:Stage) {
super(0,0, true, true, CameraType.TARGET);
camera.zoom = 1;
camera.focus = 500;
camera.z = -800;
stats = renderer.renderScene(scene, camera, viewport);
coverCount = playlist.length();
var i:Number = 0;
while(i++ < coverCount) {
theCovers[i] = new Object();
theCovers[i].cover = new Plane(new BitmapMaterial(generateReflection(art[i-1].img)), 461, 492, 4, 4);
theCovers[i].cover.name = playlist[i-1].title;
theCovers[i].cover.material.interactive = true;
theCovers[i].cover.material.doubleSided = false;
theCovers[i].cover.material.smooth = false;
theCovers[i].cover.extra = i;
theCovers[i].cover.y -= 200;
theCovers[i].isZoomed = false;
theCovers[i].mp3 = playlist[i-1].mp3;
theCovers[i].cover.addEventListener(InteractiveScene3DEvent.OBJECT_MOVE, hover);
theCovers[i].cover.addEventListener(InteractiveScene3DEvent.OBJECT_PRESS, hit);
theCovers[i].cover.addEventListener(InteractiveScene3DEvent.OBJECT_OUT, out);
stageRef.addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheel);
scene.addChild(theCovers[i].cover, "cover"+i);
}
flowCovers(int(coverCount*.5+1));
startRendering();
}
override protected function onRenderTick(e:Event = null):void {
if(needsRendered){
super.onRenderTick(e);
needsRendered=false;
}
}
private function hit(e:InteractiveScene3DEvent):void {
if(e.y <= 250){ //dont click the reflections
thisCover = e.displayObject3D;
flowCovers(thisCover.extra);
}
}
private function hover(e:InteractiveScene3DEvent):void {
if(e.y <= 250){ //dont click the reflections
this.buttonMode = true;
} else {
this.buttonMode = false;
}
}
private function out(e:InteractiveScene3DEvent):void {
this.buttonMode = false;
}
private function mouseWheel(e:MouseEvent):void {
if(e.delta < 0){
if(currentIndex > 1){
flowCovers(currentIndex-1);
}
} else {
if (currentIndex < coverCount) {
flowCovers(currentIndex+1);
}
}
}
private function generateReflection(bmp:BitmapData):BitmapData{
var reflectedBmp:BitmapData = new BitmapData(bmp.width, bmp.height*2, false, 0);
reflectedBmp.draw(bmp);
var alpha:Number = 0.3;
var flipMatrix:Matrix = new Matrix(1, 0, 0, -1, 0, bmp.height*2 + 4);
reflectedBmp.draw(bmp, flipMatrix, new ColorTransform(alpha, alpha, alpha, 1, 0, 0, 0, 0));
var holder:Shape = new Shape();
var gradientMatrix:Matrix = new Matrix();
gradientMatrix.createGradientBox(bmp.width, bmp.height, Math.PI*.5);
holder.graphics.beginGradientFill(GradientType.LINEAR, [ 0, 0 ], [ 0, 100 ], [ 0, 0xFF ], gradientMatrix);
holder.graphics.drawRect(0, 0, bmp.width, bmp.height);
holder.graphics.endFill();
var m:Matrix = new Matrix();
m.translate(0, bmp.height);
reflectedBmp.draw(holder, m);
return reflectedBmp;
}
private function loadTrack(url:String):void {
if(isPlaying) {
SoundMixer.stopAll();
audio = null;
} else {
isPlaying = true;
}
audio = new Sound(new URLRequest(url), new SoundLoaderContext(5000));
audio.play();
}
private function flowCovers(newIndex:*):void {
if(currentIndex != newIndex) {
needsRendered=true;
var i:Number = 0;
while(++i<=coverCount){
thisCover = theCovers[i].cover;
theCovers[i].isZoomed = false;
//smoothing
if(i>=newIndex-1 && i<=newIndex+1) {
thisCover.material.smooth = true;
} else {
thisCover.material.smooth = false;
}
//tween covers
if(i == newIndex) {
Tweener.addTween(thisCover, {
x: 0,
z: -180,
rotationY: 0,
time: .8,
transition: "easeOutExpo",
onUpdate: function():void{ needsRendered = true; }
});
} else if(i < newIndex) {
Tweener.addTween(thisCover, {
x: (newIndex-i+1)*-planeSeparation-planeOffset,
z: ((newIndex-i+1)*+planeSeparation)*.5,
rotationY: -planeAngle,
time: .8,
transition: "easeOutExpo",
onUpdate: function():void{ needsRendered = true; }
});
} else {
Tweener.addTween(thisCover, {
x: ((i-newIndex+1)*planeSeparation)+planeOffset,
z: ((newIndex-i+1)*-planeSeparation)*.5,
rotationY: planeAngle,
time: .8,
transition: "easeOutExpo",
onUpdate: function():void{ needsRendered = true; }
});
}
}
currentIndex = newIndex;
} else {
thisCover = theCovers[newIndex].cover;
//zoom in on selected cover
if(!theCovers[newIndex].isZoomed){
Tweener.addTween(thisCover, {
z: -390,
time: 3,
transition: "easeOutExpo",
onUpdate: function():void{ needsRendered = true; }
});
theCovers[newIndex].isZoomed = true;
loadTrack(theCovers[newIndex].mp3);
} else {
Tweener.addTween(thisCover, {
z: -180,
time: 3,
transition: "easeOutExpo",
onUpdate: function():void{ needsRendered = true; }
});
theCovers[newIndex].isZoomed = false;
}
}
}
}
}