In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Embedded PixelBender Generator

Embedded PixelBender Generator.
* pbjファイル(Pixel Bender Byte Code files)をコード内に埋め込むためのASクラスを生成するツールです.
* パラメータがある場合はgetter/setterも適宜自動生成します.
* 
* getter/setterを生成するためにpbjのディスアセンブラを作った後に,
* ShaderDataから必要な情報を取り出せることに気づき泣きました.
* pbjのディスアセンブラはまた機会があれば晒します.
* 
* 2010.08.04 パラメータの最大・最小・デフォルト値のgetterを追加
* 2010.08.04 getter/setterの命名規則を変更
* 2010.07.20 inputが複数ある場合にはMainCodeにinputの設定コードを表示するように設定
* 2010.07.13 Shaderのコンストラクタに初期化オブジェクトを渡せるように修正
* 2010.07.13 ShaderJobでの使用, 複数入力イメージ対応のためにInputのgetter/setterを追加
* 2010.07.12 パラメータのgetter/setter部分にデフォルト値が反映されていなかったのを修正
* 
* @author Yukiya Okuda<alumican.net>
Get Adobe Flash player
by alumican_net 04 Aug 2010
/**
 * Copyright alumican_net ( http://wonderfl.net/user/alumican_net )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/gD6k
 */

/**
 * Embedded PixelBender Generator.
 * pbjファイル(Pixel Bender Byte Code files)をコード内に埋め込むためのASクラスを生成するツールです.
 * パラメータがある場合はgetter/setterも適宜自動生成します.
 * 
 * getter/setterを生成するためにpbjのディスアセンブラを作った後に,
 * ShaderDataから必要な情報を取り出せることに気づき泣きました.
 * pbjのディスアセンブラはまた機会があれば晒します.
 * 
 * 2010.08.04 パラメータの最大・最小・デフォルト値のgetterを追加
 * 2010.08.04 getter/setterの命名規則を変更
 * 2010.07.20 inputが複数ある場合にはMainCodeにinputの設定コードを表示するように設定
 * 2010.07.13 Shaderのコンストラクタに初期化オブジェクトを渡せるように修正
 * 2010.07.13 ShaderJobでの使用, 複数入力イメージ対応のためにInputのgetter/setterを追加
 * 2010.07.12 パラメータのgetter/setter部分にデフォルト値が反映されていなかったのを修正
 * 
 * @author Yukiya Okuda<alumican.net>
 */
package
{
    import com.bit101.components.Label;
    import com.bit101.components.PushButton;
    import com.bit101.components.RadioButton;
    import com.bit101.components.TextArea;
    import flash.display.BlendMode;
    import flash.display.Shader;
    import flash.display.ShaderData;
    import flash.display.ShaderInput;
    import flash.display.ShaderParameter;
    import flash.display.ShaderParameterType;
    import flash.display.Sprite;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.FocusEvent;
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.events.TimerEvent;
    import flash.filters.ShaderFilter;
    import flash.net.FileFilter;
    import flash.net.FileReference;
    import flash.text.TextField;
    import flash.utils.ByteArray;
    import flash.utils.Timer;
    
    public class Main extends Sprite
    {
        private var _file:FileReference;
        private var _shader:Shader;
        private var _bytes:ByteArray;
        private var _inputs:Array;
        private var _parameters:Array;
        private var _metadata:Object;
        
        public function Main():void
        {
            Wonderfl.disable_capture();
            stage.scaleMode = StageScaleMode.NO_SCALE;
            
            var template:XML = <data><code><![CDATA[package
{
    import flash.display.Shader;
    import flash.utils.ByteArray;
    
    /**
     * %CLASS%
     * %META_DESCRIPTION%
     * @author %META_VENDER%
     * @version %META_VERSION%
     * @namespace %META_NAMESPACE%
     */
    class %CLASS% extends Shader
    {
        //Parameters
        %BEGIN_PARAMS%/**
         * (Parameter) %PARAM_NAME% %PARAM_AS3_TYPE_ARY%
         * %PARAM_DESCRIPTION%
         * @type %PARAM_PBJ_TYPE%
         * @minValue %PARAM_MIN_ARY%
         * @maxValue %PARAM_MAX_ARY%
         * @defaultValue %PARAM_DEFAULT_ARY%
         */
        public function get %PARAM_NAME%():Array { return data.%PARAM_NAME%.value; }
        public function set %PARAM_NAME%(value:Array):void { data.%PARAM_NAME%.value = value; }
        public function get %PARAM_NAME%_min():Array { return %PARAM_MIN_ARY%; }
        public function get %PARAM_NAME%_max():Array { return %PARAM_MAX_ARY%; }
        public function get %PARAM_NAME%_default():Array { return %PARAM_DEFAULT_ARY%; }
        public function get %PARAM_NAME%_type():String { return "%PARAM_PBJ_TYPE%"; }
        
        %END_PARAMS%//Inputs
        %BEGIN_INPUTS%/**
         * (Input) %INPUT_NAME%
         * @channels %INPUT_CHANNELS%
         */
        public function get %INPUT_NAME%():Object { return data.%INPUT_NAME%.input; }
        public function set %INPUT_NAME%(input:Object):void { data.%INPUT_NAME%.input = input; }
        public function get %INPUT_NAME%_width():int { return data.%INPUT_NAME%.width; }
        public function set %INPUT_NAME%_width(width:int):void { data.%INPUT_NAME%.width = width; }
        public function get %INPUT_NAME%_height():int { return data.%INPUT_NAME%.height; }
        public function set %INPUT_NAME%_height(height:int):void { data.%INPUT_NAME%.height = height; }
        
        %END_INPUTS%//Constructor
        public function %CLASS%(init:Object = null):void
        {
            if (_byte == null)
            {
                _byte = new ByteArray();
                for (var i:uint = 0, l:uint = _data.length; i < l; ++i) _byte.writeByte(_data[i]);
            }
            super(_byte);
            for (var prop:String in init) this[prop] = init[prop];
        }
        
        //Data
        private static var _byte:ByteArray = null;
        private static var _data:Vector.<int> = Vector.<int>(%DATA%);
    }
}]]></code><usage><filter><![CDATA[var myShader:%CLASS% = new %CLASS%();
var myFilter:ShaderFilter = new ShaderFilter(myShader);
%BEGIN_USAGE_INPUTS%myShader.%INPUT_NAME% = %INPUT_NAME%;
%END_USAGE_INPUTS%
//if target is DisplayObject
target.filters = [myFilter];

//if target is BitmapData
target.applyFilter(target, target.rect, new Point(), myFilter);]]></filter><shader><![CDATA[var myShader:%CLASS% = new %CLASS%();
%BEGIN_USAGE_INPUTS%myShader.%INPUT_NAME% = %INPUT_NAME%;
%END_USAGE_INPUTS%
//target is DisplayObject
target.blendMode = BlendMode.SHADER;
target.blendShader = myShader;]]></shader></usage></data>;
            
            var title:Label = new Label(this, 6, 0, "Embedded PixelBender Generator");
            title.scaleX = title.scaleY = 2;
            title.alpha = 0.7;
            
            new Label(this, 8, 333, "Main Code");
            var usageField:TextArea = new TextArea(this, 10, 353);
            usageField.width = 443;
            usageField.height = 100;
            usageField.textField.addEventListener(FocusEvent.FOCUS_IN, _selectField);
            
            var usageTypeFilter:RadioButton = new RadioButton(this, 359, 338, "Filter", true, function(e:Event):void {
                if (_shader) usageField.text = _generateCode(template.usage.filter.text());
            } );
            
            var usageTypeShader:RadioButton = new RadioButton(this, 409, 338, "Shader", false, function(e:Event):void {
                if (_shader) usageField.text = _generateCode(template.usage.shader.text());
            } );
            
            new Label(this, 8, 75, "Shader Code");
            var codeField:TextArea = new TextArea(this, 10, 95);
            codeField.width = 443;
            codeField.height = 230;
            codeField.textField.addEventListener(FocusEvent.FOCUS_IN, _selectField);
            
            _file = new FileReference();
            _file.addEventListener(Event.CANCEL, trace);
            _file.addEventListener(IOErrorEvent.IO_ERROR, trace);
            _file.addEventListener(SecurityErrorEvent.SECURITY_ERROR, trace);
            _file.addEventListener(Event.SELECT, function(e:Event):void
            {
                _file.load();
            } );
            _file.addEventListener(Event.COMPLETE, function(e:Event):void
            {
                _shader = new Shader(_bytes = _file.data);
                _inputs = new Array();
                _parameters = new Array();
                _metadata = new Object();
                var data:ShaderData = _shader.data;
                for (var prop:String in data)
                { 
                    if (data[prop] is ShaderInput) _inputs[data[prop].index] = data[prop];
                    else if (data[prop] is ShaderParameter) _parameters[data[prop].index] = data[prop];
                    else _metadata[prop] = data[prop];
                }
                codeField.text = _generateCode(template.code.text());
                usageField.text = _generateCode(usageTypeFilter.selected ? template.usage.filter.text() : template.usage.shader.text());
                codeField.textField.scrollV = 1;
                usageField.textField.scrollV = 1;
                saveButton.alpha = 1;
            } );
            
            var loadButton:PushButton = new PushButton(this, 10, 45, "Load .pbj File", function(e:Event):void {
                _file.browse([new FileFilter("Pixel Bender Byte Code files (*.pbj)", "*.pbj")]);
            } );
            loadButton.width = 215;
            
            var saveButton:PushButton = new PushButton(this, 239, 45, "Save .as File", function(e:Event):void {
                if (_shader) (new FileReference()).save(codeField.text, _metadata["name"] + ".as");
            } );
            saveButton.blendMode = BlendMode.LAYER;
            saveButton.width = 215;
            saveButton.alpha = 0.3;
        }
        
        private function _selectField(e:FocusEvent):void
        {
            var tf:TextField = TextField(e.target);
            var timer:Timer = new Timer(10);
            timer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void
            {
                e.target.removeEventListener(e.type, arguments.callee);
                var scroll:int = tf.scrollV;
                tf.setSelection(0,  tf.text.length);
                tf.scrollV = scroll;
            } );
            timer.start();
        }
        
        private function _generateCode(template:String, removeLF:Boolean = true):String
        {
            template = template.replace(/\r\n/g, "\n");
            template = template.replace(/\r/g, "\n");
            
            var byteList:Array = new Array();
            _bytes.position = 0;
            while (_bytes.bytesAvailable) byteList.push(_bytes.readByte());
            var byteString:String = "[" + byteList.join(", ") + "]";
            
            template = template.replace(/%CLASS%/g, _metadata["name"]);
            template = template.replace(/%DATA%/g, byteString);
            template = template.replace(/(.*?)%BEGIN_PARAMS%(.*?)%END_PARAMS%(.*?)/s, function(matched:String, capture0:String, capture1:String, capture2:String, index:int, string:String):String
            {
                var parameter:ShaderParameter;
                for (var index:int = 0; index < _parameters.length; ++index)
                {
                    parameter = _parameters[index];
                    var code:String = capture1;
                    
                    var type:String;
                    var length:int;
                    switch (parameter["type"])
                    {
                        case ShaderParameterType.FLOAT:
                            type = "Number";
                            length = 1;
                            break;
                        
                        case ShaderParameterType.FLOAT2:
                            type = "Number";
                            length = 2;
                            break;
                        
                        case ShaderParameterType.FLOAT3:
                            type = "Number";
                            length = 3;
                            break;
                        
                        case ShaderParameterType.FLOAT4:
                            type = "Number";
                            length = 4;
                            break;
                        
                        case ShaderParameterType.INT:
                            type = "int";
                            length = 1;
                            break;
                        
                        case ShaderParameterType.INT2:
                            type = "int";
                            length = 2;
                            break;
                        
                        case ShaderParameterType.INT3:
                            type = "int";
                            length = 3;
                            break;
                        
                        case ShaderParameterType.INT4:
                            type = "int";
                            length = 4;
                            break;
                        
                        case ShaderParameterType.BOOL:
                            type = "Boolean";
                            length = 1;
                            break;
                        
                        case ShaderParameterType.BOOL2:
                            type = "Boolean";
                            length = 2;
                            break;
                        
                        case ShaderParameterType.BOOL3:
                            type = "Boolean";
                            length = 3;
                            break;
                        
                        case ShaderParameterType.BOOL4:
                            type = "Boolean";
                            length = 4;
                            break;
                        
                        case ShaderParameterType.MATRIX2X2:
                            type = "Number";
                            length = 4;
                            break;
                        
                        case ShaderParameterType.MATRIX3X3:
                            type = "Number";
                            length = 9;
                            break;
                        
                        case ShaderParameterType.MATRIX4X4:
                            type = "Number";
                            length = 16;
                            break;
                    }
                    
                    var types:Array = new Array(length);
                    for (var i:int = 0; i < length; ++i) types[i] = type;
                    code = code.replace(/%PARAM_AS3_TYPE_ARY%/g, "[" + types.join(", ") + "]");
                    
                    code = code.replace(/%PARAM_AS3_TYPE%/g, type);
                    code = code.replace(/%PARAM_LENGTH%/g, length);
                    code = code.replace(/%PARAM_NAME%/g, parameter["name"]);
                    code = code.replace(/%PARAM_INDEX%/g, String(parameter["index"]));
                    code = code.replace(/%PARAM_PBJ_TYPE%/g, parameter["type"]);
                    code = code.replace(/%PARAM_DESCRIPTION%/g, parameter["description"] != null ? parameter["description"] : "%REMOVE_LINE%");
                    code = code.replace(/%PARAM_MIN_ARY%/g, parameter["minValue"] != null ? ("[" + parameter["minValue"].join(", ") + "]") : "%REMOVE_LINE%");
                    code = code.replace(/%PARAM_MAX_ARY%/g, parameter["maxValue"] != null ? ("[" + parameter["maxValue"].join(", ") + "]") : "%REMOVE_LINE%");
                    code = code.replace(/%PARAM_DEFAULT_ARY%/g, parameter["defaultValue"] != null ? ("[" + parameter["defaultValue"].join(", ") + "]") : "%REMOVE_LINE%");
                    
                    capture0 += code;
                }
                return capture0 + capture2;
            } );
            
            function replaceInput(template:String, capture0:String, capture1:String, capture2:String, usage:Boolean):String
            {
                if (usage && _inputs.length > 1) capture0 += "\n//set inputs\n";
                var input:ShaderInput;
                for (var index:int = usage ? 1 : 0; index < _inputs.length; ++index)
                {
                    input = _inputs[index];
                    var code:String = capture1;
                    
                    code = code.replace(/%INPUT_NAME%/g, input["name"]);
                    code = code.replace(/%INPUT_INDEX%/g, String(input["index"]));
                    code = code.replace(/%INPUT_CHANNELS%/g, String(input["channels"]));
                    
                    capture0 += code;
                }
                return capture0 + capture2;
            }
            
            template = template.replace(/(.*?)%BEGIN_INPUTS%(.*?)%END_INPUTS%(.*?)/s, function(matched:String, capture0:String, capture1:String, capture2:String, index:int, string:String):String
            {
                return replaceInput(template, capture0, capture1, capture2, false);
            } );
            template = template.replace(/(.*?)%BEGIN_USAGE_INPUTS%(.*?)%END_USAGE_INPUTS%(.*?)/s, function(matched:String, capture0:String, capture1:String, capture2:String, index:int, string:String):String
            {
                return replaceInput(template, capture0, capture1, capture2, true);
            } );
            
            template = template.replace(/%META_VENDER%/g, _metadata["vendor"] != null ? _metadata["vendor"] : "%REMOVE_LINE%");
            template = template.replace(/%META_VERSION%/g, _metadata["version"] != null ? _metadata["version"] : "%REMOVE_LINE%");
            template = template.replace(/%META_NAMESPACE%/g, _metadata["namespace"] != null ? _metadata["namespace"] : "%REMOVE_LINE%");
            template = template.replace(/%META_DESCRIPTION%/g, _metadata["description"] != null ? _metadata["description"] : "%REMOVE_LINE%");
            
            template = template.replace(/\n(.*?)%REMOVE_LINE%(.*?)\n/g, "\n");
            template = template.replace(/\n(.*?)%REMOVE_LINE%(.*?)\n/g, "\n");
            
            return template;
        }
    }
}