Stage3D Animation using setVector
Modified code from Lee Brimelow posted here : https://plus.google.com/110495278155587072613/posts/U8oXcET3TE9
Performance example of using Stage3D to draw a animation.
/**
* Copyright leichtgewicht ( http://wonderfl.net/user/leichtgewicht )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/7FdG
*/
/**
* Modified code from Lee Brimelow posted here : https://plus.google.com/110495278155587072613/posts/U8oXcET3TE9
*
* Performance example of using Stage3D to draw a animation.
*/
package {
import com.adobe.utils.Sprite3D;
import flash.display.Stage3D;
import flash.display.StageQuality;
import flash.display3D.Context3D;
import flash.display3D.Context3DBlendFactor;
import flash.display3D.Context3DCompareMode;
import flash.display3D.Context3DTriangleFace;
import flash.display3D.textures.Texture;
import flash.system.Capabilities;
import flash.utils.describeType;
import flash.display.LoaderInfo;
import flash.display.Bitmap;
import flash.system.LoaderContext;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.system.Security;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.display.Sprite;
import flash.geom.Rectangle;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.BitmapData;
import net.hires.debug.Stats;
[SWF(frameRate=60)]
public class Stage3DExample extends Sprite
{
// Holds all current blit sprites
private var animations:Vector.<SpriteSheet> = new Vector.<SpriteSheet>();
private var numAnimations:int = 0;
private var stage3D:Stage3D;
private var context3D:Context3D;
private var context:SpriteSheetContext;
public function Stage3DExample()
{
// THIS CODE CAN NOT BE COMPILED BY WONDERFL, I POSTED IT ANYWAYS
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.HIGH;
stage.frameRate = 60;
addEventListener(Event.ADDED_TO_STAGE, onAdded);
}
private function onAdded(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, onAdded);
stage3D = stage.stage3Ds[0];
if(stage3D) {
stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreate);
stage3D.requestContext3D("auto");
}
}
private function resizeStage(e:Event=null):void
{
if( context ) context.setSize(stage.stageWidth,stage.stageHeight);
}
private function onContext3DCreate(e:*=null):void
{
init();
// Remove existing frame handler. Note that a context
// loss can occur at any time which will force you
// to recreate all objects we create here.
// A context loss occurs for instance if you hit
// CTRL-ALT-DELETE on Windows.
// It takes a while before a new context is available
// hence removing the enterFrame handler is important!
removeEventListener(Event.ENTER_FRAME, loop);
stage.addEventListener(Event.RESIZE, resizeStage);
context3D = stage3D.context3D;
if ( context3D ) {
// disabling error checking will drastically improve performance
// so only enable this during developement
context3D.enableErrorChecking = true;
context3D.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA,Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA);
context3D.setCulling(Context3DTriangleFace.NONE);
context3D.setDepthTest(false, Context3DCompareMode.ALWAYS);
context = new SpriteSheetContext(context3D);
resizeStage();
addEventListener(Event.ENTER_FRAME, loop);
}
}
private function init():void
{
// You gotta track that shit
addChild(new Stats());
// Start with 50, good to compare
addAnimations(50);
// When you click the stage you get 10 more
stage.addEventListener(MouseEvent.CLICK, onClick);
}
protected function onClick(event:MouseEvent):void
{
// Create another 10 more
addAnimations(10);
}
protected function addAnimations(amount:int):void
{
for(var i:int=0; i<amount; ++i)
{
var s:SpriteSheet = new SpriteSheet(SnakeData.sheet);
s.x = Math.random() * stage.stageWidth * 2;
s.y = Math.random() * stage.stageHeight * 2;
animations.push(s);
}
numAnimations = animations.length;
}
protected function loop(event:Event):void
{
// Loop through snakes and render them
context3D.clear(1.0,1.0,1.0);
for ( var i:uint = 0; i < numAnimations; ++i ) {
var s: SpriteSheet = animations[i];
s.rotation -= 0.03490658503988659; // 2*Math.PI/180
s.nextFrame();
context.render(s);
}
context3D.present();
}
}
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.utils.Dictionary;
import flash.display3D.Context3D;
import com.adobe.utils.AGALMiniAssembler;
import com.adobe.utils.AGALMiniAssembler;
import flash.display3D.*;
import flash.display3D.textures.*;
import flash.display3D.textures.Texture;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
/**
* Renderer context that can render SpriteSheet's
*/
class SpriteSheetContext {
private static const vertexShader:AGALMiniAssembler = new AGALMiniAssembler();
vertexShader.assemble( Context3DProgramType.VERTEX,
"mov vt0.xyzw, va0.xyww\n" +
"m33 vt0.xyz, vt0, vc0\n" +
"mov op, vt0\n" +
"mov v0, va1\n"
);
private static const fragmentShader:AGALMiniAssembler = new AGALMiniAssembler();
fragmentShader.assemble( Context3DProgramType.FRAGMENT,
"tex oc, v0, fs0 <2d,linear,miplinear>\n"
);
private var _matrix:Matrix = new Matrix();
private var _matrixVector:Vector.<Number> = new Vector.<Number>();
private var _transformVector:Vector.<Number> = new Vector.<Number>();
private var _shaderProgram:Program3D = null;
private var _context3D:Context3D = null;
private var _backBufferWidth:uint = 0;
private var _backBufferWidthInv:Number = 0;
private var _backBufferHeight:uint = 0;
private var _backBufferHeightInv:Number = 0;
private var _textures:Dictionary = new Dictionary(true);
public function SpriteSheetContext(context3D:Context3D) {
_context3D = context3D;
_shaderProgram = _context3D.createProgram();
_shaderProgram.upload( vertexShader.agalcode, fragmentShader.agalcode);
for ( var c:uint = 0; c < 12; c++)
_matrixVector[c] = 0.0;
_matrixVector[3] = 1.0; _matrixVector[7] = 1.0; _matrixVector[11] = 1.0;
}
public function setSize(backBufferWidth:uint, backBufferHeight:uint):void
{
_backBufferWidth = backBufferWidth;
_backBufferWidthInv = 1.0 / backBufferWidth;
_backBufferHeight = backBufferHeight;
_backBufferHeightInv = 1.0 / backBufferHeight;
_context3D.configureBackBuffer(_backBufferWidth, _backBufferHeight, 1);
}
public function render(sprite:SpriteSheet):void
{
var data: SheetData = _textures[sprite.sheet];
if ( !data ) {
_textures[sprite.sheet] = data = new SheetData(_context3D,sprite.sheet);
}
// Applying transformations and render
_context3D.setProgram(_shaderProgram);
_matrix.createBox(1.0, 1.0, sprite.rotation, sprite.x - _backBufferWidth, _backBufferHeight - sprite.y);
_matrix.scale(_backBufferWidthInv, _backBufferHeightInv);
_matrixVector[0] = _matrix.a; _matrixVector[1] = _matrix.c; _matrixVector[2] = _matrix.tx;
_matrixVector[4] = _matrix.b; _matrixVector[5] = _matrix.d; _matrixVector[6] = _matrix.ty;
_context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 0, _matrixVector, 3);
_context3D.setTextureAt(0, data.texture);
_context3D.setVertexBufferAt(0, data.vertices, 0, Context3DVertexBufferFormat.FLOAT_2);
_context3D.setVertexBufferAt(1, data.vertices, 2, Context3DVertexBufferFormat.FLOAT_2);
_context3D.drawTriangles(data.indices, sprite.frame * 6, 2);
}
}
/**
* Spritesheet that allows positioning and rotation
*/
class SpriteSheet {
public var sheet: Sheet;
public var x: Number = 0.0;
public var y: Number = 0.0;
public var rotation: Number = 0.0;
public var frame: uint = 0;
public function SpriteSheet(sheet:Sheet) {
this.sheet = sheet;
}
public function nextFrame():void {
(frame == sheet.frames - 1) ? frame = 0 : ++frame;
}
}
/**
* A Sheet of Frame data
*/
class Sheet {
public var indices: Vector.<uint>;
public var vertices: Vector.<Number>;
public var bmp: BitmapData;
public var frames: uint;
public function Sheet(bmp:BitmapData, frames:Vector.<Rectangle>) {
this.bmp = bmp;
this.frames = frames.length;
var v:uint = 0;
var i:uint = 0;
vertices = new Vector.<Number>(frames.length*16);
indices = new Vector.<uint>(frames.length * 6);
var ws:int = 2.0;
var hs:int = 2.0;
var width:int = bmp.width;
var height:int = bmp.height;
while(ws < width) {
ws <<= 1;
}
while(hs < height) {
hs <<= 1;
}
for ( var c:uint = 0, iO: uint = 0; c < frames.length; c++, iO += 4 ) {
var frame: Rectangle = frames[c];
var u0:Number = frame.x / ws;
var v0:Number = frame.y / hs;
var u1:Number = (frame.x + frame.width) / ws;
var v1:Number = (frame.y + frame.height) / hs;
vertices[v++] = -frame.width; vertices[v++] = frame.height; vertices[v++] = u0; vertices[v++] = v0;
vertices[v++] = frame.width; vertices[v++] = frame.height; vertices[v++] = u1; vertices[v++] = v0;
vertices[v++] = frame.width; vertices[v++] = -frame.height; vertices[v++] = u1; vertices[v++] = v1;
vertices[v++] = -frame.width; vertices[v++] = -frame.height; vertices[v++] = u0; vertices[v++] = v1;
indices[i++] = (iO+0); indices[i++] = (iO+1); indices[i++] = (iO+3);
indices[i++] = (iO+1); indices[i++] = (iO+2); indices[i++] = (iO+3);
}
}
}
/**
* Data for a Sheet within one Context3D
*/
class SheetData {
public var texture: Texture;
public var vertices: VertexBuffer3D;
public var indices: IndexBuffer3D;
public function SheetData(context3D:Context3D, sheet:Sheet) {
var ws:int = 2.0;
var hs:int = 2.0;
var width:int = sheet.bmp.width;
var height:int = sheet.bmp.height;
while(ws < width) {
ws <<= 1;
}
while(hs < height) {
hs <<= 1;
}
var level:int = 0;
var tmp:BitmapData = new BitmapData(ws, hs, true, 0);
var transform:Matrix = new Matrix();
var rect:Rectangle = new Rectangle();
texture = context3D.createTexture(ws, hs, Context3DTextureFormat.BGRA, true);
while (ws >= 1.0 && hs >= 1.0) {
tmp.draw(sheet.bmp, transform, null, null, null, true);
texture.uploadFromBitmapData(tmp, level);
rect.width = ws;
rect.height = hs;
tmp.fillRect(rect, 0);
transform.scale(0.5, 0.5);
level++;
ws >>= 1;
hs >>= 1;
}
tmp.dispose();
indices = context3D.createIndexBuffer(sheet.indices.length);
indices.uploadFromVector(sheet.indices, 0, sheet.indices.length);
vertices = context3D.createVertexBuffer(sheet.vertices.length/4, 4);
vertices.uploadFromVector(sheet.vertices, 0, sheet.vertices.length/4);
}
}
class SnakeData {
[Embed(source="snake.png")]
private static const snakeRaw:Class;
private static const snakeBmp:BitmapData = new snakeRaw().bitmapData;
private static const rects:Vector.<Rectangle> = new Vector.<Rectangle>(20);
{
rects[0] = new Rectangle(0,0,106,62);
rects[1] = new Rectangle(106,0,104,62);
rects[2] = new Rectangle(210,0,104,64);
rects[3] = new Rectangle(314,0,102,64);
rects[4] = new Rectangle(0,64,100,64);
rects[5] = new Rectangle(100,64,100,64);
rects[6] = new Rectangle(200,64,100,64);
rects[7] = new Rectangle(300,64,100,64);
rects[8] = new Rectangle(400,64,98,66);
rects[9] = new Rectangle(0,130,100,64);
rects[10] = new Rectangle(100,130,100,66);
rects[11] = new Rectangle(200,130,100,66);
rects[12] = new Rectangle(300,130,100,66);
rects[13] = new Rectangle(400,130,100,66);
rects[14] = new Rectangle(0,196,102,64);
rects[15] = new Rectangle(102,196,102,64);
rects[16] = new Rectangle(204,196,104,64);
rects[17] = new Rectangle(308,196,106,64);
rects[18] = new Rectangle(0,260,106,62);
rects[19] = new Rectangle(106,260,106,64);
}
private static var _sheet: Sheet;
public static function get sheet():Sheet {
if ( !_sheet ) {
_sheet = new Sheet(snakeBmp, rects);
}
return _sheet;
}
}