Heaven Condition Particles
Stage3DでBitmapData.draw()気分。
/**
* Copyright o8que ( http://wonderfl.net/user/o8que )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/juiw
*/
package {
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.display.Stage3D;
import flash.events.Event;
import flash.filters.BlurFilter;
import flash.filters.GlowFilter;
import flash.geom.Rectangle;
import flash.text.TextField;
import net.hires.debug.Stats;
/* import ore.orelib.commons.Key;
import ore.orelib.commons.Labeler;
*/
[SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "0x000000")]
public class Main extends Sprite {
private var _ore2D:Ore2D;
private var _particles:Vector.<Particle>;
private var _particlePool:Vector.<Particle>;
private var _numParticlesLabel:TextField;
public function Main() {
var stage3D:Stage3D = stage.stage3Ds[0];
stage3D.addEventListener(Event.CONTEXT3D_CREATE, init);
stage3D.requestContext3D();
}
private function init(event:Event):void {
event.currentTarget.removeEventListener(event.type, arguments.callee);
_ore2D = new Ore2D(stage, 0, 233, 233, createImage());
_ore2D.registerSprites(new Rectangle(0, 0, 32, 32), 1, 1);
_particles = new Vector.<Particle>();
_particlePool = new Vector.<Particle>();
addChild(_numParticlesLabel = new Labeler()
.align(Labeler.BOTTOM_RIGHT).filters([new GlowFilter(0x000000, 1, 4, 4)])
.fontColor(0xFFFFFF).pos(365, 0).size(100, 20).build("0")
);
addChild(new Stats());
Key.init(this);
addEventListener(Event.ENTER_FRAME, update);
}
private function createImage():BitmapData {
var result:BitmapData = new BitmapData(32, 32, true, 0x00FFFFFF);
var sp:Sprite = new Sprite();
var g:Graphics = sp.graphics;
g.beginFill(0xFFFFFF); g.moveTo(20, 12); g.lineTo(4, 16); g.lineTo(20, 20); g.curveTo(28, 16, 20, 12); g.endFill();
sp.filters = [new BlurFilter(2, 2)];
result.draw(sp);
return result;
}
private function update(event:Event):void {
if (Key.isDown(Key.MOUSE_LEFT)) { emitParticles(stage.mouseX, stage.mouseY); }
for (var i:int = _particles.length - 1; i >= 0; i--) {
var particle:Particle = _particles[i];
particle.update();
if ( -16 < particle.pos.x && particle.pos.x < 481 && -16 < particle.pos.y && particle.pos.y < 481) {
_ore2D.draw(0, particle.matrix, particle.colorTransform);
} else {
_particles.splice(i, 1);
_particlePool.push(particle);
}
}
_numParticlesLabel.text = _particles.length.toString();
}
private function emitParticles(x:Number, y:Number):void {
for (var i:int = 0; i < 360; i++) {
var particle:Particle = (_particlePool.length) ? _particlePool.pop() : new Particle();
var rad:Number = i * Math.PI / 180;
particle.init(x, y, 10 * Math.cos(rad), 10 * Math.sin(rad), rad);
_particles.push(particle);
}
}
}
}
//package {
import com.adobe.utils.AGALMiniAssembler;
import flash.display.BitmapData;
import flash.display.Stage;
import flash.display.Stage3D;
import flash.display3D.Context3D;
import flash.display3D.Context3DBlendFactor;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.display3D.textures.Texture;
import flash.display3D.VertexBuffer3D;
import flash.events.Event;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Matrix3D;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.ByteArray;
//public
class Ore2D {
private var _context3D:Context3D;
private var _screenHalfSize:Point;
private var _spriteSheet:BitmapData;
private var _spriteDataList:Vector.<Vector.<Number>>;
private var _vertexData:Vector.<Number>;
private var _vertexBuffer:VertexBuffer3D;
private var _indexData:Vector.<uint>;
private var _indexBuffer:IndexBuffer3D;
private var _vertexProgram:ByteArray;
private var _fragmentProgram:ByteArray;
private var _numBatches:int;
private var _vertexDataIndex:int;
public function Ore2D(stage:Stage, stage3DIndex:int, halfWidth:int, halfHeight:int, spriteSheet:BitmapData) {
var stage3D:Stage3D = stage.stage3Ds[stage3DIndex];
_context3D = stage3D.context3D;
_screenHalfSize = new Point(halfWidth, halfHeight);
_spriteSheet = spriteSheet;
_spriteDataList = new Vector.<Vector.<Number>>();
_vertexData = new Vector.<Number>(4 * 12 * 16380, true);
_indexData = new Vector.<uint>(6 * 16380, true);
for (var n:int = 0, i:int = 0, v:int = 0; n < 16380; n++, i += 6, v += 4) {
_indexData[i] = v;
_indexData[i + 1] = v + 1;
_indexData[i + 2] = v + 2;
_indexData[i + 3] = v + 3;
_indexData[i + 4] = v + 2;
_indexData[i + 5] = v + 1;
}
var assembler:AGALMiniAssembler = new AGALMiniAssembler();
_vertexProgram = assembler.assemble(Context3DProgramType.VERTEX, [
"m44 op, va0, vc0",
"mov v0, va1",
"mov v1, va2",
"mul v2, va3, vc4"
].join("\n"));
_fragmentProgram = assembler.assemble(Context3DProgramType.FRAGMENT, [
"tex ft0, v0, fs0<2d, clamp, linear, nomip>",
"mul ft0, ft0, v1",
"add oc, ft0, v2"
].join("\n"));
_numBatches = _vertexDataIndex = 0;
onContext3DCreated();
stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreated);
stage.addEventListener(Event.EXIT_FRAME, present);
}
private function onContext3DCreated(event:Event = null):void {
if (event) { _context3D = event.currentTarget.context3D; }
// screen
_context3D.configureBackBuffer(_screenHalfSize.x * 2, _screenHalfSize.y * 2, 0, false);
var screenMatrix:Matrix3D = new Matrix3D();
screenMatrix.appendScale(1 / _screenHalfSize.x, 1 / _screenHalfSize.y, 1);
screenMatrix.appendTranslation( -1, 1, 0);
_context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, screenMatrix, true);
// texture
var texture:Texture = _context3D.createTexture(_spriteSheet.width, _spriteSheet.height, Context3DTextureFormat.BGRA, false);
texture.uploadFromBitmapData(_spriteSheet);
_context3D.setTextureAt(0, texture);
// vertex
_vertexBuffer = _context3D.createVertexBuffer(4 * 16380, 12);
var colorOffsetFactor:Vector.<Number> = new <Number>[1 / 255, 1 / 255, 1 / 255, 1 / 255];
_context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 4, colorOffsetFactor);
// index
_indexBuffer = _context3D.createIndexBuffer(6 * 16380);
_indexBuffer.uploadFromVector(_indexData, 0, 6 * 16380);
// program
var program3D:Program3D = _context3D.createProgram();
program3D.upload(_vertexProgram, _fragmentProgram);
_context3D.setProgram(program3D);
// blend
_context3D.setBlendFactors(Context3DBlendFactor.ONE, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);
}
private function present(event:Event):void {
_vertexBuffer.uploadFromVector(_vertexData, 0, 65520);
_context3D.setVertexBufferAt(0, _vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_2); // position
_context3D.setVertexBufferAt(1, _vertexBuffer, 2, Context3DVertexBufferFormat.FLOAT_2); // uv
_context3D.setVertexBufferAt(2, _vertexBuffer, 4, Context3DVertexBufferFormat.FLOAT_4); // colorMultiplier
_context3D.setVertexBufferAt(3, _vertexBuffer, 8, Context3DVertexBufferFormat.FLOAT_4); // colorOffset
_context3D.clear();
_context3D.drawTriangles(_indexBuffer, 0, _numBatches << 1);
_context3D.present();
_numBatches = _vertexDataIndex = 0;
}
public function registerSprites(first:Rectangle, cols:int, rows:int):void {
for (var row:int = 0; row < rows; row++) {
for (var col:int = 0; col < cols; col++) {
var spriteData:Vector.<Number> = new Vector.<Number>(6, true);
spriteData[0] = first.width; // width
spriteData[1] = first.height; // height
var left:Number = first.x + first.width * col;
var top:Number = first.y + first.height * row;
spriteData[2] = (left + 0.5) / _spriteSheet.width; // uvLeft
spriteData[3] = (top + 0.5) / _spriteSheet.height; // uvTop
spriteData[4] = (left + first.width - 0.5) / _spriteSheet.width; // uvRight
spriteData[5] = (top + first.height - 0.5) / _spriteSheet.height; // uvBottom
_spriteDataList.push(spriteData);
}
}
}
public function draw(spriteIndex:int, matrix:Matrix, colorTransform:ColorTransform):void {
if (_numBatches >= 16380 || spriteIndex >= _spriteDataList.length) { return; }
var i:int = _vertexDataIndex;
var spriteData:Vector.<Number> = _spriteDataList[spriteIndex];
var width:Number = spriteData[0];
var height:Number = spriteData[1];
var aw:Number = matrix.a * width;
var bw:Number = matrix.b * width;
var ch:Number = matrix.c * height;
var dh:Number = matrix.d * height;
var tx:Number = matrix.tx;
var ty:Number = matrix.ty;
_vertexData[i] = tx;
_vertexData[i + 1] = -ty;
_vertexData[i + 12] = aw + tx;
_vertexData[i + 13] = -(bw + ty);
_vertexData[i + 24] = ch + tx;
_vertexData[i + 25] = -(dh + ty);
_vertexData[i + 36] = aw + ch + tx;
_vertexData[i + 37] = -(bw + dh + ty);
var uvLeft:Number = spriteData[2];
var uvTop:Number = spriteData[3];
var uvRight:Number = spriteData[4];
var uvBottom:Number = spriteData[5];
_vertexData[i + 2] = _vertexData[i + 26] = uvLeft;
_vertexData[i + 3] = _vertexData[i + 15] = uvTop;
_vertexData[i + 14] = _vertexData[i + 38] = uvRight;
_vertexData[i + 27] = _vertexData[i + 39] = uvBottom;
var rm:Number = colorTransform.redMultiplier;
var gm:Number = colorTransform.greenMultiplier;
var bm:Number = colorTransform.blueMultiplier;
var am:Number = colorTransform.alphaMultiplier;
var ro:Number = colorTransform.redOffset;
var go:Number = colorTransform.greenOffset;
var bo:Number = colorTransform.blueOffset;
var ao:Number = colorTransform.alphaOffset;
_vertexData[i + 4] = _vertexData[i + 16] = _vertexData[i + 28] = _vertexData[i + 40] = rm;
_vertexData[i + 5] = _vertexData[i + 17] = _vertexData[i + 29] = _vertexData[i + 41] = gm;
_vertexData[i + 6] = _vertexData[i + 18] = _vertexData[i + 30] = _vertexData[i + 42] = bm;
_vertexData[i + 7] = _vertexData[i + 19] = _vertexData[i + 31] = _vertexData[i + 43] = am;
_vertexData[i + 8] = _vertexData[i + 20] = _vertexData[i + 32] = _vertexData[i + 44] = ro;
_vertexData[i + 9] = _vertexData[i + 21] = _vertexData[i + 33] = _vertexData[i + 45] = go;
_vertexData[i + 10] = _vertexData[i + 22] = _vertexData[i + 34] = _vertexData[i + 46] = bo;
_vertexData[i + 11] = _vertexData[i + 23] = _vertexData[i + 35] = _vertexData[i + 47] = ao;
_numBatches++;
_vertexDataIndex += 48;
}
}
//}
//package {
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
//public
class Particle {
private var _position:Point;
private var _velocity:Point;
private var _angle:Number;
private var _matrix:Matrix;
private var _colorTransform:ColorTransform;
public function Particle() {
_position = new Point();
_velocity = new Point();
_angle = 0;
_matrix = new Matrix();
_colorTransform = new ColorTransform();
}
public function init(x:Number, y:Number, vx:Number, vy:Number, angle:Number):void {
_position.setTo(x, y);
_velocity.setTo(vx, vy);
_angle = angle;
_colorTransform.redMultiplier = (Math.random() < 0.5) ? 1 : 0.5;
_colorTransform.greenMultiplier = (Math.random() < 0.5) ? 1 : 0.5;
_colorTransform.blueMultiplier = (Math.random() < 0.5) ? 1 : 0.5;
}
public function update():void {
_position.offset(_velocity.x, _velocity.y);
_matrix.identity();
_matrix.translate( -16, -16);
_matrix.rotate(_angle);
_matrix.translate(_position.x, _position.y);
}
public function get pos():Point { return _position; }
public function get matrix():Matrix { return _matrix; }
public function get colorTransform():ColorTransform { return _colorTransform; }
}
//}
//package ore.orelib.commons {
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.ContextMenuEvent;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.ui.ContextMenu;
//public
class Key {
private static var _stage:Stage;
private static var _currentStates:Vector.<Boolean>;
private static var _previousStates:Vector.<Boolean>;
public static const MOUSE_LEFT:uint = 0;
public static const MOUSE_RIGHT:uint = 255;
public static function init(documentClass:Sprite):void {
_stage = documentClass.stage;
_currentStates = new Vector.<Boolean>(256, true);
_previousStates = new Vector.<Boolean>(256, true);
_stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
_stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
_stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
_stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
_stage.addEventListener(Event.EXIT_FRAME, update);
_stage.addEventListener(Event.DEACTIVATE, clear);
var contextMenu:ContextMenu = new ContextMenu();
contextMenu.hideBuiltInItems();
contextMenu.addEventListener(ContextMenuEvent.MENU_SELECT, clear);
documentClass.contextMenu = contextMenu;
}
private static function keyDownHandler(event:KeyboardEvent):void { _currentStates[event.keyCode] = true; }
private static function keyUpHandler(event:KeyboardEvent):void { _currentStates[event.keyCode] = false; }
private static function mouseDownHandler(event:MouseEvent):void { _currentStates[Key.MOUSE_LEFT] = true; }
private static function mouseUpHandler(event:MouseEvent):void { _currentStates[Key.MOUSE_LEFT] = false; }
private static function update(event:Event):void {
for (var i:int = 0; i < 256; i++) {
_previousStates[i] = _currentStates[i];
}
}
private static function clear(event:Event):void {
for (var i:int = 0; i < 256; i++) {
_currentStates[i] = false;
}
}
public static function isDown(keyCode:uint):Boolean { return _stage.focus == null && _currentStates[keyCode]; }
public static function pressed(keyCode:uint):Boolean { return Key.isDown(keyCode) && !_previousStates[keyCode]; }
}
//}
//package ore.orelib.commons {
import flash.geom.Point;
import flash.text.AntiAliasType;
import flash.text.GridFitType;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
//public
class Labeler {
private var _hAlign:String;
private var _autoSize:String;
private var _vAlign:String;
private var _background:Boolean;
private var _backgroundColor:uint;
private var _filters:Array;
private var _fontName:String;
private var _sharpness:Number;
private var _thickness:Number;
private var _fontColor:uint;
private var _fontSize:int;
private var _position:Point;
private var _selectable:Boolean;
private var _size:Point;
private var _wordWrap:Boolean;
public static const NONE:String = "none";
public static const TOP_LEFT:String = "top_left";
public static const MIDDLE_CENTER:String = "middle_center";
public static const BOTTOM_RIGHT:String = "bottom_right";
public function Labeler() {
_hAlign = TextFormatAlign.LEFT;
_autoSize = TextFieldAutoSize.NONE;
_vAlign = Labeler.TOP_LEFT;
_background = false;
_backgroundColor = 0xFFFFFF;
_filters = [];
_fontName = "_sans";
_sharpness = _thickness = 0;
_fontColor = 0x000000;
_fontSize = 12;
_position = new Point(0, 0);
_size = new Point(100, 100);
_selectable = _wordWrap = false;
}
public function align(value:String = Labeler.TOP_LEFT):Labeler {
switch(value) {
case Labeler.MIDDLE_CENTER: { _hAlign = TextFormatAlign.CENTER; break; }
case Labeler.BOTTOM_RIGHT: { _hAlign = TextFormatAlign.RIGHT; break; }
case Labeler.TOP_LEFT: default: { _hAlign = TextFormatAlign.LEFT; break; }
}
return this;
}
public function autoSize(horizontal:String = Labeler.NONE, vertical:String = Labeler.TOP_LEFT):Labeler {
switch(horizontal) {
case Labeler.TOP_LEFT: { _autoSize = TextFieldAutoSize.LEFT; break; }
case Labeler.MIDDLE_CENTER: { _autoSize = TextFieldAutoSize.CENTER; break; }
case Labeler.BOTTOM_RIGHT: { _autoSize = TextFieldAutoSize.RIGHT; break; }
case Labeler.NONE: default: { _autoSize = TextFieldAutoSize.NONE; break; }
}
_vAlign = vertical;
return this;
}
public function background(enabled:Boolean = true, color:uint = 0xFF0000):Labeler { _background = enabled; _backgroundColor = color; return this; }
public function filters(value:Array):Labeler { _filters = value; return this; }
public function font(name:String, sharpness:Number = 0, thickness:Number = 0):Labeler { _fontName = name; _sharpness = sharpness; _thickness = thickness; return this; }
public function fontColor(value:uint):Labeler { _fontColor = value; return this; }
public function fontSize(value:int):Labeler { _fontSize = value; return this; }
public function offset(x:Number, y:Number):Labeler { _position.offset(x, y); return this; }
public function pos(x:Number, y:Number):Labeler { _position.setTo(x, y); return this; }
public function selectable(enabled:Boolean = true):Labeler { _selectable = enabled; return this; }
public function size(width:Number, height:Number):Labeler { _size.setTo(width, height); return this; }
public function wordWrap(enabled:Boolean = true):Labeler { _wordWrap = enabled; return this; }
public function build(text:String):TextField {
var result:TextField = new TextField();
result.x = _position.x; result.width = _size.x; result.height = _size.y;
result.autoSize = _autoSize;
result.background = _background; result.backgroundColor = _backgroundColor;
result.filters = _filters;
result.mouseEnabled = result.selectable = _selectable;
result.wordWrap = _wordWrap;
result.defaultTextFormat = new TextFormat(_fontName, _fontSize, _fontColor, null, null, null, null, null, _hAlign);
if (_fontName != "_sans") {
result.embedFonts = true;
result.antiAliasType = AntiAliasType.ADVANCED;
result.gridFitType = (_hAlign == TextFormatAlign.LEFT) ? GridFitType.PIXEL : GridFitType.SUBPIXEL;
result.sharpness = _sharpness; result.thickness = _thickness;
}
result.text = text;
switch(_vAlign) {
case Labeler.MIDDLE_CENTER: { result.y = _position.y + (_size.y - result.height) / 2; break; }
case Labeler.BOTTOM_RIGHT: { result.y = _position.y + (_size.y - result.height); break; }
case Labeler.TOP_LEFT: default: { result.y = _position.y; break; }
}
return result;
}
}
//}