// Copyright (c) 2018 Tsukimi
/*:ja
 * @plugindesc 
 * @author Tsukimi
 * 
 * @param -- 画面トランジション --
 * @desc -- 画面トランジション設定 --
 * 
 * @param 画面フェードに適用
 * @desc 画面トランジションにトランジション効果を使うかどうか
 * 入力値: true/false (使う/使わない)
 * @default true
 * 
 * @param 画面フェード用画像
 * @desc フェード用のルール画像
 * img/ に transitions のフォルダーを作って、画像を入れてください
 * @default 
 * 
 * @param 画面フェードイン用画像
 * @desc フェードイン用のルール画像。
 * 設定されなかったらフェード用画像を使う
 * @default 
 * 
 * @param 画面フェードアウト用画像
 * @desc フェードイン用のルール画像。
 * 設定されなかったらフェード用画像を使う
 * @default 
 * 
 * @param 画面フェードの柔らかさ
 * @desc トランジション効果の柔らかさ。
 * 0か、正整数を入力してください。
 * @default 8
 * 
 * @param 画面フェード時間
 * @desc フェードイン・アウトに掛かる時間。
 * ツクールデフォルト：24(フレーム)
 * @default 36
 * 
 * 
 * @param -- メッセージウィンドウ --
 * @desc -- メッセージウィンドウ設定 --
 * 
 * @param メッセージウィンドウに適用
 * @desc メッセージウィンドウにトランジション効果を使うかどうか
 * 入力値: true/false (使う/使わない)
 * @default false
 * 
 * @param メッセージフェード用画像
 * @desc メッセージウィンドウのフェード用のルール画像
 * img/ に transitions のフォルダーを作って、画像を入れてください
 * @default 
 * 
 * @param メッセージフェード時間
 * @desc メッセージウィンドウのフェードイン・アウトに掛かる時間。
 * @default 24
 * 
 * 
 * @help 
 */
(function() {
    "use strict";
    var getBoolean = function(bString) { if(bString.toLowerCase() === 'off')return false; return true; };
    var getNumber  = function(nString) { return Number((nString || '')) || 0; };
    var pluginName = 'JsScript31Set';
    var getParamString = function(paramNames) {
        if (!Array.isArray(paramNames)) paramNames = [paramNames];
        for (var i = 0; i < paramNames.length; i++) {
            var name = PluginManager.parameters(pluginName)[paramNames[i]];
            if (name) return name;
        }
        return null;
    };
    var getParamNumber = function(paramNames) {
        var value = getParamString(paramNames);
        return Number((value || '')) || 0;
    };
    var getParamBoolean = function(paramNames) {
        var value = getParamString(paramNames);
        return (value || '').toUpperCase() === 'TRUE';
    };
    var _Game_Interpreter_pluginCommand      = Game_Interpreter.prototype.pluginCommand;
    Game_Interpreter.prototype.pluginCommand = function(command, args) {
        _Game_Interpreter_pluginCommand.apply(this, arguments);
        switch ((command || '').toUpperCase()) {
            case 'GWTRANSITION':
                $gameScreen._useGWTrans = getBoolean(args[0]);
                break;
            case 'GWTRANS_SETTING':
                switch ((args[0] || '').toUpperCase()) {
                    case 'FADEIMG':
                        $gameScreen._GWImg = args[1];
                        break;
                    case 'FADEINIMG':
                        $gameScreen._GWInImg = args[1];
                        break;
                    case 'FADEOUTIMG':
                        $gameScreen._GWOutImg = args[1];
                        break;
                    case 'DURATION':
                        $gameScreen._fadeDuration = getNumber(args[1]);
                        break;
                                                     }
                break;
            case 'GWFADE':
                // GWFADE PICTURE ID FADEIN IMG DURATION (SOFTNESS)
                switch ((args[0] || '').toUpperCase()) {
                    case 'CHARACTER':
                        var target = this.character(getNumber(args[1]));
                        if(target) {
                            target._GWInfo = $gameScreen.createGWInfo(args.slice(2));
                        }
                        break;
                    case 'PICTURE':
                        var target = $gameScreen.picture(getNumber(args[1]));
                        if(target) {
                            target._GWInfo = $gameScreen.createGWInfo(args.slice(2));
                        }
                        break;
                                                     }
                break;
            case 'GWMESSAGEFADE':
                $gameSystem.GWMessageSetting.useGW = getBoolean(args[0]);
                break;
            case 'GWMESSAGE_SETTING':
                switch ((args[0] || '').toUpperCase()) {
                    case 'FADEIMG':
                        $gameSystem.GWMessageSetting.imgName = args[1];
                        break;
                    case 'DURATION':
                        $gameSystem.GWMessageSetting.fadeSpeed = 256 / getNumber(args[1]);
                        break;
                                                     }
                break;
                                             }
    };
    if(!ImageManager.loadTransitions) {
        ImageManager.loadTransitions = function(filename, hue) {
            return this.loadBitmap('img/transitions/', filename, hue, false);
        };
    }
    SceneManager._useGWTrans    = getParamBoolean(['Use Custom Transition', '画面フェードに適用']);
    SceneManager._GWImg         = getParamString(['Transition Fade Image', '画面フェード用画像']);
    SceneManager._GWInImg       = getParamString(['Transition FadeIn Image', '画面フェードイン用画像']);
    SceneManager._GWOutImg      = getParamString(['Transition FadeOut Image', '画面フェードアウト用画像']);
    SceneManager.GWSoftness     = getParamNumber(['Transition Softness', '画面フェードの柔らかさ']);
    SceneManager._fadeDuration  = parseInt( getParamNumber(['Transition Duration', '画面フェード時間']) );
    SceneManager.useGWTrans = function() {
        return $gameScreen ? $gameScreen.useGWTrans() : this._useGWTrans;
    };
    SceneManager.GWImg = function() {
        return $gameScreen ? $gameScreen.GWImg() : this._GWImg;
    };
    SceneManager.GWInImg = function() {
        return $gameScreen ? $gameScreen.GWInImg() : (this._GWInImg || this._GWImg);
    };
    SceneManager.GWOutImg = function() {
        return $gameScreen ? $gameScreen.GWOutImg() : (this._GWOutImg || this._GWImg);
    };
    SceneManager.fadeDuration = function() {
        return $gameScreen ? $gameScreen.fadeDuration() : (this._fadeDuration || 24);
    };
    //  custom function: apply/remove Fade GWFilter (for Screen Fading)
    //  for Scene_Base and SpriteSet_Base (they share property: _fadeSprite)
    var applyFadeGWFilter = function(imgName) {
        var GWsprite = new Sprite(ImageManager.loadTransitions(imgName)),
            f = new PIXI.filters.GradientWipeFilter(GWsprite, SceneManager.GWSoftness);
        this.removeFadeGWFilter();
        var fArr = this._fadeSprite.filters || [];
        this._GWFadeFilter = f;
        fArr.push(f);
        this._fadeSprite.filters = fArr;
    };
    var removeFadeGWFilter = function() {
        if(!this._GWFadeFilter) return;
        var fArr = this._fadeSprite.filters || [];
        var index = fArr.indexOf(this._GWFadeFilter);
        if(index >= 0) fArr.splice(index, 1);
        this._fadeSprite.filters = fArr;
        this._GWFadeFilter = undefined;
    };
    //  custom function: apply/remove GWFilter (for Sprite/Window Fading)
    var applyGWFilter = function(imgName, softness) {
        var GWsprite = new Sprite(ImageManager.loadTransitions(imgName)),
            f = new PIXI.filters.GradientWipeFilter(GWsprite, softness);
        this.removeGWFilter();
        var fArr = this.filters || [];
        this._GWFilter = f;
        fArr.push(f);
        this.filters = fArr;
    };
    var removeGWFilter = function() {
        if(!this._GWFilter) return;
        var fArr = this.filters || [];
        var index = fArr.indexOf(this._GWFilter);
        if(index >= 0) fArr.splice(index, 1);
        this.filters = fArr;
        this._GWFilter = undefined;
    };
    Scene_Base.prototype.applyFadeGWFilter  = applyFadeGWFilter;
    Scene_Base.prototype.removeFadeGWFilter = removeFadeGWFilter;
    var _Scene_Base_startFadeIn = Scene_Base.prototype.startFadeIn;
    Scene_Base.prototype.startFadeIn = function(duration, white) {
        _Scene_Base_startFadeIn.apply(this, arguments);
        if(SceneManager.useGWTrans() && SceneManager.GWInImg()) {
            this.applyFadeGWFilter(SceneManager.GWInImg());
            this._GWFadeFilter.time = 255 + this._GWFadeFilter.softness;
            this._GWSpeed = (this._GWFadeFilter.time + 1) / this._fadeDuration;
        }
    };
    var _Scene_Base_startFadeOut = Scene_Base.prototype.startFadeOut;
    Scene_Base.prototype.startFadeOut = function(duration, white) {
        _Scene_Base_startFadeOut.apply(this, arguments);
        if(SceneManager.useGWTrans() && SceneManager.GWOutImg()) {
            this._fadeSprite.opacity = 255;
            this.applyFadeGWFilter(SceneManager.GWOutImg());
            this._GWSpeed = (255+1 + this._GWFadeFilter.softness) / this._fadeDuration;
        }
    };
    var _Scene_Base_updateFade = Scene_Base.prototype.updateFade;
    Scene_Base.prototype.updateFade = function() {
        if(!SceneManager.useGWTrans()) _Scene_Base_updateFade.apply(this, arguments);
        else {
            if (this._fadeDuration > 0 && this._GWFadeFilter) {
                this._GWFadeFilter.time += - this._fadeSign * (this._GWSpeed || 0);
                this._fadeDuration--;
                if(this._fadeDuration === 0) {
                    this.removeFadeGWFilter();
                    this._fadeSprite.opacity = 127.5 - this._fadeSign * 127.5;
                }
            }
        }
    };
    Scene_Base.prototype.fadeSpeed = function() {
        return SceneManager.fadeDuration();
    };
    Game_Screen.prototype.fadeDuration = function() {
        return this._fadeDuration;
    };
    Game_Interpreter.prototype.fadeSpeed = function() {
        return $gameScreen.fadeDuration();
    };
    var _Game_Screen_initialize = Game_Screen.prototype.initialize;
    Game_Screen.prototype.initialize = function() {
        _Game_Screen_initialize.apply(this, arguments);
        this._fadeDuration  = parseInt( getParamNumber(['Transition Duration', '画面フェード時間']) );
        this._useGWTrans    = getParamBoolean(['Use Custom Transition', '画面フェードに適用']);
        this._GWImg         = getParamString(['Transition Fade Image', '画面フェード用画像']);
        this._GWInImg       = getParamString(['Transition FadeIn Image', '画面フェードイン用画像']);
        this._GWOutImg      = getParamString(['Transition FadeOut Image', '画面フェードアウト用画像']);
    };
    Game_Screen.prototype.useGWTrans = function() {return this._useGWTrans;};
    var _Game_Screen_startFadeOut = Game_Screen.prototype.startFadeOut;
    Game_Screen.prototype.startFadeOut = function(duration) {
        _Game_Screen_startFadeOut.apply(this, arguments);
        this._needFilter = -1;
    };
    var _Game_Screen_startFadeIn = Game_Screen.prototype.startFadeIn;
    Game_Screen.prototype.startFadeIn = function(duration) {
        _Game_Screen_startFadeIn.apply(this, arguments);
        this._needFilter = 1;
    };
    Game_Screen.prototype.GWImg = function() {
        return this._GWImg;
    };
    Game_Screen.prototype.GWInImg = function() {
        return this._GWInImg || this._GWImg;
    };
    Game_Screen.prototype.GWOutImg = function() {
        return this._GWOutImg || this._GWImg;
    };
    //  necessary settings of game screen fading (actually applying/removing GWFilter)
    Spriteset_Base.prototype.applyFadeGWFilter  = applyFadeGWFilter;
    Spriteset_Base.prototype.removeFadeGWFilter = removeFadeGWFilter;
    var _Spriteset_Base_updateScreenSprites = Spriteset_Base.prototype.updateScreenSprites;
    Spriteset_Base.prototype.updateScreenSprites = function() {
        _Spriteset_Base_updateScreenSprites.apply(this, arguments);
        if(!$gameScreen.useGWTrans()) return;
        if($gameScreen._needFilter) {
            this.applyFadeGWFilter($gameScreen._needFilter>0 ? $gameScreen.GWInImg():$gameScreen.GWOutImg());
            $gameScreen._needFilter = undefined;
        }
        if($gameScreen._fadeOutDuration || $gameScreen._fadeInDuration) {
            this._fadeSprite.opacity = 255;
            var f = this._GWFadeFilter;
            f.time = (255+1 + f.softness) * (255-$gameScreen.brightness())/255;
        }
        else {
            this.removeFadeGWFilter();
        }
    };
    var _Sprite_update = Sprite.prototype.update;
    Sprite.prototype.update = function() {
        _Sprite_update.apply(this, arguments);
        this.updateGW();
    };
    Sprite.prototype.updateGW = function() {
        var info = this.getGWInfo();
        this.checkGWNeed(info);
        if(this._GWFilter) this.updateGWParam(info);
    };
    Sprite.prototype.getGWInfo = function() {
        return null;
    };
    Sprite.prototype.applyGWFilter = function(info) {
        applyGWFilter.apply(this, [info.imgName, info.softness]);
    };
    Sprite.prototype.removeGWFilter = function() {
        removeGWFilter.apply(this, arguments);
    };
    Sprite.prototype.checkGWNeed = function(info) {
        if(!info) {
            this.removeGWFilter();
            return;
        }
        if(!this._GWFilter || info.isNew) {
            this.applyGWFilter(info);
            info.isNew = false;
        }
    };
    Sprite.prototype.updateGWParam = function(info) {
        this._GWFilter.time = info.time;
    };
    Sprite_Character.prototype.getGWInfo = function() {
        if(!this._character) return null;
        return this._character.GWInfo();
    };
    Sprite_Picture.prototype.getGWInfo = function() {
        if(!this.picture()) return null;
        return this.picture().GWInfo();
    };
    Game_Character.prototype.GWInfo = function() {
        return this._GWInfo;
    };
    Game_Picture.prototype.GWInfo = function() {
        return this._GWInfo;
    };
    var _Game_Character_update = Game_Character.prototype.update;
    Game_Character.prototype.update = function() {
        _Game_Character_update.apply(this, arguments);
        this.updateGWInfo();
    };
    Game_Character.prototype.updateGWInfo = function() {
        if(!this._GWInfo) return;
        this._GWInfo.time += this._GWInfo.fadeSpeed;
        if(this._GWInfo.time>(255+this._GWInfo.softness)) {
            this._GWInfo = undefined;
        }
        else if(this._GWInfo.time<0) {
            this._GWInfo = undefined;
            this._opacity = 0;
        }
    };
    var _Game_Picture_update = Game_Picture.prototype.update;
    Game_Picture.prototype.update = function() {
        _Game_Picture_update.apply(this, arguments);
        this.updateGWInfo();
    };
    Game_Picture.prototype.updateGWInfo = function() {
        if(!this._GWInfo) return;
        this._GWInfo.time += this._GWInfo.fadeSpeed;
        if(this._GWInfo.time>(255+this._GWInfo.softness)) {
            this._GWInfo = undefined;
        }
        else if(this._GWInfo.time<0) {
            this._GWInfo = undefined;
            this._opacity = 0;
        }
    };
    Game_Screen.prototype.createGWInfo = function(args) {
        var info = {};
        if(!args[1]) return undefined;
        info.isNew = true;
        info.imgName = args[1];
        var duration = getNumber(args[2]) || 1;
        info.softness = getNumber(args[3]);
        if(args[0].toUpperCase() === "FADEIN") {
            info.time = 0;
            info.fadeSpeed = (255+1 + info.softness) / duration;
            return info;
        }
        else if(args[0].toUpperCase() === "FADEOUT") {
            info.time = 255 + info.softness;
            info.fadeSpeed = -(255+1 + info.softness) / duration;
            return info;
        }
        return undefined;
    };
    var _Window_Base_initialize = Window_Base.prototype.initialize;
    Window_Base.prototype.initialize = function(x, y, width, height) {
        _Window_Base_initialize.apply(this, arguments);
        this.initGW();
    };
    Window_Base.prototype.initGW = function() {
        var setting = {};
        setting.useGW = false;
        setting.imgName = "";
        setting.fadeSpeed = 256/8;
        this.GWSetting = setting;
        if(typeof(this._GWopenness)==='undefined') this._GWopenness = this.openness;
    };
    Window_Base.prototype.useGW = function() {
        return this.GWSetting.useGW;
    };
    Window_Base.prototype.GWFadeSpeed = function() {
        return this.GWSetting.fadeSpeed;
    };
    Window_Base.prototype.GWImgName = function() {
        return this.GWSetting.imgName;
    };
    var _Window_Base_updateOpen = Window_Base.prototype.updateOpen;
    Window_Base.prototype.updateOpen = function() {
        if(!this.useGW()) {
            _Window_Base_updateOpen.apply(this, arguments);
            this._GWopenness = this.openness; 
            return;
        }
        if (this._opening) {
            this._GWopenness += this.GWSetting.fadeSpeed;
            this.checkGWNeed();
            this._GWFilter.time = this._GWopenness;
            if (this.isOpen()) {
                this._opening = false;
                this.removeGWFilter();
            }
        }
    };
    var _Window_Base_updateClose = Window_Base.prototype.updateClose;
    Window_Base.prototype.updateClose = function() {
        if(!this.useGW()) {
            _Window_Base_updateClose.apply(this, arguments);
            this._GWopenness = this.openness; 
            return;
        }
        if (this._closing) {
            this._GWopenness -= this.GWSetting.fadeSpeed;
            this.checkGWNeed();
            this._GWFilter.time = this._GWopenness;
            if (this.isClosed()) {
                this._closing = false;
                this.openness = 0;
                this.removeGWFilter();
            }
        }
    };
    var _Window_Base_open = Window_Base.prototype.open;
    Window_Base.prototype.open = function() {
        if(!this.useGW()) {
            _Window_Base_open.apply(this, arguments);
            return;
        }
        if (!this.isOpen()) {
            this.applyGWFilter();
            this._GWFilter.time = this._GWopenness;
            this._opening = true;
            this.openness = 255;
        }
        this._closing = false;
    };
    var _Window_Base_close = Window_Base.prototype.close;
    Window_Base.prototype.close = function() {
        if(!this.useGW()) {
            _Window_Base_close.apply(this, arguments);
            return;
        }
        if (!this.isClosed()) {
            this.applyGWFilter();
            this._GWFilter.time = this._GWopenness;
            if(this.contents) this.contents.clear();
            this._closing = true;
        }
        this._opening = false;
    };
    var _Window_Base_isOpen = Window_Base.prototype.isOpen;
    Window_Base.prototype.isOpen = function() {
        if(!this.useGW()) return _Window_Base_isOpen.apply(this, arguments);
        return this._GWopenness >= 255;
    };
    var _Window_Base_isClosed = Window_Base.prototype.isClosed;
    Window_Base.prototype.isClosed = function() {
        if(!this.useGW()) return _Window_Base_isClosed.apply(this, arguments);
        return this._GWopenness <= 0;
    };
    Window_Base.prototype.checkGWNeed = function() {
        if( !this._GWFilter && (this._closing || this._opening) ) {
            this.applyGWFilter();
            this._GWFilter.time = this._GWopenness = this.openness;
            this.openness = 255;
            if(this.contents) this.contents.clear();
        }
    };
    Window_Base.prototype.applyGWFilter = function() {
        applyGWFilter.apply(this, [this.GWSetting.imgName, 0]);
    };
    Window_Base.prototype.removeGWFilter = function() {
        removeGWFilter.apply(this, arguments);
    };
    Window_Message.prototype.initGW = function() {
        this.GWSetting = $gameSystem.GWMessageSetting;
        if(typeof(this._GWopenness)==='undefined') this._GWopenness = 0;
    };
    var _Game_System_initialize = Game_System.prototype.initialize;
    Game_System.prototype.initialize = function() {
        _Game_System_initialize.apply(this, arguments);
        var setting = {};
        setting.useGW = getParamBoolean(['Use Custom Message Fade', 'メッセージウィンドウに適用']);
        setting.imgName = getParamString(['Message Fade Image', 'メッセージフェード用画像']);
        setting.fadeSpeed = 256 / (getParamNumber(['Message Fade Duration', 'メッセージフェード時間']) || 8);
        this.GWMessageSetting = setting;
    };
})();
/************************************************************
/* PIXI Gradient Wipe Filter
/* DO NOT RERODUCE THE FOLLOWING SCRIPT BEFORE AGREEMENT.
*************************************************************/
/**
 * The GradientWipeFilter applies a Luma Wipe effect to an object. (or, Luma Fade/Gradient Fade ...)
 * TODO -> Description about Gradient Wipe Filter ... <br>
 * ![original](../tools/screenshots/dist/original.png)![filter](../tools/screenshots/dist/bloom.png)
 *
 * @class
 * @extends PIXI.Filter
 * @memberof PIXI.filters
 * @param {PIXI.Sprite} [gradientSprite] set gradient sprite. See 'gradientSprite' property.
 * @param {number} [softness=0] set softness of fading(wiping). See 'softness' property.
 * @param {boolean} [reverse=false] set brightness reverse. See 'reverse' property.
 * @param {number} [time=0] set current time. See 'time' property.
 */
PIXI.filters.GradientWipeFilter = function(gradientSprite, softness, reverse, time) {
    this._gradientSprite = gradientSprite;
    if (softness === null || softness === undefined) {
        softness = 0;
    }
    if (time === null || time === undefined) {
        time = 0;
    }
    reverse = !!reverse;
     /**
     * Current time. Fading(wiping) time duration is from 0 to 255+softness.
     * Increasing means fading(wiping) in; decreasing means fading(wiping) out.
     * 
     * @member {number}
     * @default 0
     */
    this.time = time;
    var vertexShader = null;
    var fragmentShader = [
        'precision mediump float;',
        '',
        'varying vec2 vTextureCoord;',
        '',
        "uniform vec2 dimensions;",
        "uniform vec4 filterArea;",
        'uniform float softness;',
        'uniform bool reverse;',
        'uniform float time;',
        'uniform sampler2D uSampler;',
        'uniform sampler2D gradSampler;',
        '',
        'float getBrightness(vec4 color)',
        '{',
        'return (0.299*color.r + 0.587*color.g + 0.114*color.b);',
        '}',
        '',
        'void main(void)',
        '{',
        "   vec2 realCoord = (vTextureCoord * filterArea.xy) / dimensions;",
        '   float alpha = 0.0;',
        '   float brightness = getBrightness(texture2D(gradSampler, realCoord));',
        '   if(reverse) brightness = 1.0 - brightness;',
        '',
        '   if(softness > 1.0) { 
        '       alpha = (- brightness * 255.0 + time) / softness;',
        '   }',
        '   else {',
        '       alpha = - brightness * 255.0 + time;',
        '   }',
        '',
        '   alpha = clamp(alpha, 0.0, 1.0);',
        '   vec4 finalColor = texture2D(uSampler, vTextureCoord);',
        '   finalColor *= alpha;',
        '   gl_FragColor = finalColor;',
        '',
        '}'
    ].join('\r\n');
    var uniforms = {};
    uniforms.gradSampler = {type: 'sampler2D', value: gradientSprite._texture};
    uniforms.softness = {type: '1f', value: softness};
    uniforms.reverse = {type: 'bool', value: reverse};
    uniforms.time = {type: '1f', value: this.time};
    uniforms.dimensions= { type: '4fv', value: new Float32Array([0, 0, 0, 0]) };
    PIXI.Filter.call(this,
        vertexShader,
        fragmentShader,
        uniforms
    );
};
PIXI.filters.GradientWipeFilter.prototype = Object.create(PIXI.Filter.prototype);
PIXI.filters.GradientWipeFilter.prototype.constructor = PIXI.filters.GradientWipeFilter;
PIXI.filters.GradientWipeFilter.prototype.apply = function(filterManager, input, output, clear){
        this.uniforms.dimensions[0] = parseFloat(input.sourceFrame.width);
        this.uniforms.dimensions[1] = parseFloat(input.sourceFrame.height);
        this.uniforms.time = this.time;
        filterManager.applyFilter(this, input, output, clear);
};
Object.defineProperties(PIXI.filters.GradientWipeFilter.prototype, {
     /**
     * The gradient sprite of the wiping effect.
     * Will be referenced and autofit to the render object.
     * 
     * @member {PIXI.Sprite}
     */
    gradientSprite: {
        get: function() {
            return this._gradientSprite;
        },
        set: function(value) {
            this._gradientSprite = value;
            this.uniforms.gradSampler = value._texture;
        }
    },
     /**
     * The softness of the Transiting ExEffectSetting. 0 or positive integer would be desirable.
     * One Pixel will take "softness" time to turn from transparent(alpha=0.0) to non-transparent(alpha=1.0).
     * 
     * @member {number}
     * @default 0
     */
    softness: {
        get: function() {
            return this.uniforms.softness;
        },
        set: function(value) {
            this.uniforms.softness = value;
        }
    },
     /**
     * At normal, Render Object will first fade(wipe) in from darker part of the gradientSprite.
     * If 'reverse' property is true, Render Object will first fade in from brighter part.
     * 
     * @member {boolean}
     * @default false
     */
    reverse: {
        get: function() {
            return this.uniforms.reverse;
        },
        set: function(value) {
            this.uniforms.reverse = value;
        }
    },
     /**
     * Check if the wiping effect(fade in) is end.
     * Won't affect any parameter of the wiping effect, just for user convinience.
     * 
     * @member {boolean}
     */
    isFadeInEnd: {
        get: function() {
            return (this.time >= this.softness+255);
        }
    },
     /**
     * Check if the wiping effect(fade out) is end.
     * Won't affect any parameter of the wiping effect, just for user convinience.
     * 
     * @member {boolean}
     */
    isFadeOutEnd: {
        get: function() {
            return (this.time <= 0);
        }
    }
});
