├── src └── com │ └── adobe │ ├── utils │ ├── .DS_Store │ ├── macro │ │ ├── Expression.as │ │ ├── NumberExpression.as │ │ ├── VariableExpression.as │ │ ├── UnaryExpression.as │ │ ├── AGALVar.as │ │ ├── VM.as │ │ ├── BinaryExpression.as │ │ ├── AGALPreAssembler.as │ │ └── ExpressionParser.as │ ├── PerspectiveMatrix3D.as │ ├── FractalGeometryGenerator.as │ ├── Sprite3D.as │ ├── AGALMacroAssembler.as │ ├── AGALMiniAssembler.as │ ├── extended │ │ └── AGALMiniAssembler.as │ └── v3 │ │ └── AGALMiniAssembler.as │ └── example │ └── GPUSprite │ ├── GPUSpriteRenderStage.as │ ├── GPUSprite.as │ ├── GPUSpriteSheet.as │ └── GPUSpriteRenderLayer.as ├── README └── index.html /src/com/adobe/utils/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe-flash/graphicscorelib/HEAD/src/com/adobe/utils/.DS_Store -------------------------------------------------------------------------------- /src/com/adobe/utils/macro/Expression.as: -------------------------------------------------------------------------------- 1 | package com.adobe.utils.macro 2 | { 3 | import com.adobe.utils.macro.VM; 4 | 5 | public class Expression 6 | { 7 | public function print( depth:int ):void { trace( "top" ); } 8 | public function exec( vm:VM ):void { 9 | trace( "WTF" ); 10 | } 11 | 12 | protected function spaces( depth:int ):String 13 | { 14 | // Must be a clever way to do this... 15 | var str:String = ""; 16 | for( var i:int=0; i = new Vector.(); 48 | private var m_ifWasTrue:Vector. = new Vector.(); 49 | } 50 | } -------------------------------------------------------------------------------- /src/com/adobe/utils/macro/BinaryExpression.as: -------------------------------------------------------------------------------- 1 | package com.adobe.utils.macro 2 | { 3 | internal class BinaryExpression extends com.adobe.utils.macro.Expression 4 | { 5 | public var op:String; 6 | public var left:Expression; 7 | public var right:Expression; 8 | override public function print( depth:int ):void { 9 | if ( AGALPreAssembler.TRACE_VM ) { 10 | trace( spaces( depth ) + "binary op " + op ); 11 | } 12 | left.print( depth+1 ); 13 | right.print( depth+1 ); 14 | } 15 | 16 | override public function exec( vm:VM ):void { 17 | var varLeft:Number = Number.NaN; 18 | var varRight:Number = Number.NaN; 19 | 20 | left.exec( vm ); 21 | varLeft = vm.stack.pop(); 22 | right.exec( vm ); 23 | varRight = vm.stack.pop(); 24 | 25 | if ( isNaN( varLeft ) ) throw new Error( "Left side of binary expression (" + op + ") is NaN" ); 26 | if ( isNaN( varRight ) ) throw new Error( "Right side of binary expression (" + op + ") is NaN" ); 27 | 28 | switch( op ) { 29 | case "*": 30 | vm.stack.push( varLeft * varRight ); 31 | break; 32 | case "/": 33 | vm.stack.push( varLeft / varRight ); 34 | break; 35 | case "+": 36 | vm.stack.push( varLeft + varRight ); 37 | break; 38 | case "-": 39 | vm.stack.push( varLeft - varRight ); 40 | break; 41 | case ">": 42 | vm.stack.push( (varLeft > varRight) ? 1 : 0 ); 43 | break; 44 | case "<": 45 | vm.stack.push( (varLeft < varRight) ? 1 : 0 ); 46 | break; 47 | case ">=": 48 | vm.stack.push( (varLeft >= varRight) ? 1 : 0 ); 49 | break; 50 | case ">=": 51 | vm.stack.push( (varLeft <= varRight) ? 1 : 0 ); 52 | break; 53 | case "==": 54 | vm.stack.push( (varLeft==varRight) ? 1 : 0 ); 55 | break; 56 | case "!=": 57 | vm.stack.push( (varLeft!=varRight) ? 1 : 0 ); 58 | break; 59 | case "&&": 60 | vm.stack.push( (Boolean(varLeft) && Boolean(varRight)) ? 1 : 0 ); 61 | break; 62 | case "||": 63 | vm.stack.push( (Boolean(varLeft) || Boolean(varRight)) ? 1 : 0 ); 64 | break; 65 | 66 | default: 67 | throw new Error( "unimplemented BinaryExpression exec" ); 68 | break; 69 | } 70 | if ( AGALPreAssembler.TRACE_VM ) { 71 | trace( "::BinaryExpression op" + op + " left=" + varLeft + " right=" +varRight + " push " + vm.stack[vm.stack.length-1] ); 72 | } 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | A Flash Platform SDK, a nice toolbox with libs for every ActionScript 3 developer. 2 | 3 | THIS SDK IS IN VERY EARLY DEVELOPMENT 4 | 5 | Current work items: 6 | - organize; move things out of top level packages. Add testing directories. 7 | - test framework for all tests. 8 | 9 | Current Projects: 10 | 11 | AGALMiniAssembler 12 | The Mini assembler generates AGAL byte code from a simple 13 | source text language. AGAL byte code is required for Molehill, 14 | the Flash 3D API. The MiniAssembler is a run time assembler - 15 | it is an AS3 class that is a part of your 3D app. 16 | 17 | AGALMiniAssembler 18 | The Mini assembler for Stage3D extended profile. 19 | 20 | AGALMacroAssembler 21 | The Macro assembler extends the Mini assembler with macros (similar 22 | to functions), basic math expressions, aliases, and constant allocation. 23 | 24 | Status: Alpha, initial testing (not yet uploaded) 25 | Test suite: TBD 26 | 27 | FractalGeometryGenerator 28 | TBD 29 | 30 | PerspectiveMatrix3D 31 | A class for creating perspective matrices, for use in 3D applications. 32 | 33 | Status: Beta, in use by early adopters 34 | Test suite: TBD 35 | 36 | Sprite3D 37 | A Sprite layer on top of the Molehill APIs (Stage3D). 38 | 39 | Status: Beta, in use by early adopters 40 | Test suite: TBD 41 | 42 | Copyright (c) 2011, Adobe Systems Incorporated 43 | All rights reserved. 44 | 45 | Redistribution and use in source and binary forms, with or without 46 | modification, are permitted provided that the following conditions are 47 | met: 48 | 49 | * Redistributions of source code must retain the above copyright notice, 50 | this list of conditions and the following disclaimer. 51 | 52 | * Redistributions in binary form must reproduce the above copyright 53 | notice, this list of conditions and the following disclaimer in the 54 | documentation and/or other materials provided with the distribution. 55 | 56 | * Neither the name of Adobe Systems Incorporated nor the names of its 57 | contributors may be used to endorse or promote products derived from 58 | this software without specific prior written permission. 59 | 60 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 61 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 62 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 63 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 64 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 65 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 66 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 67 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 68 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 69 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 70 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | flashplatformsdk/Flash-Platform-SDK @ GitHub 7 | 8 | 31 | 32 | 33 | 34 | Fork me on GitHub 35 | 36 |
37 | 38 |
39 | 40 | 41 | 42 | 43 |
44 | 45 |

Flash-Platform-SDK 46 | by flashplatformsdk

47 | 48 |
49 | Flash Platform SDK 50 |
51 | 52 |

Authors

53 |

Thibault Imbert (timbert@adobe.com)

54 |

Contact

55 |

Flash Platform SDK (timbert@adobe.com)

56 | 57 | 58 |

Download

59 |

60 | You can download this project in either 61 | zip or 62 | tar formats. 63 |

64 |

You can also clone the project with Git 65 | by running: 66 |

$ git clone git://github.com/flashplatformsdk/Flash-Platform-SDK
67 |

68 | 69 | 72 | 73 |
74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/com/adobe/utils/macro/AGALPreAssembler.as: -------------------------------------------------------------------------------- 1 | package com.adobe.utils.macro 2 | { 3 | import flash.utils.Dictionary; 4 | 5 | /* 6 | * The AGALPreAssembler implements a pre-processing language for AGAL. 7 | * The preprocessor is interpreted at compile time, which allows 8 | * run time generation of different shader types, often from one 9 | * main shader. 10 | * 11 |
 12 | 		Language:
 13 | 		#define FOO num
 14 | 		#define FOO
 15 | 		#undef FOO	
 16 | 		
 17 | 		#if 
 18 | 		#elif 
 19 | 		#else
 20 | 		#endif	
 21 | 
22 | */ 23 | 24 | public class AGALPreAssembler 25 | { 26 | public static const TRACE_VM:Boolean = false; 27 | public static const TRACE_AST:Boolean = false; 28 | public static const TRACE_PREPROC:Boolean = false; 29 | 30 | private var vm:VM = new VM(); 31 | private var expressionParser:ExpressionParser = new ExpressionParser(); 32 | 33 | public function AGALPreAssembler() 34 | { 35 | } 36 | 37 | public function processLine( tokens:Vector., types:String ):Boolean 38 | { 39 | // read per-line. Either handle: 40 | // - preprocessor tags (and call the proprocessor 'vm') 41 | // - check the current 'if' state and stream out tokens. 42 | 43 | var slot:String = ""; 44 | var num:Number; 45 | var exp:Expression = null; 46 | var result:Number; 47 | var pos:int = 0; 48 | 49 | if ( types.charAt(pos) == "#" ) { 50 | slot = ""; 51 | num = Number.NaN; 52 | 53 | if (tokens[pos] == "#define" ) { 54 | // #define FOO 1 55 | // #define FOO 56 | // #define FOO=1 57 | if ( types.length >= 3 && types.substr(pos,3) == "#in" ) { 58 | slot = tokens[pos+1]; 59 | vm.vars[ slot ] = Number.NaN; 60 | if ( TRACE_PREPROC ) { 61 | trace( "#define #i" ); 62 | } 63 | pos += 3; 64 | } 65 | else if ( types.length >= 3 && types.substr( pos,3) == "#i=" ) { 66 | exp = expressionParser.parse( tokens.slice( 3 ), types.substr( 3 ) ); 67 | exp.exec( vm ); 68 | result = vm.stack.pop(); 69 | 70 | slot = tokens[pos+1]; 71 | vm.vars[slot] = result; 72 | 73 | if ( TRACE_PREPROC ) { 74 | trace( "#define= " + slot + "=" + result ); 75 | } 76 | } 77 | else { 78 | exp = expressionParser.parse( tokens.slice( 2 ), types.substr( 2 ) ); 79 | exp.exec( vm ); 80 | result = vm.stack.pop(); 81 | 82 | slot = tokens[pos+1]; 83 | vm.vars[slot] = result; 84 | 85 | if ( TRACE_PREPROC ) { 86 | trace( "#define " + slot + "=" + result ); 87 | } 88 | } 89 | } 90 | else if ( tokens[pos] == "#undef" ) { 91 | slot = tokens[pos+1]; 92 | vm.vars[slot] = null; 93 | if ( TRACE_PREPROC ) { 94 | trace( "#undef" ); 95 | } 96 | pos += 3; 97 | } 98 | else if ( tokens[pos] == "#if" ) { 99 | ++pos; 100 | exp = expressionParser.parse( tokens.slice( 1 ), types.substr( 1 ) ); 101 | 102 | vm.pushIf(); 103 | 104 | exp.exec( vm ); 105 | result = vm.stack.pop(); 106 | vm.setIf( result ); 107 | if ( TRACE_PREPROC ) { 108 | trace( "#if " + ((result)?"true":"false") ); 109 | } 110 | } 111 | else if ( tokens[pos] == "#elif" ) { 112 | ++pos; 113 | exp = expressionParser.parse( tokens.slice( 1 ), types.substr( 1 ) ); 114 | 115 | exp.exec( vm ); 116 | result = vm.stack.pop(); 117 | vm.setIf( result ); 118 | if ( TRACE_PREPROC ) { 119 | trace( "#elif " + ((result)?"true":"false") ); 120 | } 121 | } 122 | else if ( tokens[pos] == "#else" ) { 123 | ++pos; 124 | vm.setIf( vm.ifWasTrue() ? 0 : 1 ); 125 | if ( TRACE_PREPROC ) { 126 | trace( "#else " + ((vm.ifWasTrue())?"true":"false") ); 127 | } 128 | } 129 | else if ( tokens[pos] == "#endif" ) { 130 | vm.popEndif(); 131 | ++pos; 132 | if ( TRACE_PREPROC ) { 133 | trace( "#endif" ); 134 | } 135 | } 136 | else { 137 | throw new Error( "unrecognize processor directive." ); 138 | } 139 | 140 | // eat the newlines 141 | while( pos < types.length && types.charAt( pos ) == "n" ) { 142 | ++pos; 143 | } 144 | } 145 | else { 146 | throw new Error( "PreProcessor called without pre processor directive." ); 147 | } 148 | return vm.ifIsTrue(); 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/com/adobe/example/GPUSprite/GPUSpriteRenderStage.as: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011, Adobe Systems Incorporated 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | * Neither the name of Adobe Systems Incorporated nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | package com.adobe.example.GPUSprite 34 | { 35 | import flash.display.Stage3D; 36 | import flash.display3D.Context3D; 37 | import flash.geom.Matrix3D; 38 | import flash.geom.Rectangle; 39 | 40 | public class GPUSpriteRenderStage 41 | { 42 | protected var _stage3D : Stage3D; 43 | protected var _context3D : Context3D; 44 | protected var _rect : Rectangle; 45 | protected var _layers : Vector.; 46 | protected var _modelViewMatrix : Matrix3D; 47 | 48 | public function get position() : Rectangle 49 | { 50 | return _rect; 51 | } 52 | 53 | public function set position(rect:Rectangle) : void 54 | { 55 | _rect = rect; 56 | _stage3D.x = rect.x; 57 | _stage3D.y = rect.y; 58 | configureBackBuffer(rect.width, rect.height); 59 | 60 | _modelViewMatrix = new Matrix3D(); 61 | _modelViewMatrix.appendTranslation(-rect.width/2, -rect.height/2, 0); 62 | _modelViewMatrix.appendScale(2.0/rect.width, -2.0/rect.height, 1); 63 | } 64 | 65 | internal function get modelViewMatrix() : Matrix3D 66 | { 67 | return _modelViewMatrix; 68 | } 69 | 70 | public function GPUSpriteRenderStage(stage3D:Stage3D, context3D:Context3D, rect:Rectangle) 71 | { 72 | _stage3D = stage3D; 73 | _context3D = context3D; 74 | _layers = new Vector.; 75 | 76 | this.position = rect; 77 | } 78 | 79 | public function addLayer(layer:GPUSpriteRenderLayer) : void 80 | { 81 | layer.parent = this; 82 | _layers.push(layer); 83 | } 84 | 85 | public function removeLayer(layer:GPUSpriteRenderLayer) : void 86 | { 87 | for ( var i:uint = 0; i < _layers.length; i++ ) { 88 | if ( _layers[i] == layer ) { 89 | layer.parent = null; 90 | _layers.splice(i, 1); 91 | } 92 | } 93 | } 94 | 95 | public function draw() : void 96 | { 97 | _context3D.clear(1.0, 1.0, 1.0); 98 | for ( var i:uint = 0; i < _layers.length; i++ ) { 99 | _layers[i].draw(); 100 | } 101 | _context3D.present(); 102 | } 103 | 104 | public function drawDeferred() : void 105 | { 106 | for ( var i:uint = 0; i < _layers.length; i++ ) { 107 | _layers[i].draw(); 108 | } 109 | } 110 | 111 | public function configureBackBuffer(width:uint, height:uint) : void 112 | { 113 | // TODO expose AA? 114 | _context3D.configureBackBuffer(width, height, 0, false); 115 | } 116 | } 117 | } -------------------------------------------------------------------------------- /src/com/adobe/utils/macro/ExpressionParser.as: -------------------------------------------------------------------------------- 1 | package com.adobe.utils.macro 2 | { 3 | /* 4 | The parse is based on Dijkstra's shunting yard: 5 | http://en.wikipedia.org/wiki/Shunting_yard_algorithm 6 | 7 | As aproached here: 8 | http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm 9 | 10 | 11 | Precedence (subset of C rules): 12 | ------------------------------- 13 | () Parens left-to-right 14 | ! not 15 | * Multiplication, division left-to-right 16 | + Addition, subtraction left-to-right 17 | > >= relational left-to-right 18 | == != relational left-to-right 19 | && Logical AND left-to-right 20 | || Logical OR left-to-right 21 | */ 22 | public class ExpressionParser 23 | { 24 | public function ExpressionParser() 25 | { 26 | } 27 | 28 | private var pos:int = 0; 29 | private var newline:int = 0; 30 | private static const UNARY_PRECEDENCE:int = 5; 31 | private var tokens:Vector.; 32 | private var types:String; 33 | 34 | private function expectTok( e:String ):void { 35 | if ( tokens[pos] != e ) throw new Error( "Unexpected token." ); 36 | ++pos; 37 | } 38 | 39 | private function parseSingle( token:String, type:String ):Expression 40 | { 41 | if ( type == "i" ) { 42 | var varExp:VariableExpression = new VariableExpression( token ); 43 | return varExp; 44 | } 45 | else if ( type == "0" ) { 46 | var numExp:NumberExpression = new NumberExpression( Number( token ) ); 47 | return numExp; 48 | } 49 | return null; 50 | } 51 | 52 | private function parseChunk():Expression 53 | { 54 | if ( pos == newline ) throw new Error( "parseBit out of tokens" ); 55 | 56 | // Unary operator 57 | if ( tokens[pos] == "!" ) { 58 | var notExp:UnaryExpression = new UnaryExpression(); 59 | ++pos; 60 | notExp.right = parseExpression( UNARY_PRECEDENCE ); 61 | return notExp; 62 | } 63 | 64 | if ( tokens[pos] == "(" ) { 65 | ++pos; 66 | var exp:Expression = parseExpression( 0 ); 67 | expectTok( ")" ); 68 | return exp; 69 | } 70 | 71 | if ( types.charAt(pos) == "i" ) { 72 | var varExp:VariableExpression = new VariableExpression( tokens[pos] ); 73 | ++pos; 74 | return varExp; 75 | } 76 | if ( types.charAt(pos) == "0" ) { 77 | var numExp:NumberExpression = new NumberExpression( Number( tokens[pos] ) ); 78 | ++pos; 79 | return numExp; 80 | } 81 | throw new Error( "end of parseChunk: token=" + tokens[pos] + " type=" + types.charAt(pos) ); 82 | } 83 | 84 | private function parseExpression( minPrecedence:int ):Expression 85 | { 86 | var t:Expression = parseChunk(); // consumes what is before the binop 87 | if ( t is NumberExpression ) // numbers are immutable... 88 | return t; 89 | 90 | var opInfo:OpInfo = new OpInfo(); 91 | if ( pos < tokens.length ) 92 | calcOpInfo( tokens[pos], opInfo ); 93 | 94 | while( opInfo.order == 2 && opInfo.precedence >= minPrecedence ) { 95 | var binExp:BinaryExpression = new BinaryExpression(); 96 | binExp.op = tokens[pos]; 97 | ++pos; 98 | binExp.left = t; 99 | binExp.right = parseExpression( 1+opInfo.precedence ); 100 | 101 | t = binExp; 102 | 103 | if ( pos < tokens.length ) 104 | calcOpInfo( tokens[pos], opInfo ); 105 | else 106 | break; 107 | } 108 | return t; 109 | } 110 | 111 | public function parse( tokens:Vector., types:String ):Expression 112 | { 113 | pos = 0; 114 | newline = types.indexOf( "n", pos+1 ); 115 | if ( newline < 0 ) 116 | newline = types.length; 117 | 118 | this.tokens = tokens; 119 | this.types = types; 120 | 121 | var exp:Expression = parseExpression( 0 ); 122 | //trace( "--eparser--" ); 123 | if ( AGALPreAssembler.TRACE_AST ) { 124 | exp.print(0); 125 | } 126 | if ( pos != newline ) throw new Error( "parser didn't end" ); 127 | return exp; 128 | } 129 | 130 | 131 | private function calcOpInfo( op:String, opInfo:OpInfo ):Boolean 132 | { 133 | opInfo.order = 0; 134 | opInfo.precedence = -1; 135 | 136 | var groups:Array = [ 137 | new Array( "&&", "||" ), 138 | new Array( "==", "!=" ), 139 | new Array( ">", "<", ">=", "<=" ), 140 | new Array( "+", "-" ), 141 | new Array( "*", "/" ), 142 | new Array( "!" ) 143 | ]; 144 | for( var i:int=0; i= 0 ) { 148 | opInfo.order = (i==UNARY_PRECEDENCE) ? 1 : 2; 149 | opInfo.precedence = i; 150 | return true; 151 | } 152 | } 153 | return false; 154 | } 155 | 156 | } 157 | } 158 | 159 | class OpInfo 160 | { 161 | public var precedence:int; 162 | public var order:int; // 1: unary, 2: binary 163 | } 164 | -------------------------------------------------------------------------------- /src/com/adobe/example/GPUSprite/GPUSprite.as: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012, Adobe Systems Incorporated 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | * Neither the name of Adobe Systems Incorporated nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | package com.adobe.example.GPUSprite 34 | { 35 | import flash.geom.Point; 36 | import flash.geom.Rectangle; 37 | 38 | public class GPUSprite 39 | { 40 | internal var _parent : GPUSpriteRenderLayer; 41 | internal var _spriteId : uint; 42 | internal var _childId : uint; 43 | 44 | private var _pos : Point; 45 | private var _visible : Boolean; 46 | private var _scaleX : Number; 47 | private var _scaleY : Number; 48 | private var _rotation : Number; 49 | private var _alpha : Number; 50 | 51 | 52 | public function get visible() : Boolean 53 | { 54 | return _visible; 55 | } 56 | 57 | public function set visible(isVisible:Boolean) : void 58 | { 59 | _visible = isVisible; 60 | } 61 | 62 | public function get alpha() : Number 63 | { 64 | return _alpha; 65 | } 66 | public function set alpha(a:Number) : void 67 | { 68 | _alpha = a; 69 | } 70 | 71 | public function get position() : Point 72 | { 73 | return _pos; 74 | } 75 | 76 | public function set position(pt:Point) : void 77 | { 78 | _pos = pt; 79 | } 80 | 81 | public function get scaleX() : Number 82 | { 83 | return _scaleX; 84 | } 85 | 86 | public function set scaleX(val:Number) : void 87 | { 88 | _scaleX = val; 89 | } 90 | 91 | public function get scaleY() : Number 92 | { 93 | return _scaleY; 94 | } 95 | 96 | public function set scaleY(val:Number) : void 97 | { 98 | _scaleY = val; 99 | } 100 | 101 | public function get rotation() : Number 102 | { 103 | return _rotation; 104 | } 105 | 106 | public function set rotation(val:Number) : void 107 | { 108 | _rotation = val; 109 | } 110 | 111 | public function get rect() : Rectangle 112 | { 113 | return _parent._spriteSheet.getRect(_spriteId); 114 | } 115 | 116 | public function get parent() : GPUSpriteRenderLayer 117 | { 118 | return _parent; 119 | } 120 | 121 | public function get spriteId() : uint 122 | { 123 | return _spriteId; 124 | } 125 | 126 | public function get childId() : uint 127 | { 128 | return _childId; 129 | } 130 | 131 | // GPUSprites are typically constructed by calling GPUSpriteRenderLayer.createChild() 132 | public function GPUSprite() 133 | { 134 | _parent = null; 135 | _spriteId = 0; 136 | _childId = 0; 137 | _pos = new Point(); 138 | _scaleX = 1.0; 139 | _scaleY = 1.0; 140 | _rotation = 0; 141 | _alpha = 1.0; 142 | _visible = true; 143 | } 144 | } 145 | } -------------------------------------------------------------------------------- /src/com/adobe/example/GPUSprite/GPUSpriteSheet.as: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011, Adobe Systems Incorporated 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | * Neither the name of Adobe Systems Incorporated nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | package com.adobe.example.GPUSprite 34 | { 35 | import flash.display.Bitmap; 36 | import flash.display.BitmapData; 37 | import flash.display.Stage; 38 | import flash.display3D.Context3D; 39 | import flash.display3D.Context3DTextureFormat; 40 | import flash.display3D.IndexBuffer3D; 41 | import flash.display3D.textures.Texture; 42 | import flash.geom.Point; 43 | import flash.geom.Rectangle; 44 | import flash.geom.Matrix; 45 | 46 | public class GPUSpriteSheet 47 | { 48 | internal var _texture : Texture; 49 | 50 | protected var _spriteSheet : BitmapData; 51 | protected var _uvCoords : Vector.; 52 | protected var _rects : Vector.; 53 | 54 | /** 55 | public var _stage: Stage; // for debugging 56 | **/ 57 | 58 | public function GPUSpriteSheet(width:uint, height:uint) 59 | { 60 | _spriteSheet = new BitmapData(width, height, true, 0); 61 | _uvCoords = new Vector.(); 62 | _rects = new Vector.(); 63 | } 64 | 65 | // Very simplistic for now...assume client will manage the packing of the sprite sheet bitmap 66 | // Returns sprite ID 67 | public function addSprite(srcBits:BitmapData, srcRect:Rectangle, destPt:Point) : uint 68 | { 69 | _spriteSheet.copyPixels(srcBits, srcRect, destPt); 70 | 71 | var destRect : Rectangle = new Rectangle(); 72 | destRect.left = destPt.x; 73 | destRect.top = destPt.y; 74 | destRect.right = destRect.left + srcRect.width; 75 | destRect.bottom = destRect.top + srcRect.height; 76 | 77 | _rects.push(destRect); 78 | 79 | _uvCoords.push( 80 | destRect.x/_spriteSheet.width, destRect.y/_spriteSheet.height + destRect.height/_spriteSheet.height, 81 | destRect.x/_spriteSheet.width, destRect.y/_spriteSheet.height, 82 | destRect.x/_spriteSheet.width + destRect.width/_spriteSheet.width, destRect.y/_spriteSheet.height, 83 | destRect.x/_spriteSheet.width + destRect.width/_spriteSheet.width, destRect.y/_spriteSheet.height + destRect.height/_spriteSheet.height); 84 | 85 | return _rects.length - 1; 86 | } 87 | 88 | public function removeSprite(spriteId:uint) : void 89 | { 90 | if ( spriteId < _uvCoords.length ) { 91 | _uvCoords = _uvCoords.splice(spriteId * 8, 8); 92 | _rects.splice(spriteId, 1); 93 | } 94 | } 95 | 96 | public function get numSprites() : uint 97 | { 98 | return _rects.length; 99 | } 100 | 101 | public function getUVCoords(spriteId:uint) : Vector. 102 | { 103 | var startIdx:uint = spriteId * 8; 104 | return _uvCoords.slice(startIdx, startIdx + 8); 105 | 106 | } 107 | 108 | public function getRect(spriteId:uint) : Rectangle 109 | { 110 | return _rects[spriteId]; 111 | } 112 | 113 | public function uploadTexture(context3D:Context3D) : void 114 | { 115 | if ( _texture == null ) { 116 | _texture = context3D.createTexture(_spriteSheet.width, _spriteSheet.height, Context3DTextureFormat.BGRA, false); 117 | } 118 | 119 | /** 120 | * for debugging 121 | var bitmap:Bitmap = new Bitmap(_spriteSheet); 122 | _stage.addChild(bitmap); 123 | **/ 124 | 125 | _texture.uploadFromBitmapData(_spriteSheet); 126 | 127 | // Courtesy of Starling: let's generate mipmaps 128 | var currentWidth:int = _spriteSheet.width >> 1; 129 | var currentHeight:int = _spriteSheet.height >> 1; 130 | var level:int = 1; 131 | var canvas:BitmapData = new BitmapData(currentWidth, currentHeight, true, 0); 132 | var transform:Matrix = new Matrix(.5, 0, 0, .5); 133 | 134 | while ( currentWidth >= 1 || currentHeight >= 1 ) { 135 | canvas.fillRect(new Rectangle(0, 0, Math.max(currentWidth,1), Math.max(currentHeight,1)), 0); 136 | canvas.draw(_spriteSheet, transform, null, null, null, true); 137 | _texture.uploadFromBitmapData(canvas, level++); 138 | transform.scale(0.5, 0.5); 139 | currentWidth = currentWidth >> 1; 140 | currentHeight = currentHeight >> 1; 141 | } 142 | } 143 | } 144 | } -------------------------------------------------------------------------------- /src/com/adobe/utils/PerspectiveMatrix3D.as: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011, Adobe Systems Incorporated 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | * Neither the name of Adobe Systems Incorporated nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | package com.adobe.utils 34 | { 35 | import flash.geom.Matrix3D; 36 | import flash.geom.Vector3D; 37 | 38 | public class PerspectiveMatrix3D extends Matrix3D 39 | { 40 | public function PerspectiveMatrix3D(v:Vector.=null) 41 | { 42 | super(v); 43 | } 44 | 45 | public function lookAtLH(eye:Vector3D, at:Vector3D, up:Vector3D):void { 46 | _z.copyFrom(at); 47 | _z.subtract(eye); 48 | _z.normalize(); 49 | _z.w = 0.0; 50 | 51 | _x.copyFrom(up); 52 | _crossProductTo(_x,_z); 53 | _x.normalize(); 54 | _x.w = 0.0; 55 | 56 | _y.copyFrom(_z); 57 | _crossProductTo(_y,_x); 58 | _y.w = 0.0; 59 | 60 | _w.x = _x.dotProduct(eye); 61 | _w.y = _y.dotProduct(eye); 62 | _w.z = _z.dotProduct(eye); 63 | _w.w = 1.0; 64 | 65 | copyRowFrom(0,_x); 66 | copyRowFrom(1,_y); 67 | copyRowFrom(2,_z); 68 | copyRowFrom(3,_w); 69 | } 70 | 71 | public function lookAtRH(eye:Vector3D, at:Vector3D, up:Vector3D):void { 72 | _z.copyFrom(eye); 73 | _z.subtract(at); 74 | _z.normalize(); 75 | _z.w = 0.0; 76 | 77 | _x.copyFrom(up); 78 | _crossProductTo(_x,_z); 79 | _x.normalize(); 80 | _x.w = 0.0; 81 | 82 | _y.copyFrom(_z); 83 | _crossProductTo(_y,_x); 84 | _y.w = 0.0; 85 | 86 | _w.x = _x.dotProduct(eye); 87 | _w.y = _y.dotProduct(eye); 88 | _w.z = _z.dotProduct(eye); 89 | _w.w = 1.0; 90 | 91 | copyRowFrom(0,_x); 92 | copyRowFrom(1,_y); 93 | copyRowFrom(2,_z); 94 | copyRowFrom(3,_w); 95 | } 96 | 97 | public function perspectiveLH(width:Number, 98 | height:Number, 99 | zNear:Number, 100 | zFar:Number):void { 101 | this.copyRawDataFrom(Vector.([ 102 | 2.0*zNear/width, 0.0, 0.0, 0.0, 103 | 0.0, 2.0*zNear/height, 0.0, 0.0, 104 | 0.0, 0.0, zFar/(zFar-zNear), 1.0, 105 | 0.0, 0.0, zNear*zFar/(zNear-zFar), 0.0 106 | ])); 107 | } 108 | 109 | public function perspectiveRH(width:Number, 110 | height:Number, 111 | zNear:Number, 112 | zFar:Number):void { 113 | this.copyRawDataFrom(Vector.([ 114 | 2.0*zNear/width, 0.0, 0.0, 0.0, 115 | 0.0, 2.0*zNear/height, 0.0, 0.0, 116 | 0.0, 0.0, zFar/(zNear-zFar), -1.0, 117 | 0.0, 0.0, zNear*zFar/(zNear-zFar), 0.0 118 | ])); 119 | } 120 | 121 | public function perspectiveFieldOfViewLH(fieldOfViewY:Number, 122 | aspectRatio:Number, 123 | zNear:Number, 124 | zFar:Number):void { 125 | var yScale:Number = 1.0/Math.tan(fieldOfViewY/2.0); 126 | var xScale:Number = yScale / aspectRatio; 127 | this.copyRawDataFrom(Vector.([ 128 | xScale, 0.0, 0.0, 0.0, 129 | 0.0, yScale, 0.0, 0.0, 130 | 0.0, 0.0, zFar/(zFar-zNear), 1.0, 131 | 0.0, 0.0, (zNear*zFar)/(zNear-zFar), 0.0 132 | ])); 133 | } 134 | 135 | public function perspectiveFieldOfViewRH(fieldOfViewY:Number, 136 | aspectRatio:Number, 137 | zNear:Number, 138 | zFar:Number):void { 139 | var yScale:Number = 1.0/Math.tan(fieldOfViewY/2.0); 140 | var xScale:Number = yScale / aspectRatio; 141 | this.copyRawDataFrom(Vector.([ 142 | xScale, 0.0, 0.0, 0.0, 143 | 0.0, yScale, 0.0, 0.0, 144 | 0.0, 0.0, zFar/(zNear-zFar), -1.0, 145 | 0.0, 0.0, (zNear*zFar)/(zNear-zFar), 0.0 146 | ])); 147 | } 148 | 149 | public function perspectiveOffCenterLH(left:Number, 150 | right:Number, 151 | bottom:Number, 152 | top:Number, 153 | zNear:Number, 154 | zFar:Number):void { 155 | this.copyRawDataFrom(Vector.([ 156 | 2.0*zNear/(right-left), 0.0, 0.0, 0.0, 157 | 0.0, -2.0*zNear/(bottom-top), 0.0, 0.0, 158 | -1.0-2.0*left/(right-left), 1.0+2.0*top/(bottom-top), -zFar/(zNear-zFar), 1.0, 159 | 0.0, 0.0, (zNear*zFar)/(zNear-zFar), 0.0 160 | ])); 161 | } 162 | 163 | public function perspectiveOffCenterRH(left:Number, 164 | right:Number, 165 | bottom:Number, 166 | top:Number, 167 | zNear:Number, 168 | zFar:Number):void { 169 | this.copyRawDataFrom(Vector.([ 170 | 2.0*zNear/(right-left), 0.0, 0.0, 0.0, 171 | 0.0, -2.0*zNear/(bottom-top), 0.0, 0.0, 172 | 1.0+2.0*left/(right-left), -1.0-2.0*top/(bottom-top), zFar/(zNear-zFar), -1.0, 173 | 0.0, 0.0, (zNear*zFar)/(zNear-zFar), 0.0 174 | ])); 175 | } 176 | 177 | public function orthoLH(width:Number, 178 | height:Number, 179 | zNear:Number, 180 | zFar:Number):void { 181 | this.copyRawDataFrom(Vector.([ 182 | 2.0/width, 0.0, 0.0, 0.0, 183 | 0.0, 2.0/height, 0.0, 0.0, 184 | 0.0, 0.0, 1.0/(zFar-zNear), 0.0, 185 | 0.0, 0.0, zNear/(zNear-zFar), 1.0 186 | ])); 187 | } 188 | 189 | public function orthoRH(width:Number, 190 | height:Number, 191 | zNear:Number, 192 | zFar:Number):void { 193 | this.copyRawDataFrom(Vector.([ 194 | 2.0/width, 0.0, 0.0, 0.0, 195 | 0.0, 2.0/height, 0.0, 0.0, 196 | 0.0, 0.0, 1.0/(zNear-zNear), 0.0, 197 | 0.0, 0.0, zNear/(zNear-zFar), 1.0 198 | ])); 199 | } 200 | 201 | public function orthoOffCenterLH(left:Number, 202 | right:Number, 203 | bottom:Number, 204 | top:Number, 205 | zNear:Number, 206 | zFar:Number):void { 207 | this.copyRawDataFrom(Vector.([ 208 | 2.0/(right-left), 0.0, 0.0, 0.0, 209 | 0.0, 2.0*zNear/(top-bottom), 0.0, 0.0, 210 | -1.0-2.0*left/(right-left), 1.0+2.0*top/(bottom-top), 1.0/(zFar-zNear), 0.0, 211 | 0.0, 0.0, zNear/(zNear-zFar), 1.0 212 | ])); 213 | } 214 | 215 | public function orthoOffCenterRH(left:Number, 216 | right:Number, 217 | bottom:Number, 218 | top:Number, 219 | zNear:Number, 220 | zFar:Number):void { 221 | this.copyRawDataFrom(Vector.([ 222 | 2.0/(right-left), 0.0, 0.0, 0.0, 223 | 0.0, 2.0*zNear/(top-bottom), 0.0, 0.0, 224 | -1.0-2.0*left/(right-left), 1.0+2.0*top/(bottom-top), 1.0/(zNear-zFar), 0.0, 225 | 0.0, 0.0, zNear/(zNear-zFar), 1.0 226 | ])); 227 | } 228 | 229 | private var _x:Vector3D = new Vector3D(); 230 | private var _y:Vector3D = new Vector3D(); 231 | private var _z:Vector3D = new Vector3D(); 232 | private var _w:Vector3D = new Vector3D(); 233 | 234 | private function _crossProductTo(a:Vector3D,b:Vector3D):void 235 | { 236 | _w.x = a.y * b.z - a.z * b.y; 237 | _w.y = a.z * b.x - a.x * b.z; 238 | _w.z = a.x * b.y - a.y * b.x; 239 | _w.w = 1.0; 240 | a.copyFrom(_w); 241 | } 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /src/com/adobe/utils/FractalGeometryGenerator.as: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011, Adobe Systems Incorporated 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | * Neither the name of Adobe Systems Incorporated nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | package com.adobe.utils 34 | { 35 | // =========================================================================== 36 | // Imports 37 | // --------------------------------------------------------------------------- 38 | import flash.display3D.*; 39 | import flash.geom.Matrix3D; 40 | 41 | // =========================================================================== 42 | // Class 43 | // --------------------------------------------------------------------------- 44 | public class FractalGeometryGenerator 45 | { 46 | // ====================================================================== 47 | // Properties 48 | // ---------------------------------------------------------------------- 49 | protected var m_context3D:Context3D; 50 | protected var m_levels:int; 51 | protected var m_nObjs:int; 52 | 53 | protected var m_matrix:Matrix3D; 54 | protected var m_red:Number; 55 | protected var m_green:Number; 56 | protected var m_blue:Number; 57 | protected var m_alpha:Number; 58 | 59 | protected var m_program:Program3D; 60 | protected var m_indexBufferSize:uint; 61 | protected var m_vertexBufferSize:uint; 62 | 63 | protected var m_indexBuffer:IndexBuffer3D; 64 | protected var m_vertexBuffer:VertexBuffer3D; 65 | protected var m_indexData:Vector.; 66 | protected var m_vertexData:Vector.; 67 | 68 | public function setColor( r:Number, g:Number, b:Number, a:Number ):void { 69 | m_red = r; 70 | m_green = g; 71 | m_blue = b; 72 | m_alpha = a; 73 | } 74 | 75 | public function setMatrix( matrix:Matrix3D ):void { 76 | m_matrix = matrix; 77 | } 78 | 79 | public function draw():void { 80 | m_context3D.setProgram( m_program ); 81 | m_context3D.setVertexBufferAt( 0, m_vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_2 ); 82 | m_context3D.setProgramConstantsFromMatrix( Context3DProgramType.VERTEX, 0, m_matrix, true ); 83 | m_context3D.setProgramConstantsFromVector( Context3DProgramType.FRAGMENT, 0, Vector.( [ m_red, m_green, m_blue, m_alpha ] )); 84 | m_context3D.drawTriangles( m_indexBuffer, 0, m_indexBufferSize / 3 ); // 1 tri per 3 indices 85 | } 86 | 87 | public function FractalGeometryGenerator( context3D:Context3D, levels:uint ) 88 | { 89 | m_context3D = context3D; 90 | m_levels = levels; 91 | m_matrix = new Matrix3D(); 92 | m_red = m_green = m_blue = m_alpha = 1; 93 | 94 | initProgram(); 95 | genGeom(); 96 | } 97 | 98 | protected function initProgram():void { 99 | 100 | var vertexShaderAssembler:AGALMiniAssembler; 101 | var fragmentShaderAssembler:AGALMiniAssembler; 102 | 103 | vertexShaderAssembler = new AGALMiniAssembler(); 104 | vertexShaderAssembler.assemble( Context3DProgramType.VERTEX, 105 | "dp4 op.x, va0, vc0 \n" + // 4x4 matrix transform from stream 0 to output clipspace 106 | "dp4 op.y, va0, vc1 \n" + 107 | "dp4 op.z, va0, vc2 \n" + 108 | "dp4 op.w, va0, vc3 \n" 109 | ); 110 | trace( "fractal geometry vertex program bytes:", vertexShaderAssembler.agalcode.length ); 111 | 112 | fragmentShaderAssembler = new AGALMiniAssembler(); 113 | fragmentShaderAssembler.assemble( Context3DProgramType.FRAGMENT, 114 | "mov oc, fc0 \n" 115 | ); 116 | trace( "fractal geomtery fragment program bytes:", fragmentShaderAssembler.agalcode.length ); 117 | 118 | m_program = m_context3D.createProgram(); 119 | m_program.upload( vertexShaderAssembler.agalcode, fragmentShaderAssembler.agalcode ); 120 | } 121 | 122 | protected function genGeom():void { 123 | const nobjsPerLevel:int = 4; 124 | m_nObjs = 0; 125 | 126 | var i:int; 127 | var objsOnLevel:int = 1; 128 | 129 | for ( i = 0; i < m_levels; i++ ) { 130 | m_nObjs += objsOnLevel; 131 | objsOnLevel *= nobjsPerLevel; 132 | } 133 | 134 | m_indexBufferSize = 3 * 4 * m_nObjs; // 3 indices * 4 tris * nobjs 135 | m_vertexBufferSize = 8 * m_nObjs; // 4 vertices * nobjs 136 | 137 | m_indexBuffer = m_context3D.createIndexBuffer( m_indexBufferSize ); 138 | m_vertexBuffer = m_context3D.createVertexBuffer( m_vertexBufferSize, 2 ); // x, y 139 | 140 | m_indexData = new Vector.( m_indexBufferSize ); 141 | m_vertexData = new Vector.( m_vertexBufferSize * 2 ); 142 | 143 | genLevel( 0, 0, 0, 0, 0 ); 144 | 145 | m_indexBuffer.uploadFromVector( m_indexData, 0, 12 * m_nObjs ); 146 | m_vertexBuffer.uploadFromVector( m_vertexData, 0, 8 * m_nObjs ); 147 | } 148 | 149 | protected function genLevel( level:int, ox:Number, oy:Number, indexindex:uint, vertexindex:uint ):Object { 150 | var ii : uint = indexindex; 151 | var vi : uint = vertexindex; 152 | var s:Number = 1.0 / ( 1 << level ); 153 | var d:Number = 1.0 / 16.0; 154 | 155 | /* 156 | diagonal rectangles 157 | m_vertexData[ vi * 2 + 0 ] = ox; 158 | m_vertexData[ vi * 2 + 1 ] = oy + s * d; 159 | m_vertexData[ vi * 2 + 2 ] = ox + s * ( 2.0 - d ); 160 | m_vertexData[ vi * 2 + 3 ] = oy + s * 2.0; 161 | m_vertexData[ vi * 2 + 4 ] = ox + s * 2.0; 162 | m_vertexData[ vi * 2 + 5 ] = oy + s * ( 2.0 - d ); 163 | m_vertexData[ vi * 2 + 6 ] = ox + s * d; 164 | m_vertexData[ vi * 2 + 7 ] = oy; 165 | */ 166 | 167 | /* vertical and horizontal cross 168 | m_vertexData[ vi * 2 + 0 ] = ox - s * d; 169 | m_vertexData[ vi * 2 + 1 ] = oy - s; 170 | m_vertexData[ vi * 2 + 2 ] = ox - s * d; 171 | m_vertexData[ vi * 2 + 3 ] = oy + s; 172 | m_vertexData[ vi * 2 + 4 ] = ox + s * d; 173 | m_vertexData[ vi * 2 + 5 ] = oy + s; 174 | m_vertexData[ vi * 2 + 6 ] = ox + s * d; 175 | m_vertexData[ vi * 2 + 7 ] = oy - s; 176 | 177 | m_vertexData[ vi * 2 + 8 ] = ox - s; 178 | m_vertexData[ vi * 2 + 9 ] = oy - s * d; 179 | m_vertexData[ vi * 2 + 10 ] = ox - s; 180 | m_vertexData[ vi * 2 + 11 ] = oy + s * d; 181 | m_vertexData[ vi * 2 + 12 ] = ox + s; 182 | m_vertexData[ vi * 2 + 13 ] = oy + s * d; 183 | m_vertexData[ vi * 2 + 14 ] = ox + s; 184 | m_vertexData[ vi * 2 + 15 ] = oy - s * d; 185 | */ 186 | 187 | /* vertical and horizontal chevrons */ 188 | m_vertexData[ vi * 2 + 0 ] = ox - s * d; 189 | m_vertexData[ vi * 2 + 1 ] = oy - s; 190 | m_vertexData[ vi * 2 + 2 ] = ox - s * d; 191 | m_vertexData[ vi * 2 + 3 ] = oy + s * d; 192 | m_vertexData[ vi * 2 + 4 ] = ox + s * d; 193 | m_vertexData[ vi * 2 + 5 ] = oy + s * d; 194 | m_vertexData[ vi * 2 + 6 ] = ox + s * d; 195 | m_vertexData[ vi * 2 + 7 ] = oy - s; 196 | 197 | m_vertexData[ vi * 2 + 8 ] = ox - s; 198 | m_vertexData[ vi * 2 + 9 ] = oy - s * d; 199 | m_vertexData[ vi * 2 + 10 ] = ox - s; 200 | m_vertexData[ vi * 2 + 11 ] = oy + s * d; 201 | m_vertexData[ vi * 2 + 12 ] = ox + s * d; 202 | m_vertexData[ vi * 2 + 13 ] = oy + s * d; 203 | m_vertexData[ vi * 2 + 14 ] = ox + s * d; 204 | m_vertexData[ vi * 2 + 15 ] = oy - s * d; 205 | 206 | // m_vertexData[ 0 ] = -1; 207 | // m_vertexData[ 1 ] = -1; 208 | // m_vertexData[ 2 ] = -1; 209 | // m_vertexData[ 3 ] = 1; 210 | // m_vertexData[ 4 ] = 1; 211 | // m_vertexData[ 5 ] = 1; 212 | // m_vertexData[ 6 ] = 1; 213 | // m_vertexData[ 7 ] = -1; 214 | 215 | m_indexData[ indexindex + 0 ] = vi + 0; 216 | m_indexData[ indexindex + 1 ] = vi + 1; 217 | m_indexData[ indexindex + 2 ] = vi + 2; 218 | m_indexData[ indexindex + 3 ] = vi + 0; 219 | m_indexData[ indexindex + 4 ] = vi + 2; 220 | m_indexData[ indexindex + 5 ] = vi + 3; 221 | 222 | m_indexData[ indexindex + 6 ] = vi + 4; 223 | m_indexData[ indexindex + 7 ] = vi + 5; 224 | m_indexData[ indexindex + 8 ] = vi + 6; 225 | m_indexData[ indexindex + 9 ] = vi + 4; 226 | m_indexData[ indexindex + 10 ] = vi + 6; 227 | m_indexData[ indexindex + 11 ] = vi + 7; 228 | 229 | ii += 12; 230 | vi += 8; // 16 floats (x, y) to make 8 vertices 231 | 232 | if ( level + 1 < m_levels ) { 233 | 234 | var obj : Object; 235 | 236 | obj = genLevel( level + 1, ox - s / 2, oy + s / 2, ii, vi ); 237 | ii = obj.ii; 238 | vi = obj.vi; 239 | 240 | obj = genLevel( level + 1, ox + s / 2, oy + s / 2, ii, vi ); 241 | ii = obj.ii; 242 | vi = obj.vi; 243 | 244 | obj = genLevel( level + 1, ox - s / 2, oy - s / 2, ii, vi ); 245 | ii = obj.ii; 246 | vi = obj.vi; 247 | 248 | obj = genLevel( level + 1, ox + s / 2, oy - s / 2, ii, vi ); 249 | ii = obj.ii; 250 | vi = obj.vi; 251 | } 252 | 253 | return { ii:ii, vi:vi }; 254 | } 255 | } 256 | } -------------------------------------------------------------------------------- /src/com/adobe/example/GPUSprite/GPUSpriteRenderLayer.as: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011, Adobe Systems Incorporated 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | * Neither the name of Adobe Systems Incorporated nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | package com.adobe.example.GPUSprite 34 | { 35 | import com.adobe.utils.AGALMiniAssembler; 36 | 37 | import flash.display.BitmapData; 38 | import flash.display3D.Context3D; 39 | import flash.display3D.Context3DBlendFactor; 40 | import flash.display3D.Context3DCompareMode; 41 | import flash.display3D.Context3DProgramType; 42 | import flash.display3D.Context3DTextureFormat; 43 | import flash.display3D.Context3DVertexBufferFormat; 44 | import flash.display3D.IndexBuffer3D; 45 | import flash.display3D.Program3D; 46 | import flash.display3D.VertexBuffer3D; 47 | import flash.display3D.textures.Texture; 48 | import flash.geom.Matrix; 49 | import flash.geom.Matrix3D; 50 | import flash.geom.Point; 51 | import flash.geom.Rectangle; 52 | 53 | public class GPUSpriteRenderLayer 54 | { 55 | internal var _spriteSheet : GPUSpriteSheet; // for now each layer is backed by a single, static sprite sheet 56 | internal var _vertexData : Vector.; 57 | internal var _indexData : Vector.; 58 | internal var _uvData : Vector.; 59 | 60 | protected var _context3D : Context3D; 61 | protected var _parent : GPUSpriteRenderStage; 62 | protected var _children : Vector.; 63 | 64 | protected var _indexBuffer : IndexBuffer3D; 65 | protected var _vertexBuffer : VertexBuffer3D; 66 | protected var _uvBuffer : VertexBuffer3D; 67 | protected var _shaderProgram : Program3D; 68 | protected var _updateVBOs : Boolean; 69 | 70 | 71 | public function GPUSpriteRenderLayer(context3D:Context3D, spriteSheet:GPUSpriteSheet) 72 | { 73 | _context3D = context3D; 74 | _spriteSheet = spriteSheet; 75 | 76 | _vertexData = new Vector.(); 77 | _indexData = new Vector.(); 78 | _uvData = new Vector.(); 79 | 80 | _children = new Vector.; 81 | _updateVBOs = true; 82 | setupShaders(); 83 | updateTexture(); 84 | } 85 | 86 | public function get parent() : GPUSpriteRenderStage 87 | { 88 | return _parent; 89 | } 90 | 91 | public function set parent(parentStage:GPUSpriteRenderStage) : void 92 | { 93 | _parent = parentStage; 94 | } 95 | 96 | public function get numChildren() : uint 97 | { 98 | return _children.length; 99 | } 100 | 101 | // Constructs a new child sprite and attaches it to the layer 102 | public function createChild(spriteId:uint) : GPUSprite 103 | { 104 | var sprite : GPUSprite = new GPUSprite(); 105 | addChild(sprite, spriteId); 106 | return sprite; 107 | } 108 | 109 | public function addChild(sprite:GPUSprite, spriteId:uint) : void 110 | { 111 | sprite._parent = this; 112 | sprite._spriteId = spriteId; 113 | 114 | // Add to list of children 115 | sprite._childId = _children.length; 116 | _children.push(sprite); 117 | 118 | // Add vertex data required to draw child 119 | var childVertexFirstIndex:uint = (sprite._childId * 12) / 3; 120 | _vertexData.push(0, 0, 1, 0, 0,1, 0, 0,1, 0, 0,1); // placeholders 121 | _indexData.push(childVertexFirstIndex, childVertexFirstIndex+1, childVertexFirstIndex+2, childVertexFirstIndex, childVertexFirstIndex+2, childVertexFirstIndex+3); 122 | 123 | var childUVCoords:Vector. = _spriteSheet.getUVCoords(spriteId); 124 | _uvData.push( 125 | childUVCoords[0], childUVCoords[1], 126 | childUVCoords[2], childUVCoords[3], 127 | childUVCoords[4], childUVCoords[5], 128 | childUVCoords[6], childUVCoords[7]); 129 | 130 | _updateVBOs = true; 131 | } 132 | 133 | public function removeChild(child:GPUSprite) : void 134 | { 135 | var childId:uint = child._childId; 136 | if ( (child._parent == this) && childId < _children.length ) { 137 | child._parent = null; 138 | _children.splice(childId, 1); 139 | 140 | // Update child id (index into array of children) for remaining children 141 | var idx:uint; 142 | for ( idx = childId; idx < _children.length; idx++ ) { 143 | _children[idx]._childId = idx; 144 | } 145 | 146 | // Realign vertex data with updated list of children 147 | var vertexIdx:uint = childId * 12; 148 | var indexIdx:uint= childId * 6; 149 | _vertexData.splice(vertexIdx, 12); 150 | _indexData.splice(indexIdx, 6); 151 | _uvData.splice(vertexIdx, 8); 152 | 153 | _updateVBOs = true; 154 | } 155 | } 156 | 157 | public function draw() : void 158 | { 159 | var nChildren:uint = _children.length; 160 | if ( nChildren == 0 ) return; 161 | 162 | // Update vertex data with current position of children 163 | for ( var i:uint = 0; i < nChildren; i++ ) { 164 | updateChildVertexData(_children[i]); 165 | } 166 | 167 | _context3D.setProgram(_shaderProgram); 168 | _context3D.setBlendFactors(Context3DBlendFactor.ONE, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA); 169 | _context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, _parent.modelViewMatrix, true); 170 | _context3D.setTextureAt(0, _spriteSheet._texture); 171 | 172 | if ( _updateVBOs ) { 173 | _vertexBuffer = _context3D.createVertexBuffer(_vertexData.length/3, 3); 174 | _indexBuffer = _context3D.createIndexBuffer(_indexData.length); 175 | _uvBuffer = _context3D.createVertexBuffer(_uvData.length/2, 2); 176 | _indexBuffer.uploadFromVector(_indexData, 0, _indexData.length); // indices won't change 177 | _uvBuffer.uploadFromVector(_uvData, 0, _uvData.length / 2); // child UVs won't change 178 | _updateVBOs = false; 179 | } 180 | 181 | 182 | _vertexBuffer.uploadFromVector(_vertexData, 0, _vertexData.length / 3); 183 | _context3D.setVertexBufferAt(0, _vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3); 184 | _context3D.setVertexBufferAt(1, _uvBuffer, 0, Context3DVertexBufferFormat.FLOAT_2); 185 | 186 | _context3D.drawTriangles(_indexBuffer, 0, nChildren * 2); 187 | } 188 | 189 | protected function setupShaders() : void 190 | { 191 | var vertexShaderAssembler:AGALMiniAssembler = new AGALMiniAssembler(); 192 | vertexShaderAssembler.assemble( Context3DProgramType.VERTEX, 193 | "dp4 op.x, va0, vc0 \n"+ // transform from stream 0 to output clipspace 194 | "dp4 op.y, va0, vc1 \n"+ 195 | //"dp4 op.z, va0, vc2 \n"+ 196 | "mov op.z, vc2.z \n"+ 197 | "mov op.w, vc3.w \n"+ 198 | "mov v0, va1.xy \n"+ // copy texcoord from stream 1 to fragment program 199 | "mov v0.z, va0.z \n" // copy alpha from stream 0 to fragment program 200 | ); 201 | 202 | var fragmentShaderAssembler:AGALMiniAssembler = new AGALMiniAssembler(); 203 | fragmentShaderAssembler.assemble( Context3DProgramType.FRAGMENT, 204 | "tex ft0, v0, fs0 <2d,clamp,linear,mipnearest> \n"+ 205 | "mul ft0, ft0, v0.zzzz\n" + 206 | "mov oc, ft0 \n" 207 | ); 208 | 209 | _shaderProgram = _context3D.createProgram(); 210 | _shaderProgram.upload( vertexShaderAssembler.agalcode, fragmentShaderAssembler.agalcode ); 211 | } 212 | 213 | protected function updateTexture() : void 214 | { 215 | _spriteSheet.uploadTexture(_context3D); 216 | } 217 | 218 | protected function updateChildVertexData(sprite:GPUSprite) : void 219 | { 220 | var childVertexIdx:uint = sprite._childId * 12; 221 | 222 | if ( sprite.visible ) { 223 | var x:Number = sprite.position.x; 224 | var y:Number = sprite.position.y; 225 | var rect:Rectangle = sprite.rect; 226 | var sinT:Number = Math.sin(sprite.rotation); 227 | var cosT:Number = Math.cos(sprite.rotation); 228 | var alpha:Number = sprite.alpha; 229 | 230 | var scaledWidth:Number = rect.width * sprite.scaleX; 231 | var scaledHeight:Number = rect.height * sprite.scaleY; 232 | var centerX:Number = scaledWidth * 0.5; 233 | var centerY:Number = scaledHeight * 0.5; 234 | 235 | _vertexData[childVertexIdx] = x - (cosT * centerX) - (sinT * (scaledHeight - centerY)); 236 | _vertexData[childVertexIdx+1] = y - (sinT * centerX) + (cosT * (scaledHeight - centerY)); 237 | _vertexData[childVertexIdx+2] = alpha; 238 | 239 | _vertexData[childVertexIdx+3] = x - (cosT * centerX) + (sinT * centerY); 240 | _vertexData[childVertexIdx+4] = y - (sinT * centerX) - (cosT * centerY); 241 | _vertexData[childVertexIdx+5] = alpha; 242 | 243 | _vertexData[childVertexIdx+6] = x + (cosT * (scaledWidth - centerX)) + (sinT * centerY); 244 | _vertexData[childVertexIdx+7] = y + (sinT * (scaledWidth - centerX)) - (cosT * centerY); 245 | _vertexData[childVertexIdx+8] = alpha; 246 | 247 | _vertexData[childVertexIdx+9] = x + (cosT * (scaledWidth - centerX)) - (sinT * (scaledHeight - centerY)); 248 | _vertexData[childVertexIdx+10] = y + (sinT * (scaledWidth - centerX)) + (cosT * (scaledHeight - centerY)); 249 | _vertexData[childVertexIdx+11] = alpha; 250 | 251 | } 252 | else { 253 | for (var i:uint = 0; i < 12; i++ ) { 254 | _vertexData[childVertexIdx+i] = 0; 255 | } 256 | } 257 | } 258 | } 259 | } -------------------------------------------------------------------------------- /src/com/adobe/utils/Sprite3D.as: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011, Adobe Systems Incorporated 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | * Neither the name of Adobe Systems Incorporated nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | package com.adobe.utils 33 | { 34 | import com.adobe.utils.AGALMiniAssembler; 35 | 36 | import flash.display3D.*; 37 | import flash.display3D.textures.*; 38 | import flash.display3D.textures.Texture; 39 | import flash.geom.ColorTransform; 40 | import flash.geom.Matrix; 41 | import flash.geom.Point; 42 | import flash.geom.Rectangle; 43 | 44 | public class Sprite3D 45 | { 46 | public function Sprite3D(texture:Texture, 47 | textureWidth:uint, 48 | textureHeight:uint, 49 | descriptor:XML = null, 50 | descriptorFormat:String = "cocos2d", 51 | registrationPoint:String = "center") 52 | { 53 | _texture = texture; 54 | 55 | var sizes:Vector. = new Vector.(); 56 | var offsets:Vector. = new Vector.(); 57 | var frames:Vector. = new Vector.(); 58 | 59 | if ( descriptor != null ) { 60 | if ( descriptorFormat == "cocos2d" ) { 61 | parseCocos2D(descriptor,sizes,offsets,frames); 62 | } else { 63 | throw new Error("Unknown descriptor format"); 64 | } 65 | } else { 66 | frames.push(new Rectangle(0,0,textureWidth,textureHeight)); 67 | offsets.push(new Point(0,0)); 68 | sizes.push(new Point(textureWidth,textureHeight)); 69 | } 70 | 71 | createVertices(registrationPoint,sizes,offsets,frames,textureWidth,textureHeight); 72 | } 73 | 74 | public static function init(context3D:Context3D, 75 | backBufferWidth:uint, 76 | backBufferHeight:uint):void 77 | { 78 | _context3D = context3D; 79 | 80 | _backBufferWidth = backBufferWidth; _backBufferHeight = backBufferHeight; 81 | _backBufferWidthInv = 1.0/_backBufferWidth; _backBufferHeightInv = 1.0/_backBufferHeight; 82 | 83 | for ( var c:uint=0; c<12; c++) _matrixVector[c] = 0.0; 84 | _matrixVector[3] = 1.0; _matrixVector[7] = 1.0; _matrixVector[11] = 1.0; 85 | 86 | var vertexShader:AGALMiniAssembler = new AGALMiniAssembler(); 87 | vertexShader.assemble( Context3DProgramType.VERTEX, 88 | "mov vt0.xyzw, va0.xyww\n" + 89 | "m33 vt0.xyz, vt0, vc0\n" + 90 | "mov op, vt0\n" + 91 | "mov v0, va1\n" 92 | ); 93 | var fragmentShader:AGALMiniAssembler = new AGALMiniAssembler(); 94 | fragmentShader.assemble( Context3DProgramType.FRAGMENT, 95 | "tex oc, v0, fs0 <2d,linear,miplinear>\n" 96 | ); 97 | _shaderProgram = _context3D.createProgram(); 98 | _shaderProgram.upload( vertexShader.agalcode, fragmentShader.agalcode); 99 | 100 | var fragmentShaderAlpha:AGALMiniAssembler = new AGALMiniAssembler(); 101 | fragmentShaderAlpha.assemble( Context3DProgramType.FRAGMENT, 102 | "tex ft0, v0, fs0 <2d,linear,miplinear>\n" + 103 | "mul oc, ft0, fc0\n" 104 | ); 105 | _shaderProgramAlpha = _context3D.createProgram(); 106 | _shaderProgramAlpha.upload( vertexShader.agalcode, fragmentShaderAlpha.agalcode); 107 | 108 | var fragmentShaderColorTransform:AGALMiniAssembler = new AGALMiniAssembler(); 109 | fragmentShaderColorTransform.assemble( Context3DProgramType.FRAGMENT, 110 | "tex ft0, v0, fs0 <2d,linear,miplinear>\n" + 111 | "mul ft0, ft0, fc0\n" + 112 | "add oc, ft0, fc1\n" 113 | ); 114 | _shaderProgramColorTransform = _context3D.createProgram(); 115 | _shaderProgramColorTransform.upload( vertexShader.agalcode, fragmentShaderColorTransform.agalcode); 116 | } 117 | 118 | public function set rotation(angle:Number):void { _rotation = angle; } 119 | public function get rotation():Number { return _rotation; } 120 | 121 | public function set scaleX(scale:Number):void { _scaleX = scale; } 122 | public function get scaleX():Number { return _scaleX; } 123 | 124 | public function set scaleY(scale:Number):void { _scaleY = scale; } 125 | public function get scaleY():Number { return _scaleY; } 126 | 127 | public function set scale(scale:Number):void { _scaleX = _scaleY = scale; } 128 | public function get scale():Number { return _scaleY; } 129 | 130 | public function set x(pos:Number):void { _posX = pos; } 131 | public function get x():Number { return _posX; } 132 | 133 | public function set y(pos:Number):void { _posY = pos; } 134 | public function get y():Number { return _posY; } 135 | 136 | public function set frame(frame:uint):void { _frame = frame; } 137 | public function get frame():uint { return _frame; } 138 | 139 | public function set alpha(alpha:Number):void { _alpha = alpha; } 140 | public function get alpha():Number { return _alpha; } 141 | 142 | public function set colorTransform(colorTransform:ColorTransform):void { _colorTransform = colorTransform; } 143 | public function get colorTransform():ColorTransform { return _colorTransform; } 144 | 145 | public function render():void 146 | { 147 | if ( _colorTransform == null || colorTransformIsIdentity() ) { 148 | if ( _alpha == 1.0 ) { 149 | _context3D.setProgram(_shaderProgram); 150 | } else { 151 | _context3D.setProgram(_shaderProgramAlpha); 152 | _transformVector[0] = 1.0; _transformVector[1] = 1.0; _transformVector[2] = 1.0; _transformVector[3] = _alpha; 153 | _context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, _transformVector, 1); 154 | } 155 | } else { 156 | _context3D.setProgram(_shaderProgramColorTransform); 157 | _transformVector[0] = _colorTransform.redMultiplier; _transformVector[1] = _colorTransform.greenMultiplier; 158 | _transformVector[2] = _colorTransform.blueMultiplier; _transformVector[3] = _colorTransform.alphaMultiplier; 159 | _transformVector[4] = _colorTransform.redOffset*(1./255.); _transformVector[5] = _colorTransform.greenOffset*(1./255.); 160 | _transformVector[6] = _colorTransform.blueOffset*(1./255.); _transformVector[7] = _colorTransform.alphaOffset*(1./255.); 161 | _context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, _transformVector, 2); 162 | } 163 | _matrix.createBox(_scaleX,_scaleY, 164 | _rotation*_gradToRad, 165 | _posX-_backBufferWidth, 166 | _backBufferHeight-_posY); 167 | _matrix.scale(_backBufferWidthInv,_backBufferHeightInv); 168 | _matrixVector[0] = _matrix.a; _matrixVector[1] = _matrix.c; _matrixVector[2] = _matrix.tx; 169 | _matrixVector[4] = _matrix.b; _matrixVector[5] = _matrix.d; _matrixVector[6] = _matrix.ty; 170 | _context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 0, _matrixVector, 3); 171 | _context3D.setTextureAt(0, _texture); 172 | _context3D.setVertexBufferAt(0, _vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_2); 173 | _context3D.setVertexBufferAt(1, _vertexBuffer, 2, Context3DVertexBufferFormat.FLOAT_2); 174 | _context3D.drawTriangles(_indexBuffer, (_frame%_frameCount)*6, 2); 175 | } 176 | 177 | private function createVertices(registrationPoint:String, 178 | sizes:Vector., 179 | offsets:Vector., 180 | frames:Vector., 181 | textureWidth:uint, 182 | textureHeight:uint):void 183 | { 184 | var v:uint = 0; 185 | var i:uint = 0; 186 | 187 | var vd:Vector. = new Vector.(frames.length*16); 188 | var id:Vector. = new Vector.(frames.length*6); 189 | 190 | for ( var c:uint = 0; c 0 ) { 203 | var ox:Number = offsets[c].x; 204 | var oy:Number = offsets[c].y; 205 | x0 += ox*2; 206 | y0 += oy*2; 207 | x1 += ox*2; 208 | y1 += oy*2; 209 | } 210 | 211 | if ( registrationPoint != "center" ) { 212 | var sx:Number; 213 | var sy:Number; 214 | if ( sizes.length > 0 ) { 215 | sx = sizes[c].x; 216 | sy = sizes[c].y; 217 | } else { 218 | sx = frames[0].width; 219 | sy = frames[0].height; 220 | } 221 | switch ( registrationPoint ) { 222 | case "lefttop": { 223 | x0 += sx; 224 | y0 -= sy; 225 | x1 += sx; 226 | y1 -= sy; 227 | } break; 228 | case "righttop": { 229 | x0 -= sx; 230 | y0 -= sy; 231 | x1 -= sx; 232 | y1 -= sy; 233 | } break; 234 | case "leftbottom": { 235 | x0 += sx; 236 | y0 += sy; 237 | x1 += sx; 238 | y1 += sy; 239 | } break; 240 | case "rightbottom": { 241 | x0 -= sx; 242 | y0 += sy; 243 | x1 -= sx; 244 | y1 += sy; 245 | } break; 246 | } 247 | } 248 | 249 | var u0:Number = (x ) / textureWidth; 250 | var v0:Number = (y ) / textureHeight; 251 | var u1:Number = (x+w) / textureWidth; 252 | var v1:Number = (y+h) / textureHeight; 253 | 254 | vd[v++] = x0; vd[v++] = y0; vd[v++] = u0; vd[v++] = v0; 255 | vd[v++] = x1; vd[v++] = y0; vd[v++] = u1; vd[v++] = v0; 256 | vd[v++] = x1; vd[v++] = y1; vd[v++] = u1; vd[v++] = v1; 257 | vd[v++] = x0; vd[v++] = y1; vd[v++] = u0; vd[v++] = v1; 258 | 259 | id[i++] = (c*4+0); id[i++] = (c*4+1); id[i++] = (c*4+3); 260 | id[i++] = (c*4+1); id[i++] = (c*4+2); id[i++] = (c*4+3); 261 | 262 | } 263 | 264 | _frameCount = frames.length; 265 | _indexBuffer = _context3D.createIndexBuffer( id.length ); 266 | _indexBuffer.uploadFromVector(id, 0, id.length ); 267 | _vertexBuffer = _context3D.createVertexBuffer( vd.length/4, 4); 268 | _vertexBuffer.uploadFromVector(vd, 0, vd.length/4); 269 | 270 | } 271 | 272 | 273 | private function parseCocos2D(descriptor:XML, 274 | sizes:Vector., 275 | offsets:Vector., 276 | frames:Vector.):void { 277 | 278 | // Not very generic, only tested with TexturePacker 279 | 280 | var type:String; 281 | var data:String; 282 | var array:Array; 283 | 284 | var topKeys:XMLList = descriptor.dict.key; 285 | var topDicts:XMLList = descriptor.dict.dict; 286 | 287 | for ( var k:uint = 0; k = new Vector.(); 371 | private static var _transformVector:Vector. = new Vector.(); 372 | private static var _shaderProgram:Program3D = null; 373 | private static var _shaderProgramAlpha:Program3D = null; 374 | private static var _shaderProgramColorTransform:Program3D = null; 375 | private static var _context3D:Context3D = null; 376 | private static var _backBufferWidth:uint = 0; 377 | private static var _backBufferHeight:uint = 0; 378 | private static var _backBufferWidthInv:Number = 0; 379 | private static var _backBufferHeightInv:Number = 0; 380 | 381 | private static const _gradToRad:Number = (2*Math.PI/360); 382 | } 383 | } 384 | -------------------------------------------------------------------------------- /src/com/adobe/utils/AGALMacroAssembler.as: -------------------------------------------------------------------------------- 1 | // ================================================================================ 2 | // 3 | // ADOBE SYSTEMS INCORPORATED 4 | // Copyright 2011 Adobe Systems Incorporated 5 | // All Rights Reserved. 6 | // 7 | // NOTICE: Adobe permits you to use, modify, and distribute this file 8 | // in accordance with the terms of the license agreement accompanying it. 9 | // 10 | // ================================================================================ 11 | package com.adobe.utils 12 | { 13 | // =========================================================================== 14 | // Imports 15 | // --------------------------------------------------------------------------- 16 | //import flash.display3D.*; 17 | import com.adobe.utils.macro.AGALPreAssembler; 18 | import com.adobe.utils.macro.AGALVar; 19 | 20 | import flash.display.Stage; 21 | import flash.utils.*; 22 | 23 | /** 24 | * AGALMacroAssembler 25 | *

A richer version of the AGALMiniAssembler. The MacroAssembler is 26 | * a macro based assembly substitution "compiler". Basically it adds 27 | * some nice, more human readable syntax to the MiniAssembler.

28 | * 29 | *

It never generates temporaries and doesn't have an AST. (Use PixelBender for that.)

30 | * 31 | *

Features:

32 | *
    33 | *
  • Math expressions on float4: addition, subtraction, multiplication, division, negation. 34 | * Note that expression must be simple operations.
  • 35 |
     36 |  	a = b ~~ c;			// Simple binary operation
     37 | 	a = -a;				// Simple unary operation
     38 | 	a = b~~c + d;		// Bonus: multiply-add is supported
     39 | 	a = b~~c + d~~c;	// ERROR! this isn't simple enough. (3 binary operations)
     40 | 
    41 | *
  • Macro definitions. Like functions, but are actually substitutions 42 | * into your code. The actual operation is very 43 | * similar to the C preprocessor. The Macros are processed 44 | * ahead of parsing, so order order doesn't matter, and A() can call B() as well as B() calling A(). 45 | * Recursion is not supported (or possible.).
  • 46 |
     47 |  	macro Foo( arg0 ) {
     48 | 		out = arg0;	// 'out' is always the return value.	 
     49 | 	}
     50 | 
    51 | *
  • Aliases. Very handy for keeping track of your attribute and constant registers. It's 52 | * a good idea to start any AGALMacro program with an alias block, that defines the mapping from 53 | * the shader to the constant pool and vertex stream.
  • 54 |
     55 | 	alias va0, pos
     56 | 	alias vc0, objToClip
     57 | 	
     58 | 	op = MultMat4x4( pos, objToClip );
     59 | 
    60 | *
  • Constant use. All constants must be in the constant pool. However, if you tell 61 | * the macro assembler about your constants, it can use them automatically. You can also 62 | * query what constants are expected by a shader. The 'aliases' member contains information 63 | * about all the aliases and constants used by the shader.
  • 64 |
     65 | 	alias vc0, CONST_0( 0.5, 1 );	// declares that vc0.x=0.5 and vc0.y=1. This must be true in your constant pool. 
     66 | 	macro Half( arg0 ) {
     67 | 		out = arg0 ~~ 0.5;			// will automatically use vc0.x, since you declared this to be 0.5
     68 | 	}
     69 | 	 
     70 | 
    71 | *
  • Pre-processor. Sometimes you will one a shader to have multiple 72 | * flavors. For example: 73 |
     74 | 	ft0 = tex<2d,linear,miplinear>( v0, fs0 );
     75 | 	#if USE_ALPHA;
     76 | 	 	ft0 = ft0 * fc_alpha;
     77 | 	#endif;
     78 | 	#if USE_COLOR_XFORM;
     79 | 		ft0 = ft0 + fc_colorXForm;
     80 | 	#endif;
     81 | 	oc = ft0;
     82 | 
    83 | Can be configured 4 ways with USE_ALPHA and USE_COLOR_XFORM on and off. You can easily 84 | compile an minimal, efficient shader with just alpha support by saying: 85 |
     86 |  	macroAssembler.assemble( "USE_ALPHA=1;" + SHADER_SRC_STRING );
     87 | 
    88 | The preprocessor supports the following operations: 89 |
     90 | 	#define FOO num
     91 | 	#define FOO
     92 | 	#define FOO=
     93 | 	#undef FOO	
     94 | 	
     95 | 	#if 
     96 | 	#elif 
     97 | 	#else
     98 | 	#endif	 	
     99 | 
    100 | Note that the preprocessor does NOT (currently) support the notions of "is defined". A variable has a value. 101 | The expression parser is rich and follows the c precedence rules. 102 |
    103 | 	#if VAR_ONE*VAR_TWO+VAR_THREE != VAR_ONE+VAR_THREE*VAR_TWO
    104 | 	   ... 
    105 | 	#endif 	
    106 | 
    107 | *
  • 108 |
  • Simple standard library. The following macros are always available: 109 |
    110 |  	ft0 = tex<2d,linear,miplinear>( v0, fs0 );		Function syntax for textures.
    111 | 	ft0 = mul3x3( vec, mat )						Matrix multiplication
    112 | 	ft0 = mul4x4( vec, mat )						Matrix multiplication
    113 |  
    114 |
  • 115 | 116 | *
117 | */ 118 | public class AGALMacroAssembler extends AGALMiniAssembler 119 | { 120 | // ====================================================================== 121 | // Properties 122 | // ---------------------------------------------------------------------- 123 | /** The generated AGAL Mini Assembler code. Available after the call to assemble().*/ 124 | public var asmCode:String = ""; 125 | 126 | private var isFrag:Boolean = false; 127 | public var profile:Boolean = false; 128 | public var profileTrace:String = ""; 129 | 130 | private var stages:Vector. = null; 131 | 132 | // ====================================================================== 133 | // Constructor 134 | // ---------------------------------------------------------------------- 135 | public function AGALMacroAssembler( debugging:Boolean = false ):void 136 | { 137 | super( debugging ); 138 | } 139 | // ====================================================================== 140 | // Methods 141 | // ---------------------------------------------------------------------- 142 | 143 | private static const REGEXP_LINE_BREAKER:RegExp = /[\f\n\r\v;]+/g; 144 | private static const COMMENT:RegExp = /\/\/[^\n]*\n/g 145 | 146 | private var macros:Dictionary = new Dictionary(); 147 | /** After assemble() is called, the aliases contain 148 | * information about all the variables used in the 149 | * shader. Of particular important is the constant 150 | * registers that are required to be set for the 151 | * shader to function. Each alias is of type AGALVar. 152 | * A constant, required to be set, will have agalVar.isConstant() == true 153 | */ 154 | public var aliases:Dictionary = new Dictionary(); 155 | 156 | private var tokens:Vector. = null; 157 | private var types:String = ""; 158 | private var preproc:AGALPreAssembler = new AGALPreAssembler(); 159 | 160 | // Takes a string input, normalizes newlines, and removes comments. 161 | private function cleanInput( source:String ):String 162 | { 163 | // Pull out the c-style comments first. 164 | var start:int = source.indexOf( "/*" ); 165 | while( start >= 0 ) { 166 | var end:int = source.indexOf( "*/", start+1 ); 167 | if ( end < 0 ) throw new Error( "Comment end not found." ); 168 | 169 | source = source.substr( 0, start ) + source.substr( end+2 ); 170 | start = source.indexOf( "/*" ); 171 | } 172 | 173 | source = source.replace( REGEXP_LINE_BREAKER, "\n" ); 174 | source = source.replace( COMMENT, "" ); 175 | return source; 176 | } 177 | 178 | public static const IDENTIFIER:RegExp = /((2d)|(3d)|[_a-zA-Z])+([_a-zA-Z0-9.]*)/ 179 | public static const NUMBER:RegExp = /[0-9]+(?:\.[0-9]*)?/ 180 | // Nasty regex, even by regex standards: 2 char ops 1 char ops 181 | public static const OPERATOR:RegExp = /(==)|(!=)|(<=)|(>=)|(&&)|(\|\|)|[*=+-\/()\[\]{}!<>&|]/; 182 | public static const SEPERATOR:RegExp = /\n/ 183 | public static const PREPROC:RegExp = /\#[a-z]+/ // # (space) identifier 184 | public static const TOKEN:RegExp = new RegExp( IDENTIFIER.source+"|"+ 185 | NUMBER.source+"|"+ 186 | SEPERATOR.source+"|"+ 187 | OPERATOR.source+"|"+ 188 | PREPROC.source, 189 | "g" ); 190 | 191 | private static const MACRO:RegExp = /([\w.]+)(\s*)=(\s*)(\w+)(\s*)\(/ 192 | 193 | /* @internal */ 194 | public static function joinTokens( tokens:Vector. ):String 195 | { 196 | var pos:int = 0; 197 | var newline:int = 0; 198 | var s:String = ""; 199 | var tokensLength:uint = tokens.length; 200 | 201 | while ( pos < tokensLength ) { 202 | if ( tokens[pos] == "\n" ) { 203 | ++pos; 204 | continue; 205 | } 206 | 207 | newline = tokens.indexOf( "\n", pos+1 ); 208 | if ( newline < 0 ) newline = tokensLength; 209 | 210 | s += tokens[pos++]; 211 | if ( pos < tokensLength && tokens[pos] != "." ) 212 | s += " "; 213 | 214 | while ( pos < newline ) { 215 | s += tokens[pos]; 216 | if ( tokens[pos] == "," ) 217 | s += " "; 218 | 219 | ++pos; 220 | } 221 | s += "\n"; 222 | pos = newline + 1; 223 | } 224 | return s; 225 | } 226 | 227 | private function tokenize( input:String ):Vector. 228 | { 229 | // Tokens: 230 | // identifiers: /w+ 231 | // operators: =+-/* 232 | return Vector.( input.match( TOKEN ) ); 233 | } 234 | 235 | private function tokenizeTypes( tokens:Vector. ):String 236 | { 237 | var types:String = ""; 238 | var tokensLength:uint = tokens.length; 239 | 240 | for( var i:uint=0; i = new Vector.( 0, true ); 278 | private function splice( pos:int, deleteCount:int, newTokens:Vector., newTypes:String ):void 279 | { 280 | if ( newTokens == null ) 281 | newTokens = emptyStringVector; 282 | if ( newTypes == null ) 283 | newTypes = ""; 284 | 285 | var t:Vector. = tokens.slice( 0, pos ); 286 | t = t.concat( newTokens ); 287 | t = t.concat( tokens.slice( pos+deleteCount ) ); 288 | tokens = t; 289 | 290 | types = types.substr( 0, pos ) + newTypes + types.substr( pos+deleteCount ); 291 | if ( types.length != tokens.length ) 292 | throw new Error( "AGAL.splice internal error. types.length=" + types.length + " tokens.length=" + tokens.length ); 293 | } 294 | 295 | private function basicOp( op:String, target:String, src1:String, src2:String ):String 296 | { 297 | return op + " " + target + ", " + src1 + ", " + src2; 298 | } 299 | 300 | private function convertMath( pos:int ):Boolean 301 | { 302 | // dest = rega 303 | // dest = rega + regb 304 | // dest = rega - regb 305 | // dest = rega / regb 306 | // dest = rega * regb 307 | // dest = -rega 308 | 309 | var end:int = types.indexOf( "n", pos+1 ); 310 | if ( end < pos+1 ) 311 | throw new Error( "End of expression not found." ); 312 | 313 | var body:String = ""; 314 | var s:String = types.substr( pos, end-pos ); 315 | switch( s ) { 316 | case "i=i": 317 | body = "mov "+tokens[pos+0]+", "+tokens[pos+2]; 318 | break; 319 | case "i=i+i": 320 | body = basicOp( "add", tokens[pos+0], tokens[pos+2], tokens[pos+4] ) 321 | break; 322 | case "i=i-i": 323 | body = basicOp( "sub", tokens[pos+0], tokens[pos+2], tokens[pos+4] ) 324 | break; 325 | case "i=i*i": 326 | body = basicOp( "mul", tokens[pos+0], tokens[pos+2], tokens[pos+4] ) 327 | break; 328 | case "i=i/i": 329 | body = basicOp( "div", tokens[pos+0], tokens[pos+2], tokens[pos+4] ) 330 | break; 331 | case "i=-i": 332 | body = "neg "+tokens[pos+0]+", "+tokens[pos+3]; 333 | break; 334 | 335 | case "i*=i": 336 | body = basicOp( "mul", tokens[pos+0], tokens[pos+0], tokens[pos+3] ); 337 | break; 338 | case "i/=i": 339 | body = basicOp( "div", tokens[pos+0], tokens[pos+0], tokens[pos+3] ); 340 | break; 341 | case "i+=i": 342 | body = basicOp( "add", tokens[pos+0], tokens[pos+0], tokens[pos+3] ); 343 | break; 344 | case "i-=i": 345 | body = basicOp( "sub", tokens[pos+0], tokens[pos+0], tokens[pos+3] ); 346 | break; 347 | 348 | case "i=i*i+i": 349 | body = basicOp( "mul", tokens[pos+0], tokens[pos+2], tokens[pos+4] ) + "\n" 350 | + basicOp( "add", tokens[pos+0], tokens[pos+0], tokens[pos+6] ) 351 | break; 352 | case "i=i+i*i": 353 | body = basicOp( "mul", tokens[pos+0], tokens[pos+4], tokens[pos+6] ) + "\n" 354 | + basicOp( "add", tokens[pos+0], tokens[pos+0], tokens[pos+2] ) 355 | break; 356 | 357 | default: 358 | return false; 359 | } 360 | if ( body.length > 0 ) { 361 | var tok:Vector. = tokenize( body ); 362 | var typ:String = tokenizeTypes( tok ); 363 | splice( pos, end-pos, tok, typ ); 364 | } 365 | return true; 366 | } 367 | 368 | // Add the macros to the internal table. 369 | // Returns a string without the macros. 370 | private function processMacro( pos:int ):void 371 | { 372 | // function Foo( arg0, arg1, arg2, ... ) 373 | var NAME:int = 1; 374 | var OPENPAREN:int = 2; 375 | var ARG0:int = 3; 376 | 377 | var openParen:int = 0; 378 | var closeParen:int = 0; 379 | var openBracket:int = 0; 380 | var closeBracket:int = 0; 381 | var i:int = 0; 382 | 383 | if ( tokens[pos] != "macro" ) throw new Error( "Expected 'macro' not found." ); 384 | 385 | openParen = pos+OPENPAREN; 386 | if ( tokens[openParen] != "(" ) 387 | throw new Error( "Macro open paren not found." ); 388 | 389 | closeParen = types.indexOf( ")", openParen+1 ); 390 | openBracket = types.indexOf( "{", closeParen+1 ); 391 | closeBracket = types.indexOf( "}", openBracket+1 ); 392 | 393 | var macro:Macro = new Macro(); // name, args, body 394 | macro.name = tokens[pos+NAME]; 395 | 396 | // normally: (a, b, c) 397 | // but also: (a, b, ) 398 | var argc:int = 0; 399 | for( i=openParen+1; i", openBracket+1 ); 425 | var eol:int = types.indexOf( "n", pos ); 426 | if ( eol < 0 ) eol = types.length; 427 | 428 | //oc = tex.<2d,linear,miplinear>( v0, fs0 ) 429 | // to: 430 | // tex oc, v0, fs0 <2d,linear,miplinear>" 431 | var s:String = "tex " + tokens[pos] + "," + tokens[openParen+1] + "," + tokens[openParen+3] + 432 | "<" + tokens.slice( openBracket+1, closeBracket ).join( "" ) + ">;"; 433 | 434 | var newTokens:Vector. = tokenize( s ); 435 | var newTypes:String = tokenizeTypes( newTokens ); 436 | 437 | splice( pos, eol-pos, newTokens, newTypes ); 438 | return pos + newTypes.length; 439 | } 440 | 441 | private function expandMacro( pos:int ):void 442 | { 443 | // Macro is: 444 | // ident = ident( 445 | 446 | var NAME:int = 2; 447 | var OPENPAREN:int = 3; 448 | var closeParen:int = 0; 449 | var i:uint = 0; 450 | 451 | var name:String = tokens[pos+NAME]; 452 | closeParen = types.indexOf( ")", pos+OPENPAREN ) - pos; 453 | var argc:int = ( closeParen - OPENPAREN ) / 2; 454 | var mangledName:String = createMangledName( name, argc ); 455 | 456 | if ( macros[ mangledName ] == null ) 457 | throw new Error( "Macro '"+mangledName+"' not found." ); 458 | var macro:Macro = macros[mangledName]; 459 | 460 | var output:String = tokens[pos]; 461 | var args:Vector. = tokens.slice( pos+OPENPAREN+1, pos+closeParen ); 462 | var body:Vector. = new Vector.(); 463 | var macroBodyLength:uint = macro.body.length; 464 | 465 | for ( i=0; i= 0 ) { 475 | body.push( args[2*index] ); // parameter substitution 476 | processed = true; 477 | } 478 | } 479 | } 480 | if ( !processed ) { 481 | body.push( macro.body[i] ); 482 | } 483 | } 484 | splice( pos, // where to start 485 | closeParen+1, 486 | body, macro.types ); 487 | } 488 | 489 | 490 | private function getConstant( numConst:String ):String 491 | { 492 | var num:Number = Number(numConst); 493 | 494 | // Search the aliases, with constants, for something that works. 495 | for each ( var agalVar:AGALVar in aliases ) { 496 | if ( agalVar.isConstant() ) { 497 | if ( agalVar.x == num ) return agalVar.target + ".x"; 498 | if ( agalVar.y == num ) return agalVar.target + ".y"; 499 | if ( agalVar.z == num ) return agalVar.target + ".z"; 500 | if ( agalVar.w == num ) return agalVar.target + ".w"; 501 | } 502 | } 503 | throw new Error( "Numeric constant used that is not declared in a constant register." ); 504 | return "error"; 505 | } 506 | 507 | private function readAlias( pos:int ):void 508 | { 509 | // "alias va3.x, xform0Ref \n" + 510 | // "alias va3.y, xform1Ref \n" + 511 | // "alias va3.z, weight0 \n" + 512 | 513 | if ( tokens[pos] == "alias" ) { 514 | var agalVar:AGALVar = new AGALVar(); 515 | 516 | agalVar.name = tokens[pos+3]; 517 | agalVar.target = tokens[pos+1]; 518 | aliases[ agalVar.name ] = agalVar; 519 | //trace( "alias name=" + agalVar.name + " target=" + agalVar.target ); 520 | 521 | if ( tokens[pos+4] == "(" ) { 522 | // Read the default value. 523 | var end:int = tokens.indexOf( ")", pos+5 ); 524 | if ( end < 0 ) throw new Error( "Closing paren of default alias value not found." ); 525 | 526 | agalVar.x = 0; 527 | agalVar.y = 0; 528 | agalVar.z = 0; 529 | agalVar.w = 0; 530 | 531 | if ( end > (pos+5) ) agalVar.x = Number( tokens[pos+5] ); 532 | if ( end > (pos+7) ) agalVar.y = Number( tokens[pos+7] ); 533 | if ( end > (pos+9) ) agalVar.z = Number( tokens[pos+9] ); 534 | if ( end > (pos+11) ) agalVar.w = Number( tokens[pos+11] ); 535 | } 536 | } 537 | } 538 | 539 | // Return the new pos. 540 | private function processTokens( pos:int, newline:int ):int 541 | { 542 | var brackets:int = 0; 543 | 544 | if ( types.length >= 4 && types.substr( pos, 4 ) == "i=i(" ) { 545 | // Macro! 546 | expandMacro( pos ); 547 | return pos; // re-process. Could be anything. 548 | } 549 | else if ( types.length >= 4 550 | && types.substr( pos, 4 ) == "i=i<" 551 | && tokens[pos+2] == "tex" ) 552 | { 553 | // Special texture handling. 554 | return expandTexture( pos ); 555 | } 556 | else if ( tokens[pos] == "alias" ) { 557 | readAlias( pos ); 558 | splice( pos, newline-pos+1, null, null ); 559 | return pos; 560 | } 561 | else if ( tokens[pos] == "macro" ) { 562 | processMacro( pos ); // macros remove themselves 563 | return pos; 564 | } 565 | 566 | 567 | // Substitute aliases 568 | // Substitute constants (a special kind of alias) 569 | for ( var p:int = pos; p(); 648 | stages.push( new PerfStage( "start" )); 649 | } 650 | isFrag = (mode=="fragment"); 651 | 652 | source = STDLIB + source; 653 | 654 | // Note that Macros are object scope (kept around from run to run) 655 | // but Alias are program scope 656 | aliases = new Dictionary(); 657 | 658 | source = cleanInput( source ); // C-style comments /* */ makes this a little tricky per line. 659 | tokens = tokenize( source ); 660 | types = tokenizeTypes( tokens ); 661 | 662 | mainLoop(); 663 | 664 | if ( profile ) { 665 | stages.push( new PerfStage( "join" )); 666 | } 667 | 668 | asmCode = joinTokens( tokens ); 669 | 670 | if ( profile ) { 671 | stages.push( new PerfStage( "mini" )); 672 | } 673 | var result:ByteArray = super.assemble( mode, asmCode ); 674 | if ( profile ) { 675 | stages.push( new PerfStage( "end" )); 676 | 677 | 678 | for( var k:int=0; k " + stages[k+1].name + " = " + ((stages[k+1].time-stages[k].time)/1000); 680 | trace( desc ); 681 | profileTrace += desc + "\n"; 682 | } 683 | } 684 | return result; 685 | } 686 | 687 | public static const STDLIB:String = 688 | // Matrix multiply 3x3 689 | "macro mul3x3( vec, mat ) {" + 690 | " m33 out, vec, mat; " + 691 | "}" + 692 | // Matrix multiply 4x5 693 | "macro mul4x4( vec, mat ) {" + 694 | " m44 out, vec, mat; " + 695 | "}" 696 | } 697 | 698 | } 699 | 700 | 701 | internal class Macro 702 | { 703 | public var mangledName:String = ""; 704 | public var name:String = ""; 705 | public var args:Vector. = new Vector.(); 706 | public var body:Vector. = new Vector.(); 707 | public var types:String = ""; 708 | 709 | public function traceMacro():void 710 | { 711 | trace( "Macro: " + name + " [" + mangledName + "]" ); 712 | trace( " args: " + args ); 713 | trace( "<==" ); 714 | var s:String = com.adobe.utils.AGALMacroAssembler.joinTokens( body ); 715 | trace( s ); 716 | trace( "==>" ); 717 | } 718 | } 719 | 720 | internal class PerfStage 721 | { 722 | import flash.utils.*; 723 | 724 | public var name:String; 725 | public var time:uint; 726 | 727 | public function PerfStage( name:String ) { 728 | this.name = name; 729 | this.time = getTimer(); 730 | } 731 | } -------------------------------------------------------------------------------- /src/com/adobe/utils/AGALMiniAssembler.as: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011, Adobe Systems Incorporated 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | * Neither the name of Adobe Systems Incorporated nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | package com.adobe.utils 33 | { 34 | // =========================================================================== 35 | // Imports 36 | // --------------------------------------------------------------------------- 37 | //import flash.display3D.*; 38 | import flash.utils.*; 39 | 40 | // =========================================================================== 41 | // Class 42 | // --------------------------------------------------------------------------- 43 | public class AGALMiniAssembler 44 | { 45 | // ====================================================================== 46 | // Constants 47 | // ---------------------------------------------------------------------- 48 | protected static const USE_NEW_SYNTAX:Boolean = false; 49 | 50 | protected static const REGEXP_OUTER_SPACES:RegExp = /^\s+|\s+$/g; 51 | 52 | // ====================================================================== 53 | // Properties 54 | // ---------------------------------------------------------------------- 55 | // AGAL bytes and error buffer 56 | private var _agalcode:ByteArray = null; 57 | private var _error:String = ""; 58 | 59 | private var debugEnabled:Boolean = false; 60 | 61 | private static var initialized:Boolean = false; 62 | public var verbose:Boolean = false; 63 | 64 | // ====================================================================== 65 | // Getters 66 | // ---------------------------------------------------------------------- 67 | public function get error():String { return _error; } 68 | public function get agalcode():ByteArray { return _agalcode; } 69 | 70 | // ====================================================================== 71 | // Constructor 72 | // ---------------------------------------------------------------------- 73 | public function AGALMiniAssembler( debugging:Boolean = false ):void 74 | { 75 | debugEnabled = debugging; 76 | if ( !initialized ) 77 | init(); 78 | } 79 | // ====================================================================== 80 | // Methods 81 | // ---------------------------------------------------------------------- 82 | public function assemble( mode:String, source:String ):ByteArray 83 | { 84 | var start:uint = getTimer(); 85 | 86 | _agalcode = new ByteArray(); 87 | _error = ""; 88 | 89 | var isFrag:Boolean = false; 90 | 91 | if ( mode == FRAGMENT ) 92 | isFrag = true; 93 | else if ( mode != VERTEX ) 94 | _error = 'ERROR: mode needs to be "' + FRAGMENT + '" or "' + VERTEX + '" but is "' + mode + '".'; 95 | 96 | agalcode.endian = Endian.LITTLE_ENDIAN; 97 | agalcode.writeByte( 0xa0 ); // tag version 98 | agalcode.writeUnsignedInt( 0x1 ); // AGAL version, big endian, bit pattern will be 0x01000000 99 | agalcode.writeByte( 0xa1 ); // tag program id 100 | agalcode.writeByte( isFrag ? 1 : 0 ); // vertex or fragment 101 | 102 | var lines:Array = source.replace( /[\f\n\r\v]+/g, "\n" ).split( "\n" ); 103 | var nest:int = 0; 104 | var nops:int = 0; 105 | var i:int; 106 | var lng:int = lines.length; 107 | 108 | for ( i = 0; i < lng && _error == ""; i++ ) 109 | { 110 | var line:String = new String( lines[i] ); 111 | line = line.replace( REGEXP_OUTER_SPACES, "" ); 112 | 113 | // remove comments 114 | var startcomment:int = line.search( "//" ); 115 | if ( startcomment != -1 ) 116 | line = line.slice( 0, startcomment ); 117 | 118 | // grab options 119 | var optsi:int = line.search( /<.*>/g ); 120 | var opts:Array; 121 | if ( optsi != -1 ) 122 | { 123 | opts = line.slice( optsi ).match( /([\w\.\-\+]+)/gi ); 124 | line = line.slice( 0, optsi ); 125 | } 126 | 127 | // find opcode 128 | var opCode:Array = line.match( /^\w{3}/ig ); 129 | if ( !opCode ) 130 | { 131 | if ( line.length >= 3 ) 132 | trace( "warning: bad line "+i+": "+lines[i] ); 133 | continue; 134 | } 135 | var opFound:OpCode = OPMAP[ opCode[0] ]; 136 | 137 | // if debug is enabled, output the opcodes 138 | if ( debugEnabled ) 139 | trace( opFound ); 140 | 141 | if ( opFound == null ) 142 | { 143 | if ( line.length >= 3 ) 144 | trace( "warning: bad line "+i+": "+lines[i] ); 145 | continue; 146 | } 147 | 148 | line = line.slice( line.search( opFound.name ) + opFound.name.length ); 149 | 150 | // nesting check 151 | if ( opFound.flags & OP_DEC_NEST ) 152 | { 153 | nest--; 154 | if ( nest < 0 ) 155 | { 156 | _error = "error: conditional closes without open."; 157 | break; 158 | } 159 | } 160 | if ( opFound.flags & OP_INC_NEST ) 161 | { 162 | nest++; 163 | if ( nest > MAX_NESTING ) 164 | { 165 | _error = "error: nesting to deep, maximum allowed is "+MAX_NESTING+"."; 166 | break; 167 | } 168 | } 169 | if ( ( opFound.flags & OP_FRAG_ONLY ) && !isFrag ) 170 | { 171 | _error = "error: opcode is only allowed in fragment programs."; 172 | break; 173 | } 174 | if ( verbose ) 175 | trace( "emit opcode=" + opFound ); 176 | 177 | agalcode.writeUnsignedInt( opFound.emitCode ); 178 | nops++; 179 | 180 | if ( nops > MAX_OPCODES ) 181 | { 182 | _error = "error: too many opcodes. maximum is "+MAX_OPCODES+"."; 183 | break; 184 | } 185 | 186 | // get operands, use regexp 187 | var regs:Array; 188 | if ( USE_NEW_SYNTAX ) 189 | regs = line.match( /vc\[([vif][acost]?)(\d*)?(\.[xyzw](\+\d{1,3})?)?\](\.[xyzw]{1,4})?|([vif][acost]?)(\d*)?(\.[xyzw]{1,4})?/gi ); 190 | else 191 | regs = line.match( /vc\[([vof][actps]?)(\d*)?(\.[xyzw](\+\d{1,3})?)?\](\.[xyzw]{1,4})?|([vof][actps]?)(\d*)?(\.[xyzw]{1,4})?/gi ); 192 | 193 | if ( !regs || regs.length != opFound.numRegister ) 194 | { 195 | _error = "error: wrong number of operands. found "+regs.length+" but expected "+opFound.numRegister+"."; 196 | break; 197 | } 198 | 199 | var badreg:Boolean = false; 200 | var pad:uint = 64 + 64 + 32; 201 | var regLength:uint = regs.length; 202 | 203 | for ( var j:int = 0; j < regLength; j++ ) 204 | { 205 | var isRelative:Boolean = false; 206 | var relreg:Array = regs[ j ].match( /\[.*\]/ig ); 207 | if ( relreg && relreg.length > 0 ) 208 | { 209 | regs[ j ] = regs[ j ].replace( relreg[ 0 ], "0" ); 210 | 211 | if ( verbose ) 212 | trace( "IS REL" ); 213 | isRelative = true; 214 | } 215 | 216 | var res:Array = regs[j].match( /^\b[A-Za-z]{1,2}/ig ); 217 | if ( !res ) 218 | { 219 | _error = "error: could not parse operand "+j+" ("+regs[j]+")."; 220 | badreg = true; 221 | break; 222 | } 223 | var regFound:Register = REGMAP[ res[ 0 ] ]; 224 | 225 | // if debug is enabled, output the registers 226 | if ( debugEnabled ) 227 | trace( regFound ); 228 | 229 | if ( regFound == null ) 230 | { 231 | _error = "error: could not parse operand "+j+" ("+regs[j]+")."; 232 | badreg = true; 233 | break; 234 | } 235 | 236 | if ( isFrag ) 237 | { 238 | if ( !( regFound.flags & REG_FRAG ) ) 239 | { 240 | _error = "error: register operand "+j+" ("+regs[j]+") only allowed in vertex programs."; 241 | badreg = true; 242 | break; 243 | } 244 | if ( isRelative ) 245 | { 246 | _error = "error: register operand "+j+" ("+regs[j]+") relative adressing not allowed in fragment programs."; 247 | badreg = true; 248 | break; 249 | } 250 | } 251 | else 252 | { 253 | if ( !( regFound.flags & REG_VERT ) ) 254 | { 255 | _error = "error: register operand "+j+" ("+regs[j]+") only allowed in fragment programs."; 256 | badreg = true; 257 | break; 258 | } 259 | } 260 | 261 | regs[j] = regs[j].slice( regs[j].search( regFound.name ) + regFound.name.length ); 262 | //trace( "REGNUM: " +regs[j] ); 263 | var idxmatch:Array = isRelative ? relreg[0].match( /\d+/ ) : regs[j].match( /\d+/ ); 264 | var regidx:uint = 0; 265 | 266 | if ( idxmatch ) 267 | regidx = uint( idxmatch[0] ); 268 | 269 | if ( regFound.range < regidx ) 270 | { 271 | _error = "error: register operand "+j+" ("+regs[j]+") index exceeds limit of "+(regFound.range+1)+"."; 272 | badreg = true; 273 | break; 274 | } 275 | 276 | var regmask:uint = 0; 277 | var maskmatch:Array = regs[j].match( /(\.[xyzw]{1,4})/ ); 278 | var isDest:Boolean = ( j == 0 && !( opFound.flags & OP_NO_DEST ) ); 279 | var isSampler:Boolean = ( j == 2 && ( opFound.flags & OP_SPECIAL_TEX ) ); 280 | var reltype:uint = 0; 281 | var relsel:uint = 0; 282 | var reloffset:int = 0; 283 | 284 | if ( isDest && isRelative ) 285 | { 286 | _error = "error: relative can not be destination"; 287 | badreg = true; 288 | break; 289 | } 290 | 291 | if ( maskmatch ) 292 | { 293 | regmask = 0; 294 | var cv:uint; 295 | var maskLength:uint = maskmatch[0].length; 296 | for ( var k:int = 1; k < maskLength; k++ ) 297 | { 298 | cv = maskmatch[0].charCodeAt(k) - "x".charCodeAt(0); 299 | if ( cv > 2 ) 300 | cv = 3; 301 | if ( isDest ) 302 | regmask |= 1 << cv; 303 | else 304 | regmask |= cv << ( ( k - 1 ) << 1 ); 305 | } 306 | if ( !isDest ) 307 | for ( ; k <= 4; k++ ) 308 | regmask |= cv << ( ( k - 1 ) << 1 ); // repeat last 309 | } 310 | else 311 | { 312 | regmask = isDest ? 0xf : 0xe4; // id swizzle or mask 313 | } 314 | 315 | if ( isRelative ) 316 | { 317 | var relname:Array = relreg[0].match( /[A-Za-z]{1,2}/ig ); 318 | var regFoundRel:Register = REGMAP[ relname[0]]; 319 | if ( regFoundRel == null ) 320 | { 321 | _error = "error: bad index register"; 322 | badreg = true; 323 | break; 324 | } 325 | reltype = regFoundRel.emitCode; 326 | var selmatch:Array = relreg[0].match( /(\.[xyzw]{1,1})/ ); 327 | if ( selmatch.length==0 ) 328 | { 329 | _error = "error: bad index register select"; 330 | badreg = true; 331 | break; 332 | } 333 | relsel = selmatch[0].charCodeAt(1) - "x".charCodeAt(0); 334 | if ( relsel > 2 ) 335 | relsel = 3; 336 | var relofs:Array = relreg[0].match( /\+\d{1,3}/ig ); 337 | if ( relofs.length > 0 ) 338 | reloffset = relofs[0]; 339 | if ( reloffset < 0 || reloffset > 255 ) 340 | { 341 | _error = "error: index offset "+reloffset+" out of bounds. [0..255]"; 342 | badreg = true; 343 | break; 344 | } 345 | if ( verbose ) 346 | trace( "RELATIVE: type="+reltype+"=="+relname[0]+" sel="+relsel+"=="+selmatch[0]+" idx="+regidx+" offset="+reloffset ); 347 | } 348 | 349 | if ( verbose ) 350 | trace( " emit argcode="+regFound+"["+regidx+"]["+regmask+"]" ); 351 | if ( isDest ) 352 | { 353 | agalcode.writeShort( regidx ); 354 | agalcode.writeByte( regmask ); 355 | agalcode.writeByte( regFound.emitCode ); 356 | pad -= 32; 357 | } else 358 | { 359 | if ( isSampler ) 360 | { 361 | if ( verbose ) 362 | trace( " emit sampler" ); 363 | var samplerbits:uint = 5; // type 5 364 | var optsLength:uint = opts == null ? 0 : opts.length; 365 | var bias:Number = 0; 366 | for ( k = 0; k/g ); 129 | var opts:Array; 130 | if ( optsi != -1 ) 131 | { 132 | opts = line.slice( optsi ).match( /([\w\.\-\+]+)/gi ); 133 | line = line.slice( 0, optsi ); 134 | } 135 | 136 | // find opcode 137 | var opCode:Array = line.match( /^\w{3}/ig ); 138 | if ( !opCode ) 139 | { 140 | if ( line.length >= 3 ) 141 | trace( "warning: bad line "+i+": "+lines[i] ); 142 | continue; 143 | } 144 | var opFound:OpCode = OPMAP[ opCode[0] ]; 145 | 146 | // if debug is enabled, output the opcodes 147 | if ( debugEnabled ) 148 | trace( opFound ); 149 | 150 | if ( opFound == null ) 151 | { 152 | if ( line.length >= 3 ) 153 | trace( "warning: bad line "+i+": "+lines[i] ); 154 | continue; 155 | } 156 | 157 | line = line.slice( line.search( opFound.name ) + opFound.name.length ); 158 | 159 | if ( ( opFound.flags & OP_VERSION2 ) && version<2 ) 160 | { 161 | _error = "error: opcode requires version 2."; 162 | break; 163 | } 164 | 165 | if ( ( opFound.flags & OP_VERT_ONLY ) && isFrag ) 166 | { 167 | _error = "error: opcode is only allowed in vertex programs."; 168 | break; 169 | } 170 | 171 | if ( ( opFound.flags & OP_FRAG_ONLY ) && !isFrag ) 172 | { 173 | _error = "error: opcode is only allowed in fragment programs."; 174 | break; 175 | } 176 | if ( verbose ) 177 | trace( "emit opcode=" + opFound ); 178 | 179 | agalcode.writeUnsignedInt( opFound.emitCode ); 180 | nops++; 181 | 182 | if ( nops > MAX_OPCODES ) 183 | { 184 | _error = "error: too many opcodes. maximum is "+MAX_OPCODES+"."; 185 | break; 186 | } 187 | 188 | // get operands, use regexp 189 | var regs:Array; 190 | 191 | // will match both syntax 192 | regs = line.match( /vc\[([vof][acostdip]?)(\d*)?(\.[xyzw](\+\d{1,3})?)?\](\.[xyzw]{1,4})?|([vof][acostdip]?)(\d*)?(\.[xyzw]{1,4})?/gi ); 193 | 194 | if ( !regs || regs.length != opFound.numRegister ) 195 | { 196 | _error = "error: wrong number of operands. found "+regs.length+" but expected "+opFound.numRegister+"."; 197 | break; 198 | } 199 | 200 | var badreg:Boolean = false; 201 | var pad:uint = 64 + 64 + 32; 202 | var regLength:uint = regs.length; 203 | 204 | for ( var j:int = 0; j < regLength; j++ ) 205 | { 206 | var isRelative:Boolean = false; 207 | var relreg:Array = regs[ j ].match( /\[.*\]/ig ); 208 | if ( relreg && relreg.length > 0 ) 209 | { 210 | regs[ j ] = regs[ j ].replace( relreg[ 0 ], "0" ); 211 | 212 | if ( verbose ) 213 | trace( "IS REL" ); 214 | isRelative = true; 215 | } 216 | 217 | var res:Array = regs[j].match( /^\b[A-Za-z]{1,2}/ig ); 218 | if ( !res ) 219 | { 220 | _error = "error: could not parse operand "+j+" ("+regs[j]+")."; 221 | badreg = true; 222 | break; 223 | } 224 | var regFound:Register = REGMAP[ res[ 0 ] ]; 225 | 226 | // if debug is enabled, output the registers 227 | if ( debugEnabled ) 228 | trace( regFound ); 229 | 230 | if ( regFound == null ) 231 | { 232 | _error = "error: could not find register name for operand "+j+" ("+regs[j]+")."; 233 | badreg = true; 234 | break; 235 | } 236 | 237 | if ( isFrag ) 238 | { 239 | if ( !( regFound.flags & REG_FRAG ) ) 240 | { 241 | _error = "error: register operand "+j+" ("+regs[j]+") only allowed in vertex programs."; 242 | badreg = true; 243 | break; 244 | } 245 | if ( isRelative ) 246 | { 247 | _error = "error: register operand "+j+" ("+regs[j]+") relative adressing not allowed in fragment programs."; 248 | badreg = true; 249 | break; 250 | } 251 | } 252 | else 253 | { 254 | if ( !( regFound.flags & REG_VERT ) ) 255 | { 256 | _error = "error: register operand "+j+" ("+regs[j]+") only allowed in fragment programs."; 257 | badreg = true; 258 | break; 259 | } 260 | } 261 | 262 | regs[j] = regs[j].slice( regs[j].search( regFound.name ) + regFound.name.length ); 263 | //trace( "REGNUM: " +regs[j] ); 264 | var idxmatch:Array = isRelative ? relreg[0].match( /\d+/ ) : regs[j].match( /\d+/ ); 265 | var regidx:uint = 0; 266 | 267 | if ( idxmatch ) 268 | regidx = uint( idxmatch[0] ); 269 | 270 | if ( regFound.range < regidx ) 271 | { 272 | _error = "error: register operand "+j+" ("+regs[j]+") index exceeds limit of "+(regFound.range+1)+"."; 273 | badreg = true; 274 | break; 275 | } 276 | 277 | var regmask:uint = 0; 278 | var maskmatch:Array = regs[j].match( /(\.[xyzw]{1,4})/ ); 279 | var isDest:Boolean = ( j == 0 && !( opFound.flags & OP_NO_DEST ) ); 280 | var isSampler:Boolean = ( j == 2 && ( opFound.flags & OP_SPECIAL_TEX ) ); 281 | var reltype:uint = 0; 282 | var relsel:uint = 0; 283 | var reloffset:int = 0; 284 | 285 | if ( isDest && isRelative ) 286 | { 287 | _error = "error: relative can not be destination"; 288 | badreg = true; 289 | break; 290 | } 291 | 292 | if ( maskmatch ) 293 | { 294 | regmask = 0; 295 | var cv:uint; 296 | var maskLength:uint = maskmatch[0].length; 297 | for ( var k:int = 1; k < maskLength; k++ ) 298 | { 299 | cv = maskmatch[0].charCodeAt(k) - "x".charCodeAt(0); 300 | if ( cv > 2 ) 301 | cv = 3; 302 | if ( isDest ) 303 | regmask |= 1 << cv; 304 | else 305 | regmask |= cv << ( ( k - 1 ) << 1 ); 306 | } 307 | if ( !isDest ) 308 | for ( ; k <= 4; k++ ) 309 | regmask |= cv << ( ( k - 1 ) << 1 ); // repeat last 310 | } 311 | else 312 | { 313 | regmask = isDest ? 0xf : 0xe4; // id swizzle or mask 314 | } 315 | 316 | if ( isRelative ) 317 | { 318 | var relname:Array = relreg[0].match( /[A-Za-z]{1,2}/ig ); 319 | var regFoundRel:Register = REGMAP[ relname[0]]; 320 | if ( regFoundRel == null ) 321 | { 322 | _error = "error: bad index register"; 323 | badreg = true; 324 | break; 325 | } 326 | reltype = regFoundRel.emitCode; 327 | var selmatch:Array = relreg[0].match( /(\.[xyzw]{1,1})/ ); 328 | if ( selmatch.length==0 ) 329 | { 330 | _error = "error: bad index register select"; 331 | badreg = true; 332 | break; 333 | } 334 | relsel = selmatch[0].charCodeAt(1) - "x".charCodeAt(0); 335 | if ( relsel > 2 ) 336 | relsel = 3; 337 | var relofs:Array = relreg[0].match( /\+\d{1,3}/ig ); 338 | if ( relofs.length > 0 ) 339 | reloffset = relofs[0]; 340 | if ( reloffset < 0 || reloffset > 255 ) 341 | { 342 | _error = "error: index offset "+reloffset+" out of bounds. [0..255]"; 343 | badreg = true; 344 | break; 345 | } 346 | if ( verbose ) 347 | trace( "RELATIVE: type="+reltype+"=="+relname[0]+" sel="+relsel+"=="+selmatch[0]+" idx="+regidx+" offset="+reloffset ); 348 | } 349 | 350 | if ( verbose ) 351 | trace( " emit argcode="+regFound+"["+regidx+"]["+regmask+"]" ); 352 | if ( isDest ) 353 | { 354 | agalcode.writeShort( regidx ); 355 | agalcode.writeByte( regmask ); 356 | agalcode.writeByte( regFound.emitCode ); 357 | pad -= 32; 358 | } else 359 | { 360 | if ( isSampler ) 361 | { 362 | if ( verbose ) 363 | trace( " emit sampler" ); 364 | var samplerbits:uint = 5; // type 5 365 | var optsLength:uint = opts == null ? 0 : opts.length; 366 | var bias:Number = 0; 367 | for ( k = 0; k/g ); 129 | var opts:Array; 130 | if ( optsi != -1 ) 131 | { 132 | opts = line.slice( optsi ).match( /([\w\.\-\+]+)/gi ); 133 | line = line.slice( 0, optsi ); 134 | } 135 | 136 | // find opcode 137 | var opCode:Array = line.match( /^\w{3}/ig ); 138 | if ( !opCode ) 139 | { 140 | if ( line.length >= 3 ) 141 | trace( "warning: bad line "+i+": "+lines[i] ); 142 | continue; 143 | } 144 | var opFound:OpCode = OPMAP[ opCode[0] ]; 145 | 146 | // if debug is enabled, output the opcodes 147 | if ( debugEnabled ) 148 | trace( opFound ); 149 | 150 | if ( opFound == null ) 151 | { 152 | if ( line.length >= 3 ) 153 | trace( "warning: bad line "+i+": "+lines[i] ); 154 | continue; 155 | } 156 | 157 | line = line.slice( line.search( opFound.name ) + opFound.name.length ); 158 | 159 | if ( ( opFound.flags & OP_VERSION2 ) && version<2 ) 160 | { 161 | _error = "error: opcode requires version 2."; 162 | break; 163 | } 164 | 165 | if ( ( opFound.flags & OP_VERT_ONLY ) && isFrag ) 166 | { 167 | _error = "error: opcode is only allowed in vertex programs."; 168 | break; 169 | } 170 | 171 | if ( ( opFound.flags & OP_FRAG_ONLY ) && !isFrag ) 172 | { 173 | _error = "error: opcode is only allowed in fragment programs."; 174 | break; 175 | } 176 | if ( verbose ) 177 | trace( "emit opcode=" + opFound ); 178 | 179 | agalcode.writeUnsignedInt( opFound.emitCode ); 180 | nops++; 181 | 182 | if ( nops > MAX_OPCODES ) 183 | { 184 | _error = "error: too many opcodes. maximum is "+MAX_OPCODES+"."; 185 | break; 186 | } 187 | 188 | // get operands, use regexp 189 | var regs:Array; 190 | 191 | // will match both syntax 192 | regs = line.match( /vc\[([vofi][acostdip]?[d]?)(\d*)?((\.[xyzw])?(\+\d{1,3})?)?\](\.[xyzw]{1,4})?|([vofi][acostdip]?[d]?)(\d*)?(\.[xyzw]{1,4})?/gi ); 193 | 194 | if ( !regs || regs.length != opFound.numRegister ) 195 | { 196 | _error = "error: wrong number of operands. found "+regs.length+" but expected "+opFound.numRegister+"."; 197 | break; 198 | } 199 | 200 | var badreg:Boolean = false; 201 | var pad:uint = 64 + 64 + 32; 202 | var regLength:uint = regs.length; 203 | 204 | for ( var j:int = 0; j < regLength; j++ ) 205 | { 206 | var isRelative:Boolean = false; 207 | var relreg:Array = regs[ j ].match( /\[.*\]/ig ); 208 | if ( relreg && relreg.length > 0 ) 209 | { 210 | regs[ j ] = regs[ j ].replace( relreg[ 0 ], "0" ); 211 | 212 | if ( verbose ) 213 | trace( "IS REL" ); 214 | isRelative = true; 215 | } 216 | 217 | var res:Array = regs[j].match( /^\b[A-Za-z]{1,3}/ig ); 218 | if ( !res ) 219 | { 220 | _error = "error: could not parse operand "+j+" ("+regs[j]+")."; 221 | badreg = true; 222 | break; 223 | } 224 | var regFound:Register = REGMAP[ res[ 0 ] ]; 225 | 226 | // if debug is enabled, output the registers 227 | if ( debugEnabled ) 228 | trace( regFound ); 229 | 230 | if ( regFound == null ) 231 | { 232 | _error = "error: could not find register name for operand "+j+" ("+regs[j]+")."; 233 | badreg = true; 234 | break; 235 | } 236 | 237 | if ( isFrag ) 238 | { 239 | if ( !( regFound.flags & REG_FRAG ) ) 240 | { 241 | _error = "error: register operand "+j+" ("+regs[j]+") only allowed in vertex programs."; 242 | badreg = true; 243 | break; 244 | } 245 | if ( isRelative ) 246 | { 247 | _error = "error: register operand "+j+" ("+regs[j]+") relative adressing not allowed in fragment programs."; 248 | badreg = true; 249 | break; 250 | } 251 | } 252 | else 253 | { 254 | if ( !( regFound.flags & REG_VERT ) ) 255 | { 256 | _error = "error: register operand "+j+" ("+regs[j]+") only allowed in fragment programs."; 257 | badreg = true; 258 | break; 259 | } 260 | } 261 | 262 | regs[j] = regs[j].slice( regs[j].search( regFound.name ) + regFound.name.length ); 263 | //trace( "REGNUM: " +regs[j] ); 264 | var idxmatch:Array = isRelative ? relreg[0].match( /\d+/ ) : regs[j].match( /\d+/ ); 265 | var regidx:uint = 0; 266 | 267 | if ( idxmatch ) 268 | regidx = uint( idxmatch[0] ); 269 | 270 | if ( regFound.range < regidx ) 271 | { 272 | _error = "error: register operand "+j+" ("+regs[j]+") index exceeds limit of "+(regFound.range+1)+"."; 273 | badreg = true; 274 | break; 275 | } 276 | 277 | var regmask:uint = 0; 278 | var maskmatch:Array = regs[j].match( /(\.[xyzw]{1,4})/ ); 279 | var isDest:Boolean = ( j == 0 && !( opFound.flags & OP_NO_DEST ) ); 280 | var isSampler:Boolean = ( j == 2 && ( opFound.flags & OP_SPECIAL_TEX ) ); 281 | var reltype:uint = 0; 282 | var relsel:uint = 0; 283 | var reloffset:int = 0; 284 | 285 | if ( isDest && isRelative ) 286 | { 287 | _error = "error: relative can not be destination"; 288 | badreg = true; 289 | break; 290 | } 291 | 292 | if ( maskmatch ) 293 | { 294 | regmask = 0; 295 | var cv:uint; 296 | var maskLength:uint = maskmatch[0].length; 297 | for ( var k:int = 1; k < maskLength; k++ ) 298 | { 299 | cv = maskmatch[0].charCodeAt(k) - "x".charCodeAt(0); 300 | if ( cv > 2 ) 301 | cv = 3; 302 | if ( isDest ) 303 | regmask |= 1 << cv; 304 | else 305 | regmask |= cv << ( ( k - 1 ) << 1 ); 306 | } 307 | if ( !isDest ) 308 | for ( ; k <= 4; k++ ) 309 | regmask |= cv << ( ( k - 1 ) << 1 ); // repeat last 310 | } 311 | else 312 | { 313 | regmask = isDest ? 0xf : 0xe4; // id swizzle or mask 314 | } 315 | 316 | if ( isRelative ) 317 | { 318 | var relname:Array = relreg[0].match( /[A-Za-z]{1,3}/ig ); 319 | var regFoundRel:Register = REGMAP[ relname[0]]; 320 | if ( regFoundRel == null ) 321 | { 322 | _error = "error: bad index register"; 323 | badreg = true; 324 | break; 325 | } 326 | reltype = regFoundRel.emitCode; 327 | var selmatch:Array = relreg[0].match( /(\.[xyzw]{1,1})/ ); 328 | if ( selmatch.length==0 ) 329 | { 330 | _error = "error: bad index register select"; 331 | badreg = true; 332 | break; 333 | } 334 | relsel = selmatch[0].charCodeAt(1) - "x".charCodeAt(0); 335 | if ( relsel > 2 ) 336 | relsel = 3; 337 | var relofs:Array = relreg[0].match( /\+\d{1,3}/ig ); 338 | if ( relofs.length > 0 ) 339 | reloffset = relofs[0]; 340 | if ( reloffset < 0 || reloffset > 255 ) 341 | { 342 | _error = "error: index offset "+reloffset+" out of bounds. [0..255]"; 343 | badreg = true; 344 | break; 345 | } 346 | if ( verbose ) 347 | trace( "RELATIVE: type="+reltype+"=="+relname[0]+" sel="+relsel+"=="+selmatch[0]+" idx="+regidx+" offset="+reloffset ); 348 | } 349 | 350 | if ( verbose ) 351 | trace( " emit argcode="+regFound+"["+regidx+"]["+regmask+"]" ); 352 | if ( isDest ) 353 | { 354 | agalcode.writeShort( regidx ); 355 | agalcode.writeByte( regmask ); 356 | agalcode.writeByte( regFound.emitCode ); 357 | pad -= 32; 358 | } else 359 | { 360 | if ( isSampler ) 361 | { 362 | if ( verbose ) 363 | trace( " emit sampler" ); 364 | var samplerbits:uint = 5; // type 5 365 | var optsLength:uint = opts == null ? 0 : opts.length; 366 | var bias:Number = 0; 367 | for ( k = 0; k