Alternativa3D TextureEnvironmentMaterial (環境マップ)のテスト
Alternativa3D 環境マップのテスト
画面ドラッグで回転します、
Alternativa3D platformのフォーラムで公開されていた、環境マップマテリアルの習作です。
あくまでAlternativa3Dの環境マップテストです。
他意はございません。
画像は最初に3枚読み込みますが、もし表示されなかったらリロードしてください
LOADで画像はめ込めますけどね・・・
@narutohyper
/**
* Copyright narutohyper ( http://wonderfl.net/user/narutohyper )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/aKAA
*/
package {
/**
* Alternativa3D 環境マップのテスト
* 画面ドラッグで回転します、
*
* Alternativa3D platformのフォーラムで公開されていた、環境マップマテリアルの習作です。
* あくまでAlternativa3Dの環境マップテストです。
* 他意はございません。
*
* 画像は最初に3枚読み込みますが、もし表示されなかったらリロードしてください
*
* LOADで画像はめ込めますけどね・・・
*
* @narutohyper
*/
import alternativ5.engine3d.materials.FillMaterial;
import alternativ5.engine3d.materials.TextureMaterial;
import alternativ5.engine3d.core.Object3D;
import alternativ5.engine3d.core.Mesh;
import alternativ5.engine3d.core.Vertex
import alternativ5.engine3d.core.Surface
import alternativ5.engine3d.events.MouseEvent3D
import alternativ5.engine3d.loaders.*;
import alternativ5.types.Point3D;
import alternativ5.types.Texture;
import alternativ5.utils.*
import flash.display.*;
import flash.net.URLRequest;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.system.LoaderContext;
import flash.geom.Point;
import flash.geom.Matrix;
import flash.system.Security;
import flash.text.*;
import org.libspark.thread.EnterFrameThreadExecutor;
import org.libspark.thread.Thread;
[SWF(width = 465, height = 465, frameRate = 60,backgroundColor=0x000000)]
public class SimpleDemo extends Sprite {
public static const CROSSDOMAIN:String = "http://marubayashi.net/crossdomain.xml";
public var mc1:MovieClip;
public var mc2:MovieClip;
private var bmd1:BitmapData;
private var bmd2:BitmapData;
private var bmd3:BitmapData;
private var mcm1:TextureMaterial
private var mcm2:TextureMaterial
private var mcm3:TextureEnvironmentMaterial
private var newMesh:Mesh;
public function SimpleDemo():void {
var dbg:TextField=new TextField()
dbg.autoSize=TextFieldAutoSize.LEFT
dbg.selectable=false;
dbg.mouseEnabled=false;
var format:TextFormat=new TextFormat();
format.color=0x666666
format.size=12;
format.font='_ゴシック';
dbg.defaultTextFormat=format
dbg.x=100;
addChild(dbg)
var img1:Loader=new Loader();
var img2:Loader=new Loader();
var img3:Loader=new Loader();
Security.loadPolicyFile(CROSSDOMAIN);
var context:LoaderContext = new LoaderContext(true);
img1.load(new URLRequest('http://marubayashi.net/archive/sample/images/environment/a.jpg'), context);
img1.contentLoaderInfo.addEventListener(Event.COMPLETE, img1Complete);
function img1Complete (e:Event):void {
img1.contentLoaderInfo.removeEventListener(Event.COMPLETE, img1Complete);
bmd1=new BitmapData(800,800,false,0x000000)
bmd1.perlinNoise(40, 40, 1, 1, true, true, 8, true, null);
bmd1.draw(img1.content,new Matrix(1,0,0,1,300,300),null,BlendMode.SCREEN)
img2.load(new URLRequest('http://marubayashi.net/archive/sample/images/environment/b.jpg'), context);
img2.contentLoaderInfo.addEventListener(Event.COMPLETE, img2Complete);
}
function img2Complete (e:Event):void {
img2.contentLoaderInfo.removeEventListener(Event.COMPLETE, img2Complete);
bmd2=new BitmapData(200,200,false,0)
bmd2.draw(img2.content)
img3.load(new URLRequest('http://marubayashi.net/archive/sample/images/environment/c.jpg'), context);
img3.contentLoaderInfo.addEventListener(Event.COMPLETE, img3Complete);
}
function img3Complete (e:Event):void {
img3.contentLoaderInfo.removeEventListener(Event.COMPLETE, img3Complete);
bmd3=new BitmapData(200,200,false,0)
bmd3.draw(img3.content)
}
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame(e:Event):void {
loadCheck()
}
function loadCheck():void {
if (bmd1,bmd2,bmd3) {
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
removeChild(dbg)
init()
} else {
dbg.text='now loading ';
dbg.appendText((img1.contentLoaderInfo.bytesTotal>1000)?Math.round(img1.contentLoaderInfo.bytesLoaded/img1.contentLoaderInfo.bytesTotal*100)+'% ':'-?-');
dbg.appendText((img2.contentLoaderInfo.bytesTotal>1000)?Math.round(img2.contentLoaderInfo.bytesLoaded/img2.contentLoaderInfo.bytesTotal*100)+'% ':'-?-');
dbg.appendText((img3.contentLoaderInfo.bytesTotal>1000)?Math.round(img3.contentLoaderInfo.bytesLoaded/img3.contentLoaderInfo.bytesTotal*100)+'% ':'-?-');
}
}
}
private function init():void {
// テンプレートを作成します
var template:BasicTemplate = new BasicTemplate();
addChild(template);
template.camera.coords=new Point3D(0,0,-1000)
// マテリアルを作成します
var material1:FillMaterial=new FillMaterial(0xEEEEEE,1,BlendMode.NORMAL,1,0x0000000);
var material2:FillMaterial=new FillMaterial(0x666666,1,BlendMode.NORMAL,1,0x0000000);
mcm1=new TextureMaterial(new Texture(bmd1),1,false,true)
mcm2=new TextureMaterial(new Texture(bmd2),1,false,true)
mcm3=new TextureEnvironmentMaterial(new Texture(bmd3), new Texture(bmd1),0.2,1.0,true,true)
newMesh=new Mesh();
newMesh.createVertex( 290.00, 375.00, -25.00, 0);
newMesh.createVertex( 270.00, 384.00, -25.00, 1);
newMesh.createVertex(-270.00, 384.00, -25.00, 2);
newMesh.createVertex(-290.00, 375.00, -25.00, 3);
newMesh.createVertex(-300.00, 354.00, -25.00, 4);
newMesh.createVertex(-300.00, -354.00, -25.00, 5);
newMesh.createVertex(-290.00, -375.00, -25.00, 6);
newMesh.createVertex(-270.00, -384.00, -25.00, 7);
newMesh.createVertex( 270.00, -384.00, -25.00, 8);
newMesh.createVertex( 290.00, -375.00, -25.00, 9);
newMesh.createVertex( 300.00, -354.00, -25.00,10);
newMesh.createVertex( 300.00, 354.00, -25.00,11);
newMesh.createVertex( 270.00, 354.00, -25.00,12);
newMesh.createVertex(-270.00, 354.00, -25.00,13);
newMesh.createVertex(-270.00, -354.00, -25.00,14);
newMesh.createVertex( 270.00, -354.00, -25.00,15);
newMesh.createVertex( 290.00, 375.00, 5.00,16);
newMesh.createVertex( 270.00, 384.00, 5.00,17);
newMesh.createVertex(-270.00, 384.00, 5.00,18);
newMesh.createVertex(-290.00, 375.00, 5.00,19);
newMesh.createVertex(-300.00, 354.00, 5.00,20);
newMesh.createVertex(-300.00, -354.00, 5.00,21);
newMesh.createVertex(-290.00, -375.00, 5.00,22);
newMesh.createVertex(-270.00, -384.00, 5.00,23);
newMesh.createVertex( 270.00, -384.00, 5.00,24);
newMesh.createVertex( 290.00, -375.00, 5.00,25);
newMesh.createVertex( 300.00, -354.00, 5.00,26);
newMesh.createVertex( 300.00, 354.00, 5.00,27);
newMesh.createVertex( 270.00, 354.00, 25.00,28);
newMesh.createVertex(-270.00, 354.00, 25.00,29);
newMesh.createVertex(-270.00, -354.00, 25.00,30);
newMesh.createVertex( 270.00, -354.00, 25.00,31);
newMesh.createVertex( 191.00, 260.00, 59.50,32);
newMesh.createVertex(-191.00, 260.00, 59.50,33);
newMesh.createVertex(-191.00, -260.00, 59.50,34);
newMesh.createVertex( 191.00, -260.00, 59.50,35);
newMesh.createVertex( 93.00, 140.00, 73.99,36);
newMesh.createVertex( -93.00, 140.00, 73.99,37);
newMesh.createVertex( -93.00, -140.00, 73.99,38);
newMesh.createVertex( 93.00, -140.00, 73.99,39);
var textureW:Number=600;
var textureH:Number=768;
var facesArray:Array=[]
//正面
facesArray=[];
setFaceAndUv([ 1, 0, 3, 2],textureW,textureH,'front_0','xy',true);
setFaceAndUv([ 0,11, 4, 3],textureW,textureH,'front_1','xy',true);
setFaceAndUv([11,10, 5, 4],textureW,textureH,'front_2','xy',true);
setFaceAndUv([10, 9, 6, 5],textureW,textureH,'front_3','xy',true);
setFaceAndUv([ 9, 8, 7, 6],textureW,textureH,'front_4','xy',true);
newMesh.createSurface(facesArray,'front')
//裏
facesArray=[];
setFaceAndUv([37,38,39,36],textureW,textureH,'back_0');
setFaceAndUv([33,37,36,32],textureW,textureH,'back_1');
setFaceAndUv([36,39,35,32],textureW,textureH,'back_2');
setFaceAndUv([38,34,35,39],textureW,textureH,'back_3');
setFaceAndUv([33,34,38,37],textureW,textureH,'back_4');
setFaceAndUv([29,33,32,28],textureW,textureH,'back_5');
setFaceAndUv([32,35,31,28],textureW,textureH,'back_6');
setFaceAndUv([34,30,31,35],textureW,textureH,'back_7');
setFaceAndUv([29,30,34,33],textureW,textureH,'back_8');
setFaceAndUv([18,29,28,17],textureW,textureH,'back_9');
setFaceAndUv([28,31,26,27],textureW,textureH,'back_10');
setFaceAndUv([30,23,24,31],textureW,textureH,'back_11');
setFaceAndUv([20,21,30,29],textureW,textureH,'back_12');
setFaceAndUv([16,17,28],textureW,textureH,'back_13');
setFaceAndUv([16,28,27],textureW,textureH,'back_14');
setFaceAndUv([18,19,29],textureW,textureH,'back_15');
setFaceAndUv([19,20,29],textureW,textureH,'back_16');
setFaceAndUv([30,21,22],textureW,textureH,'back_17');
setFaceAndUv([30,22,23],textureW,textureH,'back_18');
setFaceAndUv([31,24,25],textureW,textureH,'back_19');
setFaceAndUv([31,25,26],textureW,textureH,'back_20');
newMesh.createSurface(facesArray,'back')
//Side
facesArray=[];
setFaceAndUv([0,1,17,16],textureW,textureH,'side_0','xz');
setFaceAndUv([1,2,18,17],textureW,textureH,'side_1','xz');
setFaceAndUv([2,3,19,18],textureW,textureH,'side_2','xz');
setFaceAndUv([3,4,20,19],textureW,textureH,'side_3','yz');
setFaceAndUv([4,5,21,20],textureW,textureH,'side_4','yz');
setFaceAndUv([5,6,22,21],textureW,textureH,'side_5','yz');
setFaceAndUv([6,7,23,22],textureW,textureH,'side_6','yz');
setFaceAndUv([7,8,24,23],textureW,textureH,'side_7','yz');
setFaceAndUv([8,9,25,24],textureW,textureH,'side_8','yz');
setFaceAndUv([9,10,26,25],textureW,textureH,'side_9','yz');
setFaceAndUv([26,10,11,27],textureW,textureH,'side_10','yz');
setFaceAndUv([27,11,0,16],textureW,textureH,'side_11','yz');
newMesh.createSurface(facesArray,'side')
function setFaceAndUv(v:Array,w:Number,h:Number,id:Object,mode:String='xy',reverse:Boolean=false):void {
facesArray.push(id)
newMesh.createFace(v,id);
var pt:Array=[];
for (var i:uint=0;i<v.length;i++) {
if (mode=='xz') {
pt.push(new Point((newMesh.vertices[v[i]].x+w/2)/w,(newMesh.vertices[v[i]].z+h/2)/h))
} else if (mode=='yz') {
pt.push(new Point((newMesh.vertices[v[i]].y+w/2)/w,(newMesh.vertices[v[i]].z+h/2)/h))
} else {
pt.push(new Point((newMesh.vertices[v[i]].x+w/2)/w,(newMesh.vertices[v[i]].y+h/2)/h))
}
}
if (reverse) {
newMesh.setUVsToFace(pt[3],pt[2],pt[1],id)
} else {
newMesh.setUVsToFace(pt[0],pt[1],pt[2],id)
}
}
newMesh.setMaterialToSurface(mcm3,'front');
newMesh.setMaterialToSurface(mcm2,'back');
newMesh.setMaterialToSurface(new FillMaterial(0xE0E0E0),'side');
newMesh.rotationY = 180 * Math.PI / 180;
newMesh.rotationZ = 180 * Math.PI / 180;
template.scene.root.addChild(newMesh);
var me:Sprite=this;
var dragFlag:Boolean=false
var mouseSX:Number;
var mouseSY:Number;
var nowRotationX:Number;
var nowRotationY:Number;
me.stage.addEventListener(MouseEvent.MOUSE_DOWN,onDown)
function onDown(e:MouseEvent):void {
me.stage.removeEventListener(MouseEvent.MOUSE_DOWN,onDown);
me.stage.addEventListener(MouseEvent.MOUSE_UP,onUp);
mouseSX=me.mouseX
mouseSY=me.mouseY
nowRotationX=newMesh.rotationX
nowRotationY=newMesh.rotationY
dragFlag=true
}
function onUp(e:MouseEvent):void {
me.stage.addEventListener(MouseEvent.MOUSE_DOWN,onDown);
me.stage.removeEventListener(MouseEvent.MOUSE_UP,onUp);
dragFlag=false
}
Thread.initialize(new EnterFrameThreadExecutor());
new MainThread(this).start();
template.onPreRender = function():void {
if (dragFlag) {
newMesh.rotationY=nowRotationY+(mouseSX-mouseX)/-2 * Math.PI / 180;
newMesh.rotationX=nowRotationX+(mouseSY-mouseY)/2 * Math.PI / 180;
}
}
}
public function drawImage(bmd:BitmapData):void {
bmd3.draw(bmd)
mcm3=new TextureEnvironmentMaterial(new Texture(bmd3), new Texture(bmd1),0.2,1.0,true,true)
newMesh.setMaterialToSurface(mcm3,'front');
}
}
}
import org.libspark.thread.Thread;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.SimpleButton;
import flash.utils.ByteArray;
import flash.net.FileReference;
import flash.net.FileReferenceList;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.display.*;
import flash.text.*;
import flash.system.Security;
class MainThread extends Thread {
public static const CROSSDOMAIN:String = "http://assets.wonderfl.net/crossdomain.xml";
private var _base:SimpleDemo;
private var _loadButton:Button;
private var _saveButton:Button;
private var _original:Loader;
private var _guide:Guide;
private var bmd:BitmapData
public function MainThread(base:SimpleDemo) {
this._base = base;
this._loadButton = this._base.addChild(new Button('LOAD', 60)) as Button;
this._loadButton.x = this._loadButton.y = 1;
this._saveButton = this._base.addChild(new Button('SAVE', 60)) as Button;
this._saveButton.x = 1;
this._saveButton.y = this._loadButton.height + 2;
this._guide = this._base.addChild(new Guide()) as Guide;
this._guide.x = this._guide.y = (465 - 360) >> 1;
this.bmd=new BitmapData(200,160,false,0x308CCB)
}
protected override function run():void {
this._event();
}
private function _event():void {
event(this._loadButton, MouseEvent.CLICK, this._loadImage);
event(this._saveButton, MouseEvent.CLICK, this._saveImage);
Security.loadPolicyFile(CROSSDOMAIN);
}
// load image
private function _loadImage(e:MouseEvent):void {
trace(Button(e.target).label)
var file:FileReference = new FileReference();
event(file, Event.SELECT, this._loadFileSelected);
event(file, Event.CANCEL, this._loadFileCancel);
file.browse();
}
private function _loadFileSelected(e:Event):void {
var file:FileReference = FileReference(e.target);
event(file, Event.COMPLETE, this._fileLoaded);
file.load();
}
private function _fileLoaded(e:Event):void {
if (this._original) {
//this._original.parent.removeChild(this._original);
this._original.unload();
}
this._original = new Loader();
this._original.loadBytes(FileReference(e.target).data);
event(this._original.contentLoaderInfo, Event.COMPLETE, this._imageLoaded);
}
private function _loadFileCancel(e:Event):void {
this._event();
}
private function _imageLoaded(e:Event):void {
var a:Number = 159 / this._original.width;
var b:Number = 164 / this._original.height;
var mtr:Matrix=new Matrix(a,0,0,b,21,17)
this.bmd=new BitmapData(200,200,true,0x00000000)
this.bmd.draw(this._original.content,mtr)
this._base.drawImage(bmd)
this._event();
}
// save image
private function _saveImage(e:Event):void {
var raw:BitmapData = new BitmapData(360, 360, true, 0x0);
this._guide.visible = false;
raw.draw(this._base, new Matrix(1, 0, 0, 1, -this._guide.x, -this._guide.y), null, null, null, true);
this._guide.visible = true;
var png:ByteArray = PNGEnc.encode(raw);
raw.dispose();
var file:FileReference = new FileReference();
event(file, Event.SELECT, this._saveFileSelected);
event(file, Event.CANCEL, this._saveFileSelected);
file.save(png, 'noflash.png');
}
private function _saveFileSelected(e:Event):void {
this._event();
}
}
class Guide extends Shape {
public function Guide() {
var g:Graphics = this.graphics;
g.lineStyle(1, 0xFF0000, 0.3, true);
g.drawRect(0, 0, 360, 360);
}
}
class Button extends SimpleButton {
public var label:String
public function Button(_label:String, width:int = 0):void {
label=_label
var up:Sprite = _buildImage(label, 0x0, width);
var over:Sprite = _buildImage(label, 0x333333, width);
var down:Sprite = _buildImage(label, 0x333333, width);
down.y = 1;
super(up, over, down, up);
}
private static function _buildImage(label:String, color:int, width:int = 0):Sprite {
var text:TextField = new TextField();
text.defaultTextFormat = new TextFormat('Verdana', 10, 0xffffff, true, null, null, null, null, TextFormatAlign.CENTER);
text.autoSize = TextFieldAutoSize.LEFT
text.selectable = false;
text.text = label;
text.x = (width - text.width) >> 1;
text.y = 5;
var base:Shape = new Shape();
var g:Graphics = base.graphics;
g.beginFill(color);
g.drawRect(0, 0, width, text.height + 10);
g.endFill();
var sp:Sprite = new Sprite();
sp.addChild(base);
sp.addChild(text);
return sp;
}
}
import alternativ5.engine3d.controllers.CameraController;
import alternativ5.engine3d.core.Camera3D;
import alternativ5.engine3d.core.Object3D;
import alternativ5.engine3d.core.Scene3D;
import alternativ5.engine3d.display.View;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
/**
* BasicTemplate for Alternativa3D
* Alternativa3Dを扱いやすくするためのテンプレートです
* @author Yasu
*/
class BasicTemplate extends Sprite{
/**
* シーンインスタンスです。
*/
public var scene:Scene3D;
/**
* ビューインスタンスです。
*/
public var view:View;
/**
* カメラインスタンスです。
*/
public var camera:Camera3D;
/**
* カメラコントローラーです。
*/
public var cameraContoller:CameraController;
private var _viewWidth:int;
private var _viewHeight:int;
private var _scaleToStage:Boolean;
/**
* 新しい BasicTemplate インスタンスを作成します。
* @param viewWidth
* @param viewHeight
* @param scaleToStage
*/
public function BasicTemplate(viewWidth:int=640, viewHeight:int=480, scaleToStage:Boolean = true) {
_viewWidth = viewWidth;
_viewHeight = viewHeight;
_scaleToStage = scaleToStage;
// Creating scene
scene = new Scene3D();
scene.splitAnalysis = false; // not analysis for performance
scene.root = new Object3D();
// Adding camera
camera = new Camera3D();
camera.z = -1000;
scene.root.addChild(camera);
// camera contoller
cameraContoller = new CameraController(this);
cameraContoller.camera = camera;
// set view
view = new View();
view.camera = camera;
addChild(view);
// stage
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
/**
* 初期化されたときに実行されるイベントです。
* 初期化時に実行したい処理をオーバーライドして記述します。
*/
protected function atInit():void {}
/**
* 初期化されたときに実行されるイベントです。
* 初期化時に実行したい処理を記述します。
*/
private var _onInit:Function = function():void { };
public function get onInit():Function { return _onInit; }
public function set onInit(value:Function):void {
_onInit = value;
}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング前に実行したい処理をオーバーライドして記述します。
*/
protected function atPreRender():void {}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング前に実行したい処理を記述します。
*/
private var _onPreRender:Function = function():void{};
public function get onPreRender():Function { return _onPreRender; }
public function set onPreRender(value:Function):void {
_onPreRender = value;
}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング後に実行したい処理をオーバーライドして記述します。
*/
protected function atPostRender():void {
}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング後に実行したい処理を記述します。
*/
protected var _onPostRender:Function = function():void{};
public function get onPostRender():Function { return _onPostRender; }
public function set onPostRender(value:Function):void {
_onPostRender = value;
}
/**
* レンダリングを開始します。
*/
public function startRendering():void {
addEventListener(Event.ENTER_FRAME, onRenderTick);
}
/**
* レンダリングを停止します。
*/
public function stopRendering():void {
removeEventListener(Event.ENTER_FRAME, onRenderTick);
}
/**
* シングルレンダリング(レンダリングを一回だけ)を実行します。
*/
public function singleRender():void {
onRenderTick();
}
/**
* @private
*/
private function init(e:Event = null):void {
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.HIGH;
// resize
stage.addEventListener(Event.RESIZE, onResize);
onResize(null);
// render
startRendering();
atInit();
_onInit();
}
/**
* @private
*/
private function onRenderTick(e:Event = null):void {
atPostRender();
_onPostRender();
scene.calculate();
atPreRender();
_onPreRender();
}
/**
* @private
*/
private function onResize(event:Event = null):void {
if (_scaleToStage) {
view.width = stage.stageWidth;
view.height = stage.stageHeight;
}else {
view.width = _viewWidth;
view.height = _viewHeight;
}
}
}
import alternativ5.engine3d.alternativa3d;
import alternativ5.engine3d.core.Camera3D;
import alternativ5.engine3d.core.PolyPrimitive;
import alternativ5.engine3d.display.Skin;
import alternativ5.engine3d.materials.DrawPoint;
import alternativ5.engine3d.materials.Material;
import alternativ5.engine3d.materials.TextureMaterial;
import alternativ5.engine3d.materials.TextureMaterialPrecision;
import alternativ5.types.Matrix3D;
import alternativ5.types.Point3D;
import alternativ5.types.Texture;
import alternativ5.types.alternativatypes;
import alternativ5.utils.MathUtils;
import flash.display.BlendMode;
import flash.display.Graphics;
import flash.display.Shape;
import flash.geom.Matrix;
use namespace alternativatypes;
use namespace alternativa3d;
class TextureEnvironmentMaterial extends TextureMaterial {
private static const reflectionMatrix:Matrix = new Matrix();
private static var shapes:Array = new Array();
private var _reflection:Texture;
private var _reflectionBlendMode:String;
private var _reflectiveness:Number;
private var gfx:Graphics;
public function TextureEnvironmentMaterial(texture:Texture = null, reflection:Texture = null, reflectiveness:Number = 1.0, alpha:Number = 1.0, repeat:Boolean = false, smooth:Boolean = false, blendMode:String = BlendMode.NORMAL, precision:Number = TextureMaterialPrecision.MEDIUM, reflectionBlendMode:String = BlendMode.NORMAL) {
super(texture, alpha, repeat, smooth, blendMode, -1, 0, precision);
_reflection = reflection;
_reflectiveness = reflectiveness;
_reflectionBlendMode = reflectionBlendMode;
}
override alternativa3d function canDraw(primitive:PolyPrimitive):Boolean {
return _reflection != null || _texture != null;
}
override alternativa3d function clear(skin:Skin):void {
skin.gfx.clear();
var count:int = skin.numChildren;
for (var i:int = 0; i < count; i++) {
var shape:Shape = skin.removeChildAt(0) as Shape;
shape.graphics.clear();
shapes.push(shape);
}
}
/**
* @private
* @inheritDoc
*/
override alternativa3d function draw(camera:Camera3D, skin:Skin, length:uint, points:Array):void {
if (_reflectiveness < 1) {
super.draw(camera, skin, length, points);
}
if (_reflectiveness > 0) {
var gfx:Graphics;
if (_reflectiveness < 1) {
var shape:Shape = shapes.pop();
if (shape == null) {
shape = new Shape();
}
skin.addChild(shape);
gfx = shape.graphics;
shape.alpha = _reflectiveness;
shape.blendMode = _reflectionBlendMode;
} else {
skin.alpha = _reflectiveness;
skin.blendMode = _blendMode;
gfx = skin.gfx;
}
var cameraMatrix:Matrix3D = camera.cameraMatrix;
var normal:Point3D = skin.primitive.face.globalNormal;
var normalInCamX:Number = normal.x*cameraMatrix.a + normal.y*cameraMatrix.b + normal.z*cameraMatrix.c;
var normalInCamY:Number = normal.x*cameraMatrix.e + normal.y*cameraMatrix.f + normal.z*cameraMatrix.g;
var normalInCamZ:Number = normal.x*cameraMatrix.i + normal.y*cameraMatrix.j + normal.z*cameraMatrix.k;
var focalLength:Number = camera.focalLength;
var apoint:DrawPoint = points[0];
var bpoint:DrawPoint = points[1];
var cpoint:DrawPoint = points[2];
var ax:Number = apoint.x*focalLength/apoint.z;
var ay:Number = apoint.y*focalLength/apoint.z;
var bx:Number = bpoint.x*focalLength/bpoint.z;
var by:Number = bpoint.y*focalLength/bpoint.z;
var cx:Number;
var cy:Number;
var vx:Number;
var vy:Number;
var vz:Number;
var rx:Number;
var ry:Number;
var rz:Number;
var nx:Number;
var ny:Number;
var nz:Number;
var dot:Number;
var len:Number;
var aN:Boolean;
var bN:Boolean;
var cN:Boolean;
vx = apoint.x;
vy = apoint.y;
vz = apoint.z;
dot = vx*normalInCamX + vy*normalInCamY + vz*normalInCamZ;
rx = vx - 2*dot*normalInCamX;
ry = vy - 2*dot*normalInCamY;
rz = vz - 2*dot*normalInCamZ;
len = Math.sqrt(rx*rx + ry*ry + rz*rz);
nx = rx*0.5;
ny = ry*0.5;
nz = (rz - len)*0.5;
len = Math.sqrt(nx*nx + ny*ny + nz*nz);
nx /= len;
ny /= len;
aN = (nz > 0);
var au:Number = 0.5 + nx*0.5;
var av:Number = 0.5 - ny*0.5;
vx = bpoint.x;
vy = bpoint.y;
vz = bpoint.z;
dot = vx*normalInCamX + vy*normalInCamY + vz*normalInCamZ;
rx = vx - 2*dot*normalInCamX;
ry = vy - 2*dot*normalInCamY;
rz = vz - 2*dot*normalInCamZ;
len = Math.sqrt(rx*rx + ry*ry + rz*rz);
nx = rx*0.5;
ny = ry*0.5;
nz = (rz - len)*0.5;
len = Math.sqrt(nx*nx + ny*ny + nz*nz);
nx /= len;
ny /= len;
bN = (nz > 0);
var bu:Number = 0.5 + nx*0.5;
var bv:Number = 0.5 - ny*0.5;
for (var i:int = 1; i < length; i++) {
cpoint = points[i];
cx = cpoint.x*focalLength/cpoint.z;
cy = cpoint.y*focalLength/cpoint.z;
vx = cpoint.x;
vy = cpoint.y;
vz = cpoint.z;
dot = vx*normalInCamX + vy*normalInCamY + vz*normalInCamZ;
rx = vx - 2*dot*normalInCamX;
ry = vy - 2*dot*normalInCamY;
rz = vz - 2*dot*normalInCamZ;
len = Math.sqrt(rx*rx + ry*ry + rz*rz);
nx = rx*0.5;
ny = ry*0.5;
nz = (rz - len)*0.5;
len = Math.sqrt(nx*nx + ny*ny + nz*nz);
nx /= len;
ny /= len;
cN = (nz > 0);
var cu:Number = 0.5 + nx*0.5;
var cv:Number = 0.5 - ny*0.5;
var abx:Number = bx - ax;
var aby:Number = by - ay;
var acx:Number = cx - ax;
var acy:Number = cy - ay;
var abu:Number = bu - au;
var abv:Number = bv - av;
var acu:Number = cu - au;
var acv:Number = cv - av;
var det:Number = abu*acv - abv*acu;
var w:Number = _reflection._width;
var h:Number = _reflection._height;
reflectionMatrix.a = (acv*abx - abv*acx)/det;
reflectionMatrix.b = (acv*aby - abv*acy)/det;
reflectionMatrix.c = (acu*abx - abu*acx)/det;
reflectionMatrix.d = (acu*aby - abu*acy)/det;
reflectionMatrix.tx = (av - 1)*reflectionMatrix.c - au*reflectionMatrix.a + ax;
reflectionMatrix.ty = (av - 1)*reflectionMatrix.d - au*reflectionMatrix.b + ay;
reflectionMatrix.a /= w;
reflectionMatrix.b /= w;
reflectionMatrix.c /= h;
reflectionMatrix.d /= h;
gfx.beginBitmapFill(_reflection._bitmapData, reflectionMatrix, true, true);
gfx.moveTo(ax, ay);
gfx.lineTo(bx, by);
gfx.lineTo(cx, cy);
bx = cx;
by = cy;
bu = cu;
bv = cv;
}
}
}
private function lookAtMatrix(dx:Number, dy:Number, dz:Number):Matrix3D {
return Matrix3D.rotationMatrix(Math.atan2(dz, Math.sqrt(dx * dx + dy * dy) - MathUtils.DEG90), 0, -Math.atan2(dx, dy));
}
/**
* @private
*/
private function drawTriangle(ax:Number, ay:Number, au:Number, av:Number, bx:Number, by:Number, bu:Number, bv:Number, cx:Number, cy:Number, cu:Number, cv:Number):void {
var abx:Number = bx - ax;
var aby:Number = by - ay;
var acx:Number = cx - ax;
var acy:Number = cy - ay;
var abu:Number = bu - au;
var abv:Number = bv - av;
var acu:Number = cu - au;
var acv:Number = cv - av;
var det:Number = abu*acv - abv*acu;
var w:Number = _reflection._width;
var h:Number = _reflection._height;
reflectionMatrix.a = (acv*abx - abv*acx)/det;
reflectionMatrix.b = (acv*aby - abv*acy)/det;
reflectionMatrix.c = (acu*abx - abu*acx)/det;
reflectionMatrix.d = (acu*aby - abu*acy)/det;
reflectionMatrix.tx = (av - 1)*reflectionMatrix.c - au*reflectionMatrix.a + ax;
reflectionMatrix.ty = (av - 1)*reflectionMatrix.d - au*reflectionMatrix.b + ay;
reflectionMatrix.a /= w;
reflectionMatrix.b /= w;
reflectionMatrix.c /= h;
reflectionMatrix.d /= h;
gfx.beginBitmapFill(_reflection._bitmapData, reflectionMatrix, true, true);
gfx.moveTo(ax, ay);
gfx.lineTo(bx, by);
gfx.lineTo(cx, cy);
}
/**
* @inheritDoc
*/
override public function clone():Material {
var res:TextureEnvironmentMaterial = new TextureEnvironmentMaterial(_texture, _reflection, _reflectiveness, _alpha, _repeat, _smooth, _blendMode, _precision);
return res;
}
}
// http://www.5etdemi.com/blog/archives/2006/12/as3-png-encoder-faster-better/
class PNGEnc {
public static function encode(img:BitmapData, type:uint = 0):ByteArray {
// Create output byte array
var png:ByteArray = new ByteArray();
// Write PNG signature
png.writeUnsignedInt(0x89504e47);
png.writeUnsignedInt(0x0D0A1A0A);
// Build IHDR chunk
var IHDR:ByteArray = new ByteArray();
IHDR.writeInt(img.width);
IHDR.writeInt(img.height);
if(img.transparent || type == 0)
{
IHDR.writeUnsignedInt(0x08060000); // 32bit RGBA
}
else
{
IHDR.writeUnsignedInt(0x08020000); //24bit RGB
}
IHDR.writeByte(0);
writeChunk(png,0x49484452,IHDR);
// Build IDAT chunk
var IDAT:ByteArray= new ByteArray();
switch(type)
{
case 0:
writeRaw(img, IDAT);
break;
case 1:
writeSub(img, IDAT);
break;
}
IDAT.compress();
writeChunk(png,0x49444154,IDAT);
// Build IEND chunk
writeChunk(png,0x49454E44,null);
// return PNG
return png;
}
private static function writeRaw(img:BitmapData, IDAT:ByteArray):void
{
var h:int = img.height;
var w:int = img.width;
var transparent:Boolean = img.transparent;
for(var i:int=0;i < h;i++) {
// no filter
if ( !transparent ) {
var subImage:ByteArray = img.getPixels(
new Rectangle(0, i, w, 1));
//Here we overwrite the alpha value of the first pixel
//to be the filter 0 flag
subImage[0] = 0;
IDAT.writeBytes(subImage);
//And we add a byte at the end to wrap the alpha values
IDAT.writeByte(0xff);
} else {
IDAT.writeByte(0);
var p:uint;
for(var j:int=0;j < w;j++) {
p = img.getPixel32(j,i);
IDAT.writeUnsignedInt(
uint(((p&0xFFFFFF) << 8)|
(p>>>24)));
}
}
}
}
private static function writeSub(img:BitmapData, IDAT:ByteArray):void
{
var r1:uint;
var g1:uint;
var b1:uint;
var a1:uint;
var r2:uint;
var g2:uint;
var b2:uint;
var a2:uint;
var r3:uint;
var g3:uint;
var b3:uint;
var a3:uint;
var p:uint;
var h:int = img.height;
var w:int = img.width;
for(var i:int=0;i < h;i++) {
// no filter
IDAT.writeByte(1);
if ( !img.transparent ) {
r1 = 0;
g1 = 0;
b1 = 0;
a1 = 0xff;
for(var j:int=0;j < w;j++) {
p = img.getPixel(j,i);
r2 = p >> 16 & 0xff;
g2 = p >> 8 & 0xff;
b2 = p & 0xff;
r3 = (r2 - r1 + 256) & 0xff;
g3 = (g2 - g1 + 256) & 0xff;
b3 = (b2 - b1 + 256) & 0xff;
IDAT.writeByte(r3);
IDAT.writeByte(g3);
IDAT.writeByte(b3);
r1 = r2;
g1 = g2;
b1 = b2;
a1 = 0;
}
} else {
r1 = 0;
g1 = 0;
b1 = 0;
a1 = 0;
for(j=0;j < w;j++) {
p = img.getPixel32(j,i);
a2 = p >> 24 & 0xff;
r2 = p >> 16 & 0xff;
g2 = p >> 8 & 0xff;
b2 = p & 0xff;
r3 = (r2 - r1 + 256) & 0xff;
g3 = (g2 - g1 + 256) & 0xff;
b3 = (b2 - b1 + 256) & 0xff;
a3 = (a2 - a1 + 256) & 0xff;
IDAT.writeByte(r3);
IDAT.writeByte(g3);
IDAT.writeByte(b3);
IDAT.writeByte(a3);
r1 = r2;
g1 = g2;
b1 = b2;
a1 = a2;
}
}
}
}
private static var crcTable:Array;
private static var crcTableComputed:Boolean = false;
private static function writeChunk(png:ByteArray,
type:uint, data:ByteArray):void {
var c:uint;
if (!crcTableComputed) {
crcTableComputed = true;
crcTable = [];
for (var n:uint = 0; n < 256; n++) {
c = n;
for (var k:uint = 0; k < 8; k++) {
if (c & 1) {
c = uint(uint(0xedb88320) ^
uint(c >>> 1));
} else {
c = uint(c >>> 1);
}
}
crcTable[n] = c;
}
}
var len:uint = 0;
if (data != null) {
len = data.length;
}
png.writeUnsignedInt(len);
var p:uint = png.position;
png.writeUnsignedInt(type);
if ( data != null ) {
png.writeBytes(data);
}
var e:uint = png.position;
png.position = p;
c = 0xffffffff;
for (var i:int = 0; i < (e-p); i++) {
c = uint(crcTable[
(c ^ png.readUnsignedByte()) &
0xff] ^ (c >>> 8));
}
c = uint(c^uint(0xffffffff));
png.position = e;
png.writeUnsignedInt(c);
}
}