MenuFlow [Perspective]
////////////////////////////////////////////////////////////////////////////////
// MenuFlow [Perspective]
//
// [AS3.0] MenuFlowクラスに挑戦! (1)
// http://www.project-nya.jp/modules/weblog/details.php?blog_id=1007
// 目的地に近づく (4)
// http://www.project-nya.jp/modules/weblog/details.php?blog_id=760
////////////////////////////////////////////////////////////////////////////////
/**
* Copyright ProjectNya ( http://wonderfl.net/user/ProjectNya )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/5X7D
*/
////////////////////////////////////////////////////////////////////////////////
// MenuFlow [Perspective]
//
// [AS3.0] MenuFlowクラスに挑戦! (1)
// http://www.project-nya.jp/modules/weblog/details.php?blog_id=1007
// 目的地に近づく (4)
// http://www.project-nya.jp/modules/weblog/details.php?blog_id=760
////////////////////////////////////////////////////////////////////////////////
package {
import flash.display.Sprite;
[SWF(backgroundColor="#000000", width="465", height="465", frameRate="30")]
public class Main extends Sprite {
private var flow:MenuFlow;
public function Main() {
//Wonderfl.capture_delay(1);
init();
}
private function init():void {
graphics.beginFill(0x000000);
graphics.drawRect(0, 0, 465, 465);
graphics.endFill();
//
var option:Object = {cx: 232, cy: 132, r: 400, pw: 120, ph: 90, c: 6};
flow = new MenuFlow(option);
addChild(flow);
flow.dataProvider = 12;
}
}
}
//////////////////////////////////////////////////
// MenuFlowクラス
//////////////////////////////////////////////////
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
class MenuFlow extends Sprite {
private var cx:uint;
private var cy:uint;
private var radius:uint;
private var pWidth:uint;
private var pHeight:uint;
private var corner:uint;
private var max:uint;
private var objList:Array;
private var perspective:Perspective;
private var speed:Number = 0;
private var menuList:Array;
private var _angle:Number = 0;
private var targetAngle:Number;
private var direction:int;
private static var deceleration:Number = 0.1;
private static var radian:Number = Math.PI/180;
public function MenuFlow(option:Object) {
cx = option.cx;
cy = option.cy;
radius = option.r;
corner = option.c;
pWidth = option.pw + corner*2;
pHeight = option.ph + corner*2;
init();
}
private function init():void {
x = cx;
y = cy;
perspective = new Perspective();
perspective.init(cx, cy);
}
public function set dataProvider(objs:uint):void {
max = objs;
initialize();
}
private function initialize():void {
objList = new Array();
menuList = new Array();
for (var n:uint = 0; n < max; n++) {
var obj:Object3D = new Object3D();
addChild(obj);
perspective.register(obj, n);
objList.push(obj);
var hue:Number = (360/max)*n;
var option:Object = {w: pWidth, h: pHeight, c: corner, hue: hue};
var menu:MenuFlowBase = new MenuFlowBase(n, option);
obj.addChild(menu);
obj.init(180 - n*360/max);
obj.px = radius*Math.sin(obj.angle*radian);
obj.py = 0;
obj.pz = radius*Math.cos(obj.angle*radian) + radius;
menu.addEventListener(MouseEvent.CLICK, click, false, 0, true);
menuList.push(menu);
}
perspective.screen(0, radius*5);
perspective.setView(0, radius*0.5, 0);
perspective.transform();
addEventListener(Event.ENTER_FRAME, rotateMenu, false, 0, true);
}
private function rotateMenu(evt:Event):void {
var xMouse:Number = (stage.mouseX - cx)/cx;
var abs:Number = Math.abs(xMouse);
var percent:Number;
if (abs == 0) {
percent = 0;
} else {
percent = xMouse;
}
if (abs > 1) percent = 1;
speed = 0.4*percent;
angle += speed;
for (var n:uint = 0; n < max; n++) {
var obj:Object3D = objList[n];
rotate(obj);
}
perspective.transform();
}
private function rotate(obj:Object3D):void {
obj.angle = angle;
obj.px = radius*Math.sin(obj.angle*radian);
obj.pz = radius*Math.cos(obj.angle*radian) + radius;
}
private function click(evt:MouseEvent):void {
select(evt.currentTarget.id);
}
private function select(id:uint):void {
enable(false);
var ta:Number = id*360/max;
var obj:Object3D = objList[id];
var ar:Number = Math.abs(180 - obj.angle + 360)%360;
var al:Number = Math.abs(180 - obj.angle - 360)%360;
direction = (ar <= al) ? 1 : -1;
targetAngle = (ta + 360*direction)%360;
removeEventListener(Event.ENTER_FRAME, rotateMenu);
addEventListener(Event.ENTER_FRAME, update, false, 0, true);
}
private function update(evt:Event):void {
var da:Number = (targetAngle - angle + 360*direction)%360;
angle += da*deceleration;
if (Math.abs(da) < 0.1) {
angle = targetAngle;
removeEventListener(Event.ENTER_FRAME, update);
addEventListener(Event.ENTER_FRAME, rotateMenu, false, 0, true);
enable(true);
}
for (var n:uint = 0; n < max; n++) {
var obj:Object3D = objList[n];
rotate(obj);
}
perspective.transform();
}
private function get angle():Number {
return _angle;
}
private function set angle(param:Number):void {
_angle = (param + 360)%360;
}
private function enable(useful:Boolean):void {
for (var n:uint = 0; n < max; n++) {
var menu:MenuFlowBase = menuList[n];
menu.enabled = useful;
}
}
}
//////////////////////////////////////////////////
// MenuFlowBaseクラス
//////////////////////////////////////////////////
import flash.display.Sprite;
import flash.display.Shape;
import flash.geom.Matrix;
import flash.display.GradientType;
import flash.display.SpreadMethod;
import flash.display.InterpolationMethod;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.MouseEvent;
class MenuFlowBase extends Sprite {
public var id:uint;
private var _width:uint;
private var _height:uint;
private var corner:uint;
private var hue:uint;
private var holder:Shape;
private var reflection:Sprite;
private var cover:Shape;
private var container:Sprite;
private var base:Shape;
private var display:Sprite;
private static var bColor:uint = 0xFFFFFF;
private static var bgColor:uint = 0x000000;
private static var c1Color:uint = 0x33CCFF;
private static var c2Color:uint = 0x3399FF;
private static var reflect:Number = 0.4;
private static var _enabled:Boolean = true;
public function MenuFlowBase(n:uint, option:Object) {
id = n;
_width = option.w;
_height = option.h;
corner = option.c;
hue = option.hue;
init();
}
private function init():void {
holder = new Shape();
reflection = new Sprite();
cover = new Shape();
container = new Sprite();
base = new Shape();
display = new Sprite();
addChild(reflection);
addChild(cover);
addChild(container);
container.addChild(base);
container.addChild(display);
container.buttonMode = true;
container.mouseChildren = false;
initialize();
display.addChild(holder);
createReflection();
}
private function initialize():void {
createGradientBase(holder, _width - corner*2, _height - corner*2);
var colorMatrixManager:ColorMatrixManager = new ColorMatrixManager(holder);
colorMatrixManager.hue(hue);
container.x = - _width*0.5;
container.y = - _height;
base.x = _width*0.5;
createBase(base, _width, _height);
display.x = corner;
display.y = corner;
reflection.x = - _width*0.5;
createGradientCover(cover, _width, Math.ceil(_height*reflect)+1);
}
public function get enabled():Boolean {
return _enabled;
}
public function set enabled(param:Boolean):void {
_enabled = param;
container.mouseEnabled = _enabled;
container.useHandCursor = _enabled;
}
private function createReflection():void {
var content:BitmapData = new BitmapData(container.width, container.height, true, 0x00000000);
content.draw(container);
var bitmap:Bitmap = BitmapManager.reflect(new Bitmap(content), -50, reflect);
reflection.addChild(bitmap);
}
private function createBase(target:Shape, w:uint, h:uint):void {
target.graphics.beginFill(bColor);
target.graphics.drawRect(-w*0.5, 0, w, h);
target.graphics.endFill();
}
private function createGradientBase(target:Shape, w:uint, h:uint):void {
var colors:Array = [c1Color, c2Color];
var alphas:Array = [100, 100];
var ratios:Array = [51, 204];
var matrix:Matrix = new Matrix();
matrix.createGradientBox(w, h, 0.5*Math.PI, 0, 0);
target.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix, SpreadMethod.PAD, InterpolationMethod.RGB, 0.75);
target.graphics.drawRect(0, 0, w, h);
target.graphics.endFill();
}
private function createGradientCover(target:Shape, w:uint, h:uint):void {
var colors:Array = [bgColor, bgColor];
var alphas:Array = [0, 100];
var ratios:Array = [0, 255];
var matrix:Matrix = new Matrix();
matrix.createGradientBox(w, h, 0.5*Math.PI, 0, 0);
target.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix, SpreadMethod.PAD, InterpolationMethod.RGB, 0.75);
target.graphics.drawRect(-w*0.5, 0, w, h);
target.graphics.endFill();
}
}
//////////////////////////////////////////////////
// ColorMatrixManagerクラス
//////////////////////////////////////////////////
import flash.display.DisplayObject;
import flash.filters.ColorMatrixFilter;
//import com.quasimondo.geom.ColorMatrix;
class ColorMatrixManager {
private var target:DisplayObject;
private var colorMatrixFilter:ColorMatrixFilter;
//private var colorMatrix:ColorMatrix;
private var colorMatrix:Array;
private var _brightness:Number = 0;
private var _contrast:Number = 100;
private var _saturation:Number = 100;
private var _hue:Number = 0;
private static var lr:Number = 0.212671;
private static var lg:Number = 0.71516;
private static var lb:Number = 0.072169;
private static var radian:Number = Math.PI/180;
public function ColorMatrixManager(tg:DisplayObject) {
target = tg;
colorMatrixFilter = new ColorMatrixFilter();
//colorMatrix = new ColorMatrix();
colorMatrix = new Array();
}
public function brightness(param:Number):void {
_brightness = param;
setColorMatrix();
}
public function contrast(param:Number):void {
_contrast = param;
setColorMatrix();
}
public function saturation(param:Number):void {
_saturation = param;
setColorMatrix();
}
public function hue(param:Number):void {
_hue = param;
setColorMatrix();
}
private function setColorMatrix():void {
//colorMatrix.reset();
//colorMatrix.adjustBrightness(_brightness*2.55);
//colorMatrix.adjustContrast(_contrast*0.01 - 1);
//colorMatrix.adjustSaturation(_saturation*0.01);
//colorMatrix.adjustHue(_hue);
//colorMatrixFilter.matrix = colorMatrix.matrix;
colorMatrix = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0];
adjustBrightness(_brightness*2.55);
adjustContrast(_contrast*0.01 - 1);
adjustSaturation(_saturation*0.01);
adjustHue(_hue);
colorMatrixFilter.matrix = colorMatrix;
target.filters = [colorMatrixFilter];
}
public function reset():void {
_brightness = 0;
_contrast = 100;
_saturation = 100;
_hue = 0;
setColorMatrix();
}
private function concat(matrix:Array):void {
var list:Array = new Array();
var n:uint = 0;
for (var py:uint = 0; py < 4; py++) {
for (var px:uint = 0; px < 5; px++) {
list[uint(n + px)] = Number(matrix[n])*Number(colorMatrix[px]) + Number(matrix[uint(n + 1)])*Number(colorMatrix[uint(px + 5)])
+ Number(matrix[uint(n + 2)])*Number(colorMatrix[uint(px + 10)]) + Number(matrix[uint(n + 3)])*Number(colorMatrix[uint(px + 15)])
+ (px == 4 ? Number(matrix[uint(n + 4)]) : 0);
}
n += 5;
}
colorMatrix = list;
}
private function adjustBrightness(s:Number):void {
var r:Number;
var g:Number;
var b:Number;
r = g = b = s;
concat([1, 0, 0, 0, r, 0, 1, 0, 0, g, 0, 0, 1, 0, b, 0, 0, 0, 1, 0]);
}
private function adjustContrast(s:Number):void {
var r:Number;
var g:Number;
var b:Number;
r = g = b = s + 1;
concat([r, 0, 0, 0, (128 * (1 - r)), 0, g, 0, 0, (128 * (1 - g)), 0, 0, b, 0, (128 * (1 - b)), 0, 0, 0, 1, 0]);
}
private function adjustSaturation(s:Number):void {
var sv:Number = 1 - s;
var r:Number = sv*lr;
var g:Number = sv*lg;
var b:Number = sv*lb;
concat([(r + s), g, b, 0, 0, r, (g + s), b, 0, 0, r, g, (b + s), 0, 0, 0, 0, 0, 1, 0]);
}
private function adjustHue(a:Number):void {
var cos:Number = Math.cos(a*radian);
var sin:Number = Math.sin(a*radian);
concat([lr + cos*(1 - lr) - sin*lr, lg - cos*lg - sin*lg, lb - cos*lb + sin*(1 - lb), 0, 0, lr - cos*lr + sin*0.143, lg + cos*(1 - lg) + sin*0.14, lb - cos*lb - sin*0.283, 0, 0, lr - cos*lr - sin*(1 - lr), lg - cos*lg + sin*lg, lb + cos*(1 - lb) + sin*lb, 0, 0, 0, 0, 0, 1, 0]);
}
}
//////////////////////////////////////////////////
// BitmapManagerクラス
//////////////////////////////////////////////////
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Matrix;
import flash.geom.ColorTransform;
import flash.geom.Rectangle;
class BitmapManager {
public function BitmapManager() {
}
public static function reflect(content:Bitmap, brightness:Number, reflection:Number):Bitmap {
var w:Number = content.width;
var h:Number = content.height;
var bitmap:BitmapData = new BitmapData(w, h, true, 0x00000000);
var matrix:Matrix = new Matrix();
matrix.scale(1, -1);
matrix.translate(0, h);
var percent:Number = 1 - Math.abs(brightness)*0.01;
var offset:Number = (brightness > 0) ? (brightness*2.55) : 0;
var colorTrans:ColorTransform = new ColorTransform(percent, percent, percent, 1, offset, offset, offset, 0);
var rect:Rectangle = new Rectangle(0, 0, w, h*reflection);
content.smoothing = true;
bitmap.draw(content, matrix, colorTrans, null, rect);
return new Bitmap(bitmap);
}
}
//////////////////////////////////////////////////
// Perspectiveクラス
//////////////////////////////////////////////////
import flash.display.Sprite;
class Perspective {
private var objList:Array;
private var fl:Number = 250;
private var vp:Object;
private var view:Object;
private var ax:Number = 0;
private var ay:Number = 0;
private var az:Number = 0;
private var brighted:Boolean = false;
private var front:Number = -100;
private var back:Number = 100;
private var depthList:Array;
public function Perspective() {
objList = new Array();
vp = {x: 0, y: 0};
view = {x: 0, y: 0, z: 0};
depthList = new Array();
}
public function init(x:int, y:int):void {
vp = {x: x, y: -y};
}
public function register(obj:Object3D, n:uint):void {
objList.push(obj);
obj.id = n;
}
public function transform():void {
for (var n:uint = 0; n < objList.length; n++) {
var obj:Object3D = objList[n];
setPerspective(obj);
}
manageDepths();
}
private function setPerspective(obj:Object3D):void {
if (obj.pz + view.z > - fl + 50) {
var scale:Number = fl/(fl + obj.pz + view.z);
obj.scale = scale;
obj.x = vp.x + (obj.px - view.x)*scale;
obj.y = - vp.y - (obj.py + view.y)*scale;
if (brighted) obj.brightness = -100*(obj.pz + view.z - front)/(back - front);
obj.visible = true;
} else {
obj.visible = false;
}
}
private function manageDepths():void {
objList.sortOn(["pz", "id"], [Array.DESCENDING | Array.NUMERIC, Array.DESCENDING | Array.NUMERIC]);
for (var n:uint = 0; n < objList.length; n++) {
var obj:Object3D = objList[n];
obj.stage.addChildAt(obj, n+1);
}
}
public function screen(f:Number, b:Number):void {
if (front == back) {
brighted = false;
} else {
brighted = true;
front = f;
back = b;
}
}
public function setView(x:Number, y:Number, z:Number):void {
view.x = x;
view.y = -y;
view.z = -z;
transform();
}
public function rotate(x:Number, y:Number, z:Number):void {
for (var n:uint = 0; n < objList.length; n++) {
var obj:Object3D = objList[n];
angleX(obj, x - ax);
angleY(obj, y - ay);
angleZ(obj, z - az);
setPerspective(obj);
}
manageDepths();
ax = x%360;
ay = y%360;
az = z%360;
}
public function rotateX(angle:Number):void {
var a:Number = angle - ax;
for (var n:uint = 0; n < objList.length; n++) {
var obj:Object3D = objList[n];
angleX(obj, a);
setPerspective(obj);
}
manageDepths();
ax = angle%360;
}
public function rotateY(angle:Number):void {
var a:Number = angle - ay;
for (var n:uint = 0; n < objList.length; n++) {
var obj:Object3D = objList[n];
angleY(obj, a);
setPerspective(obj);
}
manageDepths();
ay = angle%360;
}
public function rotateZ(angle:Number):void {
var a:Number = angle - az;
for (var n:uint = 0; n < objList.length; n++) {
var obj:Object3D = objList[n];
angleZ(obj, a);
setPerspective(obj);
}
manageDepths();
az = angle%360;
}
private function angleX(obj:Object3D, angle:Number):void {
var radian:Number = -angle*Math.PI/180;
var cos:Number = Math.cos(radian);
var sin:Number = Math.sin(radian);
var ry:Number = obj.py*cos - obj.pz*sin;
var rz:Number = obj.pz*cos + obj.py*sin;
obj.py = ry;
obj.pz = rz;
}
private function angleY(obj:Object3D, angle:Number):void {
var radian:Number = -angle*Math.PI/180;
var cos:Number = Math.cos(radian);
var sin:Number = Math.sin(radian);
var rx:Number = obj.px*cos - obj.pz*sin;
var rz:Number = obj.pz*cos + obj.px*sin;
obj.px = rx;
obj.pz = rz;
}
private function angleZ(obj:Object3D, angle:Number):void {
var radian:Number = -angle*Math.PI/180;
var cos:Number = Math.cos(radian);
var sin:Number = Math.sin(radian);
var rx:Number = obj.px*cos - obj.py*sin;
var ry:Number = obj.py*cos + obj.px*sin;
obj.px = rx;
obj.py = ry;
}
}
//////////////////////////////////////////////////
// Object3Dクラス
//////////////////////////////////////////////////
import flash.display.Sprite;
import flash.filters.BlurFilter;
import flash.geom.ColorTransform;
class Object3D extends Sprite {
public var id:uint;
public var px:Number;
public var py:Number;
public var pz:Number;
private var _angle:Number = 0;
private var basicAngle:Number;
private var _scale:Number = 1;
private var colorTrans:ColorTransform;
private var _brightness:Number = 0;
private var _blur:Number = 0;
public function Object3D() {
colorTrans = new ColorTransform(0, 0, 0, 1, 0, 0, 0, 0);
}
public function init(a:Number):void {
basicAngle = a;
angle = 0;
}
public function get angle():Number {
return _angle;
}
public function set angle(param:Number):void {
var a:Number = basicAngle + param;
_angle = (a + 360)%360;
}
public function get scale():Number {
return _scale;
}
public function set scale(param:Number):void {
_scale = param;
scaleX = scaleY = _scale;
}
public function get blur():Number {
return _blur;
}
public function set blur(param:Number):void {
_blur = param;
var b:uint = _blur/8 >> 1;
var filter:BlurFilter = new BlurFilter(b*2, b*2, 2);
filters = [filter];
}
public function get brightness():Number {
return _brightness;
}
public function set brightness(param:Number):void {
_brightness = param;
var percent:uint = 100 - Math.abs(param);
var offset:uint = (param > 0) ? (255*param*0.01) : 0;
setColorTrans(percent, offset);
}
private function setColorTrans(percent:Number, offset:Number):void {
colorTrans.redMultiplier = percent*0.01;
colorTrans.greenMultiplier = percent*0.01;
colorTrans.blueMultiplier = percent*0.01;
colorTrans.redOffset = offset;
colorTrans.greenOffset = offset;
colorTrans.blueOffset = offset;
colorTrans.alphaMultiplier = alpha;
colorTrans.alphaOffset = 0;
transform.colorTransform = colorTrans;
}
}