【Planet】 太陽系第4惑星【3D】
/**
* Copyright tepe ( http://wonderfl.net/user/tepe )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/ndKH
*/
// forked from tepe's 【Planet】 太陽系第3惑星【3D】
// forked from tepe's 3D Planet
// forked from tepe's forked from: [wonderfl] Planet Earth 3D
package{
import com.bit101.components.HUISlider;
import com.bit101.components.VUISlider;
import com.bit101.components.Label;
import com.bit101.components.RadioButton;
import com.bit101.components.PushButton;
import flash.display.*;
import flash.events.*;
import flash.text.*;
import flash.utils.*;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.system.Security;
import net.user1.reactor.IClient;
import net.user1.reactor.Reactor;
import net.user1.reactor.ReactorEvent;
import net.user1.reactor.Room;
import net.user1.reactor.RoomEvent;
[SWF(backgroundColor = "#000000")]
public class FP10Sphere extends Sprite
{
private var _sphere:Sphere;//スフィア
private var txt:TextField = new TextField();
private var _reactor:Reactor;
private var _room:Room;
//回転速度
private var _vx:Number;
private var _vy:Number;
private var _vz:Number;
public function FP10Sphere():void
{
//Security.loadPolicyFile("http://ozmap.orz.hm/crossdomain.xml");
//stage.align = StageAlign.TOP_LEFT;
var url:String = "http://farm6.static.flickr.com/5216/5490549329_2c78fb408f_z.jpg";//火星
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.frameRate = 60;
_createSphere(url);
txt.y=100;
txt.width = 200;
addChild(txt);
addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown);
addEventListener(MouseEvent.MOUSE_WHEEL,onWheel);
stage.addEventListener(MouseEvent.MOUSE_UP,onMouseUp);
stage.addEventListener(Event.MOUSE_LEAVE,leave);
//connect();
var btn1:Btn = new Btn();
btn1.init({label:"full screen",type:2,width:100});
btn1.x = stage.stageWidth/2; btn1.y = 445;
btn1.addEventListener(MouseEvent.CLICK,screen);
stage.addChild(btn1);
}
private var n3:Number = 0;
private var n4:Number = 0;
private var n5:Number = 0;
private var sw1:Boolean = false;//マウスボタン状態
private function onWheel(e:MouseEvent):void{
_sphere.radius *= 1.0+(e.delta*0.05);
if(1000<_sphere.radius)_sphere.radius = 1000;
else if(_sphere.radius<5)_sphere.radius=5;
//_sphere.segmentH = _sphere.segmentW = 8+Math.round(_sphere.radius/50);
}
private function onMouseDown(e:MouseEvent):void{
n3 = _sphere.mouseX/_sphere.radius;
n4 = _sphere.mouseY/_sphere.radius;
stage.addEventListener(MouseEvent.MOUSE_MOVE,onMove);
if(Math.abs(n3)<1 && Math.abs(n4)){
_vx = _vy = _vz = 0;
}
sw1 = true;
}
private function onMouseUp(e:MouseEvent):void{
stage.removeEventListener(MouseEvent.MOUSE_MOVE,onMove);
sw1 = false;
}
private function leave(e:Event):void{
stage.removeEventListener(MouseEvent.MOUSE_MOVE,onMove);
sw1 = false;
}
private function onMove(e:MouseEvent):void{
//_sphere.rotateByQuaternion((n4-_sphere.mouseY/_sphere.radius)*70,(_sphere.mouseX/_sphere.radius-n3)*70,0,true);
_vy = (_sphere.mouseX/_sphere.radius-n3)*70;
_vx = (n4-_sphere.mouseY/_sphere.radius)*70;
n3 = _sphere.mouseX/_sphere.radius;
n4 = _sphere.mouseY/_sphere.radius;
}
private function screen(e:MouseEvent):void{
if(stage.displayState == StageDisplayState.NORMAL){
stage.displayState = StageDisplayState.FULL_SCREEN;
e.currentTarget.txt.text = "normal";
}
else{
stage.displayState = StageDisplayState.NORMAL;
e.currentTarget.txt.text = "full screen";
}
}
private function _createSphere(url:String):void
{
var texture:BitmapData;
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event):void {
var texture:BitmapData = Bitmap(loader.contentLoaderInfo.content).bitmapData;
_vx = 0;
_vy = 0;
_vz = 0;
//スフィアを生成する
_sphere = addChild(new Sphere(texture, 150 ,20, 20)) as Sphere;
_sphere.x = stage.stageWidth * 0.5;
_sphere.y = stage.stageHeight * 0.5;
_sphere.addEventListener(Event.ENTER_FRAME, _update);
});
loader.load(new URLRequest(url), new LoaderContext(true));
}
//エンターフレーム
private function _update(e:Event):void {
if(sw1==true){
_vx/=1.2; _vy/=1.2;
}
_sphere.rotateByQuaternion( _vx, _vy, _vz );//回転
_sphere.render();//レンダリング
}
//-------------------------------------------------------------------------------------------------
private function connect():void {
_reactor = new Reactor();//インスタンス作成
_reactor.addEventListener( ReactorEvent.READY, _reactor_readyHandler);//接続完了イベント
_reactor.connect("localhost",9100);
//_reactor.connect("tryunion.com", 9100);// Union Serverへ接続します。
}
//入室フェーズ
private function join():void {
_room = _reactor.getRoomManager().createRoom("test2def");//ルーム作成
_room.addEventListener(RoomEvent.JOIN, _room_joinHandler);//ルーム入室イベント
_room.addMessageListener("shared", _room_sharedHandler);//"shared"メッセージ受信イベント
_room.join();
}
//入室後の設定
private function activate():void {
stage.addEventListener( MouseEvent.CLICK, stage_mouseClickHandler );
}
private function _reactor_readyHandler(event:ReactorEvent):void {
join();
}
//入室イベント
private function _room_joinHandler(event:RoomEvent):void {
activate();
}
//メッセージ受信
private function _room_sharedHandler(
fromClient:IClient, color:uint,
sharedX:Number, sharedY:Number):void
{
graphics.beginFill(color);
graphics.drawCircle(sharedX, sharedY, 10);//円描画
var textField:TextField = new TextField();
textField.autoSize = TextFieldAutoSize.LEFT;
textField.text = fromClient.getClientID();//クライアントID
textField.x = sharedX;
textField.y = sharedY;
textField.mouseEnabled = false;
addChild(textField);
}
//メッセージ送信
private function stage_mouseClickHandler(event:MouseEvent):void
{
// Roomに色とマウスのx座標、y座標を引数とした shared という名の
// メッセージを送信します
_room.sendMessage( "shared", true, null, //メッセージ,エコー,内容
0x00ff00,//カラー
event.stageX, event.stageY//位置
);
}
}
}
import flash.display.*;
import flash.geom.*;
internal class Vertex3D{
// 3D座標
public var x:Number;
public var y:Number;
public var z:Number;
// UV座標
public var u:Number;
public var v:Number;
// 頂点インデックス
public var index:int;
// コンストラクタ
public function Vertex3D():void
{
index = -1;
}
}
/*****************************************//**
* 3Dオブジェクトの基底クラス
*
* @author alumican.net
*/
internal class Object3D extends Sprite{
static public const PI:Number = Math.PI;
static public const PI2:Number = PI * 2;
static public const TO_RADIAN:Number = PI / 180;// ラジアン角 → 角度
static public const TO_DEGREE:Number = 180 / PI;// 角度 → ラジアン角
// レンダリング先
public var _viewport:Sprite;
// テクスチャ画像
public var _texture:BitmapData;
// 3D変形マトリックス
private var _transform3D:Matrix3D;
// 3D頂点情報
private var _vertices3D:Vector.<Number>;// 3D座標点
private var _indices:Vector.<int>;
private var _uvData:Vector.<Number>;// UV座標点
// 頂点/サーフィス数
public function get vertexCount():uint { return _vertices3D.length / 3; }
public function get surfaceCount():uint { return _indices.length / 3; }
// プロジェクト後の座標
private var _transformedVertices3D:Vector.<Number>;
private var _transformedVertices2D:Vector.<Number>;
// projectVectors用
private var _uvtData:Vector.<Number>;
// クォータニオン
private var _qx:Number;
private var _qy:Number;
private var _qz:Number;
private var _qw:Number;
/**
* レンダリング方法の指定
* true : projectVectors
* false : transformVectors
*/
public var useProjectVectors:Boolean;
// コンストラクタ
public function Object3D(texture:BitmapData = null):void {
_viewport = addChild( new Sprite() ) as Sprite;
_texture = texture;
useProjectVectors = true;
_transform3D = new Matrix3D();
_transform3D.identity();
_qx = _qy = _qz = 0;
_qw = 1;
create();
}
// オブジェクトを生成する
public function create():void{
_vertices3D = new Vector.<Number>();
_indices = new Vector.<int>();
_uvData = new Vector.<Number>();
_createVetices(_vertices3D, _indices, _uvData);
_transformedVertices2D = new Vector.<Number>(_uvData.length, true);// UV座標点
_transformedVertices3D = new Vector.<Number>(_vertices3D.length, true);// 3D座標点
_uvtData = new Vector.<Number>(_vertices3D.length, true);
var n:uint = _uvData.length;
var i:uint = 0;
var j:uint = 0;
while (i < n)
{
_uvtData[j++] = _uvData[i++];
_uvtData[j++] = _uvData[i++];
_uvtData[j++] = null;
}
}
/**
* 3D頂点座標、頂点インデックス、UVデータを生成する(オーバーライド用)
* @param vertices3D
* @param indices
* @param uvData
*/
protected function _createVetices(vertices3D:Vector.<Number>, indices:Vector.<int>, uvData:Vector.<Number>):void{
}
// レンダリング
public function render():void {
if (!_texture) return;// テクスチャが指定されていないときはレンダリングしない
if (useProjectVectors){// projectVectorsを使う
Utils3D.projectVectors(_transform3D, _vertices3D, _transformedVertices2D, _uvtData);
}
else{// transformVectorsを使う
_transform3D.transformVectors(_vertices3D, _transformedVertices3D);
var n:uint = _uvData.length,
j:uint = 0;
for (var i:uint = 0; i < n; i += 2){//3D座標から画面座標へ変換
_transformedVertices2D[i ] = _transformedVertices3D[j ];
_transformedVertices2D[i + 1] = _transformedVertices3D[j + 1];
j += 3;
}
}
var g:Graphics = _viewport.graphics;
g.clear();// 画像リセット
g.beginBitmapFill(_texture, null, false, false);//ビットマップで塗りつぶす
g.drawTriangles(_transformedVertices2D, _indices, _uvData, TriangleCulling.NEGATIVE);
}
// クォータニオンを用いた回転を付与する
public function rotateByQuaternion(rotateX:Number, rotateY:Number, rotateZ:Number, useDegree:Boolean = true):void{
if (useDegree){//360度表現
rotateX *= TO_RADIAN;
rotateY *= TO_RADIAN;
rotateZ *= TO_RADIAN;
}
//----------------------------------------
//回転クォータニオンの生成
var fSinPitch:Number = Math.sin(rotateY * 0.5),
fCosPitch:Number = Math.cos(rotateY * 0.5),
fSinYaw:Number = Math.sin(rotateZ * 0.5),
fCosYaw:Number = Math.cos(rotateZ * 0.5),
fSinRoll:Number = Math.sin(rotateX * 0.5),
fCosRoll:Number = Math.cos(rotateX * 0.5),
fCosPitchCosYaw:Number = fCosPitch * fCosYaw,
fSinPitchSinYaw:Number = fSinPitch * fSinYaw,
rx:Number = fSinRoll * fCosPitchCosYaw - fCosRoll * fSinPitchSinYaw,
ry:Number = fCosRoll * fSinPitch * fCosYaw + fSinRoll * fCosPitch * fSinYaw,
rz:Number = fCosRoll * fCosPitch * fSinYaw - fSinRoll * fSinPitch * fCosYaw,
rw:Number = fCosRoll * fCosPitchCosYaw + fSinRoll * fSinPitchSinYaw,
//----------------------------------------
//元のクォータニオンに回転を合成
qx:Number = _qw * rx + _qx * rw + _qy * rz - _qz * ry,
qy:Number = _qw * ry - _qx * rz + _qy * rw + _qz * rx,
qz:Number = _qw * rz + _qx * ry - _qy * rx + _qz * rw,
qw:Number = _qw * rw - _qx * rx - _qy * ry - _qz * rz,
//----------------------------------------
//正規化
norm:Number = Math.sqrt(qx * qx + qy * qy + qz * qz + qw * qw),
inv:Number,
//----------------------------------------
//行列へ変換
xx:Number,
xy:Number,
xz:Number,
xw:Number,
yy:Number,
yz:Number,
yw:Number,
zz:Number,
zw:Number,
m:Vector.<Number> = _transform3D.rawData;
//----------------------------------------
//正規化
if(((norm < 0) ? -norm : norm) < 0.000001)
{
qx = qy = qz = 0.0;
qw = 1.0;
}
else
{
inv = 1 / norm;
qx *= inv;
qy *= inv;
qz *= inv;
qw *= inv;
}
//----------------------------------------
//行列へ変換
xx = qx * qx;
xy = qx * qy;
xz = qx * qz;
xw = qx * qw;
yy = qy * qy;
yz = qy * qz;
yw = qy * qw;
zz = qz * qz;
zw = qz * qw;
m[0] = 1 - 2 * (yy + zz);
m[1] = 2 * (xy - zw);
m[2] = 2 * (xz + yw);
m[4] = 2 * (xy + zw);
m[5] = 1 - 2 * (xx + zz);
m[6] = 2 * (yz - xw);
m[8] = 2 * (xz - yw);
m[9] = 2 * (yz + xw);
m[10] = 1 - 2 * (xx + yy);
_transform3D.rawData = m;
//----------------------------------------
//クォータニオンの保存
_qx = qx;
_qy = qy;
_qz = qz;
_qw = qw;
}
}
/*****************************************//**
* スフィア
*
* @author alumican.net
*/
class Sphere extends Object3D{
// 半径
public function get radius():Number { return _radius; }
public function set radius(value:Number):void { _radius = value; create(); }
private var _radius:Number;
// 水平方向の分割数
public function get segmentW():uint { return _segmentW; }
public function set segmentW(value:uint):void { _segmentW = value; create(); }
private var _segmentW:uint;
// 垂直方向の分割数
public function get segmentH():uint { return _segmentH; }
public function set segmentH(value:uint):void { _segmentH = value; create(); }
private var _segmentH:uint;
// コンストラクタ
public function Sphere(texture:BitmapData = null, radius:Number = 100, segmentW:uint = 8, segmentH:uint = 6):void
{
_radius = radius;
_segmentW = segmentW;
_segmentH = segmentH;
super(texture);
}
// 頂点情報を生成する
override protected function _createVetices(vertices3D:Vector.<Number>, indices:Vector.<int>, uvData:Vector.<Number>):void
{
var i:uint,
j:uint,
n:uint,
p:Vertex3D,
index:uint,
x:Number,
y:Number,
u:Number,
v:Number,
angleU:Number,
angleV:Number,
points:Vector.<Vertex3D> = new Vector.<Vertex3D>(),
poly:Vector.<Vertex3D> = new Vector.<Vertex3D>(4),
poleN:Vertex3D,
poleS:Vertex3D,
segW:uint = _segmentW + 1,
segH:uint = _segmentH + 1;
//頂点の生成
for (i = 0; i < segH; ++i){// 緯度方向
for (j = 0; j < segW; ++j){// 経度方向
p = new Vertex3D();
//このあたりの頂点をマージしたい
//if (i == 0 ) { if (j == 0) poleN = p; else p = poleN; } // テクスチャ上端に対応する頂点
//if (i == segH - 1) { if (j == 0) poleS = p; else p = poleS; } // テクスチャ下端に対応する頂点
//if (j == segW - 1) { p = _points[_points.length - segW + 1]; } // テクスチャ右端に対応する頂点
u = j / (segW - 1);//経度
v = i / (segH - 1);//緯度
angleU = u * PI2;//経度 一周分
angleV = v * PI;//緯度 半球分
//座標
y = -_radius * Math.cos(angleV);
x = _radius * Math.sin(angleU) * Math.sin(angleV);
z = -_radius * Math.cos(angleU) * Math.sin(angleV);
//座標登録
p.x = x;
p.y = y;
p.z = z;
p.u = u;
p.v = v;
points.push(p);//頂点追加
}
}
//ポリゴンの生成
n = points.length;//頂点数
index = 0;
for (i = 0; i < n; ++i) {
if (i + segW + 1 >= n) break;
if ((i + 1) % segW == 0) continue;
poly[0] = points[i];
poly[1] = points[i + 1];
poly[2] = points[i + segW];
poly[3] = points[i + segW + 1];
for (j = 0; j < 4; ++j)
{
//新規頂点を追加
if ((p = poly[j]).index == -1)
{
p.index = index++;
vertices3D.push(p.x, p.y, p.z);// 3D座標
uvData.push(p.u, p.v);// UV座標
}
}
//頂点インデックスに追加(時計回り)
indices.push(
poly[0].index, poly[1].index, poly[2].index,
poly[1].index, poly[3].index, poly[2].index
);
}
}
}
//////////////////////////////////////////////////
// Btnクラス
//////////////////////////////////////////////////
import flash.display.*;
import flash.text.*;
import flash.filters.GlowFilter;
import flash.events.MouseEvent;
class Btn extends Sprite {
public var id:uint;
private var shade:Shape;
private var bottom:Shape;
private var light:Shape;
private var base:Shape;
public var txt:TextField;
private var label:String = "";
private static var fontType:String = "_ゴシック";
private var _width:uint = 60;
private static var _height:uint = 20;
private static var corner:uint = 5;
private var type:uint = 1;
private static var bColor:uint = 0xFFFFFF;
private static var sColor:uint = 0x000000;
private static var upColor:uint = 0x666666;
private static var overColor:uint = 0x333333;
private static var offColor:uint = 0x999999;
private static var gColor:uint = 0x0099FF;
private var blueGlow:GlowFilter;
private var shadeGlow:GlowFilter;
private var _clicked:Boolean = false;
private var _enabled:Boolean = true;
public function Btn() {
}
public function init(option:Object):void {
if (option.id != undefined) id = option.id;
if (option.label != undefined) label = option.label;
if (option.width != undefined) _width = option.width;
if (option.type != undefined) type = option.type;
draw();
}
private function draw():void {
switch (type) {
case 1 :
bColor = 0xFFFFFF;
sColor = 0x000000;
upColor = 0x666666;
overColor = 0x333333;
offColor = 0x999999;
break;
case 2 :
bColor = 0x000000;
sColor = 0xFFFFFF;
upColor = 0x666666;
overColor = 0x999999;
offColor = 0x333333;
break;
}
blueGlow = new GlowFilter(gColor, 0.6, 5, 5, 2, 3, false, true);
shadeGlow = new GlowFilter(sColor, 0.3, 4, 4, 2, 3, false, true);
shade = new Shape();
bottom = new Shape();
light = new Shape();
base = new Shape();
txt = new TextField();
addChild(shade);
addChild(bottom);
addChild(light);
addChild(base);
addChild(txt);
createBase(shade, _width, _height, corner, sColor);
shade.filters = [shadeGlow];
createBase(bottom, _width, _height, corner, sColor, 0.3);
createBase(light, _width, _height, corner, gColor);
light.filters = [blueGlow];
createBase(base, _width, _height, corner, bColor);
txt.x = -_width*0.5;
txt.y = -_height*0.5;
txt.width = _width;
txt.height = _height - 1;
txt.type = TextFieldType.DYNAMIC;
txt.selectable = false;
//txt.embedFonts = true;
//txt.antiAliasType = AntiAliasType.ADVANCED;
var tf:TextFormat = new TextFormat();
tf.font = fontType;
tf.size = 12;
tf.align = TextFormatAlign.CENTER;
txt.defaultTextFormat = tf;
txt.text = label;
enabled = true;
mouseChildren = false;
}
private function rollOver(evt:MouseEvent):void {
_over();
}
private function rollOut(evt:MouseEvent):void {
_up();
}
private function press(evt:MouseEvent):void {
_down();
}
private function release(evt:MouseEvent):void {
_up();
}
private function click(evt:MouseEvent):void {
}
private function _up():void {
txt.y = -_height*0.5;
txt.textColor = upColor;
base.y = -1;
light.visible = false;
light.y = -1;
}
private function _over():void {
txt.y = -_height*0.5;
txt.textColor = overColor;
base.y = -1;
light.visible = true;
light.y = -1;
}
private function _down():void {
txt.y = -_height*0.5 + 1;
txt.textColor = overColor;
base.y = 0;
light.visible = true;
light.y = 0;
}
private function _off():void {
txt.y = -_height*0.5 + 1;
txt.textColor = offColor;
base.y = 0;
light.visible = false;
light.y = 0;
}
public function get clicked():Boolean {
return _clicked;
}
public function set clicked(param:Boolean):void {
_clicked = param;
enabled = !_clicked;
if (_clicked) {
_down();
} else {
_up();
}
}
public function get enabled():Boolean {
return _enabled;
}
public function set enabled(param:Boolean):void {
_enabled = param;
buttonMode = _enabled;
mouseEnabled = _enabled;
useHandCursor = _enabled;
if (_enabled) {
_up();
addEventListener(MouseEvent.MOUSE_OVER, rollOver, false, 0, true);
addEventListener(MouseEvent.MOUSE_OUT, rollOut, false, 0, true);
addEventListener(MouseEvent.MOUSE_DOWN, press, false, 0, true);
addEventListener(MouseEvent.MOUSE_UP, release, false, 0, true);
addEventListener(MouseEvent.CLICK, click, false, 0, true);
} else {
_off();
removeEventListener(MouseEvent.MOUSE_OVER, rollOver);
removeEventListener(MouseEvent.MOUSE_OUT, rollOut);
removeEventListener(MouseEvent.MOUSE_DOWN, press);
removeEventListener(MouseEvent.MOUSE_UP, release);
removeEventListener(MouseEvent.CLICK, click);
}
}
private function createBase(target:Shape, w:uint, h:uint, c:uint, color:uint, alpha:Number = 1):void {
target.graphics.beginFill(color, alpha);
target.graphics.drawRoundRect(-w*0.5, -h*0.5, w, h, c*2);
target.graphics.endFill();
}
}